我有一个工作流,它对收到的 PSCustomObjects 非常挑剔。我经常使用它Select-Object
从我想保留的对象中获取属性,有时我需要将一些值转换为更可用的格式。最简单的方法是使用该@{Name='Name'; Expression = {'Expression'}}
技术。
但是,该技术会弄乱 PSCustomObject,从而阻碍我进一步的工作流程。
该问题可以像这样重现:
$object = [pscustomobject]@{
Text = "This is a string"
}
在下面的输出中,字符串的定义是“string Text = This is a string”
$object | Select-Object * | Get-Member
<# Outputs
TypeName: System.Management.Automation.PSCustomObject
Name MemberType Definition
---- ---------- ----------
Equals Method bool Equals(System.Object obj)
GetHashCode Method int GetHashCode()
GetType Method type GetType()
ToString Method string ToString()
Text NoteProperty string Text=This is a string
#>
使用 Select-Object 技术添加新的 NoteProperty 时,定义是“System.String Text2=This is a string”
这就是导致我的下一个 cmdlet 抛出的原因。
$WhatHappensToText = $object | Select-Object @{Name='Text'; Expression={$_.Text}}
$WhatHappensToText | Get-Member
<# Outputs
TypeName: Selected.System.Management.Automation.PSCustomObject
Name MemberType Definition
---- ---------- ----------
Equals Method bool Equals(System.Object obj)
GetHashCode Method int GetHashCode()
GetType Method type GetType()
ToString Method string ToString()
Text NoteProperty System.String Text=This is a string
#>
当像下面这样剥离多余的部分时,定义又回到了'string Text2 = This is a string'
导出到 Clixml 并重新导入效果相同
$WhatHappensToText | ConvertTo-Json | ConvertFrom-Json | Get-Member
<# Outputs
TypeName: System.Management.Automation.PSCustomObject
Name MemberType Definition
---- ---------- ----------
Equals Method bool Equals(System.Object obj)
GetHashCode Method int GetHashCode()
GetType Method type GetType()
ToString Method string ToString()
Text NoteProperty string Text=This is a string
#>
如果我像这样添加新的 NoteProperty,定义就是'string Text2=This is a string',就像我喜欢的那样
$object2 = $object | Select-Object *
$object2 | foreach-object {$_ | Add-Member -MemberType NoteProperty -Name Text2 -Value $_.Text}
$object2 | Get-Member
<# Outputs
TypeName: Selected.System.Management.Automation.PSCustomObject
Name MemberType Definition
---- ---------- ----------
Equals Method bool Equals(System.Object obj)
GetHashCode Method int GetHashCode()
GetType Method type GetType()
ToString Method string ToString()
Text NoteProperty string Text=This is a string
Text2 NoteProperty string Text2=This is a string
#>
我有以下问题:
为什么该@{Name='Name'; Expression = {'Expression'}}
技术将 System.String 添加到 Definition 中而不是像 Add-Member 场景中那样添加字符串?
有没有办法让该@{Name='Name'; Expression = {'Expression'}}
技术添加字符串而不是 System.String?
这是计算属性技术在指定的
[psobject]
属性值周围创建包装器这一不幸事实的副作用。[psobject]
是一种在幕后使用的透明辅助类型,虽然这种包装器通常是不可见的,但它们在某些情况下会导致不同的行为,例如当前的情况。GitHub 问题 #5579中讨论了此有问题的行为以及行为发生变化的场景列表。
这需要避免使用
[psobject]
包装器,而这在计算属性技术中是不可能的。您的选择是:
或者:使用
Add-Member
,就像您的问题一样;如果添加开关-PassThru
,则装饰对象将被传递,从而允许您将调用用作管道的一部分:Add-Member
在管道中直接使用不允许您根据每个输入对象动态确定属性值。虽然您可以通过将调用包装在ForEach-Object
调用中来解决这个问题,但下面的技术更有效。或者:使用内在
psobject
属性向现有对象添加属性:ForEach-Object
从当前管道输入对象动态派生属性值,如图所示。$_