Why does PowerShell unwrap PSObject wrappers differently for array[] and object[]?

0
0
Asked By MellowPine47 On

I'm trying to understand two related PowerShell behaviors. These functions receive the output of Get-ChildItem:

function Test-Weird1 {
param([array[]]$InputObject)
$obj = $InputObject[0][0]
$obj.GetType().FullName
($obj -is [PSObject])
}

function Test-Weird2 {
param([object[]]$InputObject)
$obj = $InputObject[0]
$obj.GetType().FullName
($obj -is [PSObject])
}

Test-Weird1 (Get-ChildItem) returns System.IO.DirectoryInfo and False, while Test-Weird2 (Get-ChildItem) returns System.IO.DirectoryInfo and True.

There is also this behavior:

$obj = (Get-ChildItem)[0].PSObject
$obj.GetType() -eq [System.Management.Automation.PSObject] # True
$obj -is [System.Management.Automation.PSObject] # False

Why does the first parameter type change the indexing and PSObject result, and why does the PSObject property report that it has the PSObject type while the -is operator says otherwise?

3 Answers

Answered By RiverKite903 On

One extra edge case: indexing an empty result can leave you with `$null`, so `$InputObject[0].GetType()` may fail. If you need a consistently safe first-element lookup, use `@($InputObject)[0]`. In PowerShell 7, a null-conditional call such as `($obj)?.GetType().FullName` can also avoid calling a method on `$null`.

Answered By CobaltRaven62 On

The `.PSObject` member is not simply the same thing as asking whether the value itself is a `PSObject`. It exposes an object view represented by a member-set object, essentially a PowerShell inspection interface around the original value.

So in this example, `$obj.GetType()` reports the runtime type of that view, `System.Management.Automation.PSObject`, but the `-is` check tests the value in the other direction and does not consider the member-set view to be an instance of `PSObject`. In practice, `.PSObject`, `.PSAdapted`, and related intrinsic members are special PowerShell member sets rather than ordinary properties containing a normal PSObject wrapper.

Answered By QuasarMoth8 On

The first difference comes from the parameter conversion. `[array[]]` means an array whose elements are themselves arrays, so the input is coerced into a jagged array. `$InputObject[0][0]` reaches the underlying .NET `DirectoryInfo` object. During that conversion, PowerShell removes the `PSObject` wrapper, which is why `-is [PSObject]` is false.

`[object[]]` is just a one-dimensional object array. In that case, `$InputObject[0]` is the original PowerShell object, including its wrapper, so `-is [PSObject]` is true. The wrapper’s base object is still a `System.IO.DirectoryInfo`, which explains the type name returned by `GetType()`.

PowerShell normally preserves extended type system members when it unwraps and later rewraps objects, although some types—strings are a common example—can lose added members during conversion.

Related Questions

LEAVE A REPLY

Please enter your comment!
Please enter your name here

This site uses Akismet to reduce spam. Learn how your comment data is processed.