Home > Blockchain >  Powershell Add-Member with an expression for the value
Powershell Add-Member with an expression for the value

Time:10-18

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
  }
  • Related