Invoke-Command
的脚本块与PSSession一起运行时,是否应该始终在远程计算机上运行?
我对服务器列表运行了以下Powershell:
Clear-Host
$cred = get-credential 'myDomain\myUsername'
$psSessions = New-PSSession -ComputerName @(1..10 | %{'myServer{0:00}' -f $_}) -Credential $cred
Invoke-Command -Session $psSessions -ScriptBlock {
Get-Item -Path 'HKLM:\System\CurrentControlSet\Control\Lsa\Kerberos\Parameters'
} | Sort-Object PSComputerName
# $psSessions | Remove-PSSession
此返回:
Hive: HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Lsa\Kerberos
Name Property PSComputerName
---- -------- --------------
Parameters MaxPacketSize : 1 myServer01
MaxTokenSize : 65535
Parameters MaxPacketSize : 1 myServer02
MaxTokenSize : 65535
Parameters MaxPacketSize : 1 myServer03
MaxTokenSize : 65535
Parameters MaxPacketSize : 1 myServer04
MaxTokenSize : 65535
Parameters MaxPacketSize : 1 myServer05
MaxTokenSize : 65535
Parameters MaxPacketSize : 1 myServer06
MaxTokenSize : 65535
Parameters MaxPacketSize : 1 myServer07
MaxTokenSize : 65535
Parameters MaxPacketSize : 1 myServer08
MaxTokenSize : 65535
Parameters MaxPacketSize : 1 myServer09
MaxTokenSize : 65535
Parameters MaxPacketSize : 1 myServer10
MaxTokenSize : 65535
一切看起来不错;我只希望我不会看到这些值/在设置这些服务器上的值以确保没有覆盖任何内容之前,我已经将其作为一种快速检查来运行。
我使用regedit快速查看了其中一台服务器;并发现MaxTokenSize
和MaxPacketSize
不存在。
然后我修改了命令以使用Get-ItemProperty
代替Get-Item
:
Invoke-Command -Session $psSessions -ScriptBlock {
Get-ItemProperty -Path 'HKLM:\System\CurrentControlSet\Control\Lsa\Kerberos\Parameters' -Name 'MaxTokenSize'
} | Sort-Object PSComputerName
这次我有10个错误:
Property MaxTokenSize does not exist at path HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Lsa\Kerberos\Parameters.
+ CategoryInfo : InvalidArgument: (MaxTokenSize:String) [Get-ItemProperty], PSArgumentException
+ FullyQualifiedErrorId : System.Management.Automation.PSArgumentException,Microsoft.PowerShell.Commands.GetItemPropertyCommand
+ PSComputerName : myServer01
# ... (and the same for the other 9 servers, with only PSComputerName changing)
关于返回值的来源...它们来自我的本地计算机。修改我的本地注册表项并重新运行原始命令,显示所有“服务器”具有新值。
我猜这是一个错误;但是由于到目前为止我还没有玩过PSSession
,所以我想在这里检查一下,以防我理解/使用这些命令有问题,或者在使用{{1 }}。
答案 0 :(得分:1)
将其放置在fl *或ft *上,因此它不使用格式文件显示注册表项。格式文件在本地运行get-itemproperty,以尝试显示属性。
从$ PSHOME \ Registry.format.ps1xml的底部键入Microsoft.Win32.RegistryKey:
<form action="/update" method="post">
<button class="btn edit_ico btn-sm" type="submit" name="update_btn"
value="<%=post.title%>"><i class="fas fa-edit"></i></button>
</form>
答案 1 :(得分:1)
tl;博士:
根本原因是formatting instructions中注册表项的 bug (自Windows PowerShell 5.1.18362.125和PowerShell Core 7.0.0起) -preview.2)导致远程信息和本地信息的意外混合-请参阅this GitHub issue。
最好的解决方法是仅使用Get-ItemProperty
(不带-Name
参数)而不是Get-Item
。
Mathias R. Jessen在对该问题的评论中提供了关键的指针,js2010's answer提供了一个有限的解决方法和根本原因的指针,但是值得提供更多背景信息:
PowerShell带有formatting instructions,类型为Microsoft.Win32.RegistryKey
,由Get-Item
输出,具有 registry 路径。
这些格式说明为默认(表格)视图定义了名为Property
的计算列,该列有助于显示输出注册表项的值的摘要,这涉及使用Get-ItemProperty
重新访问注册表 ,如js2010的答案所示。
但是,幕后Get-ItemProperty
调用总是会访问 local 注册表-即使从其他计算机上检索到密钥也是如此,通过PowerShell远程处理,因此您将最终得到远程和本地信息的虚假组合。
请注意,从技术上讲,Get-Item
远程运行 时,您在本地收到的 是原始{的{1}}对象,由于远程处理涉及序列化和反序列化。此近似值是一个具有原始对象属性值的静态副本的自定义对象,其(模拟的)类型名称为Microsoft.Win32.RegistryKey
-注意前缀。
PowerShell根据输出对象的完整类型名称应用格式设置指令,但是在没有特定说明或给定Deserialized.Microsoft.Win32.RegistryKey
类型的情况下,PowerShell为{{1 }},这就是导致这里出现问题的原因。
A-麻烦但与版本无关的 [1] -查看有问题的格式化指令的方法是运行以下命令:
Deserialized.<originalTypeName>
这将产生表视图的列名和定义:
<originalTypeName>
js2010答案中建议的解决方法-用管道输送到(Get-FormatData Microsoft.Win32.RegistryKey -PowerShellVersion $PSVersionTable.PSVersion).FormatViewDefinition.Control | % {
$colNames = $_.Headers.Label
$colValues = $_.Rows.Columns.DisplayEntry.Value
foreach ($i in 0..($colNames.Count-1)) {
[pscustomobject] @{
ColumnName = $colNames[$i]
ColumnValue = $colValues[$i]
}
}
} | Format-Table -Wrap
或
ColumnName ColumnValue
---------- -----------
Name PSChildName
Property
$result = (Get-ItemProperty -LiteralPath $_.PSPath |
Select * -Exclude PSPath,PSParentPath,PSChildName,PSDrive,PsProvider |
Format-List | Out-String | Sort).Trim()
$result = $result.Substring(0, [Math]::Min($result.Length, 5000) )
if($result.Length -eq 5000) { $result += "..." }
$result
的意思是有效的,因为它可以防止显示不适用的 local 信息:通过显式指定属性(即使使用通配符模式Format-Table *
),也只会在输出中显示那些属性-不会显示有缺陷的计算列。
但是,虽然输出对象的真实Format-List *
属性可以访问当前注册表项中的值 names ,但它不提供实际的数据,即计算出的*
列的方式。
通过对比,使用不带Property
参数的Property
代替Get-ItemProperty
作为解决方法,将同时返回和值名称和数据(即使在远程处理时也正确)甚至没有限制(-Name
将输出限制为5000个字符。)
输出格式会稍有不同,但是所有信息都在其中。
[1]也就是说,该命令在PowerShell Core 中也有效,其中内置的格式设置指令不再作为外部Get-Item
files < / em>,而是编译为可执行文件。