Tuesday, December 24, 2013

Solution: Using StdRegProv


I recently came across an issue and a solution for it regarding the use of the StdRegProv which enables us to access the registry via all other languages except Powershell.

Lets take a look at what I'm talking about:

The MOF looks like this:

uint32 EnumKey(
  [in, optional]  uint32 hDefKey = HKEY_LOCAL_MACHINE,
  [in]            string sSubKeyName,
  [out]           string sNames[]
);
 
We call it by creating the HKEY_ value in hex or dec:
 
Const HKEY_CLASSES_ROOT = &H80000000 
or
Const HKEY_CLASSES_ROOT = 2147483648 

Dim iret
Dim Names()
Dim sKey
sKey = "clsid"

Set oReg = GetObject("winmgmts:\\.\root\cimv2").Get("StdRegProv")
oReg.EnumKey HKEY_CLASSES_ROOT, sKey, Names
For each Name in Names
   wscript.echo Name
Exit For
Next

Works flawlessly.

Now, let's turn this into a powershell script:

$HKEY_CLASSES_ROOT = 2147483648

[System.Int32]$iret
[System.String[]]$Names
[System.String]$sKey

$sKey = "clsid"
$oReg = Get-WmiObject -namespace root\cimv2 -class StdRegProv
$iret = $oReg.EnumKey($HKEY_CLASSES_ROOT, $sKey, $Names)
Foreach($Name in $Names)
{
  write-host $Name
  break
}

As it turns out, you can't call this as an instance of a class:


You cannot call a method on a null-valued expression.
At C:\Users\Administrator\Desktop\testregcode.ps1:9 char:1
+ $iret = $oReg.EnumKey($HKEY_CLASSES_ROOT, $sKey, $Names)
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (:) [], RuntimeException
    + FullyQualifiedErrorId : InvokeMethodOnNull

You need to call it as a class:

$HKEY_CLASSES_ROOT = 2147483648

[System.Int32]$iret
[System.String[]]$Names
[System.String]$sKey

$sKey = "clsid"
$oReg = [WMICLASS]"root\cimv2:StdRegProv"
$iret = $oReg.EnumKey($HKEY_CLASSES_ROOT, $sKey, $Names)
Foreach($Name in $Names)
{
  write-host $Name
  break
}

But you will still get an error:

Cannot find an overload for "EnumKey" and the argument count: "3".
At C:\Users\Administrator\Desktop\testregcode.ps1:9 char:1
+ $iret = $oReg.EnumKey($HKEY_CLASSES_ROOT, $sKey, $Names)
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [], MethodException
    + FullyQualifiedErrorId : MethodCountCouldNotFindBest


Okay, so what is going on here?  Well, it turns out that you pass in the correct  IN parameters as you normally would and get passed back out a System.Management.ManagementBaseObject.


 $HKEY_CLASSES_ROOT = 2147483648

[System.Int32]$iret
[System.String[]]$Names
[System.String]$sKey
[System.Object]$retValues

$sKey = "clsid"
$oReg = [WMICLASS]"root\cimv2:StdRegProv"
$retValues = $oReg.EnumKey($HKEY_CLASSES_ROOT, $sKey)
foreach($prop in $retValues.Properties)
{
    $prop.Name
}

This will return:

ReturnValue
sNames

You will see this in examples on the web:

$HKEY_CLASSES_ROOT = 2147483648

[System.Int32]$iret
[System.String[]]$Names
[System.String]$sKey
[System.String[]]$strValues

$sKey = "clsid"
$oReg = [WMICLASS]"root\cimv2:StdRegProv"
$strValues = $oReg.EnumKey($HKEY_CLASSES_ROOT, $sKey).snames
foreach($val in $strValues)
{
    write-host $val
}

This will return every subkey in HKEY_CLASSES_ROOT\clsid.  With that said, you really need to parse for the return Value as it will tell you whether or not the call was successful or not.


$HKEY_CLASSES_ROOT = 2147483648

[System.Int32]$iret
[System.String[]]$Names
[System.String]$sKey
$OutVal

$sKey = "clsid"
$oReg = [WMICLASS]"root\cimv2:StdRegProv"
$OutVal = $oReg.EnumKey($HKEY_CLASSES_ROOT, $sKey)
if($OutVal.Properties.Item("ReturnValue").Value -eq 0)
{
    $sNames =  $OutVal.Properties.Item("sNames").Value
    foreach($sName in $sNames)
    {
         write-host $sName
    }
}

Here's an example of getting a DWORD value: 

$HKEY_LOCAL_MACHINE = 2147483650

[System.Int32]$iret
[System.String[]]$Names
[System.String]$sKey
$OutVal

$sKey = "Software\Microsoft\Windows NT\CurrentVersion"
$oReg = [WMICLASS]"root\cimv2:StdRegProv"

$OutVal = $oReg.GetDWordValue($HKEY_LOCAL_MACHINE, $sKey, "InstallDate")
if($OutVal.Properties.Item("ReturnValue").Value -eq 0)
{
    $Value =  $OutVal.Properties.Item("uValue").Value
    $vs = '{0:x}' -f $Value
    $vs = "0x" + $vs + "(" + $Value + ")"
    write-host $vs
}

Now, let's do the Reg_Binary:


$HKEY_LOCAL_MACHINE = 2147483650

[System.Int32]$iret
[System.String[]]$Names
[System.String]$sKey
[System.Management.ManagementBaseObject]$OutVal

$sKey = "Software\Microsoft\Windows NT\CurrentVersion"
[System.String]$vs = ""
$oReg = [WMICLASS]"root\cimv2:StdRegProv"
$Name = "DigitalProductId"
$OutVal = $oReg.GetBinaryValue($HKEY_LOCAL_MACHINE, $sKey, $Name)
if($OutVal.Properties.Item("ReturnValue").Value -eq 0)
{
   $Value =  $OutVal.Properties.Item("uValue").Value
   foreach($v in $Value)
   {
       $vv = '{0:x}' -f $v
       if($vv.ToString().Length -eq 1)
       {
          $vv = "0" + $vv
       }
       if($vs -ne "")
       {
            $vs = $vs + ","
       }
       $vs = $vs + $vv
       $vv = ""
   }
   write-host $vs
}

Now, let's enumerate through Values:

$HKEY_LOCAL_MACHINE = 2147483650

[System.Int32[]]$DataTypes
[System.String[]]$ValueNames
[System.String]$sKey
[System.Management.ManagementBaseObject]$OutVal

$sKey = "SYSTEM\CurrentControlSet\Control\Session Manager"
[System.String]$vs = ""
$oReg = [WMICLASS]"root\cimv2:StdRegProv"
$Name = "DigitalProductId"
$OutVal = $oReg.EnumValues($HKEY_LOCAL_MACHINE, $sKey)
[System.String]$Value
[System.String]$v
[System.String]$vv

$ValueNames = $outVal.Properties.Item("sNames").Value
$DataTypes = $outVal.Properties.Item("Types").Value

for($x=0;$x -lt $DataTypes.GetLength(0); $x++)
{

    switch ($DataTypes[$x])
        {
            1{
                $OutVal = $oReg.GetStringValue($HKEY_LOCAL_MACHINE, $sKey, $ValueNames[$x])
                if($OutVal.Properties.Item("ReturnValue").Value -eq 0)
                {
                    $Value =  $OutVal.Properties.Item("sValue").Value
                }
                Write-Host $ValueNames[$x] REG_SZ $Value           
            }
            2{
                $OutVal = $oReg.GetExpandedStringValue($HKEY_LOCAL_MACHINE, $sKey, $ValueNames[$x])
                if($OutVal.Properties.Item("ReturnValue").Value -eq 0)
                {
                    $Value =  $OutVal.Properties.Item("sValue").Value
                }
                Write-Host $ValueNames[$x] REG_EXPAND_SZ $Value           
            }
            3{

                $OutVal = $oReg.GetBinaryValue($HKEY_LOCAL_MACHINE, $sKey, $ValueNames[$x])
                if($OutVal.Properties.Item("ReturnValue").Value -eq 0)
                {
                    $Value =  $OutVal.Properties.Item("uValue").Value
                    foreach($v in $Value)
                    {
                        $vv = '{0:x}' -f $v
                        if($vv.ToString().Length -eq 1)
                        {
                            $vv = "0" + $vv
                        }
                        if($vs -ne "")
                        {
                            $vs = $vs + ","
                        }
                        $vs = $vs + $vv
                        $vv = ""
                                         
                    }
                    Write-Host $ValueNames[$x] REG_BINARY $vs
                }
            }
            4{
                $vs = ""
                $OutVal = $oReg.GetDWordValue($HKEY_LOCAL_MACHINE, $sKey, $ValueNames[$x])
                if($OutVal.Properties.Item("ReturnValue").Value -eq 0)
                {
                    $Value =  $OutVal.Properties.Item("uValue").Value
                    foreach($v in $Value)
                    {
                        $vv = '{0:x}' -f $v
                        if($vs -ne "")
                        {
                            $vs = $vs + ","
                        }
                        $vs = $vs + $vv
                        $vv = ""
                    }
                    Write-Host $ValueNames[$x] REG_DWORD $vs
                }
            }
            7{
                $OutVal = $oReg.GetMultiStringValue($HKEY_LOCAL_MACHINE, $sKey, $ValueNames[$x])
                if($OutVal.Properties.Item("ReturnValue").Value -eq 0)
                {
                    $Value =  $OutVal.Properties.Item("sValue").Value
                }
                Write-Host $ValueNames[$x] REG_SZ $Value  
            }
        }
}