Send input to command line using AutoIt - input

I am new to autoit and am trying to automate the input to an .exe program. This executable does not have a gui and is run from the command window so can I use autoit to send the program specific input through the command window? If so how can I go about doing this?
Local $engine= "C:\Users\Davis\Desktop\Chess engine\stockfish32bit.exe"
Local $PID = RunWait(#ComSpec & " /k " & $engine, "", "#SW_MAXIMIZE")
;Insert code that sends program "uci" as input

This simple example shows how you can communicate with previously ran program.
; Demonstrates the use of StdinWrite()
#include <Constants.au3>
Local $foo = Run("sort.exe", #SystemDir, #SW_HIDE, $STDIN_CHILD + $STDOUT_CHILD)
; Write string to be sorted to child sort.exe's STDIN
StdinWrite($foo, "rat" & #CRLF & "cat" & #CRLF & "bat" & #CRLF)
; Calling with no 2nd arg closes stream
StdinWrite($foo)
; Read from child's STDOUT and show
Local $data
While True
$data &= StdoutRead($foo)
If #error Then ExitLoop
Sleep(25)
WEnd
MsgBox(0, "Debug", $data)

Local $engine= "C:\Users\Davis\Desktop\Chess engine\stockfish32bit.exe"
Local $PID = RunWait(#ComSpec & " /k " & $engine, "", "#SW_MAXIMIZE")
$hCmd=WinGetHandle($engine)
ControlSend($hCmd, "", "", "uci" & #CR)

Related

Milestone Camera Selector Software

I'm trying to create some AutoIT code for work to make launching our camera systems a bit easier. As of right now, I've been able to get my code to launch a gui, display a list of camera servers that you can add onto, and be able to add new servers to an internal directory. What I'm having a bit of trouble with is the section in which the program is supposed to switch to the newly launched Milestone software, type in the information, and click enter. I've found that the issue is linked to part of the start() function, in which WinWaitActive($handle) either isn't using the correct handle, or maybe the function I'm using is incorrect?
My end goal is to be able to wait 4 seconds, switch focus from whatever current window is selected to the newly opened Milestone window using either its handle or its PID, then send 2 TABs, the ip address, then send ENTER
#include <MsgBoxConstants.au3>
#include <Array.au3>
#include <ComboConstants.au3>
#include <ButtonConstants.au3>
#include <EditConstants.au3>
#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>
#include <GuiComboBox.au3>
#Region EDIT THE BELOW INFORMATION-------------------------------------------------------------------------------------------------------------------------------------------
Local Const $milestone = "C:\Program Files\Milestone\XProtect Smart Client\Client.exe" ;Path to software
Local $Title = "Milestone Camera Selector"
#EndRegion-------------------------------------------------------------------------------------------------------------------------------------------------------------------
#Region Script---------------------------------------------------------------------------------------------------------------------------------------------------------------
Local $iFileExists = FileExists($milestone) ;Check if the file exists, returns a 1 or 0
Global $list = IniReadSection(#TempDir & "\" & $Title & "\config.ini","Server") ;Read the ini file, this builds a 2D Array [X][0] is the key [X][1] is the value
HotKeySet("{F1}", "help")
If $iFileExists Then ;If FileExists = 1 (exists) then
If Not FileExists(#TempDir & "\" & $Title) Then ;If config directory does not exists then
Do
DirCreate(#TempDir & "\" & $Title) ;Create a directory in TempDir for the config.ini file to be stored locally
Until FileExists(#TempDir & "\" & $Title)
IniWrite(#TempDir & "\" & $Title & "\config.ini", "Server", "", "")
EndIf
Local $GUI = GUICreate($Title, 267, 115) ;Create the GUI
$start = GUICtrlCreateButton("Start", 40, 72, 65, 25) ;Create a button
$create = GUICtrlCreateButton("Add Server", 160, 72, 65, 25)
$server = GUICtrlCreateCombo("Select Server", 8, 8, 249, 25, $CBS_DROPDOWN) ;Create the combo box
For $i = 1 To UBound($list) - 1 ;Populate combo box with first value (name) from array
If $list[$i][0] <> "" Then GUICtrlSetData($server, $list[$i][0]) ;Ensure array is not empty and fill combox with KEYS
Next
$servername = GUICtrlCreateInput("Server Name", 8, 40, 121, 21)
GUICtrlSetState(-1, $GUI_HIDE)
$serverip = GUICtrlCreateInput("IP Address", 136, 40, 121, 21)
GUICtrlSetState(-1, $GUI_HIDE)
GUISetState(#SW_SHOW)
While 1 ;Enter loop until user closes or presses button
Switch GUIGetMsg()
Case $GUI_EVENT_CLOSE ;Exit when closed
Exit
Case $start ;Store selection into variable, delete the GUI, and run the start function
$selection = GUICtrlRead($server)
If $selection <> "Select Server" Then
GUIDelete()
start()
EndIf
Case $create
If GUICtrlRead($create) = "Add Server" Then
GUICtrlSetState($servername, $GUI_SHOW)
GUICtrlSetState($serverip, $GUI_SHOW)
GUICtrlSetData($create, "Create")
Else
If (GUICtrlRead($servername) <> "" And GUICtrlRead($servername) <> "Server Name" And GUICtrlRead($serverip) <> "" And GUICtrlRead($serverip) <> "IP Address") Then
IniWrite(#TempDir & "\" & $Title & "\config.ini", "Server", GUICtrlRead($servername), GUICtrlRead($serverip))
GUICtrlSetState($servername, $GUI_HIDE)
GUICtrlSetState($serverip, $GUI_HIDE)
GUICtrlSetData($create, "Add Server")
Else
MsgBox($MB_ICONINFORMATION, $Title, "Invalid Server Name and IP Address.")
EndIf
For $i = UBound($list) - 1 To 0 Step -1
_GUICtrlComboBox_DeleteString($server, $i)
Next
Local $list = IniReadSection(#TempDir & "\" & $Title & "\config.ini","Server")
For $i = 1 To UBound($list) - 1
If $list[$i][0] <> "" Then GUICtrlSetData($server, $list[$i][0])
Next
EndIf
EndSwitch
WEnd
Else ;otherwise, message
MsgBox($MB_SYSTEMMODAL, "", "Milestone XProtect wasn't found on this computer" & #CRLF)
EndIf
Func start()
$iPID = Run($milestone,"", #SW_SHOWNOACTIVATE) ;Runs the software and returns the Process ID
Sleep(4000) ;sleep for 4 seconds
If #error Then MsgBox(0, $Title, "The program could not launch.") ;If Run returns a 0 or error, there was a problem
$handle = _GetHandleFromPID($iPID) ;Retrieve the handle of the program ran, jump to the function below
If $handle = 0 Then MsgBox(0, $Title, "The handle could not be found.") ;If the Handle returned is 0, there was no match
Sleep(1000)
WinWaitActive($handle) ;Wait for the program to be activated
Send("{TAB}") ;send keystrokes to active window
Send("{TAB}")
For $i = 0 to UBound($list) - 1 ;Find the IP address that matches the selection and send it
If $list[$i][0] = $selection Then Send($list[$i][1])
Next
Send("{ENTER}")
Exit ;Exit for now until you can capture a succesful run
EndFunc
func _GetHandleFromPID($PID) ;Call function with the PID returned from Run function
$WinList = WinList() ;Assign WinList to a variable
for $i = 1 to $WinList[0][0] ;Run through each Window in WinList, 2D array [titles][handles]
If WinGetProcess($WinList[$i][1]) = $PID then ;Look for a Window with the correct PID
Return $WinList[$i][1] ;Assign the matching Windows handle to the variable
EndIf
Next
Return 0 ;Return 0 if no matches were found
EndFunc
Func help()
ShellExecute(#TempDir & "\" & $Title & "\config.ini")
EndFunc
#EndRegion--------------------------------------------------------------------------------------------------------------------------------------------------------------------
Once again, any help would be greatly appreciated in helping me finish this project I started months ago. Also, if you think this would be easier to achieve in a different programming language like python or AutoHotkey, please let me know! :)
My apologies on going MIA. I got really busy with things and did not find time to look into the details of the software.
Essentially what is happening is the PID returned is associated with a process called CiceroUIWndFrame (a parent process running in the background) and it is returning the handle of that process. Since that process never get's activated the script just stays paused waiting for it to pop up. Unfortunately due to the fact that the Milestone software does not have it's own PID (look at the Details tab within task manager, you will notice the Milestone software is just called client.exe) we cannot use a good method to obtain the correct handle.
The only solution that I am aware of is to obtain the handle of the active window. So this modified script will run the Milestone X Protect Software, wait 1 second (hopefully long enough to start) and obtain the handle of whatever program is active. It then sleeps for 4 additional seconds, and waits for you to activate the client again. So if you are in another window and wait several minutes, the moment you activate the client login again it will send the keystrokes.
The downfall to this method is that you are relying on the active window after launch to be Milestone (if it takes longer to load, you get the wrong handle, if you click out of focus before 1 second you get the wrong handle).
#include <MsgBoxConstants.au3>
#include <Array.au3>
#include <ComboConstants.au3>
#include <ButtonConstants.au3>
#include <EditConstants.au3>
#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>
#include <GuiComboBox.au3>
#include <AutoItConstants.au3>
#Region EDIT THE BELOW INFORMATION-------------------------------------------------------------------------------------------------------------------------------------------
Local Const $milestone = "C:\Program Files\Milestone\XProtect Smart Client\Client.exe" ;Path to software
Local $Title = "Program Title" ;Give me a name
Local $icon = "Full\Path\To\Icon.ico"
#EndRegion-------------------------------------------------------------------------------------------------------------------------------------------------------------------
#Region Script---------------------------------------------------------------------------------------------------------------------------------------------------------------
Local $iFileExists = FileExists($milestone) ;Check if the file exists, returns a 1 or 0
Global $list = IniReadSection(#TempDir & "\" & $Title & "\config.ini","Server") ;Read the ini file, this builds a 2D Array [X][0] is the key [X][1] is the value
HotKeySet("{F1}", "help")
If $iFileExists Then ;If FileExists = 1 (exists) then
If Not FileExists(#TempDir & "\" & $Title) Then ;If config directory does not exists then
Do
DirCreate(#TempDir & "\" & $Title) ;Create a directory in TempDir for the config.ini file to be stored locally
Until FileExists(#TempDir & "\" & $Title)
IniWrite(#TempDir & "\" & $Title & "\config.ini", "Server", "", "")
EndIf
Local $GUI = GUICreate($Title, 267, 115) ;Create the GUI
GUISetIcon($icon, -1) ;Create icon
$start = GUICtrlCreateButton("Start", 40, 72, 65, 25) ;Create a button
$create = GUICtrlCreateButton("Add Server", 160, 72, 65, 25)
$server = GUICtrlCreateCombo("Select Server", 8, 8, 249, 25, $CBS_DROPDOWN) ;Create the combo box
For $i = 1 To UBound($list) - 1 ;Populate combo box with first value (name) from array
If $list[$i][0] <> "" Then GUICtrlSetData($server, $list[$i][0]) ;Ensure array is not empty and fill combox with KEYS
Next
$servername = GUICtrlCreateInput("Server Name", 8, 40, 121, 21)
GUICtrlSetState(-1, $GUI_HIDE)
$serverip = GUICtrlCreateInput("IP Address", 136, 40, 121, 21)
GUICtrlSetState(-1, $GUI_HIDE)
GUISetState(#SW_SHOW)
While 1 ;Enter loop until user closes or presses button
Switch GUIGetMsg()
Case $GUI_EVENT_CLOSE ;Exit when closed
Exit
Case $start ;Store selection into variable, delete the GUI, and run the start function
$selection = GUICtrlRead($server)
If $selection <> "Select Server" Then
GUIDelete()
start()
EndIf
Case $create
If GUICtrlRead($create) = "Add Server" Then
GUICtrlSetState($servername, $GUI_SHOW)
GUICtrlSetState($serverip, $GUI_SHOW)
GUICtrlSetData($create, "Create")
Else
If (GUICtrlRead($servername) <> "" And GUICtrlRead($servername) <> "Server Name" And GUICtrlRead($serverip) <> "" And GUICtrlRead($serverip) <> "IP Address") Then
IniWrite(#TempDir & "\" & $Title & "\config.ini", "Server", GUICtrlRead($servername), GUICtrlRead($serverip))
GUICtrlSetState($servername, $GUI_HIDE)
GUICtrlSetState($serverip, $GUI_HIDE)
GUICtrlSetData($create, "Add Server")
Else
MsgBox($MB_ICONINFORMATION, $Title, "Invalid Server Name and IP Address.")
EndIf
For $i = UBound($list) - 1 To 0 Step -1
_GUICtrlComboBox_DeleteString($server, $i)
Next
Local $list = IniReadSection(#TempDir & "\" & $Title & "\config.ini","Server")
For $i = 1 To UBound($list) - 1
If $list[$i][0] <> "" Then GUICtrlSetData($server, $list[$i][0])
Next
EndIf
EndSwitch
WEnd
Else ;otherwise, message
MsgBox($MB_SYSTEMMODAL, "", "Milestone XProtect wasn't found on this computer" & #CRLF)
EndIf
Func start()
$iPID = Run($milestone) ;Runs the software and returns the Process ID
BlockInput(1)
Sleep(1000) ;sleep for 1 second
BlockInput(0)
If #error Then MsgBox(0, $Title, "The program could not launch.") Exit ;If Run returns a 0 or error, there was a problem
$handle = WinGetHandle("[ACTIVE]") ;Get the handle of the active window, should be Milestone software as it was just ran 1 second ago.
If $handle = 0 Then MsgBox(0, $Title, "The handle could not be found.") Exit;If the Handle returned is 0, there was no match
Sleep(4000)
WinWaitActive($handle) ;Wait for the program to be activated
Send("{TAB}") ;send keystrokes to active window
Send("{TAB}")
For $i = 0 to UBound($list) - 1 ;Find the IP address that matches the selection and send it
If $list[$i][0] = $selection Then Send($list[$i][1])
Next
Send("{ENTER}")
Exit ;Exit for now until you can capture a succesful run
EndFunc
Func help()
ShellExecute(#TempDir & "\" & $Title & "\config.ini")
EndFunc
#EndRegion--------------------------------------------------------------------------------------------------------------------------------------------------------------------
The added/modified lines is as follows, in order:
#include <AutoItConstants.au3>
$iPID = Run($milestone) ;Removed the #shownoactivate parameter, we want it to be the active window. Very important.
BlockInput(1) ;suggestion from comment, disables all input briefly
Sleep(1000) ;wait 1 second for program to launch
BlockInput(0) ;enables all user input again
If #error Then MsgBox(0, $Title, "The program could not launch.") Exit
$handle = WinGetHandle("[ACTIVE]") ;Get the handle of the active window, should be Milestone software as it was just ran 1 second ago.
If $handle = 0 Then MsgBox(0, $Title, "The handle could not be found.") Exit
Sleep(4000)
I tested this with the software on my end and it worked.

Add printer to system using Powershell within VBA?

I can make it work with a batch file using:
powershell.exe "Add-printer -ConnectionName \\PS02.samba.net\HELPS006"
But if I try to run the bat file above with VBA, it does not add the printer:
Shell ("c:\Fraktsedlar\HELPS006.bat")
If I run powershell directly from VBA, none of these works either:
Shell ("powershell.exe -Command " & Chr(34) & "Add-printer -ConnectionName \\PS02.samba.net\HELPS006" & Chr(34))
Shell ("powershell.exe -Command {" & Chr(34) & "Add-printer -ConnectionName \\PS02.samba.net\HELPS006" & Chr(34) & "}")
Shell ("powershell.exe -Command " & Chr(34) & "{Add-printer -ConnectionName \\PS02.samba.net\HELPS006}" & Chr(34))
What is it I'm doing wrong?
If powershell can do it so VBA.
From Help
http://download.microsoft.com/download/winscript56/Install/5.6/W982KMeXP/EN-US/scrdoc56en.exe This contains some libraries for system admin. You can use all of Windows Scripting Host features except for the root wscript object (used by a script to communicate with the host). 1000 times as much admin/info can be used with WMI https://msdn.microsoft.com/en-us/library/windows/desktop/aa393262(v=vs.85).aspx.
WSH has a second add printer function. Look at that one.
Adds a Windows-based printer connection to your computer system.
object.AddWindowsPrinterConnection strPrinterPath
object
WshNetwork object.
strPrinterPath
String value indicating the path to the printer connection.
Example
The following code uses the AddWindowsPrinterConnection method to connect a network printer to a Windows NT/2000 computer system.
Set WshNetwork = CreateObject("WScript.Network")
PrinterPath = "\\printserv\DefaultPrinter"
WshNetwork.AddWindowsPrinterConnection PrinterPath
Try this:
Shell ("powershell.exe -Command { Add-Printer -ConnectionName \\PS02.samba.net\HELPS006 }")
Or this:
Shell ("powershell.exe -Command " & Chr(34) & "& { Add-Printer -ConnectionName \\PS02.samba.net\HELPS006 }" & Chr(34))
You can also try this which is what Add-Printer does:
$p = Get-WmiObject -List Win32_Printer -EnableAllPrivileges
$p.AddPrinterConnection ("\\PS02.samba.net\HELPS006")

Output text File creation/saving VBA code timing issue

Problem Summary: Creating a text file for FTP commands is not finishing by the time the command file needs to be called. It won't trap with a "if file exists". How to make sure the file is created before continuing with the code?
Details: I'm working on an portion of code in my Excel workbook to FTP some files. To do that, I'm creating a FTPcmd.txt file via code containing the FTP commands, closing the file and then shelling the FTP command in the CMD window. It looks like the command file is taking too long to complete the write and, therefore, I'm getting an "Permission Refused" error. The FTP log says "Error opening script file C:\temp\FTPcmd.txt." I am error checking to see if the file exists, but I think the file shows up as existing after the open statement, not the close. I'm not hitting the else statement in the DIR <>"" The IsFileOpen function was found on "http://www.vbaexpress.com/kb/getarticle.php?kb_id=468 VBA Express : Excel - Check If a File Is Already Open"
I don't believe it's a problem ShellWait problem. I need the file to write before I call the Shell.
If I step through it manually, it works, after I see the file appear in the directory.
I'm also piping the FTP output to a file and reading it back in for success/failure messaging in a similar manner and I'm getting the same problem with that.
Anyone have any ideas? Thanks in advance!
Open temppath & "FTPcmd.txt" For Output As #2
Print #2, "user " & FSOUserName
Print #2, FSOpw
Print #2, "lcd " & temppath
Print #2, "cd public_html"
Print #2, "binary"
Print #2, "mput " & Chr(34) & "index.htm" & Chr(34)
Print #2, "cd .."
Print #2, "cd public_ftp"
Print #2, "mput " & Chr(34) & myfilename & Chr(34)
Print #2, "bye"
Close #2
Start = Timer
FTPlooper:
If Timer - Start > 30 Then saveme = 1: Text = Text & " FTP Failure": GoTo failpoint
If Dir(temppath & "FTPcmd.txt") <> "" And IsFileOpen(temppath & "FTPcmd.txt") = False Then
Shell "cmd /c ftp -n -i -g -s:" & temppath & "FtpCmd.txt " & FSOHostURL & ">" & temppath & "ftpout.txt 2>&1"
Else
GoTo FTPlooper
End If
Here's the function I'm using to see if the file is open.
Code:
Function IsFileOpen(FileName As String)'http://www.vbaexpress.com/kb/getarticle.php?kb_id=468
Dim iFilenum As Long
Dim iErr As Long
On Error Resume Next
iFilenum = FreeFile()
Open FileName For Input Lock Read As #iFilenum
Close iFilenum
iErr = Err
On Error GoTo 0
Select Case iErr
Case 0: IsFileOpen = False
Case 70: IsFileOpen = True
Case Else: Error iErr
End Select
End Function
Output of FTPout.txt:
Error opening script file C:\Users\Theresa\Downloads\FTPcmd.txt.
Transfers files to and from a computer running an FTP server service
(sometimes called a daemon). Ftp can be used interactively.
FTP [-v] [-d] [-i] [-n] [-g] [-s:filename] [-a] [-A] [-x:sendbuffer]
[-r:recvbuffer] [-b:asyncbuffers] [-w:windowsize] [host]
-v Suppresses display of remote server responses. -n
Suppresses auto-login upon initial connection. -i Turns
off interactive prompting during multiple file
transfers. -d Enables debugging. -g Disables filename globbing (see GLOB command). -s:filename
Specifies a text file containing FTP commands; the
commands will automatically run after FTP starts. -a Use any local interface when binding data connection. -A login as anonymous. -x:send sockbuf Overrides the default SO_SNDBUF size of 8192. -r:recv sockbuf Overrides the
default SO_RCVBUF size of 8192. -b:async count Overrides the
default async count of 3 -w:windowsize Overrides the default
transfer buffer size of 65535. host Specifies the host
name or IP address of the remote
host to connect to.
Notes:
- mget and mput commands take y/n/q for yes/no/quit.
- Use Control-C to abort commands.

How to stop script from automatically closing?

I open an .exe file but the script immediately closes after opening it. How can I prevent the script from closing?
Local $engine= "C:\Users\Davis\Desktop\chessEngine\stockfish-5-win\Windows\stockfish_14053109_32bit.exe"
Run($engine, "", #SW_MAXIMIZE, $STDOUT_CHILD)
Removing $STOUT_CHILD from Run() leaves the script open after executing, but I need this to read output from the program. Why is this happening?
Local $engine = "C:\Users\Davis\Desktop\chessEngine\stockfish-5-win\Windows\stockfish_14053109_32bit.exe"
Local $iPID = Run($engine, "", #SW_MAXIMIZE, $STDOUT_CHILD)
ProcessWaitClose($iPID)
This ist an example how to get output from a DOS command.
ConsoleWrite(_getDOSOutput('ipconfig /all') & #CRLF)
Func _getDOSOutput($command)
Local $text = '', $Pid = Run('"' & #ComSpec & '" /c ' & $command, '', #SW_HIDE, 2 + 4)
While 1
$text &= StdoutRead($Pid, False, False)
If #error Then ExitLoop
Sleep(10)
WEnd
Return StringStripWS($text, 7)
EndFunc ;==>_getDOSOutput

Shell Command Gives Error "error after : and."

I used :
Shell("cmd /k type " & System.IO.Path.GetTempPath & "file.exe > " & Application.ExecutablePath & ":file.exe")
Temp Folder : C:\Documents and Settings\Admin\Local Settings\Temp\
Command Prompt Window gives error : File not found, error after : and. System can't find destination path.
I think the problem is in this name : Documents and Settings
What should I do to bring it to life?
P.S : File exists, it works when I use : start command.
You need extra wrapping quotes.
Shell("cmd /k type """ & System.IO.Path.GetTempPath & "file.exe"" > " & Application.ExecutablePath & ":file.exe")
Spaces are delimiters in command line parameters. If you have a space in a single parameter, you need to wrap the entire parameter in quotes.
you probably need to put your path between "". something like
Shell("cmd /k type \"" & System.IO.Path.GetTempPath & "file.exe\" > " & Application.ExecutablePath & ":file.exe")