4

在 PowerShell 5.0 中使用作业时,我注意到了奇怪的行为。运行返回的作业PSObject,也返回一些哈希表。返回字符串、整数等的作业可以正常工作。

跑步

Start-Job { New-Object PSObject -Property @{ A = 1 } } |
  Receive-Job -Wait -AutoRemoveJob

返回

答:1
运行空间 ID:6921e85f-301e-4e95-8e4b-c0882fc2085f
PSSourceJobInstanceId : 2992ef77-5642-4eac-8617-f26449a87801

跑步

Start-Job { New-Object PSObject } | Receive-Job -Wait -AutoRemoveJob

返回

@{PSComputerName=localhost; 运行空间 ID=3e783d5f-254a-4951-bb4a-7ff6fa2812c5;PSShowComputerName=假;PSSourceJobInstanceId=1d951dec-0823-4cde-8219-4a6263550441}

然而,运行

Start-Job { ,@(New-Object PSObject -Property @{ A = 1 }) } |
  Receive-Job -Wait -AutoRemoveJob

返回

一个
-
1

为什么Receive-Jobcmdlet 只为PSObjects 添加该哈希表?

更新:在 PowerShell 4.0 中相同。

4

2 回答 2

3

PowerShell 不是所见即所得的外壳。通常,“你得到什么”不是文本,而是具有属性和方法的对象。而“你所看到的”是它们的一些文本表示。在许多情况下,默认情况下,PowerShell 不会显示对象的所有属性,而只会显示格式文件中定义的最常见的属性。并且一些对象使用自定义格式,例如字符串和整数只显示它们的值,而不显示它的任何属性,并且集合显示它们的内容而不是集合本身。

因此,实际上,PowerShell 为从作业接收到的所有对象添加了额外的属性。但是这个属性并不总是被显示出来。您可以通过将作业输出传递给Get-Membercmdlet 来查看这些额外的属性:

Start-Job { 1,'',@() } | Receive-Job -Wait -AutoRemoveJob | Get-Member

或使用适当的选项格式化 cmdlet 以强制格式化原始类型并且不枚举集合:

Start-Job { 1,'',@() } | Receive-Job -Wait -AutoRemoveJob | Format-List -Force -Expand CoreOnly
于 2016-10-25T18:54:16.727 回答
3

根据 PetSerAl 的有用评论,为了补充 PetSerAl 的出色答案重点关注不是(哈希表)的哈希表:

的输出Start-Job { New-Object PSObject } | Receive-Job -Wait -AutoRemoveJob

@{PSComputerName=localhost; RunspaceId=3e783d5f-254a-4951-bb4a-7ff6fa2812c5; PSShowComputerName=False; PSSourceJobInstanceId=1d951dec-0823-4cde-8219-4a6263550441}

只是看起来像一个哈希表文字;事实上,它是“无属性”自定义对象的默认输出格式,事实上,这些对象确实具有属性,但只有 PowerShell 本身添加的属性。

这种表示形式与哈希表文字可疑地相似,但是通常需要它的值周围的引用丢失了 - 例如 around localhost
另请注意,输出实际哈希表会产生更好的两列键值格式。

请注意,即使 PS 本身已向其添加属性后,PS 仍将原本没有属性的自定义对象视为无属性,例如通过Receive-Job此处 - 有关详细信息,请参见下文。

在其原始状态(PS 尚未添加任何属性),无属性对象的默认输出为 (空字符串)。(根据提示直接尝试New-Object PSCustomObject。)

一旦Receive-Job将其“元”属性添加到自定义对象,它们的存在就会触发类似哈希表输出格式。


PetSerAl 提供了指向源代码的链接,这表明在以下情况下会触发“PropertyLessObject”格式

  • 一个对象根本没有属性,或者只有 PowerShell 在远程处理的上下文中自动添加的属性(显然还包括与作业相关的 cmdlet),如此处所做的Receive-Object

  • 换句话说:在判断一个对象是否无属性时,不会考虑 PS 自动添加的属性。

源代码链接将告诉您在远程处理期间可能添加并触发格式化的特定 3、4 或 5 元素的远程处理属性集,但这里是一个最小的(3 属性)示例。
同样,请注意,仅触发类似哈希表的格式,因为对象具有的唯一属性是为与远程相关的自动添加的属性命名的:

PS> [PSCustomObject] @{PSComputerName='Hi, Mom'; RunspaceId=0; PSShowComputerName=$true}
@{PSComputerName=Hi, Mom; RunspaceId=0; PSShowComputerName=False}

请注意,即使命令中包含哈希表文字,它也仅用于构造自定义对象

您可以使用or强制执行普通列表或表格视图,但请注意,布尔属性永远不会显示,而是隐式控制关联的属性是否包含在列表/表格中。Format-List -ForceFormat-Table -ForcePSShowComputerName PSComputerName


PetSerAl 还指出,您可以根据需要为任何自定义对象获取类似哈希表的输出格式:只需调用.PSObject.ToString()(注意关键.PSObject部分;没有它,您将得到输出)。

PS> ([pscustomobject] @{ one = 'Hi, Mom'; two = 2 }).PSObject.ToString()
@{one=Hi, Mom; two=2}

或者,更简单地说,使用字符串插值(可能只是.PSObject.ToString()在幕后调用):

PS> "$([pscustomobject] @{ one = 'Hi, Mom'; two = 2 })"
@{one=Hi, Mom; two=2}

请注意,这种字符串插值不适用于任何其他类型的实例(不是type 的对象[System.Management.Automation.PSCustomObject]

  • PowerShell 遵循他们的.ToString()方法,即使您调用.PSObject.ToString().

  • 默认情况下,直接基于 .NET 的类型(例如,添加Add-Type)仅返回其完整类型名称(来自.ToString()/.PSObject.ToString()和 PS 中的默认输出);例如:

    PS> (Add-Type -PassThru 'namespace net.same2u { public class SomeType {} }')::New()
    net.same2u.SomeType  # the full type name
    
  • 这同样适用于自定义 PowerShell 类的实例(用 定义class { ... })。

于 2016-10-26T03:43:32.197 回答