Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to access the 64-bit registry from a 32-bit Powershell instance?

If you launch a 32-bit instance of Powershell (%SystemRoot%\syswow64\WindowsPowerShell\v1.0\powershell.exe), then the registry provider only sees the limited 32-bit parts of the registry.

**32-bit console**
PS> (dir HKLM:\SOFTWARE | measure).count - (dir HKLM:\SOFTWARE\wow6432node | measure).count

0

**64-bit console**
PS> (dir HKLM:\SOFTWARE | measure).count - (dir HKLM:\SOFTWARE\wow6432node | measure).count

-5

Is there any way to force the provider into 64-bit mode? I could drop down to [Microsoft.Win32] .Net APIs, or maybe WMI, but I'd rather not. I'm using Powershell v2 CTP3 if that expands the possibilities at all.

like image 960
Richard Berg Avatar asked Mar 10 '09 14:03

Richard Berg


People also ask

How do I open a 64-bit registry?

To view or edit 64-bit keys, you must use the 64-bit version of Registry Editor (Regedit.exe). You can also view or edit 32-bit keys and values by using the 32-bit version of Registry Editor in the %systemroot%\Syswow64 folder.

How do I change my registry from 32-bit to 64-bit?

Right-click one of them and select the "Properties" menu. In the "Edit Component Properties" dialog set the Condition field to VersionNT64. Tick the option 64-bit Component.

How do I query a registry key in PowerShell?

One of the easiest ways to find registry keys and values is using the Get-ChildItem cmdlet. This uses PowerShell to get a registry value and more by enumerating items in PowerShell drives. In this case, that PowerShell drive is the HKLM drive found by running Get-PSDrive .

How do I open a 64-bit PowerShell?

The 64-bit version of PowerShell (the one that 64-bit Windows opens by default) is located under: “C:\Windows\SysWOW64\WindowsPowerShell\v1. 0.” To run the program as administrator, right-click on powershell.exe and then choose the “Run as administrator” option.


2 Answers

With .NET API you can read 64-bit values like this:

$key = [Microsoft.Win32.RegistryKey]::OpenBaseKey([Microsoft.Win32.RegistryHive]::LocalMachine, [Microsoft.Win32.RegistryView]::Registry64)
$subKey =  $key.OpenSubKey("SOFTWARE\Microsoft\.NETFramework")
$root = $subKey.GetValue("InstallRoot")
like image 54
SergVro Avatar answered Sep 23 '22 04:09

SergVro


When Powershell is running as a 32 bit process, I am not aware of a mechanism to "switch it" to 64bit mode. The whole point of virtualization support in 64bit systems is to make 32bit processes believe they are living in a 32bit OS...

However, that said I used the following technique in the past and it worked very nicely for me (the following code was tested on Vista SP1 x64 with Powershell v1). The technique relies on the fact that .NET's "Any CPU" executables will run as 64bit process even when invoked from a 32bit process. The steps we will be performing:

  1. Compile a short C# program that will start powershell (i.e. a very simple "fork" implementation :-) )
  2. Run the compiled C# program
  3. The compiled C# program will start Powershell, but because it's "Any CPU", it will be running as a 64bit process so it will start 64bit Powershell (note that because this is just a proof-of-concept, I expect powershell to be in your 'path')
  4. The new 64bit Powershell will run a commandlet of our choice

This is a screenshot of the above in action (notice bit-ness of the processes): Process tree http://img3.imageshack.us/img3/3248/powershellfork.png

The following program expects all the files listed to reside in the same directory. I recommend creating a test directory, e.g. C:\Temp\PowershellTest, and storing all the files there).

Entry point to the program will be a simple commandlet:

# file "test.ps1"
$basePath = Split-Path -resolve $myInvocation.MyCommand.Path
$exe = Join-Path $basePath test.exe
&"$env:SystemRoot\Microsoft.NET\Framework\v3.5\csc.exe" /nologo /target:exe /out:$exe (Join-Path $basePath test.cs)
&$exe (Join-Path $basePath visibility.ps1)

It runs csc (32bit, but it doesn't matter :-) ) and then runs result of csc compiler, passing one argument, (full path to) visibility.ps1 (this is the commandlet we want to run in 64bit Powershell).

The C# code is very simple as well:

// file "test.cs"
using System.Diagnostics;
static class Program {
    static int Main(string[] args) {
        ProcessStartInfo i = new ProcessStartInfo("powershell", args[0]);
        i.UseShellExecute = false;
        using(Process p = Process.Start(i)) {
            p.WaitForExit();
            return p.ExitCode;
        }
    }
}

And finally, your "visibility" script:

# file "visibility.ps1"
(dir HKLM:\SOFTWARE).count - (dir HKLM:\SOFTWARE\wow6432node).count

Running the entry script from 32bit Powershell now yields desired result (just to show I was not cheating I run the visibility script directly first, then using our fork technique):

Program run http://img3.imageshack.us/img3/2766/powershellrunc.png

like image 28
Milan Gardian Avatar answered Sep 25 '22 04:09

Milan Gardian