Accessing 64bit registry keys via 32bit scripting languages

Accessing 64bit registry keys via 32bit scripting languages:

This is a very often requirement since the evolution of 64bit platforms.  By default, an application or script receives data from the corresponding provider when two versions of providers exist. The 32-bit provider returns data to a 32-bit application, including all scripts, and the 64-bit provider returns data to the 64-bit compiled applications. However, an application or script can request data from the nondefault provider, if it exists, by notifying WMI through flags on method calls.

Context Flags

The __ProviderArchitecture and __RequiredArchitecture string flags have a set of values handled by WMI but not defined in SDK header or type library files. The values are placed in a context parameter to signal WMI that it should request data from the nondefault provider.

Windows Server 2003, Windows 2000, and Windows XP:  These flags were not available until Windows Server 2003 with Service Pack 1 (SP1).

The following table lists the flags and their possible values.

Flag

Description

__ProviderArchitecture
Integer value, either 32 or 64, that specifies the 32-bit or 64-bit version.

__RequiredArchitecture
Boolean value used in addition to __ProviderArchitecture to force load the specified provider version. If the version is unavailable, then WMI returns the error 0x80041013, wbemErrProviderLoadFailure for Visual Basic and WBEM_E_PROVIDER_LOAD_FAILURE for C++. The default value for this flag when it is not specified is FALSE.

On a 64-bit system that has side-by-side versions of a provider, a 32-bit application or script automatically receives data from the 32-bit provider, unless these flags are supplied and indicate that the 64-bit provider data should be returned.

Using the Context Flags

C++ applications can use the IWbemContext interface with IWbemServices::ExecMethod to communicate the use of a nondefault provider to WMI.

In scripting and Visual Basic, you must create a SWbemNamedValueSet object containing the flags for the objWbemNamedValueSet parameter ofSWbemServices.ExecMethod. For more information about setting up the parameters objects for this call, see Constructing InParameters Objects and Parsing OutParameters Objects.

You can safely run scripts and applications using the context flags in older operating systems, because WMI ignores them in systems in which they are not implemented. While 32-bit and 64-bit versions of the System Registry provider exist, note that only one version of the WMI repository exists.

Accessing the Default Registry Hive

The following series of examples use the Registry Provider, which has side-by-side 32-bit and 64-bit versions preinstalled on 64-bit operating systems. In these examples, 32-bit clients get data returned by the provider from the 32-bit nodeHKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft. 64-bit clients get data returned by the provider from the 64-bit nodeHKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Logging.

The scripts show how to call the methods of the Registry StdRegProv class through SWbemServices.ExecMethod to obtain data from the 32-bit registry hive.

The following script gets back data from the provider that matches the bit width of the caller, in this case 64 bits, because it is a script running under the 64-bit Windows Script Host (WSH). The script gets the value from the 64-bit registry nodeHKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\WBEM\CIMOM\Logging rather than the 32-bit nodeHKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\WBEM\CIMOM.

[code language=”vb”]
strComputer = "."
Const HKLM = &h80000002
Set objReg = Getobject("winmgmts:" _
    & "{impersonationLevel=impersonate}!\\" & strComputer _
    & "\root\default:stdregprov")
‘Set up inParameters object
Set Inparams = objReg.Methods_("GetStringValue").Inparameters
Inparams.Hdefkey = HKLM
Inparams.Ssubkeyname = "Software\Microsoft\Wbem\CIMOM"
Inparams.Svaluename = "Logging"
set Outparams = objReg.ExecMethod_("GetStringValue", Inparams)

‘Show output parameters object and the registry value HKLM\SOFTWARE\
WScript.Echo Outparams.GetObjectText_
WScript.Echo "WMI Logging is set to  " & Outparams.SValue
[/code]

If the Logging value in the default hive is set to 1, then the output from the script should look something like the following:

Here I wanted to make it an easy task for all the systems engineers who has to mull over with this requirement. Below are some of the default MSFT provided examples of objects coding for this requirement and I am also including a full script that explains you how exactly we can invoke those calls in VBscript.

[code language=”vb”]
instance of __PARAMETERS
{
    ReturnValue = 0;
    sValue = "1";
};
WMI Logging is set to 1
[/code]

Example: Specifically Requesting the 32-bit Registry Hive on a 64-bit Computer

The following modified example of the default script uses the __ProviderArchitecture string flag to request access to the 32-bit registry data on a 64-bit computer. The caller is connected to the 32-bit hive irrespective of whether it is a 32- or 64-bit application.

[code language=”vb”]
strComputer = "."
Const HKLM = &h80000002
Set objCtx = CreateObject("WbemScripting.SWbemNamedValueSet")
objCtx.Add "__ProviderArchitecture", 32
Set objLocator = CreateObject("Wbemscripting.SWbemLocator")
Set objServices = objLocator.ConnectServer("","root\default","","",,,,objCtx)
Set objStdRegProv = objServices.Get("StdRegProv")

Set Inparams = objStdRegProv.Methods_("GetStringValue").Inparameters
Inparams.Hdefkey = HKLM
Inparams.Ssubkeyname = "Software\Microsoft\Wbem\CIMOM"
Inparams.Svaluename = "Logging"
set Outparams = objStdRegProv.ExecMethod_("GetStringValue", Inparams,,objCtx)

‘show output parameters object and the registry value HKLM\SOFTWARE\
WScript.Echo Outparams.GetObjectText_
WScript.Echo "WMI Logging is set to  " & Outparams.SValue
[/code]

Example: Forcing WMI to Access the 32-bit Registry Hive on a 64-bit Computer

The following modification of the script above by adding the __ProviderArchitecture and __RequiredArchitecture flags to the context parameter forces WMI to load the 32-bit provider and get 32-bit data. If the provider does not exist, then a provider load error occurs. The context object must be supplied in the connection to WMI by calling SWbemLocator.ConnectServer.

[code language=”vb”]
strComputer = "."
Const HKLM = &h80000002
Set objCtx = CreateObject("WbemScripting.SWbemNamedValueSet")
objCtx.Add "__ProviderArchitecture", 32
objCtx.Add "__RequiredArchitecture", TRUE
Set objLocator = CreateObject("Wbemscripting.SWbemLocator")
Set objServices = objLocator.ConnectServer("","root\default","","",,,,objCtx)
Set objStdRegProv = objServices.Get("StdRegProv")

‘ Use ExecMethod to call the GetStringValue method
Set Inparams = objStdRegProv.Methods_("GetStringValue").Inparameters
Inparams.Hdefkey = HKLM
Inparams.Ssubkeyname = "Software\Microsoft\Wbem\CIMOM"
Inparams.Svaluename = "Logging"
set Outparams = objStdRegProv.ExecMethod_("GetStringValue", Inparams,,objCtx)

‘Show output parameters object and the registry value HKLM\SOFTWARE\
WScript.Echo Outparams.GetObjectText_
WScript.Echo "WMI Logging is set to  " & Outparams.SValue
[/code]

32-bit VBScript to query the 64-bit registry keys:

[code language=”vb”]
‘===============================================================================
‘ Script name   : generic_uninstall.vbs
‘ Author        : Govardhan Gunnala
‘ Date          : mm/dd/yyyy
‘ Objective     : Uninstall script for xxx-64bit application

‘ $Header: $

‘===============================================================================
‘ Global Statements
‘===============================================================================
On Error Resume Next

‘===============================================================================
‘ Global Constants and Variables
‘===============================================================================
Dim pkgidArray(1)

‘===============================================================================
‘ Initialize Globals
‘===============================================================================
pkgidArray(0) = "{0A0CADCF-78DA-33C4-A350-CD51849B9702}"

‘===============================================================================
‘ main()
‘===============================================================================
Set WshShell    = CreateObject("WScript.Shell")

For Each pkgid in pkgidArray
    pkgName     = RegRead("HKLM", "SOFTWARE\Microsoft\Windows\" &_
                "CurrentVersion\Uninstall\" & pkgid, "DisplayName")
    If Not IsNull(pkgName) Then
        WScript.Echo "The DisplayName of " & pkgid, " is [" & pkgName & "]"
    End If
Next

‘===============================================================================
‘ Functions
‘===============================================================================
Function RegRead(sRegHive, sRegKey, sRegValue)
    On Error Resume Next

    ‘ WScript.Echo "Entered RegRead() with values: &_
    ‘ [" & sRegHive & "], [" & sRegKey & "], [" & sRegValue & "]"

    strComputer           = "."
    Const HKLM           = &h80000002
    Set objCtx           = CreateObject("WbemScripting.SWbemNamedValueSet")
    objCtx.Add "__ProviderArchitecture", 64
    Set objLocator       = CreateObject("Wbemscripting.SWbemLocator")
    Set objServices      = objLocator.ConnectServer("","root\default","","",,,,objCtx)
    Set objStdRegProv    = objServices.Get("StdRegProv")

    Set Inparams         = objStdRegProv.Methods_("GetStringValue").Inparameters
    Inparams.Hdefkey     = sRegHive
    Inparams.Ssubkeyname = sRegKey
    Inparams.Svaluename  = sRegValue
    set Outparams        = objStdRegProv.ExecMethod_("GetStringValue",Inparams,,objCtx)
    RegRead              = Outparams.SValue

    ‘WScript.Echo Outparams.GetObjectText_
    ‘WScript.Echo "The value of [sRegHive\sRegKey\sRegValue] is [" &_
        ‘ Outparams.SValue & "]"

    ‘ If a value is present but uninitialized the RegRead method
    ‘ returns the input value in Win2k.
&nbsp;   If VarType(RegRead) < vbArray Then
&nbsp;       If RegRead = sRegValue Then
&nbsp;           RegRead = NULL
&nbsp;       End If
&nbsp;   End If

&nbsp; &nbsp; On Error Goto 0
End Function

‘===============================================================================
‘ End
‘===============================================================================
[/code]

Output:

[code language=”vb”]

—————————
Windows Script Host
—————————
The DisplayName of {0A0CADCF-78DA-33C4-A350-CD51849B9702} is [Microsoft .NET Framework 4 Extended]
—————————
OK
—————————
[/code]

Leave a Reply

Your email address will not be published. Required fields are marked *