Trying to add a new member to an array of powershell objects, can't get the expression to evaluate. Here's some example code:
$testData =
@([pscustomobject]@{Name="Cat";Legs=4},
[pscustomobject]@{Name="Parrot";Legs=2},
[pscustomobject]@{Name="Snake";Legs=0})
# this works
$testData | Select-Object Name, Legs, @{N='CopyName';E={$_.Name}}
# why doesnt this work?
$testData | Add-Member -NotePropertyName "CopyName" -NotePropertyValue $_.Name
$testData
(Using Powershell 7)
CodePudding user response:
this works:
$testData | Select-Object Name, Legs, @{N='CopyName';E={$_.Name}}
This works, because you're using a calculated property to define the CopyName
property, and the script block ({ ... }
) in your E
(Expression
) entry allows you to refer to the .Name
property of the input object at hand via the automatic $_
variable.
As an aside: You don't have to explicitly enumerate the existing properties (Name, Legs
): you can refer to them abstractly as *
, given that wildcard expressions as property names are supported:
$testData | Select-Object *, @{N='CopyName';E={$_.Name}}
why doesnt this work?:
$testData | Add-Member -NotePropertyName "CopyName" -NotePropertyValue $_.Name
This doesn't work, because using $_
to refer to the current pipeline input object only works inside a script block.
However, -NotePropertyValue { $_.Name }
does not work either:
Because the parameter type of
-NotePropertyValue
is[object]
(System.Object
),{ $_.Name }
would become the property value as-is, as a script block.There is another mechanism (in addition to calculated properties) that allows determining parameter values dynamically: delay-bind script blocks.
However, there are two prerequisites, neither of which is met by
Add-Member
's-NotePropertyValue
parameter:- The targeted parameter must be declared as pipeline-binding (accepting input from the pipeline).
- The targeted parameter's type must not be
[object]
or[scriptblock]
-typed.
In the case of
Add-Member
, the fact that-NotePropertyValue
is[object]
-typed (to support any value) alone precludes support for this feature.
Given the above, you must call Add-Member
on the objects in $testData
individually, such as via ForEach-Object
:
$testData |
ForEach-Object {
# Due to being inside the ForEach-Object script block, $_.Name
# now refers to the current input object's .Name property.
# Add -PassThru to also *output* the modified object.
Add-Member -InputObject $_ -NotePropertyName "CopyName" -NotePropertyValue $_.Name
}