问题描述
直接登录系统,我运行这个语句,得到这个输出:
Logged in to the system directly, I run this statement, and get this output:
(Get-ClusterNetwork 'cluster backups').role
None
这太完美了......甚至很漂亮,因为它很简单.
This is perfect... beautiful even, in it's simplicity.
但是,当我使用 invoke-command 从远程机器运行完全相同的语句时,直到现在我一直认为就像在机器的 CLI 中输入这个确切的语句一样,我得到了这个输出
However, when I run the exact same statement from a remote machine using invoke-command, which up until now i always just assumed was like typing this exact statement into the CLI of the machine, I get THIS output instead
Invoke-Command -Session $hi -ScriptBlock {(Get-ClusterNetwork 'cluster backups').role}
PSComputerName RunspaceId Value
-------------- ---------- -----
dumdum a84b6c89-dumdum-80d3-ed43230ee8ab None
现在真正有趣的事情来了.如果我为 invoke-command 输出分配一个变量,它将具有上面显示的相同输出,除非我将其通过管道传输到 set-clipboard
Now here's the really funny thing. If i assign a variable to the invoke-command output, it'll have the same output shown above UNLESS - i pipe it to set-clipboard
所以变量
$hello = invoke-command -session $hi -scriptblock {(get-networkcluster 'cluster backups').role}
现在在提示符中输入 $hello ,我得到:
Now type $hello into prompt and I get:
PSComputerName RunspaceId Value
-------------- ---------- -----
dumdum a84b6c89-dumdum-80d3-ed43230ee8ab None
这是预期的.但是现在当我将其通过管道传输到 set-clipboard 并粘贴时 - 值是:
Which is expected. But now when I pipe that to set-clipboard and paste - the value is:
$hello | set-clipboard;
get-clipboard
None
这是我想要的实际值.以某种方式设置剪贴板的管道知道只提取我最初要求的属性.即使变量,也具有所有属性.当我运行 $hello.gettype() - 我看到的值为 Int32.如果 $hello 只返回我想要的值,这是有道理的,但它......不是.
Which is the actual value I want. Somehow piping to set-clipboard knows to only pull the property that i originally asked for. Even though the variable, has all the properties. When i run $hello.gettype() - i see the value as Int32. Which makes sense if $hello was only returning the value I wanted, but it's... not.
但如果这还不够奇怪——我在 invoke-command 中运行了几个函数,这只是一个——所有函数都返回一个我试图报告的值.所以:
But if that wasn't weird enough - I'm running a few functions within the invoke-command, this is only one piece - all of the functions return a value i'm trying to report on. So:
$row = '' | select computername, ClusterNetworkRole, IP;
$row.computername = $name;
$row.clusternetworkrole = $hello;
$row.ip = dum.dum.dum.dum;
Return $row;
你知道 $row.clusternetworkrole 的输出是什么吗?大胆猜测一下.这是除我想要的之外的所有财产.
Do you know what the output of $row.clusternetworkrole is? Take a wild guess.It's every property EXCEPT the one I want.
$row
PSComputerName : dumdum
RunspaceId : b898bdad-dumdum-9eff-8a2beeefe78a
ClusterNetworkRole :
Computername : dum
IP : dum.dum.dum.dum
它不仅给了我我不想要的确切属性 - 它实际上将这些属性添加为 $row 的成员.
Not only does it give me the exact properties i DON'T want - it actually adds those properties as members of $row.
$row.RunspaceID
b898bdad-dumdum-9eff-8a2beeefe78a
现在我可以通过在语句的末尾附加.value"来获得我想要的值,所以这不是一个需要解决的问题,而是一个到底是什么地狱powershell的问题正在做.它采取了这个简单、美丽的小声明——对我的生活造成了严重破坏.
Now i can get the value i want by appending ".value" at the end of the statement, so this isn't so much a problem to be solved as much as it is a question of just what the hell powershell is doing. It's taken this simple, beautiful tiny statement - and wreaked havoc on my life.
推荐答案
在您的特定情况下枚举值的实例(System.Enum
-派生类型):
In your specific case of an instance of an enum value (an instance of a System.Enum
-derived type):
使用
[int] $hello
获取原始枚举的数值(System.Enum
-衍生)值,没有额外的NoteProperty
成员,例如远程处理基础结构添加的PSComputerName
(见下文).
Use
[int] $hello
to get the numeric value of the original, enum (System.Enum
-derived) value, without the extraNoteProperty
members such asPSComputerName
that the remoting infrastructure adds (see below).
使用 $hello.Value
来获取枚举值的 string 表示(它的符号 name 而不是它的 >编号).
Use $hello.Value
to get the string representation of the enum value (its symbolic name rather than its number).
如果您知道原始的 System.Enum
派生类型,并且该类型在您的本地会话中也可用,您可以将反序列化的对象转换回到其原始类型;例如:[Microsoft.Foo.Bar.ClusterRole] $hello
If you know the original System.Enum
-derived type, and that type is also available in your local session, you can cast the deserialized object back to its original type; e.g.:[Microsoft.Foo.Bar.ClusterRole] $hello
$hello
在技术上是一个 [int]
,但是用额外的属性修饰,并且关于 原始 类型的信息记录在隐藏的 .pstypenames
数组,它反映了原始类型的继承层次结构,类型名称以 Deserialized.
为前缀;例如Deserialized.Microsoft.Foo.Bar.ClusterRole
;PowerShell 的输出格式化系统会导致通过(隐式应用)Format-Table
对此类对象进行格式化,在这种情况下,它显示了所有但实际的[int]
值 - 仅显示 NoteProperty
成员.
$hello
is technically an [int]
, but decorated with extra properties, and information about the original type recorded in the hidden .pstypenames
array, which reflects the original type's inheritance hierarchy with the type names prefixed with Deserialized.
; e.g. Deserialized.Microsoft.Foo.Bar.ClusterRole
; PowerShell's output formatting system causes such an object to be formatted via (implicitly applied) Format-Table
, which in this case shows everything but the actual [int]
value - only the NoteProperty
members are shown.
通常,您可以排除不需要的属性,如下所示:
对于反序列化类型忠实的对象,包括字符串和.NET基本类型(例如
[int]
、[long]
、...) 加上 更多(请参阅 MS-PSRP,PowerShell 远程处理协议规范),您可以访问$hello.psobject.BaseObject
获取没有任何NoteProperty
成员的底层对象.
For objects of types that deserialize type-faithfully, which includes strings and .NET primitive types (such as
[int]
,[long]
, ...) plus a few more (see MS-PSRP, the PowerShell Remoting Protocol specification), you can access$hello.psobject.BaseObject
to get the underlying object without anyNoteProperty
members.
对于其他人,您可以创建一个 new 对象(类型总是 [pscustomobject]
),通过管道传输到 Select-Object
> 将不需要的属性排除,正如 Lee Dailey 所建议的那样):
For others, you can create a new object (invariably of type [pscustomobject]
), by piping to Select-Object
with the unwanted properties excluded, as suggested by Lee Dailey):
$hello |Select-Object * -Exclude PSComputerName, PSShowComputerName, RunspaceId
或者,您可以专注于选择您确实想要的属性.
Alternatively, you can focus on selecting just the properties you do want.
继续阅读,了解为什么需要这样做.
Read on for why that is necessary.
PowerShell 的远程处理基础结构将以下属性添加到从远程调用返回的每个 对象中,作为 NoteProperty
成员:
PowerShell's remoting infrastructure adds the following properties to every object returned from a remote invocation, as NoteProperty
members:
PSComputerName
...远程计算机的名称
PSComputerName
... the name of the remote computer
RunspaceId
... 执行远程命令的运行空间的 ID.
RunspaceId
... the ID of the runspace in which the remote command executed.
PSShowComputerName
... 一个 隐藏 属性,当在通过 Invoke 返回的所有对象上设置为
的 $true
时-Command-HideComputerName
开关,在默认输出中抑制 PSComputerName
属性的显示(但该属性仍然存在);如果您将远程接收到的对象通过管道传输到 Get-Member -Force
,则您只能看到 PSShowComputerName
本身.
PSShowComputerName
... a hidden property that, when set to $true
on all objects returned via Invoke-Command
's -HideComputerName
switch, suppresses display of the PSComputerName
property in the default output (but the property is still there); you can only see the PSShowComputerName
itself if you pipe a remotely received object to Get-Member -Force
.
此外,System.Enum
-派生类型,作为 [int]
实例返回,一个 [string]
-typed Value
属性 NoteProperty
成员被添加,包含枚举值的符号名称.
Additionally, System.Enum
-derived types, which are returned as [int]
instances, a [string]
-typed Value
property NoteProperty
member is added that contains the enum value's symbolic name.
PSComputerName
和 RunspaceId
属性可用于同时针对 多台 计算机的远程命令:假设接收输出的顺序不能保证,这些属性会告诉您给定输出对象的来源.
The PSComputerName
and RunspaceId
properties are useful in remoting commands that target multiple computers at once: given that the order in which output is received is not guaranteed, these properties tell you where a given output object originated from.
PSShowComputerName
属性允许您控制默认的显示行为 - 但奇怪的是,它对是否显示 RunspaceId
没有影响.
The PSShowComputerName
property allows you to control default display behavior - though, curiously, it has no effect on whether RunspaceId
is displayed.
System.Enum
派生类型的 Value
属性补偿了通常发生在远程命令(和后台作业)中的类型保真度损失 - 只有有限的一组已知类型的反序列化类型保真度 - 请参阅此答案.
The Value
property for System.Enum
-derived types compensates for the loss in type fidelity that typically occurs in remoting commands (and background jobs) - only a limited set of known types deserialize with type fidelity - see this answer.
虽然这些属性总是存在,但它们是否默认显示取决于返回对象的特定类型以及与它们关联或默认应用的格式数据通过 PowerShell.
While these properties always exist, whether they show by default depends on the specific types of the object returned and either what formatting data is associated with them or applied by default by PowerShell.
此外,它们可能会在您明确地通过管道传输到 Format-*
cmdlet 时以及在序列化期间显示,例如使用 ConvertTo-Json
.
Also, they may show when you pipe to Format-*
cmdlets explicitly, and during serialization, such as with ConvertTo-Json
.
这篇关于本地语句输出与调用命令输出非常不同的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!