Windows stores all underlying application and system configuration information in the registry.
The registry information is stored in a hierarchical tree structure that contains keys. Each key can contain values as well as additional keys.
The ability to manipulate the registry enables you to change virtually any system setting. This might involve changing desktop settings, colors or fonts, application settings (such as the location of documents), or system configuration (such as network settings).
While all of these settings can be accessed manually through a configuration utility such as a Control Panel applet, the ability to make mass changes to consistently set multiple settings at once programmatically can save you a great deal of time and effort.
There are a number of alternatives available to perform registry manipulation with Windows Script Host (WSH). One is the WScript.Shell object, which is included with all versions of WSH and provides basic registry functionality.
Another is Windows Management Instrumentation (WMI) version 1.5 or later. WMI is included with Windows 2000 and XP, and it is available as a separate installation for Windows 9x/ME and NT 4.0.
If your registry manipulation requirements are limited to string and basic numeric values, especially if you are working with a large installed base of Windows 9x, ME, and NT 4.0 systems, the WScript.Shell object is sufficient. If you need to read or write large binary values, enumerate the registry, or access remote computer registry values, WMI is the way to go.
One problem you might encounter is determining what registry keys contain the values for the setting you are attempting to change. There are literally thousands of keys.
An excellent free utility called Regmon is available from Sysinternals (http://www.sysinternals.com/) that shows modifications made to the registry in real time.
Another option is the sysdiff.exe utility available on the Windows NT 4.0 CD or in the NT Resource Kit. Sysdiff creates a "snapshot" of Windows NT configuration, including the registry, and it can perform a comparison to show the differences between the snapshot and the current settings.
There is also a large amount of registry setting information available on Microsoft's Web site (http://www.microsoft.com/), as well as third-party Web sites such as http://www.regedit.com/.
Also be aware of other alternatives to managing system settings, such as the Windows NT System Policy Editor or Windows 2000 Group Policies. These tools can provide a more robust solution, and they are easier to manage through a graphical interface.
You want to read a value from the registry.
Use the WScript.Shell object's RegRead method to read a specified registry value:
Dim objShell Set objShell = CreateObject("WScript.Shell") WScript.Echo "Your wallpaper Is "& _ objshell.RegRead("HKCU Control PanelDesktopWallpaper")
WSH supports reading of values from the registry using the WScript.Shell object's RegRead method. The syntax is as follows:
strVal = objShell.RegRead(strKeyPath)
strKeyPath is a path to the registry value you want to read. The path consists of the registry root key name followed by the path to the registry key you want to read. Each element of the path is separated by a backslash ().
The registry root key is always the first part of the path to the registry key you are trying to read. Table 7-1 lists the registry root key names. Some registry root keys can be listed in short or long form.
SHORT |
LONG |
---|---|
HKCU |
HKEY_CURRENT_USER |
HKLM |
HKEY_LOCAL_MACHINE |
HKCR |
HKEY_CLASSES_ROOT |
None |
HKEY_USERS |
None |
HKEY_CURRENT_CONFIG |
None |
HKEY_DYN_DATA |
For example, the path to the Windows 98 version number can be represented as HKLMSoftwareMicrosoftWindowsCurrentVersionVersionNumber or HKEY_LOCAL_MACHINESoftwareMicrosoftWindowsCurrentVersionVersionNumber.
One way to get the path for registry values is to use the RegEdit application to search for registry information and copy the key path to the clipboard using Edit > Copy Key Name. Then paste the registry path into the script where required.
A registry key can store different data types, such a string, DWORD (which is an integer), binary, and multistring values. If the value is a string or integer value, it is returned when the RegRead method is called.
Set objShell = CreateObject("WScript.Shell") WScript.Echo "Your Windows 98 Version Number is "& _ objshell.RegRead("HKLMSoftwareMicrosoftWindowsCurrentVersionVersionNumber")
Binary values are returned as an array of byte values.
Set objShell = CreateObject("WScript.Shell") 'read a binary value aBinary = _ objshell.RegRead("HKEY_CURRENT_USERSoftwareMyAppConfigcoords") 'loop through and display each value For Each val In aBinary WScript.Echo val Next
Multistring values are returned as an array of strings and can be read using the same method as binary values.
If the registry value does not exist or you do not have appropriate security access to the key, a runtime error will occur.
The most recent versions (1.5 or later) of WMI include a registry services provider that allows you to create, read, write, and enumerate registry values.
The Shell object's registry methods are capable of reading and writing some registry information. The WMI provider offers additional features. For instance, the Shell object cannot read or write the "default" registry value.
WMI is included with Windows 2000/XP and can be installed separately on Windows NT and Windows 9x/ME. See Chapter 10 for more information on how to use WMI.
To use the provider, connect to the rootdefault namespace. Create an instance of the StdRegProv provider class. This class exposes a number of static methods that perform registry operations.
To read a value, you need to call the appropriate Get method for the registry value data type you want to read. The generic syntax for these methods is as follows:
nReturn= objRegistry.GetTypeValue([nRootKey], strKey, strValueName, vValue)
The optional nRootKey parameter represents the root key value for the root key. If the nRootKey parameter is not specified, the local machine (HKEY_LOCAL_MACHINE) root key is used. Table 7-2 lists valid root key values.
DOCUMENT TITLE |
VALUE |
---|---|
HKEY_LOCAL_MACHINE |
&H80000002 |
HKEY_CURRENT_USER |
&H80000001 |
HKEY_CLASSES_ROOT |
&H80000000 |
HKEY_USERS |
&H80000003 |
HKEY_CURRENT_CONFIG |
&H80000005 |
HKEY_DYN_DATA |
&H80000006 |
strKey represents the path to the key where the value is located. Each key in the path is separated by a backslash ().
strValueName is the name of the value to read. If strValueName is an empty string, the "default" registry value will be set.
The value read is returned through the vValue parameter. The data type returned depends upon the method being used to read the data. Table 7-3 lists the methods that are available to read registry values.
METHOD |
VALUE RETURNED |
---|---|
GetStringValue |
String value |
GetMultiStringValue |
Array of string values |
GetExpandedStringValue |
String value |
GetBinaryValue |
Array of byte values |
GetDWORDValue |
Integer |
If the read is successful these methods return 0.
The following sample reads the registry value Identifier under the key path HARDWAREDESCRIPTIONSystem from the HKEY_LOCAL_MACHINE root key:
Const WMICONST = "winmgmts:{impersonationLevel=impersonate}!rootdefault:" Const HKEY_CURRENT_USER = &H80000001 Dim objRegistry, nRet, strValue 'create an instance of the StdRegProv registry provider Set objRegistry = GetObject(WMICONST & "StdRegProv") 'read the value Identifier under key HARDWAREDESCRIPTIONSystem 'since the local machine root key is the default, the first parameter is omitted nRet = objRegistry.GetStringValue(, "HARDWAREDESCRIPTIONSystem", _ "Identifier", strValue) If nRet = 0 Then WScript.Echo "The system type is "& strValue Else WScript.Echo "Error reading the HARDWAREDESCRIPTIONSystem key" End If
For more information about GetStringValue, visit http://msdn.microsoft.com/library/en-us/wmisdk/hh/wmisdk/r_prov_2kae.asp. Information about RegRead is available for download from http://msdn.microsoft.com/library/en-us/wsh/htm/wsMthRegRead.asp.
You want to write a value to the registry.
You can use the Shell object's RegWrite method to write to a specified registry value:
'change the default document directory for Word 97 Set objShell = CreateObject("WScript.Shell") objShell.RegWrite _ " HKEY_CURRENT_USERSoftwareMyAppConfigusername" _ , "H:DataWord" 'create new registry key objShell.RegWrite _ "HKEY_CURRENT_USERSoftwareMyAppConfigNewKey" , ""
The Shell object's RegWrite method writes a value to a specified key value or creates a new key. The syntax is as follows:
objShell.RegWrite strPath, anyValue [,strType]
The strPath parameter is the path to the key to write. If the registry path ends with a backslash, RegWrite will attempt to create a new key.
Table 7-4 lists possible values for the optional strType parameter.
REGISTRY TYPE |
VALUE |
DESCRIPTION |
---|---|---|
REG_SZ |
String value |
This is the default value. |
REG_EXPAND_SZ |
Expandable string |
|
REG_DWORD |
Integer value |
|
REG_BINARY |
Binary value |
Registry values of type REG_EXPAND_SZ appear to be functionally the same as REG_SZ string values. But applications that read entries of type REG_EXPAND_SZ expand any elements surrounded by percent signs (%) to their corresponding environment variable values.
Dim objShell Set objShell = CreateObject("WScript.Shell") strPath = "HKCUSoftwareMyAppConfigcoordinates" objshell.RegWrite strPath, "%SystemRoot%heh", "REG_EXPAND_SZ"
RegWrite creates a registry path if it does not already exist.
Under regedit, the registry entry appears to be the same as a string. Using Windows NT/2000/XP RegEdt32, you can see the data type shown in Figure 7-1.
Figure 7-1: Regedt32.exe registry value types
Reading the REG_EXPAND_SZ value back using RegRead does not expand the environment variables in the string. You must manually expand any environment variables by using the Shell object's ExpandEnvironmentStrings method.
Binary values cannot be written in the same method they can be read. RegRead returns an array of byte values. RegWrite does not allow this array to be written back to the binary key. The following code sample attempts to write a binary value to the same registry value from which it was read:
Dim objShell, aVal, strPath Set objShell = CreateObject("WScript.Shell") strPath = "HKCUSoftwareMyAppConfigcoordinates" 'read the value aVal =objshell.RegRead(strPath) 'attempt to write the value back to the same string - this will not work 'an error will occur objshell.RegWrite strPath, aVal, "REG_BINARY"
You can only write an integer (4 byte) value to a binary key using RegWrite. Each byte of the value represents one byte entry under regedit.
Dim objShell, strPath Set objShell = CreateObject("WScript.Shell") strPath = "HKCUSoftwareMyAppConfigcoordinates" 'write value to binary key objshell.RegWrite strPath, 65535, "REG_BINARY"
You cannot write more than 4-byte values to a binary key using RegWrite.
The WMI registry provider offers more powerful methods of writing to the registry. You require WMI version 1.5 or later. Windows 2000/XP installs WMI 1.5 by default, and it can be installed onto Windows 9x and NT 4.0 separately. See Chapter 10 for more information on how to implement scripts that use WMI functionality. To write a value, connect to the namespace for the registry provider and call the appropriate method for the data type. Table 7-5 lists the methods that are available.
METHOD |
VALUE |
---|---|
SetStringValue |
String value |
SetMultiStringValue |
Array of string values |
SetExpandedStringValue |
String value |
SetBinaryValue |
Array of byte values |
SetDWORDValue |
Integer |
The generic syntax for these methods is as follows:
nReturn= objRegistry.SetTypeValue([nRootKey], strKey, strValueName, vValue)
The optional nRootKey parameter represents the root key value. These values are listed in Table 7-2. If the nRootKey parameter is not specified, the local machine HKEY_LOCAL_MACHINE root key is used:
If the path that is specified by strKey does not exist, it is not created and an error will occur. If you require a key to be created, use the StdRegProv provider's CreateKey method. The syntax is as follows:
nReturn= objRegistry.CreateKey ([nRootKey], strKeyPath)
The optional nRootKey parameter represents the root key value. These values are listed in Table 7-2. If the nRootKey parameter is not specified, the local machine HKEY_LOCAL_MACHINE root key is used.
The strKeyPath parameter specifies the path to be created. Each subkey in the path is separated by a backslash (). Any subkeys that do not exist are created.
The following code sample creates a registry key with the path software est and writes a string, multistring, binary, and expanded string registry value:
Const WMICONST = "winmgmts:{impersonationLevel=impersonate}!rootdefault:" Const HKEY_LOCAL_MACHINE = &H80000002 Dim strPath, nRet, objRegistry, strKeyPath 'set the key path to write the values to. strKeyPath = "software est" 'create an instance of the registry provider Set objRegistry = GetObject(WMICONST & "StdRegProv") 'write a binary value nRet = objRegistry.CreateKey(HKEY_LOCAL_MACHINE, strKeyPath) 'write a binary value nRet = objRegistry.SetBinaryValue(HKEY_LOCAL_MACHINE, _ strKeyPath, "binary", Array(1, 2, 3, 4)) 'write expanded registry string nRet = objRegistry.SetExpandedStringValue(HKEY_LOCAL_MACHINE, _ strKeyPath, "expanded", "%path%") 'write expanded string nRet = objRegistry.SetStringValue(HKEY_LOCAL_MACHINE, _ strKeyPath, "string", "heh") 'write multistring value nRet = objRegistry.SetMultiStringValue(HKEY_LOCAL_MACHINE, strKeyPath, _ "multistring", Array("1", "2", "3", "4"))
Information about the SetBinaryValue method is available for download at http://msdn.microsoft.com/library/en-us/wmisdk/hh/wmisdk/r_prov_6rzq.asp. For more information about the RegWrite method, visit http://msdn.microsoft.com/library/en-us/wsh/htm/wsMthRegWriteC.asp.
You want to delete a value from the registry.
Use the Shell object's RegDelete method to delete a value or key:
Set objShell = CreateObject("WScript.Shell") 'delete a registry value objShell.RegDelete "HKEY_CURRENT_USERSoftwareMyAppConfigcoords"
The Shell object's RegDelete method deletes an existing registry key or value. The syntax follows:
objShell.RegDelete strPath
The strPath parameter is the path to the value or key you want to delete. If the registry path ends with a backslash, RegDelete attempts to delete the specified key.
RegDelete functions differently depending on the operating system it is executed under. Under Windows 9x/ME, executing RegDelete deletes all child values and keys. Under Windows NT, you must delete all child keys and values before deleting a key that contains values and subkeys.
The WMI registry provider has separate methods for deleting registry keys and values: DeleteKey and DeleteValue.
nRet = objRegistry.DeleteKey([nRootKey], strKey) nRet = objRegistry.DeleteValue([nRootKey], strKey, strValueName)
The optional nRootKey parameter represents the root key value. These values are listed in Table 7-2. If the nRootKey parameter is not specified, the local machine HKEY_LOCAL_MACHINE root key is used.
strKey represents the key path. Each key in the path is separated by a back-slash (). This is the registry key that gets deleted by the DeleteKey method.
strValueName is the name of the registry value to delete by the DeleteValue method.
The DeleteKey method will not delete a key if it contains any subkeys, even if the subkeys are empty. The method will delete a key if it contains registry values. The following sample deletes a key called subkey from the HKEY_CURRENT_USER registry root:
Const WMICONST = "winmgmts:{impersonationLevel=impersonate}!rootdefault:" Const HKEY_CURRENT_USER = &H80000001 Dim strPath, nRet, objRegistry, strKeyPath 'set the key path strKeyPath = "software est" 'create an instance of the registry provider Set objRegistry = GetObject(WMICONST & "StdRegProv") 'delete a key called 'subkey' nRet = objRegistry.DeleteKey(HKEY_CURRENT_USER, "testkeysubkey")
Information about the DeleteValue method is available for download at http://msdn.microsoft.com/library/en-us/wmisdk/hh/wmisdk/r_prov_7j5i.asp.
For information about the CreateKey method, visit http://msdn.microsoft.com/library/en-us/wmisdk/hh/wmisdk/r_prov_7tme.asp. You can find information about the RegDelete method at http://msdn.microsoft.com/library/en-us/wsh/htm/wsMthRegDelete.asp.
You want to list all of the values under a registry key.
The following script lists all the values in a specified key using the WMI provider:
'enumwmi.vbs Const WMICONST = "winmgmts:{impersonationLevel=impersonate}!rootdefault:" Const HKEY_LOCAL_MACHINE = &H80000002 Dim strPath, nRet, objRegistry, strKeyPath, aNames Dim strValue, aValues, nF, nRoot, aRet strKeyPath = "software est" nRoot = HKEY_LOCAL_MACHINE 'create an instance of the registry provider Set objRegistry = GetObject(WMICONST & "StdRegProv") 'enumerate all values nRet = objRegistry.EnumValues(nRoot, strKeyPath, aNames, aValues) 'if enumeration successful, loop through returned values and display values If nRet = 0 Then For nF = LBound(aValues) To UBound(aValues) strValue = "" Select Case aValues(nF) Case 1 'String nRet = objRegistry.GetStringValue(nRoot, strKeyPath, _ aNames(nF), strValue) Case 2 'Expanded String nRet = objRegistry.GetExpandedStringValue(nRoot, strKeyPath, _ aNames(nF), strValue) Case 3 'Binary values nRet = objRegistry.GetBinaryValue(nRoot, strKeyPath, _ aNames(nF), aRet) strValue = Join(aRet) Case 4 'DWORD nRet = objRegistry.GetDWORDValue(nRoot, strKeyPath, _ , aNames(nF), strValue) Case 7 'Multi string values nRet = objRegistry.GetMultiStringValue(nRoot, strKeyPath, _ aNames(nF), aRet) strValue = Join(aRet) End Select WScript.Echo "Value "& aNames(nF) & "has value "& strValue Next End If
The WScript.Shell does not provide any methods to enumerate registry values and keys. Registry values and keys can be enumerated using the WMI registry provider, which exposes two methods: EnumKey and EnumValues.
EnumKey enumerates any subkeys below a specified key, while EnumValues enumerates all values within a key.
The WMI registry provider has a separate method for deleting registry keys and values:
nRet = objRegistry.EnumKey ([nRootKey], strKey, aNames) nRet = objRegistry.EnumValues([nRootKey], strKey, aNames, aTypes)
The optional nRootKey parameter represents the root key value. These values are listed in Table 7-2. If the nRootKey parameter is not specified, the local machine HKEY_LOCAL_MACHINE root key is used.
The EnumValues method returns an array of value types through the aTypes parameter. This array contains the data type for the corresponding value name returned in the aNames array. The values for each data type are listed in Table 7-6.
REGISTRY TYPE |
VALUE |
---|---|
String |
1 |
Expanded string |
2 |
Binary |
3 |
DWORD |
4 |
Multistring |
7 |
Solution 11.1. Information about the EnumValues method is available for download at http://msdn.microsoft.com/library/en-us/wmisdk/hh/wmisdk/r_prov_5kc6.asp.
You want to search and optionally replace registry values.
The following command-line script searches a specified registry path and all subkeys in the path for any string value that matches a search string and optionally replaces the value:
'regsrch.vbs 'searches for specified registry values and optionally replaces them Const WMICONST = "winmgmts:{impersonationLevel=impersonate}!rootdefault:" Dim strRoot, nPos Dim strFind, strPath, strReplace, bReplace, objRegistry, nRoot 'check the argument count If WScript.Arguments.Count < 2 Or WScript.Arguments.Count > 3 Then ShowUsage End If strPath = WScript.Arguments(0) strFind = WScript.Arguments(1) nPos = InStr(strPath, "") If nPos > 0 Then strRoot = Mid(strPath, 1, InStr(strPath, "") - 1) strPath = Mid(strPath, nPos + 1) Else End If 'get the registry root key Select Case strRoot Case "HKEY_LOCAL_MACHINE", "HKLM" nRoot = &H80000002 Case "HKEY_CURRENT_USER", "HKCU" nRoot = &H80000001 Case "HKEY_CLASSES_ROOT" nRoot = &H80000000 Case "HKEY_USERS" nRoot = &H80000003 Case "HKEY_CURRENT_CONFIG" nRoot = &H80000005 Case "HKEY_DYN_DATA" nRoot = &H80000006 Case Else WScript.Echo "Invalid registry root key: "& strRoot WScript.Quit End Select 'create an instance of the registry provider Set objRegistry = GetObject(WMICONST & "StdRegProv") 'check if replace parameter is passed If WScript.Arguments.Count = 3 Then strReplace = WScript.Arguments(2) bReplace = True End If RecurseReg strPath Sub ShowUsage WScript.Echo "regsrch search and optional replace registry values." & vbLf & _ "Syntax:" & vbLf & _ "regsrch.vbs key findvalue [replacevalue] "& vbCrLf & _ "key key to search. Will search child keys." & vbCrLf & _ "findvalue value to search for" & vbCrLf & _ "replacevalue optional. Value to replace" WScript.Quit -1 End Sub Sub RecurseReg(strRegPath) Dim nRet, aNames, bFound Dim strValue, aValues, nF, aRet nRet = objRegistry.EnumKey(nRoot, strRegPath, aNames) 'loop through and enumerate any sub-keys If nRet = 0 Then For nF = LBound(aNames) To UBound(aNames) RecurseReg strRegPath & "" & aNames(nF) Next End If 'enumerate all values nRet = objRegistry.EnumValues(nRoot, strRegPath, aNames, aValues) If nRet = 0 Then For nF = LBound(aValues) To UBound(aValues) strValue = "" 'check values, only interested in string or expand string values Select Case aValues(nF) Case 1 'String nRet = objRegistry.GetStringValue(nRoot, strRegPath, _ aNames(nF), strValue) Case 2 'Expanded String nRet = objRegistry.GetExpandedStringValue(nRoot, strRegPath, _ aNames(nF), strValue) End Select If strValue = strFind And (aValues(nF) = 1 Or aValues(nF) = 2) Then WScript.Echo "Value '"& strValue & "' found in "_ & strRegPath & "" & aNames(nF) 'replace the registry value? If bReplace Then 'check what type and call appropriate method Select Case aValues(nF) Case 1 'write registry string nRet = objRegistry.SetStringValue(nRoot, _ strRegPath, aNames(nF), strReplace) Case 2 'write expanded registry string nRet = objRegistry.SetExpandedStringValue(nRoot, _ strRegPath, aNames(nF), strReplace) End Select 'was replace successful? If nRet = 0 Then WScript.Echo "Value '"& strValue & "' change to '"_ & strReplace & "' in "& strRegPath & "" & aNames(nF) Else WScript.Echo "Value '"& strValue & "' not replaced '"_ & strReplace & "' in "& strRegPath & "" & aNames(nF) End If End If End If Next End If End Sub
Neither WScript.Shell nor WMI provides any built-in methods to search a key and all registry subkeys below it. The Solution script implements a commandline program to search and optionally replace a registry value. It searches all values, including subkeys, below the start key.
The script uses the WMI StdRegProv provider to recursively search a specified key path.
You want to manipulate remote registry values.
You can connect to a remote computer using WMI and perform the required registry operation using StdRegProv. The following script connects to the remote computer Odin and reads a registry value:
Const WMICONST = "winmgmts:{impersonationLevel=impersonate}!\odin ootdefault:" Const HKEY_CURRENT_USER = &H80000001 Dim objRegistry, nRet, strValue 'create an instance of the StdRegProv registry provider Set objRegistry = GetObject(WMICONST & "StdRegProv") 'read the value Identifier under key HARDWAREDESCRIPTIONSystem 'since the local machine root key is the default, the first parameter is omitted nRet = objRegistry.GetStringValue(, "HARDWAREDESCRIPTIONSystem", _ "Identifier", strValue) If nRet = 0 Then WScript.Echo "The system type is "& strValue Else WScript.Echo "Error reading the HARDWAREDESCRIPTIONSystem key" End If
The WScript.Shell object registry methods do not provide access to the registries of remote machines.
By default, WMI supports a connection to remote computers. All WMI StdRegProv provider registry operations that are detailed in this chapter can be performed on a remote computer. A version of WMI must exist on the local computer as well as a remote computer that can perform the registry operations.
No changes are required to registry manipulation code using WMI apart from the connection string. You must have appropriate security rights to access the remote computer, and the appropriate version of WMI must be installed on the local and remote computers.
Note |
See Chapter 10 for more information about connecting WMI to remote computers. |
Solution 7.4.
Foreword