Creating Custom Objects in PowerShell with the Original Object

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.

Lost and Found : Original Object

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.

Sponsored Content

Passwords Haven’t Disappeared Yet

123456. Qwerty. Iloveyou. No, these are not exercises for people who are brand new to typing. Shockingly, they are among the most common passwords that end users choose in 2021. Research has found that the average business user must manually type out, or copy/paste, the credentials to 154 websites per month. We repeatedly got one question that surprised us: “Why would I ever trust a third party with control of my network?

Fig1: Creating custom objects - Selected Object Type

Figure 1: A selected object type

Here’s what the actual result looks like:

Computername                   RequiredCount Name            DisplayName

------------                   ------------- ----            -----------

SERENITY                                   2 spooler         Print Spooler


Defining a New Object Member Using Add-Member

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:

PS C:\> Get-Service Spooler | Add-Member -MemberType NoteProperty -Name “Foo” -Value 123  -PassThru Status   Name               DisplayName ——   —-               ———– Running  Spooler            Print Spooler

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.

PS C:\> Get-Service Spooler | Add-Member -MemberType NoteProperty -Name “Foo” -Value 123  -PassThru | Select Name,Displayname,Status,Foo   Name               DisplayName                  Status               Foo —-               ———–                  ——               — Spooler            Print Spooler                Running              123

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:

Get-Service Spooler | foreach { $_ | Add-Member -MemberType NoteProperty -Name “RequiredCount” -Value (($_.RequiredServices | Measure).count) $computer=If ($_.Machinename -eq “.”) { $env:computername } else { $_.Machinename.ToUpper() } $_ | Add-Member -MemberType NoteProperty -Name “Computername” -Value $computer -PassThru }

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:

Get-Service -computer “quark”,”.” | foreach { $_ | Add-Member -MemberType NoteProperty -Name “RequiredCount” -Value (($_.RequiredServices | Measure).count) $computer=If ($_.Machinename -eq “.”) { $env:computername } else { $_.Machinename.ToUpper() } $_ | Add-Member -MemberType NoteProperty -Name “Computername” -Value $computer -PassThru } | Where {$_.RequiredCount -gt 3} | Sort Computername,RequiredCount -descending | Format-Table -GroupBy Computername -Property DisplayName,Status,RequiredCount

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.

Fig 2: Custom Properties in Powershell

Figure 2 : Using Add-Member Results

The other way you’ll see this used is when creating entirely new objects out of thin air.

PS C:\> $obj=New-Object PSObject PS C:\> $obj | Add-Member Noteproperty -Name Name -value “Jeff Hicks” PS C:\> $obj | Add-Member Noteproperty -Name Size -value 12345 PS C:\> $obj | Add-Member Noteproperty -Name Title -value “Author & Trainer” PS C:\> $obj | Add-Member Noteproperty -Name MVP -value $True PS C:\> $obj | Add-Member Noteproperty -Name Blog -value “http://jdhitsolutions.com/blog” PS C:\> $obj Name : Jeff Hicks Size : 12345 Title : Author & Trainer MVP : True Blog : http://jdhitsolutions.com/blog

Custom Objects Cliffhanger

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.

Related Topics:


Don't have a login but want to join the conversation? Sign up for a Petri Account

Comments (1)

One response to “Creating Custom Objects in PowerShell with the Original Object”

Leave a Reply

Don't leave your business open to attack! Come learn how to protect your AD in this FREE masterclass!REGISTER NOW - Thursday, December 2, 2021 @ 1 pm ET

Active Directory (AD) is leveraged by over 90% of enterprises worldwide as the authentication and authorization hub of their IT infrastructure—but its inherent complexity leaves it prone to misconfigurations that can allow attackers to slip into your network and wreak havoc. 

Join this session with Microsoft MVP and MCT Sander Berkouwer, who will explore:

  • Whether you should upgrade your domain controllers to Windows Server
    2019 and beyond
  • Achieving mission impossible: updating DCs within 48 hours
  • How to disable legacy protocols and outdated compatibility options in
    Active Directory

Sponsored by: