Objects in PowerShell

Objects are essentially known quantities of something that programming languages can use, interact with, perform computations and transformations on, and in general "consume." Technically, an object is simply the programmatic representation of anything. Objects are usually considered as two types of things: Properties, which simply describe attributes of whatever the .NET object is representing, and methods, which describe the types of actions (think verbs, or short instructions) that the .NET object can undertake.

For example, let us consider a car as an example. If we were making a car into a .NET object, then its properties would include its engine, doors, accelerator and brake pedals, steering wheel and headlights. Its methods would include turn engine on, turn engine off, open doors, close doors, press accelerator, release accelerator, turn steering wheel left, turn steering wheel right, turn on headlights, turn off headlights, turn on brights and turn off brights. (That is not an exhaustive list, but it should serve to demonstrate to you that the properties of the car are a description of its components, and the methods of the car describe how you can operate and interact with the properties.)


The Full-Form Way

This is the way most people would probably choose to create a custom object. It’s what I call the “textbook approach.” It has the advantage of being pretty clear, although it involves a lot of typing. Assuming I have an object in the variable $os, and another in $bios, I could combine selected pieces of information from them like this.

$object = New-Object –TypeNamePSObject $object | Add-Member –MemberTypeNoteProperty –Name OSBuild –Value $os.BuildNumber $object | Add-Member –MemberTypeNoteProperty –Name OSVersion –Value $os.Version $object | Add-Member –MemberTypeNoteProperty –Name BIOSSerial –Value $bios.SerialNumber Write-Output $object

You can continue that pattern to add whatever other information you need to the final output object, prior to writing it to the pipeline.

-PassThru: A Brief Shortcut

You can make that first approach a bit more concise by telling Add-Member to put the object back into the pipeline.

$object = New-Object –TypeNamePSObject $object | Add-Member –MemberTypeNoteProperty –Name OSBuild –Value $os.BuildNumber –PassThru | Add-Member –MemberTypeNoteProperty –Name OSVersion –Value $os.Version –PassThru | Add-Member –MemberTypeNoteProperty –Name BIOSSerial –Value $bios.SerialNumber Write-Output $object

When you end a line with a pipe character, Windows PowerShell knows to go to the next physical line to look for the next command in the pipeline. Essentially, it’s a way of breaking up a long command into multiple physical lines. That trick, combined with the –PassThru switch, makes this a series of three distinct commands.

While the previous approaches are effective, they’re also very wordy. In a script, it can actually be hard for you to visually determine what’s happening. Using the New-Object feature is a more concise approach. This lets you create a hashtable (or associative array) that contains the property names and values you want to add to the newly created object. These properties are each automatically created as a NoteProperty

$properties = @{'OSBuild'=$os.BuildNumber; 'OSVersion'=$os.version; 'BIOSSerial'=$bios.SerialNumber} $object = New-Object –TypeNamePSObject –Prop $properties Write-Output $object

This has the same effect, but is much more concise. Some clever folks will use a parenthetical expression to make it even shorter. However, I think this makes it a bit more difficult to read:

$object = New-Object –TypeNamePSObject –Prop (@{'OSBuild'=$os.BuildNumber; 'OSVersion'=$os.version; 'BIOSSerial'=$bios.SerialNumber}) Write-Output $object

You’ll notice that in all these examples, I save the custom object to a variable ($object) before writing it to the pipeline. The reason for this is simple. You might want to manipulate the object a bit more. For example, you might want to give your object a custom type name.

$object.PSObject.TypeNames.Insert(0,'My.Custom.Name')

There’s no “wrong” way to do anything in Windows PowerShell, as long as your approach gets the job done. That said, there are certain approaches I avoid, mostly because they’re less readable and harder to teach—especially to newcomers. Here’s one, still assuming that my $os and $bios variables contain the raw objects I want to extract information from

$os | Select-Object –Property @{n='OSVersion';e={$_.Version}}, @{n='OSBuild';e={$_.BuildNumber}}, @{n='BIOSSerial';e={$bios.SerialNumber}}

You’ll generate the same results as the previous examples, but the syntax is appalling. There’s lots of punctuation, lots of structure, and you have to understand a lot about what Select-Object is doing with those three hashtables. It’s basically generating custom properties using a syntax unique to that cmdlet (and shared by the Format cmdlets). You’ll see that syntax used by folks with a software development-style background. It’s harder for me (and many other folks) to mentally parse, so I tend to not use it as much.

Windows PowerShell is unique in that it lets you get away with some crazy stuff. For example, go back to my hashtable example. You could also do it this way

$info = @{} $info.OSBuild=$os.BuildNumber $info.OSVersion=$os.version $info.BIOSSerial=$bios.SerialNumber $object = New-Object –TypeNamePSObject –Prop $info Write-Output $object

You’re creating an empty hashtable, then adding information by referring to properties that don’t exist. When you first try to access OSBuild, for example, Windows PowerShell realizes that no such property exists in the $info object (which was an empty hashtable). It implicitly creates the property and assigns your value. Crazy stuff—but it works..

However you choose to create your custom objects, you can create custom objects instead of outputting mere text to the console window. Objects are infinitely more flexible, and they let your script or function output integrate with everything else Windows PowerShell.