A while ago I changed my Join-Object
cmdlet which appeared to cause a bug which didn’t reveal in any of my testing.
The objective of the change was mainly code minimizing and trying to improve performance by preparing a custom PSObject and reusing this in the pipeline.
As the Join-Object
cmdlet is rather complex, I have created a simplified cmdlet to show the specific issue:
(The PowerShell version is: 5.1.16299.248
)
Function Test($Count) {
$PSObject = New-Object PSObject -Property @{Name = $Null; Value = $Null}
For ($i = 1; $i -le $Count; $i++) {
$PSObject.Name = "Name$i"; $PSObject.Value = $i
$PSObject
}
}
Directly testing the output gives exactly what I expected:
Test 3 | ft
Value Name
----- ----
1 Name1
2 Name2
3 Name3
Presuming that it shouldn't matter whether I assign the result to a variable (e.g. $a
) or not, but it does:
$a = Test 3
$a | ft
Value Name
----- ----
3 Name3
3 Name3
3 Name3
So, apart from sharing this experience, I wonder whether this is programming flaw or a PowerShell bug/quirk?
Your original approach is indeed conceptually flawed in that you're outputting the same object multiple times, iteratively modifying its properties.
The discrepancy in output is explained by the pipeline's item-by-item processing:
Outputting to the console (via
ft
/Format-Table
) prints the then-current state of$PSObject
in each iteration, which gives the appearance that everything is fine.Capturing in a variable, by contrast, reflects
$PSObject
's state after all iterations have completed, at which point it contains only the last iteration's values,Name3
and3
.You can verify that output array
$a
indeed references the very same custom object three times as follows:The solution is therefore to create a distinct
[pscustomobject]
instance in each iteration:PSv3+ offers syntactic sugar for creating custom objects: you can cast a hashtable (literal) to
[pscustomobject]
. Since this also creates a new instance every time, you can use it to simplify your function:Here's your own PSv2-compatible solution: