Jump to content

Recommended Posts

Posted

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:

  1. Create new-pssession from linux machine
  2. Execute autoit script using PsExec with -i parameter with the required session
  3. 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

#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!!!

Posted (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 by MattHiggs
Posted (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 by takkar
Posted (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 by MattHiggs
Posted
  1. The parameter $buttonName in the function  PressButtonInApplication is used in switch case statement  
  2. 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
  3. 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 !!!

Posted (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 by MattHiggs
Posted

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.

Posted (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?

gzRvmDz.png

Consolewrite doesn't do much good if you do not have a console to write to.

Edited by MattHiggs
Posted

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.

Posted
  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.

Posted

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.

Posted

 

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.  

Posted

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.

Posted

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.

Posted

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

Posted

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. 

Posted

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 ?

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 account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...