December 6th, 2007

How Can I Start a Script in a Hidden Window?

Hey, Scripting Guy! Question

Hey, Scripting Guy! How can I start a script in a hidden window?

— OT

SpacerHey, Scripting Guy! AnswerScript Center

Hey, OT. You know, today is kind of a disappointing day for the Scripting Guys, or at least for the Scripting Guy who writes this column. As we noted yesterday, the Seattle area was hit by a freak “Pineapple Express” rainstorm that seemed destined to set all sorts of records for most precipitation to fall on the region in a single day. Alas, we ended up well short of the record: officially we recorded 3.77 inches of rain in 24 hours, nowhere near the record of 5 inches plus. To be honest, the Scripting Guy who writes this column would have preferred that we got no rain at all; nevertheless, if we had to get a bunch of rain, well, then we might as well have gone for it and set a record. Instead, we’re reduced to this:

“Hey, Scripting Guy who writes that column: I heard you guys got a lot of rain the other day.”

“We sure did: 3.77 inches.”

“Wow, that must be a record!”

“Well, actually, no; I’m afraid it wasn’t even close to the record.”

“Oh …. You know, I think I’ll go talk to that guy from Bremerton. Did you hear that they got 10.78 inches that same day? Now that’s rain!”

Such is life in Seattle; seems like around here the best we can ever do is “almost.” For example, we almost have a plan to solve all traffic problems: in the year 2010, 14 years (and several billion dollars) after it was voted in, we’ll have a light rail system that runs from downtown Seattle to the airport. (Well, almost to the airport.) In Seattle, we almost have a professional basketball team; barring a miracle of some sort, the Sonics are bound for Oklahoma City. (We’re not sure what the people of Oklahoma City did to deserve that, but we don’t want to say anything lest they change their mind.) And, of course, we almost set a record for the most rainfall in a single day.

So near and yet so far.

Note to readers from Bremerton. We know you’re proud of your 10.78 inches of rain, as well you should be; you whipped us fair and square. But don’t start feeling too smug; after all, the city of Holt, MO once received 12 inches of rain in just 42 minutes. Give us a call when you beat that record; then we’ll be impressed.

Anyway, now that things are beginning to dry out (well, almost beginning to dry out) we can concentrate on other things, things like, say, starting a script in a hidden window.

So how do you start a script in a hidden window? Well, there are actually a couple of ways to do this. For example, you could simply write a script like the following:

Set objShell = CreateObject(“Wscript.Shell”)
objShell.Run “Wscript.exe C:\Scripts\Test.vbs”

This usually works simply because the Wscript script host doesn’t use the command window; because of that, if you start a script under Wscript you won’t see anything happen on screen. Well, unless the script echoes back information, that is; in that case, you’ll see a message box each time the Wscript.Echo command gets called. However, as long as you stay clear of anything that would cause a message box or input box to appear on screen you can simply run a script under the Wscript script host and rest assured that no one will see that script running.

So, if that’s all true (and it is), why didn’t we just give you the preceding script and call it good? Well, we could have, except that the Scripting Guys are always on the lookout for scripts that can be used in more than one scenario. The preceding script works great for .VBS scripts, but it also works only for .VBS scripts. (Which makes sense: you can’t run, say, a command-line tool under one of the Windows Script Host script hosts.)

Therefore, we decided to go with a different approach, an approach that can run pretty much anything in a hidden window. An approach, come to think of it, that looks remarkably like the following:

Const HIDDEN_WINDOW = 0

strComputer = “.”

Set objWMIService = GetObject(“winmgmts:\\” & strComputer & “\root\cimv2”)

Set objStartup = objWMIService.Get(“Win32_ProcessStartup”) Set objConfig = objStartup.SpawnInstance_ objConfig.ShowWindow = HIDDEN_WINDOW

Set objProcess = GetObject(“winmgmts:\\” & strComputer & “\root\cimv2:Win32_Process”)

objProcess.Create “Cscript.exe C:\Scripts\Test.vbs”, null, objConfig, intProcessID

So what’s going on here? Good question. As you can see, we start out by defining a constant named HIDDEN_WINDOW and setting the value to 0; as you might expect, we’ll use this constant to tell the script that we want our second script (or our command-line tool) to start up in a hidden window. After defining the constant we then connect to the WMI service on the local computer.

What’s that? Could we run this same script on a remote computer? Yes, we could, although it would be overkill. Why? Because we don’t need to configure all the startup options (which we’re about to do) if we’re going to run the script on a remote computer; after all, any processes started on a remote machine always run in a hidden window. But, sure, you can leave this script as-is and run it on a remote machine; just assign the name of that remote machine to the variable strComputer:

strComputer = “atl-fs-001”

After we connect to the WMI service we then run smack-dab into this block of code:

Set objStartup = objWMIService.Get(“Win32_ProcessStartup”)
Set objConfig = objStartup.SpawnInstance_
objConfig.ShowWindow = HIDDEN_WINDOW

As you might have guessed, this is the portion of the script where we configure our startup options. To do that, we first create an object reference to the Win32_ProcessStartup class; this is the class that – well, yeah, this is the class that enables you to configure startup options for a process. After we connect to the Win32_ProcessStartup class we then call the SpawnInstance_ method (note the underscore at the end of the method name); this gives us a “blank” startup object we can then configure to our heart’s content. For this particular script our heart is content merely to set the value of the ShowWindow property to 0 (using the constant HIDDEN_WINDOW):

objConfig.ShowWindow = HIDDEN_WINDOW

What will that do? You got it: that will cause the script (or command-line tool) to start up in a hidden window.

By the way, there are lots of other things you can do with the Win32_ProcessStartup class; for example, you can start a process in a minimized window or a maximized window, or you can start a process with a higher (or lower) priority than normal. For more information, see the WMI SDK on MSDN. Just to whet your appetite, here’s code that configures any script or application that runs in a command window. In this case, that command window will:

Have the Window title Test Window.

Have a bright red background.

Be located squarely in the upper left-hand corner of the screen.

Here’s the code:

Set objStartup = objWMIService.Get(“Win32_ProcessStartup”)
Set objConfig = objStartup.SpawnInstance_
objConfig.Title = “Test Window”
objConfig.FillAttribute = 192 
objConfig.X = 0
objConfig.Y = 0

Again, see the WMI SDK for more details.

As for our script, after we configure the startup options we use the following line of code to bind to the Win32_Process class:

Set objProcess = GetObject(“winmgmts:\\” & strComputer & “\root\cimv2:Win32_Process”)

From there we call the Create method to actually run our script (or command-line tool) in a hidden window:

objProcess.Create “Cscript.exe C:\Scripts\Test.vbs”, null, objConfig, intProcessID

As you can see, we need to pass Create four parameters:

Cscript.exe C:\Scripts\Test.vbs. Full path to the .VBS script we want to run. By prefacing the path with Cscript.exe that causes the script to run under the CScript script host. That’s a good thing to do here, because then any Wscript.Echo commands will simply be echoed to the hidden console window. If we run Test.vbs under the Wscript script host then any such commands will be echoed back to the screen in the form of message boxes. That’s fine, except for one thing: those message boxes will pop up in a hidden window, and we won’t be able to see them. In turn, that means those message boxes will sit there forever waiting (in vain) for someone to click them. And until they do get clicked, the script will also sit there waiting, forever and ever.

Null. Specifies the working directory for the script or command-line tool. If set to Null (like here) that simply means that we want Test.vbs to run in the same directory as the script that started it.

objConfig. Object reference to our startup options object.

intProcessID. An “out parameter” that holds the PID (process ID) assigned to our new process. All we do is supply a variable name; the Create method will then populate this variable for us.

That’s all we have to do: start this script and Test.vbs will run, but it will run in a hidden window and no one will ever be the wiser. See you all tomorrow!

Wait, hold on a second; we wouldn’t feel right about leaving without giving you a few more rainfall statistics. What kind of statistics? How about this one: on July 4, 1956 the city of Unionville, MD got 1.23 inches of rain in a single minute. (Wonder how many people got caught in that after saying, “I’ll be right back; I just need to dash outside for a minute.”) In 1979 the city of Alvin, TX received 42 inches of rain in a single 24-hour period. And, believe it or not, that’s nothing: in 1966 72 inches of rain fell on the tiny island of La Réunion in a single day. What a great day that must have been, huh?

Note. If you’re thinking, “La Réunion? That sounds like a neat place to for a vacation,” well, consider this: in 1980, La Réunion received 46 inches of rain in a 12-hour period. That was part of a 5-day span in which 156 inches of rain (over 31 inches per day) fell on the island.

But, yeah, it does sound like a neat place for a vacation, doesn’t it?

Last, but surely not least, we have Cherrapunji, India. In 1860, the same year the Scripting Editor graduated from high school, Cherrapunji received a grand total of 1,042 inches (nearly 87 feet) of rain. That means, on average, Cherrapunji received almost 3 inches of rain every single day for an entire year. Good luck beating that record, Bremerton!

Author

0 comments

Discussion are closed.