Wait until program starts - cmd

I was wondering if there is any better way to wait until program starts before interacting with it?
Right now I'm using sleep which isn't exactly great.
Just to be clear I don't want to wait until program is finished (terminated) just to wait until it starts to be able to interact with it.
my code:
set MyShell = WScript.CreateObject("WScript.Shell")
MyShell.Run "<path to my exe app>"
WScript.Sleep 4000
MyShell.AppActivate "<my app name>"
MyShell.SendKeys "{TAB}"
...

Related

How to write a script to automate Putty (PLINK) on Windows 10

I am doing a manual process that is done each day within Putty and wanted to automate it. There is no need for a person to do this because all of the keyboard inputs do not change each day. I'm trying to free up time to increase productivity, not to mention it is mind-numbing to continually do this every day. The process requires someone to open Putty (this would use plink of course), login (storing the password and username in plain text is fine, steps for generating a key are not necessary), enter the same keyboard presses, output the file manually, and then save it to a network drive folder. So this is a completely unnecessary process to have someone doing it manually and I am seeking a way to complete this automation.
Currently, this is being used in a Windows 10 environment and from what I have read, Putty (plink) is the best route to go. I can utilize other SSH programs if there is a better method as well, but I think this may be the better route from the research I've done. I haven't scripted much at all and I'm trying to learn a bit as I go with this. I need to automate logging into PLINK (done) and then multiple keyboard entries (kind of done) for each screen within the server I'm accessing. Essentially, each screen needs to enter predetermined keyboard keys, such as "ENTER", some numbers 1-10 depending on the screen and then when it is complete, I need to print the results to a file, which preferably would be a xlsx, but csv or text would suffice as well.
I have added the code that I was able to create so far below. I am stuck at this point because PLINK does not remain visible so it's tough to analyze the issue and the cursor keeps jumping to any active window when running it.
Dim WshShell
Set WshShell = WScript.CreateObject("WScript.Shell")
WshShell.Run "C:\PuTTY\plink.exe 123.server.com -l username -pw password -t{ENTER}"
WScript.Sleep 3000
WshShell.AppActivate "plink.exe"
WScript.Sleep 2000
WshShell.AppActivate "plink.exe"
WshShell.SendKeys "{ENTER}"
WScript.Sleep 6000
WshShell.AppActivate "plink.exe"
WshShell.SendKeys "{ENTER}"
WScript.Sleep 6000
WshShell.AppActivate "plink.exe"
WshShell.SendKeys "command123{ENTER}"
Update
I attempted to use the suggested code and it does work in terms of automating the login and bringing up the application within the server, but it is not accepting any of the inputs I attempt to code. Every time an input is used the following message below is displayed. Please note, my command I'm passing is 100% correct, it just seems to not even consider it. The script does actually input the text into the proper field, but it just errors it out.
Enter program name (or abbreviation): I don't recognize
that program name. Press <return> for a list of programs."
(I have updated code per suggestions).
(
echo WEST COAST
timeout /t 5 > nul
echo 09
timeout /t 5 > nul
echo third_screen_keys
) | C:\PuTTY\plink.exe 123.server.com:PORT# -l username -pw password -t
There's a rather similar question here:
Wait between sending login and commands to serial port using Plink
So you should be able to use a batch file like this:
(
echo first_screen_keys
timeout /t 5 > nul
echo second_screen_keys
timeout /t 5 > nul
echo third_screen_keys
) | C:\PuTTY\plink.exe 123.server.com -l username -pw password -t
(or the PowerShell equivalent, if you *nix CR line endings)

Does cmd.exe write to stdout/stderr?

This is a weird question based on bad VBScript behavior that I am trying to work around. Please bear with me and thank you in advance.
In VBScript, you can do the following to start a task:
Set WshShell = CreateObject("WScript.Shell")
Set WshShellExec = WshShell.Exec(strCommand)
Do While WshShellExec.Status <> WshFinished
WScript.Sleep(1000)
Loop
However, there is a bug where, if the command/task started by the WshShell.Exec call writes >=4kb to either StdOut or StdErr, WshShellExec.Status will never be equal to WshFinished (1). I assume this is because there is no space in a buffer the system uses for stdout/stderr, so the initiated task hangs on the next write to stdout/stderr once it writes enough bytes to the buffer(s).
Depending on the program running, you may be able to do something like the following to get around it:
Set wshShellExec = WshShell.Exec(cmd)
Set objStdOut = wshShellExec.StdOut
Set objStdErr = wshShellExec.StdErr
Do Until objStdOut.AtEndOfStream
standardout = standardout & objStdOut.ReadLine & vbCrlf
Loop
Do Until objStdErr.AtEndOfStream
errtext = errtext & objStdErr.ReadLine & vbCrlf
Loop
However, this does not always work. If the running program writes 4kb to stderr before writing anything to stdout, this code hangs on the evaluation of objStdOut.AtEndOfStream or on objStdOut.ReadLine (note, you cannot use objStdOut.ReadAll because that will also block forever).
So, I've come up with the following solution that seems to work:
strCommand = "c:\Windows\System32\cmd.exe /C StdOutTester.exe > " & rsltTextFile & " 2>&1 || call echo %^errorLevel% > " & rsltErrCodeFile
Set WshShellExec = WshShell.Exec(strCommand)
Do While WshShellExec.Status <> WshFinished
Wscript.Sleep(1000)
secCount = secCount+1
If secCount >= 10 Then 'kill children
If KillTaskChildren(WshShellExec.ProcessID) <> 0 Then
WScript.Echo "WMI Terminate Failed. Killing CMD..."
WshShellExec.Terminate
End If
End If
Loop
What this does is run the actual task in another cmd window and redirect both stdout/stderr into a file (and also the error code if applicable). Because I'm running the command in another cmd window, stdout and stderr are decoupled from the WshShellExec object. This also allows me to kill the running task for a timeout (the real one, i.e. not the cmd window but the actual task, by using WMI).
So, my question becomes this:
Since I am running another cmd.exe window, it is possible that cmd prompt itself runs into the same issue if it writes enough data into stdout/stderr (in which case, my timeout logic should kill it)? Does it ever actually write anything into stdout/stderr? What about if I use the /Q option?

How do I create a .bat (batch) file that presses Enter key every 10800 seconds in a loop?

I've tried to make it myself, but it didn't work, as I'm not experienced enough with .bat to get it working.
So what I need is bascily a .bat file which I only need to click once and it will "simulate" me clicking the key 'Enter' every 10800 seconds (3 hours) in a loop, so that it doesn't ever stop clicking the key 'Enter' with a loop time of 10800 seconds, would someone help me out please! :)
You can do this with VBScript and the WScript host:
Save this as "press_enter.vbs" and run it from the CLI with "wscript press_enter.vbs"
Dim WshShell, FSO, secs
Set WshShell = WScript.CreateObject("WScript.Shell")
Set FSO = CreateObject("Scripting.FileSystemObject")
secs = 10800
kill_file = "C:\Users\Public\Documents\kill_switch.txt"
Do While true
WScript.Sleep(secs * 1000) ' this is in milliseconds, multiple by 1000
WshShell.SendKeys "{ENTER}"
if FSO.FileExists(kill_file) then exit do
Loop
As you probably guessed, the program runs forever until it detects the existence of the file "C:\Users\Public\Documents\kill_switch.txt"
You can also kill the program by opening Task Manager and killing the "Microsoft Windows Based Script Host" which will be listed under the "Background processes" section...
Remember that if you stop the application with the "kill_switch.txt" file, you will need to remove it before you start the application again. Perhaps it is best just to kill it with Task Manager...

How Can I make A Shorter Delay in CMD (XP)

Im using ping to create a delay in my batch file, but there seems to be quite a big limit on how short you can make the ping delay.
ping -n 1 -w 1 1.1.1.1
this will wait for maybe 500ms
ping 127.0.0.1
this will wait for maybe 100ms
So is there a way to get an even smaller delay?
This is on XP, so "timeout" isnt enabled
You can do this in XP with Windows scripting, by creating a VBScript file millisleep.vbs that looks like this (with decent error checking built in):
if wscript.arguments.count <> 1 then
wscript.echo "millisleep.vbs: Not enough arguments"
wscript.quit 1
end if
delay = wscript.arguments(0)
if not isnumeric(delay) then
wscript.echo "millisleep.vbs: " & delay & " is not numeric"
wscript.quit 1
end if
wscript.sleep delay
Then, from your own script, you can use something like this to get a quarter-second delay:
cscript //nologo millisleep.vbs 250

.vbs to stop .bat being run past a certain time

I have a scheduled task which runs on my server to put 2 other desktop machines asleep at 2am.
I also have a .bat file scheduled to run at 1:40am on all of my systems to let me know of the impending shutdown operation and give me the option to cancel, standby immediately or close the window and allow it to proceed. Works fine on all systems except a Win7 Laptop.
Despite me having the task set not to run past it's scheduled time, if I open my laptop and it resumes from standby any time after 2am, the file will still run.
I wanted to try and create a workaround by scheduling a .vbs to launch the .bat instead. Along the lines of:
if Hour(Time) > 1 Then
wscript.quit
else if Hour(Time) = 1 Then
Set objShell = WScript.CreateObject("WScript.Shell")
objShell.Run "cancel-confirm-autostandby.bat C:\WINDOWS\system32\cmd.exe", 1
end if
wscript.quit
But the .bat file runs regardless, even testing now at 3am. If I try;
msgbox Hour(Time)
It returns a value of 3, so I don't understand this behavior. 3 is > than 1...
I have tried assigning the cutoff time (2am) to a varible tried Hour(Now) & Hour(Date).
Any suggestions welcome, thank you for reading...
Seem to have got it with
if Hour(Time) > 1 Then
wscript.quit
else if Hour(Time) = 1 Then
Set objShell = WScript.CreateObject("WScript.Shell")
objShell.Run "cancel-confirm-autostandby.bat C:\WINDOWS\system32\cmd.exe", 1
end if
wscript.quit
End if
Don't know why it wouldn't work with just the second last "End if", but there you go...

Resources