Reputation: 403
Using PowerShell Core 6.1 on Mac. It appears that piping an array to ForEach-Object is modifying or wrapping each element such that the -is operator considers all of them to be PSCustomObjects.
Let me demonstrate:
Set up an array of four items of different types (use of JSON because that's where the data is coming from in my real use case):
$a = '[4, "Hi", {}, true]' | ConvertFrom-Json
Iterate the list by index and determine which ones are PSCustomObjects:
0..3 | ForEach-Object {
$v = $a[$_]
$t = $v.GetType().FullName
$is = $v -is [PSCustomObject]
"$t - $is"
}
The output (for me) is exactly what I would expect:
System.Int64 - False
System.String - False
System.Management.Automation.PSCustomObject - True
System.Boolean - False
But if I just pipe the array to ForEach-Object:
$a | ForEach-Object {
$v = $_
$t = $v.GetType().FullName
$is = $v -is [PSCustomObject]
"$t - $is"
}
Now the output claims that all four are PSCustomObjects:
System.Int64 - True
System.String - True
System.Management.Automation.PSCustomObject - True
System.Boolean - True
Could anyone explain what is happening here?
Upvotes: 2
Views: 488
Reputation: 437608
PetSerAl, as he frequently does, has provided the crucial pointer in a comment:
Piping objects to ForEach-Object
wraps them in a [psobject]
instance (as reflected in $_
/ $PSItem
), which causes -is [pscustomobject]
/ -is [psobject]
to return $True
for any input object, because - confusingly - [pscustomobject]
is the same as [psobject]
: they're both type accelerators for [System.Management.Automation.PSObject]
- against what one would expect,[pscustomobject]
is not short for [System.Management.Automation.PSCustomObject]
.
Therefore, test the input objects for being instances of [System.Management.Automation.PSCustomObject]
rather than [pscustomobject]
:
$a | ForEach-Object {
$_ -is [System.Management.Automation.PSCustomObject]
}
Note that if you use a foreach
loop, even -is [pscustomobject]
would work, because the objects being enumerated are then not wrapped in an extra [psobject]
instance:
foreach ($element in $a) {
$element -is [pscustomobject]
}
This works, because even a bona fide [System.Management.Automation.PSCustomObject]
is technically also a [System.Management.Automation.PSObject]
behind the scenes.
Upvotes: 1