我的工作流程对其接收的 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
#>
使用选择对象技术添加新的 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 =这是一个字符串”,因为我喜欢它
$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 添加到定义中,而不是像添加成员场景中那样添加字符串?
有没有办法让
@{Name='Name'; Expression = {'Expression'}}
技术添加字符串而不是 System.String?
为什么
技术[即使用计算属性]将@{Name='Name'; Expression = {'Expression'}}
添加到定义中,而不是像System.String
string
场景中那样添加Add-Member
?
这是不幸事实的副作用,即计算属性技术在指定的属性值
周围创建了一个
[psobject]
包装器。
[psobject]
是在幕后使用的透明辅助类型,虽然此类包装器通常不可见,但它们可能会在不同情况下导致不同的行为,例如在手头的情况下。
这种有问题的行为以及行为发生变化的场景列表在 GitHub 问题 #5579 中进行了讨论。
有没有办法让
技术添加@{Name='Name'; Expression = {'Expression'}}
而不是string
?System.String
这需要避免使用
[psobject]
包装器,而计算属性技术是不可能实现这一点的。
您的选择是:
Add-Member
,如您的问题所示;如果添加 -PassThru
开关,则修饰对象将被传递,允许您将调用用作管道的一部分:
[object]::new() | Add-Member -PassThru Text Hi! | Get-Member
Add-Member
不允许您根据每个输入对象动态地确定属性值。虽然您可以通过将调用包装在 ForEach-Object
调用中来解决这个问题,但下面的技术更有效。
使用 内在 psobject
属性
将属性添加到现有对象:
[object]::new() |
ForEach-Object {
# Add a property.
$_.psobject.Properties.Add(
[psnoteproperty]::new('Text', "Hash code: $($_.GetHashCode())")
)
$_ # Pass the modified object through.
} |
Get-Member
由于在管道中使用此技术无论如何都需要使用 ForEach-Object
自动
$_
变量从当前管道输入对象动态派生属性值,如图所示。