Petri Newsletter Sign-up
Office 365 Insider

Here at, we get IT — and so can you. Subscribe today to stay informed and knowledgeable regarding the latest on IT.

    See All Petri Newsletters

    PowerShell Problem Solver: Process Performance For All

    Posted on by Jeff Hicks in PowerShell

    We have covered a lot of ground in this series, but we’ll wrap it up today. In the last PowerShell Problem Solver article, we looked at a variety of ways to get a single performance object for a single computer. The goal was to easily present the average processor time and the top five processes consuming the most processor time. As useful as the examples were in the last article, our jobs would be tedious if we had to manage one computer at a time. In this article, I want you think about management at scale with PowerShell. So let’s take our baby steps with a single server and see what it takes to scale.

    Collecting Data

    First, I’ll define a variable for the computers I plan on querying. I’m manually defining a list but you can read in a text file, query Active Directory or import a CSV file.

    As before I’ll be using Get-Counter. I want the same counters I used last time.

    For the sake of demonstration I’m going to collect 30 samples every 2 seconds, which means about one minute of sampling. Naturally you can decide how much sampling you need to get the values you want.

    Once this is complete, I need to filter out the counters I don’t want. This is the same command I used in the last article.

    But now things change a little. My data includes counters from multiple computers. Each computername is in the Path property. I know that eventually I will need to create objects for each computer, which means I’ll need to group all of the countersamples per computer. I’ll use a scriptblock with Group-Object.

    Performance counters grouped by computername (Image Credit: Jeff Hicks)
    Performance counters grouped by computername (Image Credit: Jeff Hicks)

    Now for the tricky part.

    Processing the Data

    I need to go through each server in $computergroup and create a custom object for each one. To make it easier to understand, I’ll use the ForEach enumerator.

    Since I know I will be using New-Object, I’ll build a hashtable for each server beginning with the computer name.

    Next I need to get the average processor time and add it to the hash table.

    I am using the Round() method from the Math class to trim the value to four decimal places.

    I now need to get process counter data.

    With this, I can get the top five processes using the most CPU time.

    At this point, you have to make a decision. How do you want to display the nested process information? I decided to use my technique of defining a property name with an incremental counter.

    Finally, I can turn the hashtable into an object and write it to the pipeline.

    As an alternative, you could also use the [pscustomobject] type accelerator.

    Here is the complete final step.

    An important note about using the ForEach enumerator is that it doesn’t write objects to the pipeline in the way that ForEach-Object does. By that I mean you can’t pipe anything after the closing curly brace ( } ). That’s why for my demonstration I’m assigning the results to a variable $results. But this is completely optional. I’m doing it so I can show you different ways to use the results.

    Performance results for multiple servers (Image Credit: Jeff Hicks)
    Performance results for multiple servers (Image Credit: Jeff Hicks)

    If you recall, I stressed the importance of writing one type of object to the pipeline. This is so that I can run expressions like this:

    Formatted performance results (Image Credit: Jeff Hicks)
    Formatted performance results (Image Credit: Jeff Hicks)

    Or I can break things down.

    A performance counter breakdown (Image Credit: Jeff Hicks)
    A performance counter breakdown (Image Credit: Jeff Hicks)

    I can even filter for a specific computer.

    Filtering for a specific server (Image Credit: Jeff Hicks)
    Filtering for a specific server (Image Credit: Jeff Hicks)

    I have stepped through the process, but you can take it to the next step and create a script or function. In fact, there are several items that come immediately to mind that you could also incorporate into the output:

    • the sampling date
    • number of samples
    • sampling interval
    • the number of physical processors
    • the number of processor cores
    • the computer operating system

    As long as you think about objects in the pipeline, there’s no limit to what you can come up with Windows PowerShell.


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