如何从32位Powershell实例访问64位注册表?

时间:2009-03-10 14:11:10

标签: powershell registry 64-bit

如果启动32位Powershell实例(%SystemRoot%\ syswow64 \ WindowsPowerShell \ v1.0 \ powershell.exe),则注册表提供程序只能看到注册表中有限的32位部分。

**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

有没有办法强制提供程序进入64位模式?我可以下载到[Microsoft.Win32] .Net API,或者WMI,但我不愿意。我正在使用Powershell v2 CTP3,如果它扩大了可能性。

9 个答案:

答案 0 :(得分:23)

使用.NET API,您可以读取如下所示的64位值:

$key = [Microsoft.Win32.RegistryKey]::OpenBaseKey([Microsoft.Win32.RegistryHive]::LocalMachine, [Microsoft.Win32.RegistryView]::Registry64)
$subKey =  $key.OpenSubKey("SOFTWARE\Microsoft\.NETFramework")
$root = $subKey.GetValue("InstallRoot")

答案 1 :(得分:8)

当Powershell作为32位进程运行时,我不知道将其“切换”到64位模式的机制。 64位系统的虚拟化支持的全部要点是让32位进程相信它们生活在32位操作系统中......

然而,这说我过去使用了以下技术,它对我来说非常好用(以下代码在带有Powershell v1的Vista SP1 x64上进行了测试)。该技术依赖于.NET的“任何CPU”可执行文件即使在从32位进程调用时也将作为64位进程运行的事实。我们将要执行的步骤:

  1. 编译一个简短的C#程序,它将启动powershell(即一个非常简单的“fork”实现:-))
  2. 运行已编译的C#程序
  3. 编译好的C#程序将启动Powershell,但由于它是“任何CPU”,它将作为64位进程运行,因此它将启动64位Powershell(请注意,因为这只是一个概念验证,我希望PowerShell进入你的“道路”)
  4. 新的64位Powershell将运行我们选择的命令行开关
  5. 这是上面的操作截图(注意过程的位置): Process tree http://img3.imageshack.us/img3/3248/powershellfork.png

    以下程序希望列出的所有文件都驻留在同一目录中。我建议创建一个测试目录,例如C:\ Temp \ PowershellTest,并存储所有文件。)

    程序的入口点将是一个简单的命令行开关:

    # 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)
    

    它运行csc(32位,但没关系:-))然后运行csc编译器的结果,传递一个参数,(完整路径)visibility.ps1(这是我们想要在64位运行的命令行开关的powershell)。

    C#代码也非常简单:

    // 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;
            }
        }
    }
    

    最后,你的“可见性”脚本:

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

    从32位Powershell运行入口脚本现在产生了预期的结果(只是为了表明我没有作弊我首先直接运行可见性脚本,然后使用我们的fork技术):

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

答案 2 :(得分:5)

我相信内置的cmdlet Start-Job将允许您从32位实例检查64位注册表。

如果没有,请使用Invoke-Command循环回本地计算机。 64位计算机将具有两个端点(64位和32位),64位端点将是默认端点。

创建注册表值并确保它位于64位路径中的示例,而不是32位。

Invoke-Command -scriptblock {
    New-ItemProperty -Path HKLM:\SOFTWARE\Acme 
                     -Name NameofNewReg 
                     -PropertyType String -Value "1"
    } -computername .

答案 3 :(得分:1)

根据Bart De Smet的blog,米兰的回答略有不同,就是使用C#程序主持PowerShell。尽管该博客文章主要针对.NET 4.0进行编译,但您也可以针对.NET 3.5进行编译。结果是一个二进制文件,它是一个PowerShell主机,当从32位进程调用时可以访问64位注册表:

using System;
using System.Management.Automation.Runspaces;
using Microsoft.PowerShell;

namespace PSHost
{
    class Program
    {
        static void Main(string[] args)
        {

            var config = RunspaceConfiguration.Create();
            ConsoleShell.Start(
                config,
                "Windows PowerShell - Compiled for ANY CPU",
                "",
                args
            );

        }
    }
}

答案 4 :(得分:1)

如果环境变量PROCESSOR_ARCHITEW6432存在且值为AMD64,那么您在64位计算机上运行32位。 您必须在虚拟64位路径%windir%\ sysnative中运行powershell。

if ($env:PROCESSOR_ARCHITEW6432 -eq "AMD64") {
    write-warning "changing from 32bit to 64bit PowerShell..."
    $powershell=$PSHOME.tolower().replace("syswow64","sysnative").replace("system32","sysnative")

    if ($myInvocation.Line) {
        &"$powershell\powershell.exe" -NonInteractive -NoProfile $myInvocation.Line
    } else {
        &"$powershell\powershell.exe" -NonInteractive -NoProfile -file "$($myInvocation.InvocationName)" $args
    }

    exit $lastexitcode
}

答案 5 :(得分:1)

要扩展Milan Gardian的答案,请将此函数用于小代码块:

function RunAs-64Bit ([ScriptBlock]$scriptblock)
{
    [string]$code = '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; } } }'
    [string]$exeName = $env:temp + '\' + [System.IO.Path]::GetRandomFileName() + '.exe';
    $params = New-Object 'System.CodeDom.Compiler.CompilerParameters'; 
    @('mscorlib.dll',  'System.dll', ([System.Reflection.Assembly]::GetAssembly([PSObject]).Location)) | %{ $params.ReferencedAssemblies.Add( $_ ) } | Out-Null
    $params.GenerateExecutable      = $true
    $params.GenerateInMemory        = $false;
    $params.CompilerOptions         = '/optimize';
    $params.OutputAssembly          = $exeName;
    $params.TreatWarningsAsErrors   = $false;
    $params.WarningLevel            = 4;

    $csprovider = New-Object 'Microsoft.CSharp.CSharpCodeProvider'; #disposable
    try {
        $compileResults = $csprovider.CompileAssemblyFromSource($params, $code)
        $errors = $compileResults.Errors | ?{ -not $_.IsWarning }
        if ($errors.Count -gt 0) 
        {
            Write-Host -f red 'Compiler errors are found.'
            foreach ($output in $compileResults.Output) { Write-Host -$output }
            foreach ($err in $errors) { Write-Host -f red $('Compile Error: ' + $err); }            
        }
        else 
        {
            $compileResults.Errors | %{ Abr-Write-UtilLog 'Util Get assembly from code' $('Compile Warning: ' + $_); }            
            $assembly = $compileResults.CompiledAssembly
            $commandParam = '-encodedCommand  ' + [System.Convert]::ToBase64String([System.Text.Encoding]::UNICODE.GetBytes($scriptblock));
            &$exeName $commandParam
        }
        Remove-Item -force $exeName -ErrorAction 'SilentlyContinue';
    } finally{
        $csprovider.Dispose();
        Remove-Variable 'csprovider';
    }
}

当64位模式可用时,现在使用此函数在64位模式下运行任何脚本块(只要它不是太大)

答案 6 :(得分:1)

最简单的方法是使用此快捷方式: C:\ WINDOWS \ sysnative 这相当于 C:\ Windows \ System32 - 但关键的区别是该进程是作为64位进程启动的。因此,从32位PowerShell访问64位注册表的最简单方法是通过C:\ Windows \ sysnative调用reg.exe 例如:

C:\Windows\sysnative\reg.exe QUERY HKLM\SOFTWARE\JavaSoft\JDK

来源:https://stackoverflow.com/a/25103599

如果由于某种原因,您需要从64位命令行访问32位注册表,请使用C:\ Windows \ syswow64

C:\Windows\syswow64\reg.exe QUERY HKLM\SOFTWARE\JavaSoft

答案 7 :(得分:0)

REG.EXE命令可以写入64位注册表,因此以下内容对于来自PowerShell的32/64位应该是安全的。

&REG.EXE @('ADD','HKLM\YOURPATH\...','/v','KEY','/t','REG_DWORD','/d','12c','/f','/reg:64')

与其他解决方案相比,它似乎更简单,更不容易出错。这可能是在您介意多年后才出现的。

答案 8 :(得分:0)

试试这个。 (REG 查询 "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall" /reg:64) 使用您喜欢的任何键。我正在搜索卸载键。

我注意到其他类似的答案,但它们没有包含 /reg:64 参数。另请注意,HKLM 后没有“:”

相关问题