首页 > 解决方案 > Powershell - .net 远程注册表返回空白

问题描述

当使用 .NET 方法[Microsoft.win32.registrykey]尝试查询远程注册表项时,我只会在每一步都获得空值

像这样建立一些变量:

$computer = '192.168.200.10'
$key = "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\7-zip"
$type = [Microsoft.Win32.RegistryHive]::LocalMachine
$reg = [Microsoft.win32.registrykey]::OpenRemoteBaseKey($type, $computer)

如果我然后尝试这样的事情:

$reg.opensubkey($key)

我会得到一个空白的“名称”和“属性”列。我已经尝试删除这remote方面的内容并尝试::OpenBaseKey查看我自己的 HKLM 配置单元,但它仍然返回空白。

这一切都始于一个脚本,该脚本将找到给定程序的卸载字符串,包括它是否仅在 HKU 配置单元中注册。最终目的是针对 LAN 上的远程计算机运行它,以查找我感兴趣的任何程序的卸载字符串。
尝试在不导入任何其他模块的情况下执行此操作,因为我希望能够按原样共享它。只是挠头弄清楚如何查询远程注册表。

这是我的查询在本地显示的示例。

$64bit = get-itemproperty HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\*,HKU:\${sid}\Software\Microsoft\Windows\CurrentVersion\Uninstall\* | Select-Object DisplayName, DisplayVersion, UninstallString, PSChildName | Where-Object { $_.DisplayName -like "$process*"}
$32bit = get-itemproperty HKLM:\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\* | Select-Object DisplayName, DisplayVersion, UninstallString, PSChildName | Where-Object { $_.DisplayName -like "$process*"}

$sid变量是根据登录用户较早找到的。

标签: .netpowershellregistry

解决方案


我会得到一个空白的“名称”和“属性”列。

这本身并不表示问题;这只是一个显示问题 - 见底部。

虽然您可以直接使用该[Microsoft.Win32.RegistryHive]类型来获得所需的内容,但它会比使用 PowerShell 的Get-ItemPropertycmdlet 更复杂、更冗长。

Get-ItemProperty本身缺乏针对远程注册表的能力,但您可以将其与PowerShell remoting结合使用,这可能需要在目标计算机上进行事先设置 - 请参阅about_Remote_FAQ

# Create a session on the target computer.
# The target machine must have PowerShell remoting enabled.
# You may have to specify credentials with -Credential
$session = New-PSSession -ComputerName '192.168.200.10' 

# Use Invoke-Command with the session to execute your commands remotely.
$64bit = Invoke-Command -Session $session { 
  get-itemproperty HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\*, HKU:\${using:sid}\Software\Microsoft\Windows\CurrentVersion\Uninstall\* |
    Select-Object DisplayName, DisplayVersion, UninstallString, PSChildName |
      Where-Object { $_.DisplayName -like "${using:process}*"}
}

$32bit = Invoke-Command -Session $session { 
  get-itemproperty HKLM:\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\* |
    Select-Object DisplayName, DisplayVersion, UninstallString, PSChildName |
      Where-Object { $_.DisplayName -like "${using:process}*"}
}

# Close the session.
Remove-PSSession $session

重要提示:注意局部变量$sid和如何$process被引用为${using:sid}${using:process},这是远程执行的脚本块看到它们所必需的。

请注意,通过远程处理接收到的输出在远程端进行序列化,在本地端进行反序列化,这意味着只有少数众所周知的类型被反序列化为其原始类型。所有其他都是基于类型的具有静态属性值的原始对象的近似值。[pscustomobject]

虽然有时这可能是个问题,但在您的情况下不会出现这种情况,因为您的命令输出的对象是[pscustomobject]开始时的实例,因为使用Select-Object.


至于你原来的症状

看似空白的属性是一个显示问题与针对远程注册表[1]无关:

应用的输出格式$reg.opensubkey($key)基于type的 PowerShell格式指令Microsoft.Win32.RegistryKey,但这些指令依赖于此类实例,以使用 PowerShell 提供程序属性进行扩充,这些属性仅在您通过/获取Microsoft.Win32.RegistryKey实例时存在。Get-ItemGet-ChildItem

相比之下,Microsoft.Win32.RegistryKey直接通过 .NET API 获得的实例缺少格式化所依赖的提供程序添加的属性,导致格式化定义呈现空白列值

如前所述,无论您是针对本地注册表还是远程注册表,此问题都会独立存在,因此让我用本地密钥演示该问题:

$base = [Microsoft.Win32.RegistryKey]::OpenBaseKey([Microsoft.Win32.RegistryHive]::CurrentUser, 'Registry64')
$subkey = $base.OpenSubKey('Console')

$subkey   # output

以上,即使打开HKEY_CURRENT_USER]\Console成功,也会产生一个看似空的对象:


Name                           Property
----                           --------

一个简单的解决方法是使用 强制显式显示真实属性Format-List *,例如:

PS> $subkey | Format-List *

SubKeyCount : 2
View        : Registry64
Handle      : Microsoft.Win32.SafeHandles.SafeRegistryHandle
ValueCount  : 46
Name        : HKEY_CURRENT_USER\Console

请注意,以上内容不会提供目标键的值和数据的显示,这是 PowerShell 默认提供的方式,出于礼貌,通过计算Property列提供;你也必须做更多的工作才能显示出来。


[1] 顺便说一句:当前(PowerShell Core 7.0.0-preview.3)针对远程注册表时存在一个单独但相关的问题,但前提是您确实使用Get-Item/ Get-ChildItem:请参阅此帖子


推荐阅读