Why does PowerShell sometimes report objects as PSObject and sometimes not?

0
0
Asked By VelvetKite42 On

I'm trying to understand some behavior involving PowerShell parameter binding, arrays, and the PSObject wrapper. Why do these two functions produce different results? In the first, the parameter is declared as [array[]] and the code examines $InputObject[0][0]. In the second, it is declared as [object[]] and examines $InputObject[0]. Calling either function with Get-ChildItem produces a System.IO.DirectoryInfo object, but the first reports that it is not a PSObject while the second reports that it is. Also, if I assign (Get-ChildItem)[0].PSObject to a variable, GetType() says it is a System.Management.Automation.PSObject, yet the -is operator returns False. What exactly is being wrapped or unwrapped here?

4 Answers

Answered By QuietOrbit88 On

One unrelated edge case: indexing an empty result can leave you with $null. If the function needs to tolerate no matching items, use @( $InputObject )[0] before calling methods. In PowerShell 7+, a null-safe call such as ($obj)?.GetType().FullName can also prevent a null-method error.

Answered By CopperMango7 On

The key difference is the parameter type. [array[]] means an array whose elements are themselves arrays, so PowerShell converts each incoming item to an array. During that conversion, the PSObject wrapper around the underlying .NET object is removed, leaving the base System.IO.DirectoryInfo instance. That is why $InputObject[0][0] has the expected .NET type but -is [PSObject] is False.

With [object[]], PowerShell creates one ordinary object array and does not need to convert each element into another array. The existing PSObject wrappers remain, so $InputObject[0] is still recognized as a PSObject. Casting or parameter binding can therefore change whether you observe the wrapper or the wrapped object, even though the underlying .NET type is the same.

Answered By MarbleFox19 On

Get-ChildItem returns provider-enhanced objects. A file-system item is based on DirectoryInfo or FileInfo, but PowerShell attaches extended type system members and keeps that information through PSObject machinery. In older PowerShell versions, unwrapping could even make those extended members disappear; newer versions track the association and can restore it if the object is wrapped again.

So this is not because Get-ChildItem returns an array of arrays. The nested indexing in the first function comes from the [array[]] parameter declaration and its conversion behavior.

Answered By NimbleHarbor6 On

The second example is a separate PSObject detail. The .PSObject property is not simply the same thing as asking whether the base value is a PSObject. It exposes a member view represented by a PSMemberSet, which provides access to the object's adapted, extended, and base members. Calling GetType() through that view can return the PSObject implementation, while the -is test is performed against the value you assigned and can still report False for the underlying object.

For example, (1).PSObject and (1).PSAdapted are member sets, not ordinary replacement values for the integer itself. They are PowerShell's introspection interface around the object.

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.