Powershell 远程会话上的Invoke命令返回本地值 问题:

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

使用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
一切看起来都很好;只是我没想到会看到这些值/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
属性
属性提供了对值名称的访问