Stop only those scripts you really want to end
If you've ever needed to terminate one of several running Windows Script Host (WSH) scripts through Task Manager, you know how difficult it can be to determine which script to end. Because Task Manager displays the name of the executable that's hosting a process and not a specific script or document name, you see only cscript.exe or wscript.exe for each script and no information that tells you the name of the actual script behind the executable. Your only option is to end all the scripts and restart those you really need.
Fortunately, there are some workarounds for this problem. In general, solutions fall into three categories:
- Use a specially renamed script host.
- Provide an onscreen window that you can close to terminate the script.
- Obtain more complete process information so that you can terminate a specific process.
Let's explore all three workarounds and the advantages and disadvantages of each.
Using a Renamed Script Host
One of the oldest tricks for easily identifying a script that's running in Task Manager is to create a copy of wscript.exe or cscript.exe and give the copy a new name, then run the script using the renamed wscript.exe or cscript.exe as the host executable. For example, if your script is Monitor.vbs, you can copy wscript.exe as monitor.exe, then run the command
Renaming the script host makes it easy to quickly glance at Task Manager to see which scripts are running. This technique also lends itself to script monitoring because each script file that's running shows an identifying task name. This method does have some drawbacks, though:
- You must copy and rename cscript.exe or wscript.exe for every scrip
- Each copy takes about 100KB of space, so making many copies eats up disk space.
- No safeguard exists to prevent you from running a script with the "wrong" executable.
- You can't distinguish between separate copies of the same script that are running.
You can mitigate the drawbacks with a couple of tricks. To prevent the renamed files from using extra space on NTFS-formatted Windows Server 2003 and Windows XP systems, you can create a hard link from the script executable file to a new location on the same disk. A hard link looks and acts like an independent copy of a file with an arbitrary name but really just points to the original file it was linked from. To hard-link a file, you use the Fsutil command. For example, if you want to give the C:\bin\checklogs.vbs script its own executable, you simply create a hard link to wscript.exe by using the command
fsutil hardlink create c:\bin\checklogs.exe c:\windows\system32 \wscript.exe
This command creates what looks like a new file: checklogs.exe in C:\bin. However, because it's really just a link to wscript.exe, it lets you run the CheckLogs.vbs script the same way as in the earlier Monitor.vbs example:
Checklogs.exe will now be displayed in Task Manager while the script is running. You can freely delete the checklogs.exe hard-link file when you no longer need it without affecting the original wscript.exe file.
Another way to ensure that you use the correct executable to launch a script is to verify the host name within the script. For example, when the CheckLogs.vbs script runs, have it make sure that it was launched with checklogs.exe. In a running script, the path to the executable that launched the script is always available in the WScript.FullName property, and the name of the script itself is available in the WScript.ScriptFullName property. In the CheckLogs example, WScript.FullName contains the string c:\bin\checklogs.exe and WScript.ScriptFullName contains checklogs.vbs. When the script starts, simply compare the base names (i.e., filenames without extensions) of the hosting executable and the script, then terminate the script if they don't match.
I've wrapped up this process in the MatchScriptToHost subroutine, which Listing 1 shows. Simply insert the subroutine into a script and call it by using a line of code such as
before the script executes any external tasks; the script will exit if the names don't match. If the host and script names don't match, the True argument makes the script display an error message before it exits to let you know that the script isn't running—a useful feature if you're running the scripts in a servicelike mode. The error message contains the correct name that a launching executable should have, so you can easily relaunch the script with the correct executable. If you don't want the message to be displayed, just use False instead of True.
Provide a Script-Closing Window
Another way to shut down a script is to create an onscreen window that you can close to force the script to terminate. There are two techniques you can use to create the window.
Use CScript. One technique is to run your scripts in CScript. As long as the script is running, it will be inside a visible command-line console window. This approach is ideal for limiting memory use because each cmd.exe instance typically takes up only about 64KB of space. Pressing Ctrl+C twice causes the script to terminate. You can even set the title of the console window before starting the script to let you more easily locate the correct console window. For example, if you're running a script named CheckLogs
title System Log Check and press Enter, then run cscript checklogs.vbs
The window title is then System Log Check — cscript checklogs.vbs, which lets you distinguish between different runs of the same script. Note that the title changes only while the script is running; after the script ends, the title changes back to the default.
Use an application that displays a window while processing. Using an application that displays a window is a little more complicated than using CScript because the dialog boxes that are directly available to the script—for example, MsgBox—block the script's execution. The process pauses until you close the dialog box.
Creating a window that doesn't block execution but that you can use to halt the script typically involves event handling. I document a fairly advanced technique for script termination that uses Microsoft Internet Explorer (IE) as the interface in "Using IE to Control Script Execution," June 2003, InstantDoc ID 38664. Alistair G. Lowe-Norris goes into more detail about this topic in his article "How to Raise and Trap Events," March 2004, InstantDoc ID 41503.
Use Win32_Process to Obtain Process Information
The most flexible script termination technique is to use Windows Management Instrumentation's (WMI's) Win32_Process class to obtain process information so that you can determine which process is running the script you want to terminate. However, this technique works only on XP and later. In XP and later, the Win32_Process class includes the CommandLine property, which contains the command used to start a specific process. Thus, you can retrieve this property value for each running process and test whether the retrieved command contains the name of the script you want to terminate. If so, you can then terminate that process.
FindScript.vbs, which Listing 2 shows, gives you a way to identify the script and optionally terminate it. You run the script from the command line and specify at least a partial name match for a script. For example, if you have several WSH scripts running and want to stop CheckLogs.vbs, you can run the following command:
cscript findscript.vbs checklogs.vbs
The check isn't case sensitive, and you can supply just a fragment of the name—for example, checklogs—if you want. Be aware that the script will also find itself and self-terminate. Because the script enumerates matches in order of process creation, this self-termination usually shouldn't matter.
FindScript.vbs obtains a list of all running processes, filters the list down to processes that are hosted by cscript.exe and wscript.exe, then echoes back the ProcessId and CommandLine properties of any running scripts that match the script name you specified. After the script returns the ProcessId property, you can terminate the script from Task Manager. If you want to terminate the script directly, simply add the /x switch to the command line, like this:
cscript findscript.vbs checklogs.vbs /x
Specifying the /x switch immediately ends the CheckLogs.vbs script without returning any process information. Be careful when using the /x switch, though, because it lets you kill as many scripts as match the pattern. If you used an empty string or just .vbs as a match pattern, for example, the script could terminate itself before doing anything else.
If you're like me, you've probably wished for a way to easily identify and terminate a script without affecting other scripts that are running. The techniques I've described provide some handy ways to help you more easily manage script execution. Use the method that works best in your environment.