I don’t know VBScript, but recently I needed to write a script that had the SendKeys functionality, and I couldn’t do that in a batch file. When I run the following code from command prompt in my Windows 7 machine using the command cscript test.vbs, the sleep happened before telnet was started. The issue might be that the command is executed but the resulting output isn’t displayed until after the sleep is finished. How would I fix this?
Set WshShell = WScript.CreateObject("WScript.Shell")
WshShell.SendKeys "telnet localhost 25" & vbCr
wscript.sleep 5000
EDIT: I can get my script to work if I put a sleep command before it starts and then click on the command prompt window it has to type into. This way, when the script pauses, it pauses execution but doesn’t pause the output in command prompt from being displayed. I still need a command line solution.
Ok, your script has two fundamental flaws that are causing you problems with a possible third. They’re pretty easy to miss, but I think they’ll make sense to you once you see them.
First, the SendKeys method is executed asynchronously meaning that script execution does not pause while keystrokes are being sent. The amount of time you wait for your command to be executed must also account for the time it takes to send the keystrokes in the first place. You’re really much better off monitoring the window you are sending keystrokes to. I’ll show you two ways to do that.
Second, you should never use the SendKeys method by itself since it doesn’t provide any way of controlling what window actually receives the sent keystrokes. You should always use it with the Shell object’s AppActivate method which allows your script to bring any open window into focus (thereby making it available to receive the keystrokes you are about to send).
Finally, I’m not sure whether you are trying to open telnet in a new command prompt or grab a current instance. Your script implies the latter but that’s probably not a good approach since it’s more prone to errors. You’re likely better off opening it’s own command prompt instance. You can do this easily using the WshShell object’s Run method. So at a basic level, your script should look like this.
While this is pretty effective, it’s not at all bulletproof. For example, the AppActivate method has a required parameter that is the title of the Window to be activated. This isn’t always easy to figure out and it can differ from one machine to another making this code less portable. It’s also prone to errors if there is more than one window of the same type open at one time. But there is another way.
Let’s use WMI instead. The Win32_Process class has a Create method that will allow us to create, or start, our own process. What’s unique about this approach over the native WSH one is that we can configure some of the properties for the new startup process. This includes (for console applications) the window title. That means we can set, and thereby know definitively the window title for the application we want to send keystrokes to. Here’s what this looks like.
The script is pretty easy to understand if you take it in steps. The first step is to provide the command line of console application we wish to run. In this case, telnet. We then use the name of our script to create some unique window title for the window we are about to open. This can be anything that you are sure won’t match any other open window.
The meat of the script starts off by setting up WMI constants and connecting to the WMI service. We also create an instance of the Win32_ProcessStartup class which is used as a configuration object that houses the settings for the process we will be creating. This is where we make sure that the new process window is launched is a visible state and where we set the new window’s title.
With all of the prerequisites in place, it’s time to actually launch our console application. To do that, I need to use the Win32_Process class’s Create method. Traditionally, WMI scripts will query the WMI service to return an instance of a particular class. Since we are creating one, there isn’t an existing instance for me to query for. That means I need to use a little different syntax than what you might be used to. Using VBScript’s GetObject method, I connect directly to the Win32_Process class namespace. With a reference to that namespace, I can call the Create method and return an object that represents the newly created process instance.
The Create method I used returns an integer that indicates whether the process was created successfully or not. So just to be sure there wasn’t any problems, I wrap the remainder of the code in an If block.
One nice thing about the way this particular approach works is that the Win32_Process class’s Create method does not execute asynchronously. It will not return until the new process has been created so I never need to worry about making my script sleep while this is done. This method also provides a constant WMI reference to the running process. This means we can actively monitor it’s state to make sure that our script is running properly and to make sure that the process is closed properly before the script exits. I hope that this has been helpful.