Skip to content
Menu
The Lonely Administrator
  • PowerShell Tips & Tricks
  • Books & Training
  • Essential PowerShell Learning Resources
  • Privacy Policy
  • About Me
The Lonely Administrator

The Power of Custom Properties

Posted on March 1, 2016

The other day fellow PowerShell MVP Adam Bertram published an article about using custom properties with Select-Object. It is a good article in that it gets you thinking about PowerShell in terms of objects and not simple text. But I want to take Adam's article as a jumping off point and take his ideas a bit further. I'm going to use Adam's same example as a learning tool. Don't get distracted by other ways to get the same information. The process and techniques are what matter here.

Manage and Report Active Directory, Exchange and Microsoft 365 with
ManageEngine ADManager Plus - Download Free Trial

Exclusive offer on ADManager Plus for US and UK regions. Claim now!

Whenever I'm working with PowerShell, I'm always thinking about how I can use this at scale.  How can I get this same information for 10 or 100 servers? And of course,  at this point I need to make sure I include a computername in the results.  First, I'll try something with a single computer.

Get-CimInstance -ClassName Win32_PhysicalMemory -ComputerName chi-hvr1 |
Select PSComputername,@{Name = "MemoryGB";Expression = { ($_.Capacity | Measure -sum).sum/1GB}}

image

Close but not quite. Get-CimInstance is writing multiple objects to the pipeline.  The server in question has 2  8GB sticks of memory which is what you see in the output. I need something more along Adam's original idea to that this becomes 16GB.

What I really want is the Sum property from Measure-Object and to that I need to add a Computername property. I'll turn things around a bit.

Get-CimInstance -ClassName Win32_PhysicalMemory -ComputerName chi-hvr1 -PipelineVariable pv|
Measure-Object -Property capacity -Sum |
Select @{Name="Computername";Expression={$pv.pscomputername}},
@{Name="MemoryGB";Expression = {$_.sum/1GB}}

image

This works because I'm using the common PipelineVariable parameter introduced in PowerShell 4.  What happens is that the pipeline output from Get-CimInstance is stored in a variable, pv, which I can access later in the expression. In my case I'm defining a new property for the computername using $pv and adding it to the selected output from Measure-Object.

However, if I try this for multiple computer names, I don't get the expected result.

image

That's because I'm adding up the physical memory instances from all servers, which isn't really what I want. Instead, this is a situation where I have to process each computer individually.

$computers = "chi-hvr1","chi-hvr2","chi-web02","chi-win10","chi-tp04","win81-ent-01"
foreach ($computer in $computers) {
    Get-CimInstance -ClassName Win32_PhysicalMemory -ComputerName $computer -PipelineVariable pv|
    Measure-Object -Property capacity -Sum |
    Select @{Name="Computername";Expression={$pv.pscomputername}},
    @{Name="MemoryGB";Expression = {$_.sum/1GB}}
}

image

One thing to be careful of when using the ForEach enumerator is that you can't pipe the output to another cmdlet like Export-CSV, unless you explicitly save the results to a variable.

$data = Foreach ($computer in $computers) { …

Then you can pipe $data to other cmdlets. You can use ForEach-Object although it might be little harder to follow.

$computers | foreach {
Get-CimInstance -ClassName Win32_PhysicalMemory -ComputerName $_ -PipelineVariable pv|
    Measure-Object -Property capacity -Sum |
    Select @{Name="Computername";Expression={$pv.pscomputername}},
    @{Name="MemoryGB";Expression = {$_.sum/1GB}}
} | Sort MemoryGB,Computername

But this makes it easier if you need to pipe the output to something else.

image

To wrap this up let's go all out and define a few more custom properties.

$computers | foreach {
Get-CimInstance -ClassName Win32_PhysicalMemory -ComputerName $_ -PipelineVariable pv|
    Measure-Object -Property capacity -Sum |
    Select @{Name = "Computername";Expression={$pv.pscomputername}},
    @{Name = "Computer";Expression = {
     $cs = Get-CimInstance Win32_computersystem -ComputerName $pv.psComputername
     #construct a string with manufacturer and model
     "$($cs.Manufacturer):$($cs.Model)"
    }},
    @{Name = "MemoryGB";Expression = {$_.sum/1GB}},
    @{Name="NumberSticks";Expression = {$_.Count}}
} | Sort MemoryGB,Computername

image

Even though I'm selecting a few properties from the output of Measure-Object, I'm defining several others which are calculated on the fly. There is so much you can do with this technique,  but if I lost you anywhere please let me know.


Behind the PowerShell Pipeline

Share this:

  • Click to share on X (Opens in new window) X
  • Click to share on Facebook (Opens in new window) Facebook
  • Click to share on Mastodon (Opens in new window) Mastodon
  • Click to share on LinkedIn (Opens in new window) LinkedIn
  • Click to share on Pocket (Opens in new window) Pocket
  • Click to share on Reddit (Opens in new window) Reddit
  • Click to print (Opens in new window) Print
  • Click to email a link to a friend (Opens in new window) Email

Like this:

Like Loading...

Related

6 thoughts on “The Power of Custom Properties”

  1. Rohin McDermott says:
    March 15, 2016 at 7:13 pm

    You could always group by pscomputername first, and then apply the custom property.

    $computers = “chi-hvr1″,”chi-hvr2″,”chi-web02″,”chi-win10″,”chi-tp04″,”win81-ent-01″
    $MemoryGB = @{Name=”MemoryGB”;Expression = {($_.Group.Capacity | Measure -Sum).Sum/1GB}}
    Get-CimInstance -ClassName Win32_PhysicalMemory -ComputerName $Computers | group pscomputername | Select Name,$MemoryGB

    Love custom properties, use them every day! Also useful is using Add-Member to add your property to the existing object, or a creating new custom object.

    1. Jeffery Hicks says:
      March 16, 2016 at 8:50 am

      Sure. There are many ways you could apply these ideas. The primary takeaway is for people to think about working with objects in PowerShell and not text. Once you get that in your head there are many roads you can take.

  2. TacoTacoTaco says:
    April 1, 2016 at 1:17 pm

    When you run Get-CimInstance does the connection open then close right away or does it stay open for a little bit extra? Wouldn’t it be better to call New-CimSession then use that session with Get-CimInstance?

    1. Jeffery Hicks says:
      April 1, 2016 at 3:21 pm

      If you are referring to the last code example, yes, I am technically opening a 2nd connection for the nested Get-CimInstance command. The whole thing could probably be revised to use CimSessions, although the main point of the article is about using custom properties. I just happened to use a Cim command for my demonstration.

  3. Adrian says:
    April 21, 2016 at 12:50 pm

    Jeffery, thanks for that great article!
    But, how does that work when I have already a variable containing CIM sessions?
    The following doesn’t work:
    Get-CimInstance -ClassName Win32_PhysicalMemory -CimSession $AllCimSession -PipelineVariable pv |
    Measure-Object -Property capacity -Sum |
    Select @{Name = “Computername”;Expression={$pv.pscomputername}},
    @{Name = “Computer”;Expression = {
    $cs = Get-CimInstance Win32_computersystem -ComputerName $pv.psComputername
    #construct a string with manufacturer and model
    “$($cs.Manufacturer):$($cs.Model)”
    }},
    @{Name = “MemoryGB”;Expression = {$_.sum/1GB}},
    @{Name=”NumberSticks”;Expression = {$_.Count}}

    1. Jeffery Hicks says:
      April 21, 2016 at 12:56 pm

      It doesn’t. This example doesn’t take existing sessions into account. I just happened to use this command to illustrate my point about custom properties.

Comments are closed.

reports

Powered by Buttondown.

Join me on Mastodon

The PowerShell Practice Primer
Learn PowerShell in a Month of Lunches Fourth edition


Get More PowerShell Books

Other Online Content

github



PluralSightAuthor

Active Directory ADSI Automation Backup Books CIM CLI conferences console Friday Fun FridayFun Function functions Get-WMIObject GitHub hashtable HTML Hyper-V Iron Scripter ISE Measure-Object module modules MrRoboto new-object objects Out-Gridview Pipeline PowerShell PowerShell ISE Profile prompt Registry Regular Expressions remoting SAPIEN ScriptBlock Scripting Techmentor Training VBScript WMI WPF Write-Host xml

©2025 The Lonely Administrator | Powered by SuperbThemes!
%d