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.