When accessing the registry remotely from Powershell it is common knowledge to use the "Microsoft.Win32.RegistryKey" .Net classes. This technique has been described here http://mybsinfo.blogspot.com/2007/01/powershell-remote-registry-and-you-part.html or in this other article on Technet Script Center http://www.microsoft.com/technet/scriptcenter/resources/qanda/jan09/hey0105.mspx and in a number of places on the Web.

A number of places suggest a function similar to the following:

Function GetValueFromRegistry ([string]$computername, $regkey, $value)   
{   
     $reg = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey('LocalMachine', $computername)   
     $regKey= $reg.OpenSubKey("$regKey")   
     $result = $regkey.GetValue("$value")   
     return $result 
}  

Even if the above works in most cases, when using the a 32bit powershell process (or a 32bit machine) to access the registry on a 64bit machine, such a script will fail and will not be able to access certain registry keys - but only some other ones.

The issue is happening because the 32 bit machine (or process), when accessing a 64bit machine, will be redirected by default to the Wow6432Node location in the registry.  You can learn a bit more on registry Redirection between 32bit and 64bit processes here http://msdn.microsoft.com/en-us/library/aa384232(VS.85).aspx

The function provided here will use the WMI COM objects (the same ones you have always used in VBScript) instead, which will let you specify you want to retrieve data from the *REAL* 64bit registry values.

It is based on sample code explained on http://msdn.microsoft.com/en-us/library/aa393067(VS.85).aspx , but it has been ported to Powershell.

I first blogged about this here: http://www.muscetta.com/2009/09/10/mistery-of-lost-registry-values/ 

PowerShell
Edit|Remove
Function GetValueFromRegistryThruWMI([string]$computername, $regkey, $value)   
{   
    #constant for the HLKM   
    $HKLM = "&h80000002"  
  
    #creates an SwbemNamedValueSet object 
    $objNamedValueSet = New-Object -COM "WbemScripting.SWbemNamedValueSet"  
  
    #adds the actual value that will requests the target to provide 64bit-registry info 
    $objNamedValueSet.Add("__ProviderArchitecture", 64) | Out-Null  
  
    #back to all the other usual COM objects for WMI that you have used a zillion times in VBScript 
    $objLocator = New-Object -COM "Wbemscripting.SWbemLocator"  
    $objServices = $objLocator.ConnectServer($computername,"root\default","","","","","",$objNamedValueSet)   
    $objStdRegProv = $objServices.Get("StdRegProv")   
  
    # Obtain an InParameters object specific to the method.   
    $Inparams = ($objStdRegProv.Methods_ | where {$_.name -eq "GetStringValue"}).InParameters.SpawnInstance_()   
   
    # Add the input parameters   
    ($Inparams.Properties_ | where {$_.name -eq "Hdefkey"}).Value = $HKLM  
    ($Inparams.Properties_ | where {$_.name -eq "Ssubkeyname"}).Value = $regkey  
    ($Inparams.Properties_ | where {$_.name -eq "Svaluename"}).Value = $value  
  
    #Execute the method   
    $Outparams = $objStdRegProv.ExecMethod_("GetStringValue", $Inparams, "", $objNamedValueSet)   
  
    #shows the return value   
    ($Outparams.Properties_ | where {$_.name -eq "ReturnValue"}).Value   
  
    if (($Outparams.Properties_ | where {$_.name -eq "ReturnValue"}).Value -eq 0)   
    {   
       write-host "it worked"  
       $result = ($Outparams.Properties_ | where {$_.name -eq "sValue"}).Value   
       write-host "Result: $result"  
       return $result  
    }   
    else  
    {   
        write-host "nope"  
    }   
}   



#call the above function with
GetValueFromRegistryThruWMI "servername" "SOFTWARE\Microsoft\Microsoft Operations Manager\3.0\Setup" "DatabaseServerName"