takkar Posted May 14, 2020 Posted May 14, 2020 Hello everyone, I am new to using AutoIt. I have tried my best to get answers in the help forums and documentation but I did not get anything that I was looking for. So, I apologize in advance if I am asking something which is already there. I am using AutoIt to perform tasks like pressing a button on a proprietary application running on a remote windows machine. The function returns whether the action was successful or not. For example, if the window in which button has to be pressed does not exist then function should return a message that action could not be completed because the required window is not open. As per my research I can only use PsExec.exe from PSTools as it gives an option for interaction with desktop. The process that I am following is as follows: Create new-pssession from linux machine Execute autoit script using PsExec with -i parameter with the required session Get response The relevant code is as follows: Linux code $password = ConvertTo-SecureString "<password>" -AsPlainText -Force $cred = New-Object System.Management.Automation.PSCredential ("<username>", $password) $session = New-PSSession -ComputerName "<computer ip>" -Credential $cred -Authentication Negotiate Invoke-Command -Session $session -ScriptBlock {$userSession=<active session number>} Invoke-Command -Session $session -ScriptBlock {C:\Windows\PsTools\PsExec -s "\\$env:computername" -u "$env:computername\<username>" -p "<password>" -i $userSession $env:AUTOITSCRIPT_PATH\<scriptName>.exe "<buttonName>"} AutoIt script code expandcollapse popup#AutoIt3Wrapper_Change2CUI=Y ;this is needed to write output to CLI $result = PressButtonInApplication($CmdLine[1]) ; call function and pass the arguments If @error = 0XDEAD And @extended = 0XBEEF Then $result= "Error in function call" EndIf ; return back the response ConsoleWrite($result & @CRLF ) #cs ##################################### Function definition starts from here ##################################### #CE #CS This function presses a button. @param $buttonName: Name of the button to be pressed @returns String message containing whether the result has passed or failed #CE Func PressButtonInApplication($buttonName) Local $BUTTON1_STRING = "Button 1" Local $BUTTON2_STRING = "Button 2" Local $WINDOW_NAME = "<Window Name>" Local $BUTTON_PANEL_CONTROL_ID = "[CLASS:<button class panel>;INSTANCE:<instance number>]" LOCAL $SUCCESS_MESSAGE = "SUCCESS" ; check if we have the window open $hButton = ControlGetHandle($WINDOW_NAME,"",$BUTTON_PANEL_CONTROL_ID) If $hButton Then WinActivate($WINDOW_NAME) ; bring window to the front in case it is minimised or inactive Switch $buttonName Case $ACCEPT_BUTTON_STRING ControlClick($WINDOW_NAME,"",$BUTTON_PANEL_CONTROL_ID,"left",1,216,27) ; press button 1 Case $REJECT_BUTTON_STRING ControlClick($WINDOW_NAME,"",$BUTTON_PANEL_CONTROL_ID,"left",1,633,37) ; press button 2 Case Else Return "Error: button name "& $buttonName &" is not recognised" EndSwitch Return $SUCCESS_MESSAGE Else Return "Error: Window Not Found" EndIf EndFunc The response is as follows: PsExec v2.2 - Execute processes remotely Copyright (C) 2001-2016 Mark Russinovich Sysinternals - www.sysinternals.com Connecting to local system... Starting PSEXESVC service on local system...Connecting with PsExec service on <computer name>...Starting C:\<path to auto it>\<script name>.exe on <computer name>... C:\<path to auto it>\<script name>.exe exited on <computer name> with error code 0. As you can see there is no response that I got from here. Any help would be appreciated. If this is not the right method please suggest any other method Cheers!!!
MattHiggs Posted May 14, 2020 Posted May 14, 2020 (edited) Ok. Hold one. Let me see if I am understanding this correctly. You are logged onto a linux machine, on which you have powershell for every system installed. You then use powershell on the linux machine to create a ps-session to remotely connect to what I assume is a windows machine. Then, on the Windows machine, you run psexec to run an autoit script on the local machine to press whatever button you are trying to press. Is that correct? Edited May 14, 2020 by MattHiggs
takkar Posted May 14, 2020 Author Posted May 14, 2020 (edited) Quote Ok. Hold one. Let me see if I am understanding this correctly. You are logged onto a linux machine, on which you have powershell for every system installed. You then use powershell on the linux machine to create a ps-session to remotely connect to what I assume is a windows machine. Then, on the Windows machine, you run psexec to run an autoit script on the local machine to press whatever button you are trying to press. Is that correct? Expand Yes, I have powershell 6.6.2 installed on my linux machine. Link Then I create PSSession to connect to windows machine using cmdlet New-PsSession and then use psexec to run autoit script. Please let me know if you need any further info Edited May 14, 2020 by takkar
MattHiggs Posted May 14, 2020 Posted May 14, 2020 (edited) Also, the autoit function doesn't really make a lot of sense. If the autoit script is going to be looking for the same window and same control each time, why not just hard code the values into the autoit script and not even bother with a function? Also, how is the GUI the autoit script is supposed to interact with being launched? Is it being launched within the autoit script, or by an external process? Edited May 14, 2020 by MattHiggs
takkar Posted May 14, 2020 Author Posted May 14, 2020 The parameter $buttonName in the function PressButtonInApplication is used in switch case statement The function is looking for same window for now. Later this function will evolve into be able to click different windows and buttons depending on the user input The application GUI with which AutoIt script will interact will be launched separately. In most cases the application window will already be there before this function is called. For off-chance when someone by mistake closes the window on which the button is supposed to be clicked I have created the check to return the relevant message. Hope this helps !!!
MattHiggs Posted May 14, 2020 Posted May 14, 2020 (edited) Looking a little more closely at the code, is this button you are trying to click not being detected as a single control? The fact that you specify a location within the control to click tells me that this button isn't itself a standalone control? Edited May 14, 2020 by MattHiggs
takkar Posted May 14, 2020 Author Posted May 14, 2020 Yes, the button control is not really well made. Luckily, this script is running fine
MattHiggs Posted May 14, 2020 Posted May 14, 2020 On 5/14/2020 at 9:15 PM, takkar said: Yes, the button control is not really well made. Luckily, this script is running fine Expand So you don't need anymore help?
takkar Posted May 14, 2020 Author Posted May 14, 2020 I am sorry, if I was not clear. I needed help with getting responses via PsExec.exe If you see the response mentioned in the first post of this thread. The response that I get after executing script via PSExec does not contain any result that I write to console. I am putting the response here for your easy reference: PsExec v2.2 - Execute processes remotely Copyright (C) 2001-2016 Mark Russinovich Sysinternals - www.sysinternals.com Connecting to local system... Starting PSEXESVC service on local system...Connecting with PsExec service on <computer name>...Starting C:\<path to auto it>\<script name>.exe on <computer name>... C:\<path to auto it>\<script name>.exe exited on <computer name> with error code 0. This response should also have message "SUCCESS" in it . However, I do not get anything.
MattHiggs Posted May 14, 2020 Posted May 14, 2020 (edited) On 5/14/2020 at 9:21 PM, takkar said: I am sorry, if I was not clear. I needed help with getting responses via PsExec.exe If you see the response mentioned in the first post of this thread. The response that I get after executing script via PSExec does not contain any result that I write to console. I am putting the response here for your easy reference: PsExec v2.2 - Execute processes remotely Copyright (C) 2001-2016 Mark Russinovich Sysinternals - www.sysinternals.com Connecting to local system... Starting PSEXESVC service on local system...Connecting with PsExec service on <computer name>...Starting C:\<path to auto it>\<script name>.exe on <computer name>... C:\<path to auto it>\<script name>.exe exited on <computer name> with error code 0. This response should also have message "SUCCESS" in it . However, I do not get anything. Expand Just to make sure, did you compile the autoit script as a commandline script? Consolewrite doesn't do much good if you do not have a console to write to. Edited May 14, 2020 by MattHiggs
takkar Posted May 14, 2020 Author Posted May 14, 2020 I am not sure about that I thought using #AutoIt3Wrapper_Change2CUI=Y was enough. Can you tell me how do I access that window as I do not get this window while building/compiling.
MattHiggs Posted May 14, 2020 Posted May 14, 2020 On 5/14/2020 at 9:36 PM, takkar said: I am not sure about that I thought using #AutoIt3Wrapper_Change2CUI=Y was enough. Can you tell me how do I access that window as I do not get this window while building/compiling. Expand The line that you mention is the equivalent of checking that box. If the line you mentioned is in your script, then your script should compile as a cui. Ok. So here is what I would do. Rather than return a string within the function, I would instead Return the function "Seterror". This allows you to specify the value returned by the @error and @extended macros as well as a return value. For example: $result = PressButtonInApplication($CmdLine[1]) ; call function and pass the arguments If @error <> 0 Then $result= "Error in function call" EndIf ; return back the response ConsoleWrite($result & @CRLF ) Func PressButtonInApplication($buttonName) Local $BUTTON1_STRING = "Button 1" Local $BUTTON2_STRING = "Button 2" Local $WINDOW_NAME = "<Window Name>" Local $BUTTON_PANEL_CONTROL_ID = "[CLASS:<button class panel>;INSTANCE:<instance number>]" LOCAL $SUCCESS_MESSAGE = "SUCCESS" ; check if we have the window open $hButton = ControlGetHandle($WINDOW_NAME,"",$BUTTON_PANEL_CONTROL_ID) If $hButton Then WinActivate($WINDOW_NAME) ; bring window to the front in case it is minimised or inactive Switch $buttonName Case $ACCEPT_BUTTON_STRING ControlClick($WINDOW_NAME,"",$BUTTON_PANEL_CONTROL_ID,"left",1,216,27) ; press button 1 Case $REJECT_BUTTON_STRING ControlClick($WINDOW_NAME,"",$BUTTON_PANEL_CONTROL_ID,"left",1,633,37) ; press button 2 Case Else Return Seterror (3, -1, "Error: button name " & $buttonName & " is not recognised") #so error code EndSwitch Return Setextended ( 0, $SUCCESS_MESSAGE ) Else Return Seterror ( 2, -1, "Error: Window Not Found" ) EndIf EndFunc Or something to that effect. I am not sure where you are pulling the values that you are looking for in your original function, but if you yourself control the error code that is read after your function call, you can more easily control the flow of your script. Also, if you actually set the error code, you can test to see if psexec returns a different error code value.
takkar Posted May 14, 2020 Author Posted May 14, 2020 Using SetError will set the @error macro value which will help me set up $result variable. Controlling the flow of the script is not an issue. The problem is ConsoleWrite($result & @CRLF ) is not giving me anything in the output of the script.
MattHiggs Posted May 14, 2020 Posted May 14, 2020 Also, have you tried running the script that you have written locally on the computer to make sure that it is running correctly? As in, log into the remote computer. open a command line, and run the script to see if it returns the values you expect when running it standalone? First step in creating a complicated process like this to run remotely is to get it working on the local machine first and see if it returns the values you expect. If the script is running as it should locally, then we can focus on troubleshooting the remote execution. In all honesty, what you are trying to do is not easy, as the user that you connect to the remote machine with (generally) also needs to also be logged onto the remote machine. This is because the user needs to be logged in in order to actually load and display the GUI with which the script needs to interact. That is the easiest way to code the solution, but not necessarily the easiest to setup in the environment, as it requires the user that you use to remotely connect to the machine to be logged in to the machine whenever the script needs to run. There are a couple of things you can try that MIGHT help, but its a long shot.
takkar Posted May 14, 2020 Author Posted May 14, 2020 I ran the script locally and it works fine with all the messages showing up. I only get this problem when I have to use PsExec.exe and I was not able to find any other alternative.
MattHiggs Posted May 14, 2020 Posted May 14, 2020 Depending on the version of windows running on your remote machine, it may have a service available called the Interactive services detection service. This service enables user notification of user input for interactive services, which enables access to dialogs created by interactive services when they appear. If you include this code in your autoit script to forcefully enable that service, that COULD allow you to load the GUI and allow your script to interact with the controls even when the user is not logged in: $reg = RegRead ( "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Windows", "NoInteractiveServices" ) If @error Or $reg <> 0 Then SetError ( 0 ) RegWrite ( "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Windows", "NoInteractiveServices", "REG_DWORD", 0 ) EndIf RunWait ( @ComSpec & " /c net stop UIODetect", @SystemDir, @SW_HIDE ) RunWait ( @ComSpec & " /c net start UIODetect", @SystemDir, @SW_HIDE ) This will edit the registry to allow you to manually enable the the UIODetect service manually, as you normally are not able to without the registry modification.
MattHiggs Posted May 14, 2020 Posted May 14, 2020 By the way, do this without psexec. If the user account is logged into the machine or you are using the method I mentioned above, execute the autoit script directly. Also, did you compile the autoit script to require admin permissions to execute? Is the pssession you are running have admin permissions? Things you might want to account for. Also, rather than use powershell to remotely connect to the windows server, have you considered deploying openssh to the windows server and using native ssh to connect to the windows device? https://github.com/PowerShell/Win32-OpenSSH/releases
takkar Posted May 14, 2020 Author Posted May 14, 2020 I do not have any experience with your last two posts. I will need to do little bit of research and get back to you. Thank you for giving me these leads.
takkar Posted May 15, 2020 Author Posted May 15, 2020 I enabled interactive services detection services and ran the script again but that didnt work. I also tried different ways of creating session like using Enter-Session to execute the script. In this case the script is not able to find the window. Only difference between using PsExec and using the session to run the script is that the PsExec has -i parameter that helps in interaction between windows and the script. The PsSession does have admin permissions. So script not having permission should not be an issue. Is there any other information that you need from my side ?
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now