A trouble with automation of Windows RDP through console - python

A brief description of my problem:
1.
My Jenkins job is required to establish an RDP connection to another machine to perform some activities.
2.
Until recently, the default password was maintained between sessions. But now some settings have changed, and the password needs to be reentered by hand each time I creating a new RDP session.
I prepared a short python script interacting with the Windows gui via the win32gui package.
I built a stand alone executable file from this script using the pyinstaller.
And finally I added a call to this executable file directly to the job.
Somethig like that:
while attempts:
security_window_title = "Windows Security"
try:
hwnd_credentials = win32gui.FindWindow(0, security_window_title)
window_controls = []
win32gui.EnumChildWindows(hwnd_credentials, collect_window_control, None)
focus_on_window(hwnd_credentials)
sleep(0.5)
prev_user_login = window_controls[2]["hwnd"]
x = int(window_controls[1]["x"] + 80)
y = int(window_controls[1]["y"] + 20)
click(x, y)
type_message(password)
ok_button = window_controls[6]["hwnd"]
push_button(ok_button)
except win32gui.error:
sleep(1)
attempts -= 1
if not attempts:
raise RuntimeError("Can't interact with window: {}.".format(security_window_title))
else:
break
while attempts:
sleep(timeout)
attempts -= 1
if check_connection_started():
break
if check_certificate_errors():
for control in window_controls[::-1]:
if control["text"] == "&Yes":
push_button(control["hwnd"])
if not attempts:
raise RuntimeError("Connection not established.")
3.
This would not be a problem when script running from the job working with the fully functional Windows ui. I can find a window in which my script is supposed to specify a password using the win32gui python package. I can generate all the appropriate keyboard events to enter a password.
Using RDP via console provides me a very strange set of windows-like objects which I can not interact with using the win32gui python package the same way as with ordinary windows. For example, I do locate a window with non zero hwnd and with text property equal to "Remote Desktop Connection". But I can't focus on such a window using the basic method win32gui.SetForegroundWindow(hwnd). This leads to an unnamed win32gui exception.
Is there any possibility to transfer the password to the desired control of the desired window-like structure, so that the job does not interrupt its execution?
Thank you so much for any help.

I can focus on both "Remote Desktop Connection" and "Windows Security" with win32gui.SetForegroundWindow(hwnd).
Sample code:
import win32api
import win32gui
import win32con
import time
from pynput.keyboard import Key, Controller
def main():
Remote = "Remote Desktop Connection"
Security = "Windows Security"
try:
hwnd_Remote = win32gui.FindWindow(0, Remote)
print(hwnd_Remote)
win32gui.ShowWindow(hwnd_Remote,win32con.SW_SHOWNORMAL)
win32gui.SetForegroundWindow(hwnd_Remote)
keyboard = Controller()
keyboard.type('ipaddress')
keyboard.press(Key.enter)
keyboard.release(Key.enter)
time.sleep(3)
hwnd_Security = win32gui.FindWindow(0, Security)
print(hwnd_Security)
win32gui.ShowWindow(hwnd_Security,win32con.SW_SHOWNORMAL)
win32gui.SetForegroundWindow(hwnd_Security)
keyboard.type('password')
keyboard.press(Key.enter)
keyboard.release(Key.enter)
except win32gui.error:
raise RuntimeError("Can't interact with window: {}.".format(Remote))
if __name__ == "__main__":
main()
Make sure that the foreground process did not disable calls to the SetForegroundWindow function. Add the LockSetForegroundWindow(LSFW_UNLOCK) or AllowSetForegroundWindow(ASFW_ANY) to enable the call of SetForegroundWindow.

Related

pywinauto - how to right-click in systemtray, select an item then subitem

I have an application in the hidden part of the systray in Windows 10. I am trying to connect to the application, right-click on it, and then select something like "About". I understand that once I have the target application, I need to connect to the application, which I do in line 25 of the code, but I cannot get further from there.
This is the code I have so far:
from pywinauto import Application
import time
app = Application(backend="uia").connect(path="explorer.exe")
systemTray = app.window(class_name="Shell_TrayWnd")
systemTray.child_window(title="Notification Chevron").click_input(button="left")
#systemTray.print_control_identifiers()
time.sleep(0.25)
list_box = Application(backend="uia").connect(class_name="NotifyIconOverflowWindow")
list_box_win = list_box.window(class_name="NotifyIconOverflowWindow")
list_box_win.wait('visible', timeout=30, retry_interval=3)
# List all the icons in the systray
for notification_area in list_box_win.children():
for app_in_tray in notification_area.children():
print(str(app_in_tray))
target_app = list_box_win.child_window(title="TrayStatus Pro Trial 4.6\r\nCaps Lock: Off")
target_app.wait('visible', timeout=30, retry_interval=3)
target_app.click_input(button="right")
target_app.target_app.print_control_identifiers()
target_app.dump_tree()
sysapp = Application().connect(path='TrayStatus.exe')
sysapp.menu_select('About') #This part fails
Application() class represents the application and sometime it fails to identify the window. Having said that, you have not mentioned the backend of the application at the beginning you have used UIA backend so figure out for the line sysapp = Application().connect(path='TrayStatus.exe') as well and add, Also adding timeout=10 parameter to the connect() works many times.
Still if the above option doesn't not work for you then try using Desktop class.
again you can mention backend of your choice and compatibility, there is no such way to identify backend of application.
window2 = Desktop(backend="win32").window(title='title of the rayStatus.exe window')
you will need to import -
from pywinauto import Desktop.
Finally you can print the titile of windows using
list_window = Desktop().windows()
for window in list_window:
window.window_texts() # this should print the all open window names on desktop

How can I use psutil to constantly check if a process/application is running?

I tried using the answer in Python check if a process is running or not to help me. However, when I tried to implement psutil into my code it did not work successfully.
I created a GUI using tkinter and I am trying to make it so as soon as the application opens, the application will be moved to the selected location. Am I using psutil incorrectly?
Here's a portion of my code:
if clicked1.get() == "Google Chrome"
os.startfile(r"{google chrome file location}")
time.sleep(4) # time.sleep to allow the application time to open
app.connect(path=r"{google chrome file location}")
app1 = app.top_window()
app1.move_window(-20, -2150) # moves application to those x and y coordinates
time.sleep(.5) # gives the application time to move before maximizing
app1.maximize()
Here's my code when I tried to implement psutil:
if clicked1.get() == "Google Chrome"
os.startfile(r"{google chrome file location}")
while True:
if "Google Chrome" in (p.name() for p in psutil.process_iter()
app.connect(path=r"{google chrome file location}")
app1 = app.top_window()
app1.move_window(-20, -2150) # moves application to those x and y coordinates
time.sleep(.5) # gives the application time to move before maximizing
app1.maximize()
break # breaks from the loop when the application is started and is moved

Waiting for user input when controlling 3rd party application via python script

I am writing a script intended to be used by members of a project team. As part of the script, I am launching a 3rd party proprietary application run through Citrix. I am going to use the script mostly to send keys to this application, but the first step once it launches is for the user to log in.
Because I would like the user to log in while the script is running, rather than asking for user/pass from some kind of GUI input earlier, and because the time it takes Citrix to launch varies, I would like to include some kind of logic that detects when the user has logged in and then resume the script from there, rather than including an obnoxiously long implicit wait or risking the script timing out.
Is there a way to detect user keystrokes using win32com.client (or to detect a change in state of the application itself)? See below for the relevant code to launch the app:
import win32com.client
shell = win32com.client.Dispatch("WScript.Shell")
shell.Run('C:\Citrix\[rest of path])
EDIT:
Per Vasily's suggestion in the comments below, I attempted to adapt the "hook and listen" code to my scenario, but was unsuccessful. When I launch my file, I don't even get an exception message in my terminal, I get a Windows pop-up that says Python encountered a problem and needs to quit.
This is how I adapted it:
#[omitting import lines for brevity]
def on_timer():
"""Callback by timer out"""
win32api.PostThreadMessage(main_thread_id, win32con.WM_QUIT, 0, 0);
def on_event(args):
"""Callback for keyboard and mouse events"""
if isinstance(args, KeyboardEvent):
for i in range(1,100):
time.sleep(1)
if args.pressed_key == 'Lcontrol':
break
def init():
hk = Hook()
hk.handler = on_event
main_thread_id = win32api.GetCurrentThreadId()
t = Timer(55.0, on_timer) # Quit after 55 seconds
t.start()
hk.hook(keyboard=True, mouse=True)
At the point when the 3rd party Citrix app begins to launch in my main script, I call hookandlisten.init().
As a reminder, my goal is to wait until the user sends a certain keystroke (here I chose Control) before proceeding with the rest of the main script.
Solved this by eliminating the timer and unhooking the keyboard upon the correct keystroke:
import win32api
import win32con
from pywinauto.win32_hooks import Hook
from pywinauto.win32_hooks import KeyboardEvent
from pywinauto.win32_hooks import MouseEvent
def on_event(args):
"""Callback for keyboard and mouse events"""
if isinstance(args, KeyboardEvent):
if args.current_key == 'Lcontrol' and args.event_type == 'key down':
print("Success")
hk.unhook_keyboard()
return
def init():
hk.handler = on_event
hk.hook(keyboard=True, mouse=False)
hk = Hook()

Make script executable on OSX?

I wrote a little script in python, it basically open a VPN program and then it open a new window in firefox and log in a website. I would like now to avoid launching it from the terminal, and be able to make double click on it(is it called an executable file?). How can I achieve this? I work with python 2.7 on a mac 10.11.1.
I am sorry for eventual mistake but programming is still quite new for me!
import webbrowser
from Quartz.CoreGraphics import *
import subprocess as sp
import time
import pyautogui
def mouseEvent(type, posx, posy):
theEvent = CGEventCreateMouseEvent(None, type, (posx,posy),
kCGMouseButtonLeft)
CGEventPost(kCGHIDEventTap, theEvent)
def mousemove(posx,posy):
mouseEvent(kCGEventMouseMoved, posx,posy);
def mouseclick(posx,posy):
mouseEvent(kCGEventLeftMouseDown, posx,posy);
mouseEvent(kCGEventLeftMouseUp, posx,posy);
# opening strong VPN
xfoil = sp.Popen(['open', '-a', '/Applications/StrongVPN Client.app'], stdin=sp.PIPE, stdout=sp.PIPE)
time.sleep(5)
mouseclick(900,360);
time.sleep(1)
#open firefox and going to skygo
b = webbrowser.get('firefox')
b.open('http://skygo.sky.it/index.shtml')
time.sleep( 5 )
mouseclick(1010,225);
#clicking on login;
mouseclick(1074,123);
time.sleep( 5 )
mouseclick(830,225);
time.sleep(2)
pyautogui.typewrite('myusername')
time.sleep(1)
#inserting password
mouseclick(830,290);
time.sleep(2)
pyautogui.typewrite('mypassword')
time.sleep(1)
#pressing enter
mouseclick(920,400);
time.sleep(2)
#mousemove(int(currentpos.x),int(currentpos.y)); # Restore mouse position
You can use Automator to wrap a Python script to a normal Mac App bundle that can be opened from OSX GUI.
Better still, what you are trying to achieve can be probably better implemented as set of action in Automator without having to write any Python scripts.

Basic GUI for shell commands with Python Tk threading and os.system calls

I'm doing a basic GUI to provide some user feedback after some shell commands, a little interface for a shell script really.
Showing a TK window, waiting for a os.system call to complete and updating the TK window multiple times, after each os.system call.
How does threading work with tk?
That's it, thanks!
The standard threading library should be perfectly okay if you run it with Tk. This source says, that you should just let the main thread run the gui and create threads for your os.system() calls.
You could write an abstraction like this which updates your GUI upon finishing the task:
def worker_thread(gui, task):
if os.system(str(task)) != 0:
raise Exception("something went wrong")
gui.update("some info")
The thread can be started using thread.start_new_thread(function, args[, kwargs]) from the standard library. See the documentation here.
Just a basic example of what I did, with credit to Constantinius for pointing out that Thread works with Tk!
import sys, thread
from Tkinter import *
from os import system as run
from time import sleep
r = Tk()
r.title('Remote Support')
t = StringVar()
t.set('Completing Remote Support Initalisation ')
l = Label(r, textvariable=t).pack()
def quit():
#do cleanup if any
r.destroy()
but = Button(r, text='Stop Remote Support', command=quit)
but.pack(side=LEFT)
def d():
sleep(2)
t.set('Completing Remote Support Initalisation, downloading, please wait ')
run('sleep 5') #test shell command
t.set('Preparing to run download, please wait ')
run('sleep 5')
t.set("OK thanks! Remote Support will now close ")
sleep(2)
quit()
sleep(2)
thread.start_new_thread(d,())
r.mainloop()

Categories