接收作业中出现意外结果 [英] Unexected results in Receive-Job

查看:84
本文介绍了接收作业中出现意外结果的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

运行

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

返回

A                     : 1
RunspaceId            : 6921e85f-301e-4e95-8e4b-c0882fc2085f
PSSourceJobInstanceId : 2992ef77-5642-4eac-8617-f26449a87801

运行

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}

但是,正在运行

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

返回

A
-
1

为什么Receive-Job cmdlet仅为PSObject s添加该哈希表?

更新:在PowerShell 4.0中相同.

解决方案

补充 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}

看起来像哈希表文字;实际上,这是无属性" 自定义对象的默认输出格式,实际上, do 具有属性,但仅添加了由PowerShell本身 .

该表示形式与哈希表文字可疑地相似,但是缺少通常需要它的值的引号-例如localhost周围.
另外请注意,输出 actual 哈希表会产生更好的两列键值格式.

请注意,即使PS本身已向其添加属性(例如,按Receive-Job的方式,请参见此处,详情如下),PS仍会认为自定义对象最初没有属性缺乏属性. /p>

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

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


PetSerAl提供了指向:

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

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

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

您可以使用Format-List -ForceFormat-Table -Force 强制普通列表或表格视图,但请注意,布尔属性PSShowComputerName 从不出现,而是隐式控制关联 PSComputerName属性是否包含在列表/表中.


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

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}

请注意,这种字符串内插对其他任何类型的实例(类型为[System.Management.Automation.PSCustomObject]的对象 not ) not 不起作用:

  • 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 { ... }定义)的实例.

I noticed weird behavior when using jobs in PowerShell 5.0. Running job that returns PSObject, also returns some hashtable. Jobs that return strings, integers, etc work propertly.

Running

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

returns

A                     : 1
RunspaceId            : 6921e85f-301e-4e95-8e4b-c0882fc2085f
PSSourceJobInstanceId : 2992ef77-5642-4eac-8617-f26449a87801

Running

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

returns

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

However, running

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

returns

A
-
1

Why does Receive-Job cmdlet add that hashtable only for PSObjects?

UPDATE: Same in PowerShell 4.0.

解决方案

To complement PetSerAl's excellent answer with a focus on the hashtable that wasn't (a hashtable), based on PetSerAl's helpful comments:

The output from 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}

only looks like a hashtable literal; in fact, it is the default output formatting for "property-less" custom objects that, in fact, do have properties, but only ones added by PowerShell itself.

This representation is suspiciously similar to a hashtable literal, but the quoting around values that would normally need it is missing - such as around localhost.
Also note that outputting an actual hashtable results in a much nicer, two-column key-value format.

Note that PS still considers a custom object that originally had no properties property-less even after PS itself has added properties to it, such as by Receive-Job here - see below for details.

In its original state (no properties added by PS yet), a property-less object's default output is empty (the empty string). (Try New-Object PSCustomObject directly at the prompt.)

Once Receive-Job has added its "meta" properties to the custom object, their existence triggers the hashtable-like output formatting.


PetSerAl has provided a link to the source code, which suggests that the "PropertyLessObject" formatting is triggered under the following conditions:

  • An object has no properties at all or only has properties automatically added by PowerShell in the context of remoting (which apparently also includes job-related cmdlets), as done by Receive-Object here.

  • To put it differently: Properties automatically added by PS aren't taken into account when deciding whether an object is propertyless.

The source-code link will tell you the specific 3-, 4-, or 5-element sets of remoting properties that may be added during remoting and trigger the formatting, but here's a minimal (3-property) example.
Again, note that the hashtable-like formatting is only triggered because the only properties that the object has are named for remoting-related, automatically added properties:

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

Note that even though a hashtable literal is involved in the command, it is merely used to construct a custom object.

You can force a normal list or table view with Format-List -Force or Format-Table -Force, but note that Boolean property PSShowComputerName never shows up and instead implicitly controls whether the associated PSComputerName property is included in the list / table.


PetSerAl also points out that you can get the hashtable-like output format on demand for any custom object: simply invoke .PSObject.ToString() (note the crucial .PSObject part; without it, you get empty output).

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

Or, more simply, with string interpolation (which, presumably, simply calls .PSObject.ToString() behind the scenes):

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

Note that this kind of string interpolation does not work for instances of any other types (objects not of type [System.Management.Automation.PSCustomObject]):

  • PowerShell defers to their .ToString() method even when you invoke .PSObject.ToString().

  • A directly .NET-based type (e.g., as added with Add-Type) by default simply returns its full type name (both from .ToString() / .PSObject.ToString() and as default output in PS); e.g.:

    PS> (Add-Type -PassThru 'namespace net.same2u { public class SomeType {} }')::New()
    net.same2u.SomeType  # the full type name
    

  • The same applies to instances of custom PowerShell classes (defined with class { ... }).

这篇关于接收作业中出现意外结果的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆