As I often say, PowerShell is all about the objects. Getting your head around this object nature is one of the primary hurdlers for PowerShell newcomers. Cmdlets write objects to the pipeline, but you can also create your own custom objects either from a script or directly in the console.
This is a four-part series. In part one, I discussed the basics of creating custom objects in PowerShell to meet your needs; however, in this version, we lost the original object. Today I’ll show you how to modify and create the custom object while retaining the original.
Later, in part three we’ll learn how to create a custom object from scratch. Finally, in part four, I’ll go deeper and include the enhancements found in PowerShell 3.0.
In Part 1 of this series, I demonstrated how to use Select-Object to create a custom object in Windows PowerShell. One potential downside to that technique is that you lose the original object. Assuming Select-Object is the last part of your expression, you end up with a Selected object type as you see in Figure 1.
Figure 1: A selected object type
Here’s what the actual result looks like:
Computername RequiredCount Name DisplayName ------------ ------------- ---- ----------- SERENITY 2 spooler Print Spooler
But what if I wanted to keep the original object type yet still add these properties? The solution is to define a new object member using the Add-Member cmdlet. If you just need to add a single member, you can do it with a one-line command:
You can specify a number of member types with Add-Member (typically you just need NoteProperty). I give it a new name and assign it a value. You must use –Passthru so that the cmdlet writes the object to the pipeline. But where’s the Foo property? It’s there, but you can’t see it because the default format for this type of object only uses Status, Name, and Displayname. But I can still use the property.
If I had piped this to Get-Member I’d also see the property. Things get a bit trickier when you want to add multiple properties or use something from the existing object. Here’s how I normally handle this situation:
The service object is piped to Foreach-Object, which in turns passes each object to Add-Member. The first expression adds a property that shows the number of required objects. Then I define a variable for the computername depending on the value of Machinename. Notice that only on the last Add-Member do I need to use –Passthru.
Again, I won’t see these properties unless I pipe the expression to Get-Member or Select-Object and grab all properties. But there’s nothing preventing me from using it like this:
By creating a new type of object, I can look at service information in ways the author of Get-Service never imagined. I can filter, sort, and format the results based on my new properties. You can see my results below in Figure 2.
Figure 2 : Using Add-Member Results
The other way you’ll see this used is when creating entirely new objects out of thin air.
I’ve seen variations on this idea over the years. There’s nothing wrong with this approach and if you are using it, stick with it. I would certainly encourage you to look at full help and examples for Add-Member, as it can be a valuable scripting tool. I’ll admit there are situations where I use this technique. But generally, when I’m writing custom objects to the pipeline, I think there is an even better way. I’ll cover that in the next part of this series.