Functions/Union-Object.ps1
function Union-Object ([String[]]$Property = @()) { <# .SYNOPSIS Returns a 'clean' array of objects that have all property names in each element of the array .DESCRIPTION Returns a 'clean' array of objects that have all property names in each element of the array .NOTES Inspired by Union-Object on https://powersnippets.com/union-object/ Notes from the web page: Union-Object Most native PowerShell cmdlets that handle an array of objects (like e.g. Export-CSV) only look to the first object to define the concerned properties. This behavior can lead to unexpected results. Consider the following object: $List = @( New-Object -TypeName PSObject -Property @{Id = 2} New-Object -TypeName PSObject -Property @{Id = 1} New-Object -TypeName PSObject -Property @{Id = 3; Name = "Test"} ) If you simply display this object array, only the Id property will be listed: PS C:\> $List Id -- 2 1 3 You might quickly fix this by aligning the properties of the first object with the rest of the objects (Name = $Null): $List = @( New-Object -TypeName PSObject -Property @{Id = 2; Name = $Null} New-Object -TypeName PSObject -Property @{Id = 1} New-Object -TypeName PSObject -Property @{Id = 3; Name = "Test"} ) This will work for most of the cases: PS C:\> $List Id Name -- ---- 2 1 3 Test But not in every case: PS C:\> $List | Sort Id Id -- 1 2 3 In other words, it is required to align every object in the array to prevent that you lose any properties. The quickest way is to use the Select-Object cmdlet: Select-Object Id, Name, knowing that just selecting all objects: Select-Object *, doesn't resolve the issue. This mean that it is still required to iterate through all the objects to define all the properties. Fixed array example: $List = @( New-Object -TypeName PSObject -Property @{Id = 2} New-Object -TypeName PSObject -Property @{Id = 1} New-Object -TypeName PSObject -Property @{Id = 3; Name = "Test"} ) $NewList = $List | Union-Object $NewList Id Name -- ---- 2 1 3 Test Made following changes * added help * formatting changes #> [cmdletbinding()] $Objects = $Input | ForEach-Object {$_} if (-not $Property) { foreach ($Object in $Objects) { $Property += $Object.PSObject.Properties | Select-Object -ExpandProperty Name } } $Objects | Select-Object -Property ([String[]]($Property | Select-Object -Unique)) } Set-Alias -Name Union -Value Union-Object |