Long story short - it seems impossible to get a pipeline value to resolve to plain text in a ScriptProperty
and so I'm looking for a way to either do that, or to somehow parameterize when I'm adding properties to an object. I would be perfectly happy to add the values as NotePropertyMembers
rather than a ScriptProperty
; but I can't find a way to do that without looping through the entire object multiple times. The advantage of the ScriptProperty
is the ability to use the $this
variable so that I don't need to call Add-Member
on each member of the object itself.
Here's what an example of what I'm trying to accomplish and where it is breaking down.
# This sample file contains the values that I'm interested in
@'
ID,CATEGORY,AVERAGE,MEDIAN,MIN,MAX
100,"",52,50,10,100
100,1,40,40,20,60
100,2,41,35,15,85
'@ > values.csv
# To access the values, I decided to create a HashTable
$map = @{}
(Import-Csv values.csv).ForEach({$map[$_.ID + $_.CATEGORY] = $_})
# This is my original object. In reality, it has several additional columns of data - but it is
# missing the above values which is why I want to pull them in
@'
ID,CATEGORY
100,""
100,1
100,2
'@ > object.csv
$object = Import-Csv object.csv
# This is the meat of my attempt. Loop through all of the properties in the HashTable that
# I need to pull into my object and add them
$map.Values | Get-Member -MemberType NoteProperty | Where-Object {$_.Name -NotIn 'ID', 'CATEGORY'} | ForEach-Object {$object | Add-Member -MemberType ScriptProperty -Name "$($_.Name)" -Value {$map[$this.ID + $this.CATEGORY]."$($_.Name)"}}
In theory, I know that it works because I can display the values for a particular member of my object using the code below
$map.Values | Get-Member -MemberType NoteProperty | Where-Object {$_.Name -NotIn 'ID', 'CATEGORY'} | ForEach-Object {"$($_.Name) = " + $map[$object[0].ID + $object[0].CATEGORY]."$($_.Name)"}
Displays
AVERAGE = 52
MAX = 100
MEDIAN = 50
MIN = 10
However - it is clear that $_.Name
and "$($_.Name)"
do not resolve to their plain text description when they're in the ScriptProperty
PS> $object | GM -MemberType ScriptProperty
# Displays
TypeName: System.Management.Automation.PSCustomObject
Name MemberType Definition
---- ---------- ----------
AVERAGE ScriptProperty System.Object AVERAGE {get=$map[$this.ID + $this.CATEGORY]."$($_.Name)";}
MAX ScriptProperty System.Object MAX {get=$map[$this.ID + $this.CATEGORY]."$($_.Name)";}
MEDIAN ScriptProperty System.Object MEDIAN {get=$map[$this.ID + $this.CATEGORY]."$($_.Name)";}
MIN ScriptProperty System.Object MIN {get=$map[$this.ID + $this.CATEGORY]."$($_.Name)";}
To me, an obvious workaround is to individually add each column which still allows me to take advantage of using Add-Member
on the object itself instead of each individual member. However, the entire idea is to be able to dynamically add values without knowing ahead of time what their names are - in order to do that, I need to find a way to force the name to resolve within the ScriptProperty
# Workaround for this incredibly simple example
PS> $object | Add-Member -MemberType ScriptProperty -Name AVERAGE -Value {$map[$this.ID + $this.CATEGORY]."AVERAGE"}
PS> $object | Add-Member -MemberType ScriptProperty -Name MEDIAN -Value {$map[$this.ID + $this.CATEGORY]."MEDIAN"}
PS> $object | Add-Member -MemberType ScriptProperty -Name MIN -Value {$map[$this.ID + $this.CATEGORY]."MIN"}
PS> $object | Add-Member -MemberType ScriptProperty -Name MAX -Value {$map[$this.ID + $this.CATEGORY]."MAX"}
PS> $object | GM -MemberType ScriptProperty
# Displays
TypeName: System.Management.Automation.PSCustomObject
Name MemberType Definition
---- ---------- ----------
AVERAGE ScriptProperty System.Object AVERAGE {get=$map[$this.ID + $this.CATEGORY]."AVERAGE";}
MAX ScriptProperty System.Object MAX {get=$map[$this.ID + $this.CATEGORY]."MAX";}
MEDIAN ScriptProperty System.Object MEDIAN {get=$map[$this.ID + $this.CATEGORY]."MEDIAN";}
MIN ScriptProperty System.Object MIN {get=$map[$this.ID + $this.CATEGORY]."MIN";}