Introduction
In traditional trades, the Journeyman (often called Jman) is someone who has experience and can get stuff done effectively. They will forsee problems and adequately protect assets (especially coworkers) to keep things running smoothly. My expectation is that before you can be a “PowerShell Journeyman”, you should have experience with many aspects that can help your projects get done quickly and effectively. This entry deals with taking advantage of the PSObject intrinsic property.
Intrinsic Properties
PowerShell has some property members that get added to all objects. These properties are documented in the About intrinsic members article on Microsoft Learn.
You really should know about at least the PSObject property in order to inspect objects in PowerShell.
When You Need to Inspect Objects
A user on reddit recently asked how to dynamically select column names for use with Out-GridView after having spent days trying to figure it out. As a sample of what he was seeing, objects with different property names didn’t show up when using Out-GridView
or Select-Object
.
To illustrate what the was, consider this array of objects with differing properties:
[PSCustomObject]@{a=1;b=2},[PSCustomObject]@{b=2;c=3}
if you view this on the console, you’ll only see the properties a and b by default. Even if you use Select-Object *
as shown here:
But if you view as a list, you can see the c property. What gives?!
The user wanted some way to see all of these columns at one without having to use list format.
Understanding PowerShell’s Helpful Mentality
PowerShell is trying to help you out. It really is. And most of the time, its very handy. When you send a list of objects down the pipeline to something like Select-Object
or Out-GridView
, PowerShell will inspect the first pipeline object that comes down and get all the property names from that object. It will assume that all the rest of the objects to come down the pipeline will also have the same property names.
You need to access the PSObject properties and pull them out manually so that you can feed those properties to Select-Object
isntead.
Accessing PSObject Properties
Enter PSObject. It contains a property called Properties
that has all the properties that are defined on that object. Every object in PowerShell has the intrinsic property PSObject. Even simple primitives and other value type objects like 1
. Ex: (1).PSObject
.
Note that accessing PSObject on an array of objects will access the ARRAY PSObject, not the PSObject of the first item in the array. Here’s how you can get all the property names from the first item in an array:
$array = [PSCustomObject]@{a=1;b=2},[PSCustomObject]@{b=2;c=3}
$array[0].PSObject.Properties.Name
Cultivating a List of All Property Names From an Array
To get a list of all the property names from all objects in an array, you just need to iterate through all objects in the array and then select only the unique property names. Then supply that list of properties to Select-Object to prevent the default/helper property selection behavior:
$columns = $Array |
ForEach-Object { $_.PSObject.Properties.Name } |
Select-Object -Unique
$Array | Select-Object $columns
Going Further
This approach relies on Select-Object -Unique
, which is case sensitive. There was a bug filed just before COVID that called out how Select-Object -Unique
being case sensitive is inconsistent and unexpected in PowerShell (like Sort-Object -Unique
). In that issue, a workaround I used was improved on by mklement0 that allows you to maintain order of objects while also selecting unique values with case insensitivity.
Good news, that issue is now closed because the upcoming PowerShell Core 7.4 release provides a -CaseInsensitive
switch that you can use with Select-Object -Unique -CaseInsensitive
to achieve all of this easily. Hopefully it will reach GA status here soon :D
RANT: MS SHOULD BE OPEN TO MORE BREAKING CHANGES THAT BENEFIT THE COMMUNITY
Wrapping Up
You can tell that u/Sentenced4Life is a happy camper now that he can dynamically have the AppPool names show up in his Out-GridView
table:
If you want to say something about this blog post, come say hi in the comment thread.