Powershell - .net 远程注册表返回空白



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

建立一些变量,如下所示:

$computer = '192.168.200.10'
$key = "SOFTWAREMicrosoftWindowsCurrentVersionUninstall7-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:SoftwareMicrosoftWindowsCurrentVersionUninstall*,HKU:${sid}SoftwareMicrosoftWindowsCurrentVersionUninstall* | Select-Object DisplayName, DisplayVersion, UninstallString, PSChildName | Where-Object { $_.DisplayName -like "$process*"}
$32bit = get-itemproperty HKLM:SoftwareWow6432NodeMicrosoftWindowsCurrentVersionUninstall* | Select-Object DisplayName, DisplayVersion, UninstallString, PSChildName | Where-Object { $_.DisplayName -like "$process*"}

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

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

本身并不表示存在问题;它只是一个显示问题 - 见底部部分。

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

Get-ItemProperty本身缺少面向远程注册表的功能,但你可以将其与PowerShell 远程处理结合使用,这可能需要在目标计算机上事先进行设置 - 请参阅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:SoftwareMicrosoftWindowsCurrentVersionUninstall*, HKU:${using:sid}SoftwareMicrosoftWindowsCurrentVersionUninstall* |
Select-Object DisplayName, DisplayVersion, UninstallString, PSChildName |
Where-Object { $_.DisplayName -like "${using:process}*"}
}
$32bit = Invoke-Command -Session $session { 
get-itemproperty HKLM:SoftwareWow6432NodeMicrosoftWindowsCurrentVersionUninstall* |
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]类型的具有静态属性值的原始对象的近似值。

虽然这有时可能是一个问题,但在您的情况下并非如此,因为由于使用了Select-Object,您的命令输出的对象一开始就是[pscustomobject]实例。


至于你最初的症状

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

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

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

如前所述,此问题的退出与你是针对本地注册表还是远程注册表无关,因此让我演示一下本地键的问题:

$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_USERConsole

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


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

这不完全是一个答案,而是对我问题的跟进,以表明我从中得到了我想要的东西,我感谢你的帮助。

此脚本在本地和远程(在同一域内(成功工作,以从给定程序收集卸载字符串。 下一个困难的部分实际上是远程使用这些卸载字符串......

#Requires -RunAsAdministrator
[cmdletbinding()]
param(
[parameter(mandatory=$true)]
[Validatescript({
$regex = '[!$%^&*()_+|~=`{}[]:";<>?./]'
if ($_ -match $regex) {
throw "Please exclude special characters from your input"
}
return $true
})]
[string]$process,
[string]$computer = 'localhost'
)

if ($computer -match 'localhost') { # if -computer parameter is not defined it defaults to localhost
New-PSDrive HKU Registry HKEY_USERS | out-null
$strings = get-itemproperty HKLM:SoftwareMicrosoftWindowsCurrentVersionUninstall*,HKU:*SoftwareMicrosoftWindowsCurrentVersionUninstall*,HKLM:SoftwareWow6432NodeMicrosoftWindowsCurrentVersionUninstall* | Select-Object DisplayName, DisplayVersion, UninstallString, PSChildName | Where-Object { $_.DisplayName -match "^*$process*"}
Remove-PSDrive HKU
$results = if ($strings.DisplayName.count -eq 0) {
Write-Host "Cannot find the uninstall string" -ForegroundColor Red
}
else {
if ($strings -match "msiexec.exe") {
[PSCustomObject]@{
'DisplayName' = $process
'DisplayVersion' = $strings.DisplayVersion
'UninstallString' = $strings.UninstallString -replace 'msiexec.exe /i','msiexec.exe /x'
'PSComputerName' = $computer
}
}
else {
[PSCustomObject]@{
'DisplayName' = $process
'DisplayVersion' = $strings.DisplayVersion
'UninstallString' = $strings.UninstallString
'PSComputerName' = $computer
}
}
}
} # end of localhost
else { # beginning of remote computers
# set up variables
$RE1 = '^((d{1,3}.){3}d{1,3})'
if ($computer -match $RE1) {
$computerip = $computer
$computername = (Resolve-DnsName $computer).namehost.split('.')[0]
}
else {
$computername = $computer
$computerip = (Resolve-DnsName $computer).ipaddress
}
$svcname = 'WinRM'
$service = get-service -name $svcname -ComputerName $computername
Write-Host "Checking if the WinRM service is running on $computer" -ForegroundColor Cyan
if ($service.Status -eq "stopped" ) {
Write-Host " "
Write-Host "Windows Remote Management serivce is stopped" -ForegroundColor Green
Write-Host " "
Write-Host "Starting the $svcname service on $computer " -ForegroundColor Green
(Get-WmiObject -computer $computerip Win32_service -filter "Name='$svcname'").invokemethod("StartService",$null) | Out-Null
}
else {
Write-Host " "
Write-Host " Windows Remote Management serivce is already running on $computer" -ForegroundColor Green
Write-Host " "
}
$results = invoke-command -ComputerName $computername -ArgumentList $process -ScriptBlock {
param($process)
New-PSDrive HKU Registry HKEY_USERS | out-null
get-itemproperty HKLM:SoftwareMicrosoftWindowsCurrentVersionUninstall*,HKU:*SoftwareMicrosoftWindowsCurrentVersionUninstall*,HKLM:SoftwareWow6432NodeMicrosoftWindowsCurrentVersionUninstall* | Select-Object DisplayName, DisplayVersion, UninstallString, PSChildName | Where-Object { $_.DisplayName -match "^*$process*"}
Remove-PSDrive HKU
}
Write-Host " "
Write-Host "Stopping the $svcname service on $computer..." -ForegroundColor Green
Write-Host " "
(Get-WmiObject -computer $computerip Win32_service -filter "Name='$svcname'").invokemethod("StopService",$null) | Out-Null
}
$results | ft displayname,displayversion,uninstallstring,pscomputername

最新更新