Workaround for Add-Member on plain .Net objects

Workaround for Add-Member on plain .Net objects

  • Comments 3

Introduction

While I was fixing bugs, I came across an interesting bug (https://connect.microsoft.com/PowerShell/feedback/ViewFeedback.aspx?FeedbackID=382818) that seemed to have a very simple fix upon first glance. However, after doing some more research, I found out that it was actually very tricky to fix the root cause. If you do the following:

$table = @{ key1="val1"; key2="val2" }
Add-Member -in $table -MemberType NoteProperty -Name test -Value testValue

Now if you pipe $table to Get-Member you will notice that the test property is missing. No matter how many times you repeat the same Add-Member operation, $table seems to be totally unaffected. However, if you access the test property or even a nonexistent property before you use Add-Member, the command will behave correctly.

Why is this happening?

In PowerShell, we create .Net objects as System.Object as opposed to System.Management.Automation.PSObject for performance reasons. This is because every time an object is converted from System.Object to PSObject, PowerShell has to build the metadata information by reflecting on the .Net object. Doing so can introduce unnecessary overhead since not all operations require PSObjects. When you do something with it (i.e. property access), it becomes a PSObject. However, when you pass a variable ($table) bound to an Object to a cmdlet such as Add-Member, the cmdlet internally converts the bound object into a PSObject. This effectively creates a copy of the original object and anything done to the PSObject is not reflected on the input object.

How can we work around it?

We are hoping to fix the root cause in the next release. However, the workaround is actually quite simple. Since Add-Member is able to emit the modified object if the –PassThru flag is specified, all you have to do is assigned the object back to your initial variable.

$table = Add-Member -in $table NoteProperty Test "Test property" –PassThru

Tianjie (James) Wei [MSFT]
Software Design Engineer
Windows PowerShell Team

Leave a Comment
  • Please add 4 and 1 and type the answer here:
  • Post
  • This is definitely not the only bug related to bare-objects and psobjects being treated differently.   Your blog post prompted me to get around to reporting two other such bugs.  Here they are:

    https://connect.microsoft.com/PowerShell/feedback/ViewFeedback.aspx?FeedbackID=508091

    and

    https://connect.microsoft.com/PowerShell/feedback/ViewFeedback.aspx?FeedbackID=508100

  • HA!  I've had that problem but solved it a different way.

    $table = @{ key1="val1"; key2="val2" }

    $table.psobject.members.Add((new-object management.automation.PSNoteProperty "Test","TestVal"))

    -PassThru would be easier and I may have stumbled onto it but didn't pickup the pattern.

  • I complained about this exact issue on microsoft.public.windows.powershell roughly two years ago. It's nice to know that some one on the team finally has looked at it. Thank you! =)

Page 1 of 1 (3 items)