Difference between PSObject, Hashtable, and PSCustomObject

One scenario where [PSCustomObject] is used instead of HashTable is when you need a collection of them. The following is to illustrate the difference in how they are handled:

$Hash = 1..10 | %{ @{Name="Object $_" ; Index=$_ ; Squared = $_*$_} }
$Custom = 1..10 | %{[PSCustomObject] @{Name="Object $_" ; Index=$_ ; Squared = $_*$_} }

$Hash   | Format-Table -AutoSize
$Custom | Format-Table -AutoSize

$Hash   | Export-Csv .\Hash.csv -NoTypeInformation
$Custom | Export-Csv .\CustomObject.csv -NoTypeInformation

Format-Table will result in the following for $Hash:

Name    Value
----    -----
Name    Object 1
Squared 1
Index   1
Name    Object 2
Squared 4
Index   2
Name    Object 3
Squared 9
...

And the following for $CustomObject:

Name      Index Squared
----      ----- -------
Object 1      1       1
Object 2      2       4
Object 3      3       9
Object 4      4      16
Object 5      5      25
...

The same thing happens with Export-Csv, thus the reason to use [PSCustomObject] instead of just plain HashTable.


Say I want to create a folder. If I use a PSObject you can tell it is wrong by looking at it

PS > [PSObject] @{Path='foo'; Type='directory'}

Name                           Value
----                           -----
Path                           foo
Type                           directory

However the PSCustomObject looks correct

PS > [PSCustomObject] @{Path='foo'; Type='directory'}

Path                                    Type
----                                    ----
foo                                     directory

I can then pipe the object

[PSCustomObject] @{Path='foo'; Type='directory'} | New-Item