Share

Quick note about objects in PowerShell

I decided to move this note out from another post.

It’s a kind of summary on a question “Why [PSCustomObject]@{} syntax is the preferred way to create objects in PS”. After looking into StackOverflow (one, two) and some other resources (three), I decided to test and write it down for myself.

Nothing really new here. I only hope it will work as a good summary.

Update: Select-Object examples. Additional links.


First, PSCustomObject is smarter than regular hash-table and PSObject when it comes to output and it keeps order of parameters:

PS C:\some-folder
> @{One=1; Two=2; Three=3}

Name                           Value
----                           -----
One                            1
Three                          3
Two                            2


PS C:\some-folder
> [PSObject]@{One=1; Two=2; Three=3}

Name                           Value
----                           -----
One                            1
Three                          3
Two                            2


PS C:\some-folder
> [PSCustomObject]@{One=1; Two=2; Three=3}

One Two Three
--- --- -----
  1   2     3


PS C:\some-folder
> New-Object PSObject -Property @{One=1; Two=2; Three=3}

One Three Two
--- ----- ---
  1     3   2


PS C:\some-folder
> '' | Select-Object @{Name="One"; Expression={1}},@{Name="Two"; Expression={2}},@{Name="Three"; Expression={3}}

One Two Three
--- --- -----
  1   2     3

Note that parameters ordered alphabetically in all the cases except PSCustomObject and Select-Object. And since Select-Object not meant to be used on its own, it looks very cumbersome here.

Second, PSCustomObject is faster than New-Object cmdlet (and it has easier syntax too):

PS C:\some-folder
> Measure-Command { 1..100000 | %{ @{Name="Object $_" ; Index=$_ ; Squared = $_*$_} } }


Days              : 0
Hours             : 0
Minutes           : 0
Seconds           : 2
Milliseconds      : 517
Ticks             : 25173493
TotalDays         : 2,91359872685185E-05
TotalHours        : 0,000699263694444444
TotalMinutes      : 0,0419558216666667
TotalSeconds      : 2,5173493
TotalMilliseconds : 2517,3493



PS C:\some-folder
> Measure-Command { 1..100000 | %{ [PSObject]@{Name="Object $_" ; Index=$_ ; Squared = $_*$_} } }


Days              : 0
Hours             : 0
Minutes           : 0
Seconds           : 2
Milliseconds      : 717
Ticks             : 27173889
TotalDays         : 3,14512604166667E-05
TotalHours        : 0,00075483025
TotalMinutes      : 0,045289815
TotalSeconds      : 2,7173889
TotalMilliseconds : 2717,3889



PS C:\some-folder
> Measure-Command { 1..100000 | %{ [PSCustomObject]@{Name="Object $_" ; Index=$_ ; Squared = $_*$_} } }


Days              : 0
Hours             : 0
Minutes           : 0
Seconds           : 4
Milliseconds      : 748
Ticks             : 47482940
TotalDays         : 5,49571064814815E-05
TotalHours        : 0,00131897055555556
TotalMinutes      : 0,0791382333333333
TotalSeconds      : 4,748294
TotalMilliseconds : 4748,294


PS C:\some-folder
> Measure-Command { 1..100000 | %{ New-Object PSObject -Property @{Name="Object $_" ; Index=$_ ; Squared = $_*$_} } }


Days              : 0
Hours             : 0
Minutes           : 0
Seconds           : 13
Milliseconds      : 414
Ticks             : 134148763
TotalDays         : 0,000155264771990741
TotalHours        : 0,00372635452777778
TotalMinutes      : 0,223581271666667
TotalSeconds      : 13,4148763
TotalMilliseconds : 13414,8763


PS C:\some-folder
> Measure-Command { 1..100000 | Select-Object @{Name="Name"; Expression={"Object $_"}},@{Name="Index"; Expression={$_}},@{Name="Squared"; Expression={$_*$_}} }


Days              : 0
Hours             : 0
Minutes           : 0
Seconds           : 5
Milliseconds      : 640
Ticks             : 56404673
TotalDays         : 6,52831863425926E-05
TotalHours        : 0,00156679647222222
TotalMinutes      : 0,0940077883333333
TotalSeconds      : 5,6404673
TotalMilliseconds : 5640,4673

While creating PSCustomObject is slower than just a hash-table, it’s much faster than New-Object cmdlet.

Summary

Syntax Proper formatting Keeps order Relative time
@{} (bare hash-table) 1.0
[PSObject]@{} 1.08
[PSCustomObject]@{} + + 1.89
New-Object PSObject -Property @{} + 5.33
Select-Object + + 2.24

So, overall PSCustomObject is well-balanced - not far from bare hash-table in performance and with some usage benefits.

The only possible issue with PSCustomObject is that it was introduced in PowerShell 3.0. I don’t know how many users still stick with Windows 7 (where PowerShell 2.0 was available by default).

What puzzles me now is the [PSObject]@{} syntax. While PSCustomObject and PSObject are aliases for the same type System.Management.Automation.PSObject, this type accelerator is free from some implementation magic and behaves almost indistinguishable from bare hash-table. It looks like I’m testing some nonsense here as there is no reason to use it like that %)

Additional reading:

PowerShell: Creating Custom Objects - more ways illustrated and additional links provided.

comments powered by Disqus