How can I add PSObjects to a PSObject as a collection?

by willsteele at 2012-08-22 13:46:49

I have a set of files I want to analyze. I am creating a simple PSObject (with a few members) within each iteration of a foreach loop. But, I want to then add this newly created PSObject to a collection. Do I need to explicitly declare the type for the "collection" object or is there a way PowerShell can infer this dynamically? I tried += but there is no operator override to add objects to PSObjects. Here is a sample script that reads through a file set and grabs two properties, adds them to a loop scoped object, and, attempted to add them the collection. It fails on the += call.

Clear-Host
$bytes = New-Object -TypeName PSObject
Get-ChildItem -Path ‘C:\Data\Documents\Powershell\test\File Format’ |
ForEach-Object {
$bytes += New-Object -TypeName PSObject |
Add-Member -Name Name -MemberType NoteProperty -Value $.Name -PassThru |
Add-Member -Name Bytes -MemberType NoteProperty -Value ([System.IO.File]::ReadAllBytes($
.fullname) -join ’ ')
}
$bytes


Here is my exception:

+= : Method invocation failed because [System.Management.Automation.PSObject] doesn’t contain a method named ‘op_Addition’.

At C:\Users\wsteele\AppData\Local\Temp\7859c7a9-5e03-417e-be47-cc535f279f6a.ps1:5 char:11
+ $bytes += <<<< New-Object -TypeName PSObject |
+ CategoryInfo : InvalidOperation: (op_Addition:String) , RuntimeException
+ FullyQualifiedErrorId : MethodNotFound


The underlying question is how do I add dynamically created objects to a collection without naming each object?
by poshoholic at 2012-08-22 13:56:06
If you define your collection as a collection, then the += operator will apply to the collection rather than the object.

[script=powershell]$bytes = @()[/script]

You can strongly type your collection if you want, like this:

[script=powershell][PSObject]$bytes = @()[/script]

That isn’t necessary though for generic objects…it wouldn’t buy you anything. For objects that are not generic, it would ensure that any objects that you add to the collection are of the right type.
by poshoholic at 2012-08-22 13:57:34
Also note that in the script you provided, you are missing a necessary -PassThru on the second pipeline stage with Add-Member; as it is now, nothing will be returned from that New-Object to Add-Member pipeline.
by willsteele at 2012-08-22 14:16:47
Okay, switching to an array got me there.

Clear-Host
[PSObject] $bytes = @()
Get-ChildItem -Path ‘C:\Data\Documents\Powershell\test\File Format’ |
ForEach-Object {
$bytes += New-Object -TypeName PSObject |
Add-Member -Name Name -MemberType NoteProperty -Value $.Name -PassThru |
Add-Member -Name Bytes -MemberType NoteProperty -Value ([System.IO.File]::ReadAllBytes($
.fullname) -join ’ ') -PassThru |
Add-Member -Name Hex -MemberType NoteProperty -Value (([System.IO.File]::ReadAllBytes($.fullname) | % {"{0:X2}" -f $ }) -join ’ ') -PassThru
}
$bytes


produced:

Name Bytes Hex
---- ----- —
mac.txt 116 101 115 116 13 116 101 115 116 13 74 65 73 74 0D 74 65 73 74 0D
pc.txt 116 101 115 116 13 10 116 101 115 116 74 65 73 74 0D 0A 74 65 73 74
unix.txt 116 101 115 116 10 116 101 115 116 10 74 65 73 74 0A 74 65 73 74 0A