Powershell 远程会话上的Invoke命令返回本地值 问题:
使用PSSession运行时,Powershell 远程会话上的Invoke命令返回本地值 问题:,powershell,formatting,powershell-5.0,winrm,invoke-command,Powershell,Formatting,Powershell 5.0,Winrm,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 $psSes
调用命令的脚本块是否应始终在远程计算机上运行
上下文
我针对服务器列表运行了以下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
一切看起来都很好;只是我没想到会看到这些值/I在设置这些服务器上的值之前,运行此操作是为了快速检测,以确保没有覆盖任何内容
我快速浏览了一个使用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
s,所以我想在这里检查一下,以防我对这些命令的理解/使用有问题,或者在使用PSSession
s时是否有已知的问题需要注意。将其传输到fl*或ft*,这样它就不会使用格式文件来显示注册表项。格式文件在本地运行get-itemproperty以尝试显示属性
从Microsoft.Win32.RegistryKey类型的$PSHOME\Registry.format.ps1xml底部:
<ScriptBlock>
$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
</ScriptBlock>
$result=(Get-ItemProperty-LiteralPath$\uUx.PSPath|
选择*-排除PSPath、PSParentPath、PSChildName、PSDrive、PsProvider|
格式列表|输出字符串|排序).Trim()
$result=$result.Substring(0,[Math]::Min($result.Length,5000))
如果($result.Length-eq 5000){$result+=“…”}
$result
tl;博士:
- 根本原因是for注册表项(自Windows PowerShell 5.1.18362.125和PowerShell Core 7.0.0-preview.2起)中的一个错误,导致远程和本地信息意外混合-请参阅
- 旁白:类似地,PowerShell也会带来问题,如Mathias的回答所示
- 最好的解决方法是简单地使用
Get ItemProperty
(不带-Name
参数)而不是Get Item
在对问题的评论中提供了关键指针,并提供了有限的解决方法和指向根本原因的指针,但值得提供更多背景信息:
PowerShell为Microsoft.Win32.RegistryKey类型提供了一个注册表路径,作为Get Item
的输出
这些格式化说明为默认(表格)视图定义了一个名为Property
的计算列,该列有助于显示输出注册表项值的摘要,这涉及使用Get ItemProperty
再次访问注册表,如js2010的答案所示
但是,幕后的Get ItemProperty
调用始终访问本地注册表-即使是通过PowerShell远程处理从不同的机器检索到密钥,因此您最终会得到远程和本地信息的虚假混合
请注意,从技术上讲,当远程运行Get Item
时,您在本地收到的是原始Microsoft.Win32.RegistryKey
对象的近似值,这是因为远程处理涉及到序列化和反序列化。此近似值是一个自定义对象,具有原始对象属性值的静态副本,其(模拟)类型名称是反序列化的。Microsoft.Win32.RegistryKey
-请注意前缀
PowerShell会根据输出对象的完整类型名称应用格式化指令,但如果没有特定指令或给定的反序列化。
类型,PowerShell会应用
的指令,这就是此处出现问题的原因
A-麻烦,但版本不可知[1]-查看有问题的格式化指令的方法是运行以下命令:
(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
---------- -----------
名称PSChildName
财产
$result=(Get-ItemProperty-LiteralPath$389;.PSPath |
选择*-排除PSPath、PSParentPath、PSChildName、PSDrive、PsProvider |
格式列表|输出字符串|排序).Trim()
$result=$result.Substring(0,[Math]::Min($result.Length,5000))
如果($result.Length-eq 5000){$result+=“…”}
$result
js2010的答案中建议的解决方法-管道到
格式表*
或格式列表*
是有效的,因为它可以防止不适用的本地信息被显示:通过明确指定属性(甚至通过通配符模式*
),输出上仅显示这些属性,而不显示有缺陷的计算列
但是,输出对象的true属性
属性提供了对值名称的访问