Scripting Using Windows Script Host
Scripts give IT professionals the ultimate ability to control and automate Windows. These aren't batch files; they're full-fledged administrative programs that, considering the wealth of power that they enable, are surprisingly easy to create. You can write a script that inventories a computer and writes the result to a file on the network, for example. You can automate an application to perform redundant steps automatically. The possibilities are endless, really, but I'm here to tell you how to use scripts to edit the registry, so I'm confining the discussion a bit.
The scripting technology in Windows is Windows Script Host. The current version is 5.6 and is far more technologically advanced than what was provided by Microsoft Windows 2000. Windows Script Host is called a host because it's not aware of a script's language, or as Microsoft says, it is language agnostic. Windows Script Host uses different scripting engines to parse the different languages in which you might write a script. Windows provides two scripting engines: VBScript and JScript. If you've ever used the C or C++ languages, you'll be more comfortable using JScript to write scripts. If you've ever used Visual Basic in any of its incarnations, you're going to be more comfortable using VBScript to write scripts.
Focusing this chapter on how to use scripts to edit the registry assumes that you're already familiar with Windows Script Host. If that's not true, I suggest that you find a good book about scripts. If you don't want a book about it, see http://msdn.microsoft.com/library/en-us/dnanchor/html/scriptinga.aspor http://www.microsoft.com/technet/scriptcenter/default.mspx. These are Microsoft's Scripting Web sites, and they contain everything that you need to know about writing scripts for Windows, including accessing WMI (Windows Management Instrumentation) through scripts. After you've mastered the languages, which aren't difficult, you'll appreciate the Web sites' reference content. The content describes the object model and how to use it–which is the most difficult part of writing scripts for Windows.
NOTE
Using WMI to edit the registry is an alternative to using pure VBScript. WMI enables you to manage remote computer's registries. For complete samples of WMI scripts that edit the registry, see http://www.microsoft.com/technet/scriptcenter/scripts/os/registry/default.mspx. This is the Registry section of the Script Repository in the TechNet Script Center. It includes sample WMI scripts for adding, changing, listing, and removing various types of registry settings. It also includes scripts for monitoring registry settings.
Tweakomatic
Chapter 5, “Mapping Tweak UI,” describes one of the most popular utilities for customizing Windows registry settings. The problem with Tweak UI is that you must log on to the computer and run the utility locally. You can of course write your own scripts to change the same settings that Tweak UI changes, because Chapter 5 documents almost every setting and its registry value for you.
However, the Scripting Guys, the fellows who write all that interesting content in the TechNet Script Center, have created Tweakomatic to automatically create these scripts for you. Tweakomatic writes scripts that retrieve and configure Windows and Microsoft Internet Explorer settings on remote computers. It doesn't support every setting that Tweak UI supports, but you can easily modify the scripts that it creates to change just about any setting you want.
For more information about downloading and using Tweakomatic, see http://www.microsoft.com/technet/scriptcenter/tools/twkmatic.mspx.
Creating Script Files
Script files can have two file extensions, and the script's file extension indicates which language the file contains. Use the .js extension for files that contain JScript. Use the .vbs extension for files that contain VBScript. Regardless, script files are nothing more than text files that contain the language's keywords, so you can use your favorite text editor, Notepad, to create them. When you save a script file using Notepad, make sure that you enclose the file's name in quotation marks, or choose All Files from the Save As Type drop-down list, so that Notepad doesn't add the .txt extension to the file.
You access the registry through the Shell object. This object contains the methods that you call to add, remove, and update values in the registry. You'll add one of the statements in the following code to every script in which you want to access the registry. The first line shows you how to create the Shell object using VBScript, and the second shows you how to do it using JScript. It's very easy to create a script: open Notepad, and type the contents of Listing 11-7. The JScript language is case sensitive, so type carefully. VBScript has the benefit of not being case sensitive. Save the file using the .js extension, and then double-click the file to run it. You'll see a message from me. Because double-clicking the script file runs it, you must right-click the file and then click Edit to edit the file.
set WshShell = WScript.CreateObject("WScript.Shell") var WshShell = WScript.CreateObject("WScript.Shell");
Listing 11-7 Example.js
var WshShell = WScript.CreateObject("WScript.Shell"); WshShell.Popup("Hello from Jerry Honeycutt" );
Why Write Scripts When INF Files Are Easier?
I usually write INF files to edit the registry. If I'm not using INF files, I write batch files and use Reg.exe. I like the simplicity of these methods. There are times when writing a script is the only suitable method, however.
Writing a script is necessary in a number of cases. The first is when you must have a user interface. If you want to display settings to or collect settings from users, scripting is the best choice. Also, scripting is the only method that provides rather full access to Windows. For example, you can use a script to inventory the computer and dump the information to a text file on the network. You can use a script to configure users' computers using logic, if-this-then-that, which isn't possible with the other methods. So if you're doing anything more complicated than just adding, changing, or removing values, you're going to end up writing scripts. I've seen some fairly complicated scripts. For example, one fellow I worked with wrote a script that searched the registry for services that Sysprep disabled, and then permanently removed them from the registry. This is a great example of scripting.
Combined with WMI, scripting is amazing. The following script shows you how to use VBScript and WMI to inventory a computer's configuration. It displays the amount of physical memory installed on the computer, the name of the computer, the BIOS version, the type of processor, and more. This script and many more like it are available on Microsoft's TechNet Script Center, which is a large library of scripts that you can download, modify, and use. All these scripts are at http://www.microsoft.com/technet/scriptcenter/default.mspx.
strComputer = "." Set objWMIService = GetObject("winmgmts: " _ & "{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2") Set colSettings = objWMIService.ExecQuery _ ("Select * from Win32_OperatingSystem") For Each objOperatingSystem in colSettings Wscript.Echo "OS Name: " & objOperatingSystem.Name Wscript.Echo "Version: " & objOperatingSystem.Version Wscript.Echo "Service Pack: " & _ objOperatingSystem.ServicePackMajorVersion _ & "." & objOperatingSystem.ServicePackMinorVersion Wscript.Echo "OS Manufacturer: " & objOperatingSystem.Manufacturer Wscript.Echo "Windows Directory: " & _ objOperatingSystem.WindowsDirectory Wscript.Echo "Locale: " & objOperatingSystem.Locale Wscript.Echo "Available Physical Memory: " & _ objOperatingSystem.FreePhysicalMemory Wscript.Echo "Total Virtual Memory: " & _ objOperatingSystem.TotalVirtualMemorySize Wscript.Echo "Available Virtual Memory: " & _ objOperatingSystem.FreeVirtualMemory Wscript.Echo "OS Name: " & objOperatingSystem.SizeStoredInPagingFiles Next Set colSettings = objWMIService.ExecQuery _ ("Select * from Win32_ComputerSystem") For Each objComputer in colSettings Wscript.Echo "System Name: " & objComputer.Name Wscript.Echo "System Manufacturer: " & objComputer.Manufacturer Wscript.Echo "System Model: " & objComputer.Model Wscript.Echo "Time Zone: " & objComputer.CurrentTimeZone Wscript.Echo "Total Physical Memory: " & _ objComputer.TotalPhysicalMemory Next Set colSettings = objWMIService.ExecQuery _ ("Select * from Win32_Processor") For Each objProcessor in colSettings Wscript.Echo "System Type: " & objProcessor.Architecture Wscript.Echo "Processor: " & objProcessor.Description Next Set colSettings = objWMIService.ExecQuery _ ("Select * from Win32_BIOS") For Each objBIOS in colSettings Wscript.Echo "BIOS Version: " & objBIOS.Version Next
Running Script Files
Windows provides two scripting hosts. The Windows-based version runs scripts when you double-click a script file. The script engine is Wscript.exe. You can also use the command-line version, which is handy when the script outputs data similar to the way in which most command-line programs do. The example given in Listing 11-7 in the section “Why Write Scripts When INF Files Are Easier?” is one script that's better run from the command-line. The command-line scripting engine is Cscript.exe.
Syntax
cscript script [//B|//I] [//D] [//E:engine] [//H:cscript|//H:wscript] [//Job:name] [//Logo|//Nologo] [//S] [//T:time] [//X] [//?]
//B | This specifies batch mode, which does not display alerts, scripting errors, or input prompts. |
//I | This specifies interactive mode, which displays alerts, scripting errors, and input prompts. This is the default and the opposite of //B. |
//D | This turns on the debugger. |
//E: engine | This specifies the scripting language that is used to run the script. |
//H:cscript|//H:wscript | This registers either Cscript.exe or Wscript.exe as the default script host for running scripts. If neither is specified, the installation default is Wscript.exe. |
//Job:name | This runs the job identified by name in a .wsf script file. |
//Logo | This specifies that the Windows Script Host banner is displayed in the console window before the script runs. This is the default and the opposite of //Nologo. |
//Nologo | This specifies that the Windows Script Host banner is not displayed before the script runs. |
//S | This saves the current command-line options for the current user. |
//T:time | This specifies the maximum time the script can run (in seconds). You can specify up to 32,767 seconds. The default is no time limit. |
//X | This starts the script in the debugger. |
//? | This displays available command parameters and provides help for using them. (This is the same as typing Cscript.exe with no parameters and no script.) |
You can specify some of the same options when using the Windows-based scripting host. Right-click the script file, and then click Properties. You'll see the dialog box shown in Figure 11-3. You can set the amount of time that the script is allowed to run and whether or not the host displays a log. The result is a file (a shortcut to the actual script file) with the .wsh extension that contains these settings. It looks like your average INI file. You then execute the script by double-clicking the WSH file.
Figure 11-3 You create a WSH file, which contains a script file's settings, by right-clicking the script, clicking Properties, and then clicking the Script tab.
Formatting Key and Value Names
Before I show you how to edit the registry with a script, there's one more detail: how to format the names of keys and values in a script. Unlike other scripting methods I've described in this chapter, the Windows Script Host object model doesn't have separate parameters for the key and value names. Thus, you distinguish key names from value names by how you format them. The rule is simple: if a string ends with a backslash, it's a key name; if a string doesn't end with a backslash, it's a value name. Also, the JScript language reserves the backslash character (\) as the escape character: \n is a newline character, and \t is a tab, for example. That means that you must escape the backslashes in your keys. Thus, any time you have a backslash in a key, you must use two backslashes (\\). For information that can help you keep these clear, see Table 11-4.
Object | VBScript | JScript |
Value | "HKLM\Subkey\Value" | "HKLM\\Subkey\\Value" |
Key | "HKLM\Subkey\" | "HKLM\\Subkey\\" |
Adding and Updating Values
The Shell object's RegWrite method adds keys and values or changes existing values. If you want to change a key's default value, set strName to the name of the key, including the trailing backslash, and then assign a value to it.
TIP
One of the RegWrite method's biggest weaknesses is that it writes only four bytes of REG_BINARY values. It can't handle larger binary values. If you want to change longer binary values or change types of values that this method doesn't support, use the Shell object's Run method to import a REG file. For example, you can put your settings in a REG file called Settings.reg. Then import that REG file using the statement WshShell.Run( "Settings.reg").
Syntax
object.RegWrite( strName, anyValue [,strType] )
object | This is the Shell object. |
strName | This is the string indicating the name of the key or value. You can add keys. You can add or change values. This string must be a fully-qualified path to a key or value and begin with one of the root keys: HKCR, HKCU, HKLM, or HKU. |
anyValue | This is the data to assign to new or existing values. Use the format that is appropriate for the value's type. |
strType | This is the type of value to create: REG_SZ, REG_EXPAND_SZ, REG_DWORD, or REG_BINARY. The RegWrite method doesn't support the REG_MULTI_SZ value type. Also, this method writes only four-byte REG_BINARY values. |
Example (VBScript)
Set WshShell = WScript.CreateObject("WScript.Shell" ) WshShell.RegWrite "HKCU\Software\Sample\", 1, "REG_BINARY" WshShell.RegWrite "HKCU\Software\Sample\Howdy", "World!", "REG_SZ"
Example (JScript)
var WshShell = WScript.CreateObject("WScript.Shell" ); WshShell.RegWrite("HKCU\\Software\\Sample\\", 1, "REG_BINARY" ); WshShell.RegWrite("HKCU\\Software\\Sample\\Howdy", "World!", "REG_SZ");
Removing Keys and Values
The Shell object's RegDelete method removes keys and values from the registry. Be careful, however, because removing an entire branch is easy; there's no confirmation. To remove a key, end strName with a backslash; otherwise, you're removing a value.
Syntax
object.RegDelete( strName )
object | This is the shell object. |
strName | This is the string indicating the name of the key or value to delete. This string must be a fully qualified path to a key or value and must begin with one of the root keys: HKCR, HKCU, HKLM, or HKU. |
Example (VBScript)
Set WshShell = WScript.CreateObject("WScript.Shell" ) WshShell.RegDelete "HKCU\Software\Honeycutt\Howdy" WshShell.RegDelete "HKCU\Software\Honeycutt\"
Example (JScript)
var WshShell = WScript.CreateObject("WScript.Shell" ); WshShell.RegDelete ("HKCU\\Software\\Honeycutt\\Howdy" ); WshShell.RegDelete ("HKCU\\Software\\Honeycutt\\" );
Querying Registry Values
The Shell object's RegRead method returns a value's data. To read a key's default value, end strName with a backslash; otherwise, you're reading a value.
Syntax
object.RegRead( strName )
object | This is the shell object. |
strName | This is the string indicating the name of the value to read. strName must be a fully qualified path to a key or value and begin with one of the root keys: HKCR, HKCU, HKLM, or HKU. |
Example (VBScript)
Dim WshShell, dwFlag, strValue Set WshShell = WScript.CreateObject("WScript.Shell" ) dwFlag = WshShell.RegRead("HKCU\Software\Honeycutt\" ) strValue = WshShell.RegRead("HKCU\Software\Honeycutt\Howdy" )
Example (JScript)
var WshShell = WScript.CreateObject("WScript.Shell" ); var dwFlag = WshShell.RegRead("HKCU\\Software\\Honeycutt\\" ); var strValue = WshShell.RegRead("HKCU\\Software\\Honeycutt\\Howdy" );