Saturday, May 18, 2013

Managing Windows Registry with Scripting



Virtually every single person using any of the operating systems from the Windows family has to resort, at some point, to making configuration changes via direct registry access (instead of using the more "friendly" and Microsoft-recommended GUI-based tools). Typically, such changes are performed with considerable caution and a strict following of the directions contained in one of the Microsoft knowledge base articles (which always include the standard disclaimer about dangers associated with such procedures). 

In order to minimize your risks when dealing with the registy, you can use scripting. This way, you're able to protect yourself against accidental typos, and you also enjoy the additional significant benefit of being able to automate registry modifications, which becomes a very important factor when dealing with larger environments.

 The Standard Registry Provider offers the following methods:
  • GetBinaryValue - reads regisry value of BINARY type
  • GetDWORDValue - reads registry value of DWORD type
  • GetExpandedStringValue - reads registry value of EXPANDED STRING type
  • GetMultiStringValue - reads registry value of MULTI STRING type
  • GetStringValue - reads registry value of STRING type
  • CreateKey - creates registry key
  • SetBinaryValue - writes registry value of BINARY type
  • SetDWORDValue - writes registry value of DWORD type
  • SetExpandedStringValue - writes registry value of EXPANDED STRING type
  • SetMultiStringValue - writes registry value of MULTI STRING type
  • SetStringValue - writes registry value of STRING type
  • DeleteKey - deletes registry key
  • DeleteValue - deleting registry value
  • EnumKey - enumerates registry key
  • EnumValues - enumerates registry value
  • CheckAccess - checks permissions on registry key
Lets see the  implementation of some of these methods.

As usual, we will start with defining constants. Five of them will correspond to the registry trees, viewed in REGEDIT.EXE as top level folders.

Const HKEY_CLASSES_ROOT        = &H80000000
Const HKEY_CURRENT_USER        = &H80000001
Const HKEY_LOCAL_MACHINE       = &H80000002
Const HKEY_USERS               = &H80000003
Const HKEY_CURRENT_CONFIG      = &H80000005


The StdRegProv class, which all the listed previously methods are a part of, resides in rood/default WMI namespace. This means that in our scripts we will first need to connect to this namespace (and the StdRegProv class within it). The most straightforward way of performing this step is by using so-called moniker notation.

Set oRegistry = GetObject("winmgmts:{impersonationLevel=impersonate}//" & _
               sComputer & "/root/default:StdRegProv")

where sComputer is the variable containing the name of the target computer.
Next, we need to create an object corresponding to the method being invoked. This is done using the following syntax:

Set oMethod = oRegistry.Methods_(sMethod)
where sMethod contains the name of the method (from the list above).

Depending on the method, one or more additional parameters might be required. These parameters are stored in an additional object we create called oInParam).
Set oInParam = oMethod.inParameters.SpawnInstance_()

This is followed by setting different parameters that are part of the oInParam object. For example:

oInParam.hDefKey = HKEY_CURRENT_USER
where HKEY_CURRENT_USER is one of the previously defined constants.

In order to execute the method, we need to call ExecMethod_ method of oRegistry object, which takes two arguments -- the name of the method (stored in sMethod variable) and the object containing all input parameters (called by us oInParam). This is done with the following line:
Set oOutParam = oRegistry.ExecMethod_(sMethod, oInParam)

The result of calling the method can be retrieved by checking the content of oOutParam object.
The best way to get familiar with the described process is by looking at examples. Here is the way to read a string value from the registry -- in this case, we want to retrieve the value of :

Const HKEY_CLASSES_ROOT        = &H80000000
Const HKEY_CURRENT_USER        = &H80000001
Const HKEY_LOCAL_MACHINE       = &H80000002
Const HKEY_USERS               = &H80000003
Const HKEY_CURRENT_CONFIG      = &H80000005

sComputer      = "TargetComputer"
sMethod        = "GetStringValue"
hTree          = HKEY_LOCAL_MACHINE
sKey           = "SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon"
sValue         = "DefaultUserName"

Set oRegistry  = GetObject("winmgmts:{impersonationLevel=impersonate}//" & _
               sComputer & "/root/default:StdRegProv")

Set oMethod    = oRegistry.Methods_(sMethod)
Set oInParam   = oMethod.inParameters.SpawnInstance_()

oInParam.hDefKey = hTree
oInParam.sSubKeyName = sKey
oInParam.sValueName = sValue

Set oOutParam = oRegistry.ExecMethod_(sMethod, oInParam)
WScript.Echo oOutParam.Properties_("sValue")

The same script can be used to read registry values of type multi-string and expanded-string (just remember to change the value of sMethod variable to "GetMultiStringValue" or "GetExpandedStringValue" and point to appropriate registry key and value). Also, note that you need to set the value of sComputer to match the actual name of the target computer. You can use single dot (".") when referring to the local system.
Retrieving binary value from the registry will be done almost identically. The obvious change is the new value of the sMethod variable (since we are calling the "GetBinaryValue" method) as well as the registry key and value. Another, less obvious change is the way the results are retrieved. The binary value is returned as "uValue" property (unlike "sValue" property from the previous example). "uValue" property is an array of bytes, each displayed in decimal format (a value between 0 and 255).

Const HKEY_CLASSES_ROOT        = &H80000000
Const HKEY_CURRENT_USER        = &H80000001
Const HKEY_LOCAL_MACHINE       = &H80000002
Const HKEY_USERS               = &H80000003
Const HKEY_CURRENT_CONFIG      = &H80000005

sComputer      = "TargetComputer"
sMethod        = "GetBinaryValue"
hTree          = HKEY_LOCAL_MACHINE
sKey           = "SOFTWARE\Microsoft\Windows NT\CurrentVersion"
sValue         = "DigitalProductId"

Set oRegistry  = GetObject("winmgmts:{impersonationLevel=impersonate}//" & _
               sComputer & "/root/default:StdRegProv")

Set oMethod    = oRegistry.Methods_(sMethod)
Set oInParam   = oMethod.inParameters.SpawnInstance_()

oInParam.hDefKey = hTree
oInParam.sSubKeyName = sKey
oInParam.sValueName = sValue

Set oOutParam = oRegistry.ExecMethod_(sMethod, oInParam)
For iCount = 0 To UBound(oOutParam.Properties_("uValue"))
        WScript.Echo oOutParam.Properties_("uValue")(iCount)
Next
The same script can be used to read the registry value of DWORD type (after changing value of the sMethod variable to GetDwordValue and specifying appropriate registry key and value).