本地语句输出与调用命令输出非常不同
Local statement output very different than invoke-command output
直接登录系统,我运行这个语句,得到这个输出:
(Get-ClusterNetwork 'cluster backups').role
None
这是完美的...甚至美丽,简单。
然而,当我 运行 使用 invoke-command 从远程机器发出完全相同的语句时,直到现在我一直只是假设就像在机器的 CLI 中输入这个确切的语句,我得到此输出改为
Invoke-Command -Session $hi -ScriptBlock {(Get-ClusterNetwork 'cluster backups').role}
PSComputerName RunspaceId Value
-------------- ---------- -----
dumdum a84b6c89-dumdum-80d3-ed43230ee8ab None
下面是真正有趣的事情。如果我为 invoke-command 输出分配一个变量,它将具有与上面显示的相同的输出,除非 - 我将其通过管道传输到 set-clipboard
所以变量
$hello = invoke-command -session $hi -scriptblock {(get-networkcluster 'cluster backups').role}
现在在提示符中输入 $hello,我得到:
PSComputerName RunspaceId Value
-------------- ---------- -----
dumdum a84b6c89-dumdum-80d3-ed43230ee8ab None
这是意料之中的。但是现在当我将其通过管道传输到 set-clipboard 并粘贴时 - 值为:
$hello | set-clipboard;
get-clipboard
None
这是我想要的实际值。不知何故,设置剪贴板的管道知道只拉出我最初要求的 属性 。即使是变量,也具有所有的属性。当我 运行 $hello.gettype() - 我看到的值为 Int32。如果 $hello 只是 return 我想要的值,这是有道理的,但它...不是。
但如果这还不够奇怪的话 - 我在调用命令中 运行 设置了一些函数,这只是一部分 - 所有函数 return 一个值 i '试图报告。所以:
$row = '' | select computername, ClusterNetworkRole, IP;
$row.computername = $name;
$row.clusternetworkrole = $hello;
$row.ip = dum.dum.dum.dum;
Return $row;
你知道 $row.clusternetworkrole 的输出是什么吗?大胆猜测。
每个 属性 除了我想要的那个。
$row
PSComputerName : dumdum
RunspaceId : b898bdad-dumdum-9eff-8a2beeefe78a
ClusterNetworkRole :
Computername : dum
IP : dum.dum.dum.dum
它不仅提供了我不想要的确切属性 - 它实际上将这些属性添加为 $row 的成员。
$row.RunspaceID
b898bdad-dumdum-9eff-8a2beeefe78a
现在我可以通过在语句末尾附加“.value”来获得我想要的值,所以这不是一个需要解决的问题,而是一个到底是什么的问题powershell 正在做。它采取了这个简单、美丽的小声明 - 并对我的生活造成了严重破坏。
在您的特定情况下 枚举值的实例(System.Enum
-派生类型):
使用[int] $hello
获取原始枚举(System.Enum
-派生)值的数值,无需额外的NoteProperty
成员,例如远程处理基础结构添加的 PSComputerName
(见下文)。
使用 $hello.Value
获取枚举值的 string 表示(其符号 name 而不是比它的数量).
如果您知道原始的 System.Enum
派生类型,并且该类型在您的本地会话中也可用,您可以 cast 反序列化的对象恢复到原来的类型;例如:
[Microsoft.Foo.Bar.ClusterRole] $hello
$hello
在技术上是一个 [int]
,但装饰了额外的属性,并且有关 原始 类型的信息记录在隐藏文件中.pstypenames
数组,反映了原始类型的继承层次,类型名称以Deserialized.
为前缀;例如Deserialized.Microsoft.Foo.Bar.ClusterRole
; PowerShell 的输出格式化系统导致通过(隐式应用)Format-Table
格式化此类对象,在本例中显示所有内容 但 实际 [int]
值 - 只有已显示 NoteProperty
个成员。
一般,您可以排除不需要的属性,如下所示:
对于反序列化 type-faithfully 类型的对象,包括 strings 和 。 NET 原始类型 (例如 [int]
、[long]
、...)加上 一些 (参见 MS-PSRP, PowerShell 远程处理协议规范),您可以访问 $hello.psobject.BaseObject
以获取没有任何 NoteProperty
成员的基础对象。
对于其他人,您可以创建一个 new 对象(总是 [pscustomobject]
类型),通过管道连接到 Select-Object
不需要的属性 已排除 ,如 Lee Dailey 所建议:
$hello | Select-Object * -Exclude PSComputerName, PSShowComputerName, RunspaceId
或者,您可以专注于选择您想要的属性。
请继续阅读,了解为什么需要这样做。
PowerShell 的远程处理基础结构将以下属性添加到从远程调用返回的 每个 对象,作为 NoteProperty
成员:
PSComputerName
...远程计算机的名称
RunspaceId
...执行远程命令的运行空间的ID。
PSShowComputerName
... a hidden 属性 即,在通过返回的所有对象上设置为 $true
时Invoke-Command
的 -HideComputerName
开关,在默认输出中抑制 显示 PSComputerName
属性(但 属性仍然存在);如果将远程接收的对象通过管道传输到 Get-Member -Force
.
,则只能看到 PSShowComputerName
本身
此外,System.Enum
派生类型作为 [int]
个实例返回,[string]
类型的 Value
属性 NoteProperty
添加了包含枚举值的 符号名称 .
的成员
PSComputerName
和 RunspaceId
属性在一次针对 多台 台计算机的远程命令中很有用:假定接收输出的顺序是不能保证,这些属性会告诉您给定输出对象的来源。
PSShowComputerName
属性 允许您控制默认显示行为 - 但奇怪的是,它对是否显示 RunspaceId
没有影响。
System.Enum
派生类型的 Value
属性 补偿了通常发生在远程处理命令(和后台作业)中的类型保真度损失 - 只有一组有限的已知使用类型保真度反序列化类型 - 请参阅 .
虽然这些属性始终存在,但它们是否默认显示取决于返回对象的具体类型以及格式化数据与它们关联或由 PowerShell 默认应用。
此外,它们可能会在您明确地通过管道传输到 Format-*
cmdlet 时以及在序列化期间显示,例如使用 ConvertTo-Json
.
如果您不想要计算机名,我相信这会起作用:
(invoke-command $hi {Get-ClusterNetwork 'cluster backups'}).role
直接登录系统,我运行这个语句,得到这个输出:
(Get-ClusterNetwork 'cluster backups').role
None
这是完美的...甚至美丽,简单。
然而,当我 运行 使用 invoke-command 从远程机器发出完全相同的语句时,直到现在我一直只是假设就像在机器的 CLI 中输入这个确切的语句,我得到此输出改为
Invoke-Command -Session $hi -ScriptBlock {(Get-ClusterNetwork 'cluster backups').role}
PSComputerName RunspaceId Value
-------------- ---------- -----
dumdum a84b6c89-dumdum-80d3-ed43230ee8ab None
下面是真正有趣的事情。如果我为 invoke-command 输出分配一个变量,它将具有与上面显示的相同的输出,除非 - 我将其通过管道传输到 set-clipboard
所以变量
$hello = invoke-command -session $hi -scriptblock {(get-networkcluster 'cluster backups').role}
现在在提示符中输入 $hello,我得到:
PSComputerName RunspaceId Value
-------------- ---------- -----
dumdum a84b6c89-dumdum-80d3-ed43230ee8ab None
这是意料之中的。但是现在当我将其通过管道传输到 set-clipboard 并粘贴时 - 值为:
$hello | set-clipboard;
get-clipboard
None
这是我想要的实际值。不知何故,设置剪贴板的管道知道只拉出我最初要求的 属性 。即使是变量,也具有所有的属性。当我 运行 $hello.gettype() - 我看到的值为 Int32。如果 $hello 只是 return 我想要的值,这是有道理的,但它...不是。
但如果这还不够奇怪的话 - 我在调用命令中 运行 设置了一些函数,这只是一部分 - 所有函数 return 一个值 i '试图报告。所以:
$row = '' | select computername, ClusterNetworkRole, IP;
$row.computername = $name;
$row.clusternetworkrole = $hello;
$row.ip = dum.dum.dum.dum;
Return $row;
你知道 $row.clusternetworkrole 的输出是什么吗?大胆猜测。 每个 属性 除了我想要的那个。
$row
PSComputerName : dumdum
RunspaceId : b898bdad-dumdum-9eff-8a2beeefe78a
ClusterNetworkRole :
Computername : dum
IP : dum.dum.dum.dum
它不仅提供了我不想要的确切属性 - 它实际上将这些属性添加为 $row 的成员。
$row.RunspaceID
b898bdad-dumdum-9eff-8a2beeefe78a
现在我可以通过在语句末尾附加“.value”来获得我想要的值,所以这不是一个需要解决的问题,而是一个到底是什么的问题powershell 正在做。它采取了这个简单、美丽的小声明 - 并对我的生活造成了严重破坏。
在您的特定情况下 枚举值的实例(System.Enum
-派生类型):
使用
[int] $hello
获取原始枚举(System.Enum
-派生)值的数值,无需额外的NoteProperty
成员,例如远程处理基础结构添加的PSComputerName
(见下文)。使用
$hello.Value
获取枚举值的 string 表示(其符号 name 而不是比它的数量).如果您知道原始的
System.Enum
派生类型,并且该类型在您的本地会话中也可用,您可以 cast 反序列化的对象恢复到原来的类型;例如:
[Microsoft.Foo.Bar.ClusterRole] $hello
$hello
在技术上是一个[int]
,但装饰了额外的属性,并且有关 原始 类型的信息记录在隐藏文件中.pstypenames
数组,反映了原始类型的继承层次,类型名称以Deserialized.
为前缀;例如Deserialized.Microsoft.Foo.Bar.ClusterRole
; PowerShell 的输出格式化系统导致通过(隐式应用)Format-Table
格式化此类对象,在本例中显示所有内容 但 实际[int]
值 - 只有已显示NoteProperty
个成员。
一般,您可以排除不需要的属性,如下所示:
对于反序列化 type-faithfully 类型的对象,包括 strings 和 。 NET 原始类型 (例如
[int]
、[long]
、...)加上 一些 (参见 MS-PSRP, PowerShell 远程处理协议规范),您可以访问$hello.psobject.BaseObject
以获取没有任何NoteProperty
成员的基础对象。对于其他人,您可以创建一个 new 对象(总是
[pscustomobject]
类型),通过管道连接到Select-Object
不需要的属性 已排除 ,如 Lee Dailey 所建议:$hello | Select-Object * -Exclude PSComputerName, PSShowComputerName, RunspaceId
或者,您可以专注于选择您想要的属性。
请继续阅读,了解为什么需要这样做。
PowerShell 的远程处理基础结构将以下属性添加到从远程调用返回的 每个 对象,作为 NoteProperty
成员:
PSComputerName
...远程计算机的名称RunspaceId
...执行远程命令的运行空间的ID。PSShowComputerName
... a hidden 属性 即,在通过返回的所有对象上设置为$true
时Invoke-Command
的-HideComputerName
开关,在默认输出中抑制 显示PSComputerName
属性(但 属性仍然存在);如果将远程接收的对象通过管道传输到Get-Member -Force
. ,则只能看到 此外,
System.Enum
派生类型作为[int]
个实例返回,[string]
类型的Value
属性NoteProperty
添加了包含枚举值的 符号名称 . 的成员
PSShowComputerName
本身
PSComputerName
和 RunspaceId
属性在一次针对 多台 台计算机的远程命令中很有用:假定接收输出的顺序是不能保证,这些属性会告诉您给定输出对象的来源。
PSShowComputerName
属性 允许您控制默认显示行为 - 但奇怪的是,它对是否显示 RunspaceId
没有影响。
System.Enum
派生类型的 Value
属性 补偿了通常发生在远程处理命令(和后台作业)中的类型保真度损失 - 只有一组有限的已知使用类型保真度反序列化类型 - 请参阅
虽然这些属性始终存在,但它们是否默认显示取决于返回对象的具体类型以及格式化数据与它们关联或由 PowerShell 默认应用。
此外,它们可能会在您明确地通过管道传输到 Format-*
cmdlet 时以及在序列化期间显示,例如使用 ConvertTo-Json
.
如果您不想要计算机名,我相信这会起作用:
(invoke-command $hi {Get-ClusterNetwork 'cluster backups'}).role