Performance counters are a useful way to track server performance metrics and monitor resource usage. Back in the day, I used to use the perfmon* utility. This allowed me to tap into the performance counters in Windows and display all kinds of metrics and data. Nowadays, though, I turn to PowerShell.

One way to investigate performance issues of a Window Server is to fire up resource monitor. This is a handy tool to investigate CPU, memory, disk, and network activity, but it's not convenient when you need to work with many servers at once.

Using PowerShell to read performance counters lets us not only query many servers at once but also build scripts and automation around the data the performance counters return.

The way to read performance counters in PowerShell is to use the Get-Counter cmdlet. This cmdlet lets us query performance counters both locally and remotely.

By default, Get-Counter returns a summary of information. It queries a few default monitors and returns the results. It does a single poll.

Performance counter summary

Performance counter summary

The cmdlet groups performance counters into sets. We can investigate what sets are available by running Get-Counter -ListSet * as shown below. This returns all sets available on your machine. The sets you see will be different depending on whether you have SQL installed, Hyper-V, Exchange, and so on. Many different products add their own performance counters.

Viewing all counter sets

Viewing all counter sets

Let's say we need to find some information about processes. I can narrow down this list by defining Process for the ListSet value and running Get-Counter -ListSet Process.

Process ListSet

Process ListSet

Let's assign a variable to this counter set and then check out the Counter property, which lists all individual counters part of this set.

$set = Get-Counter -ListSet Process
Counters in process counter set

Counters in process counter set

Now that I know all the counter names, I can pass one of these directly to Get-Counter. The counters above match to all processes. I can replace that asterisk with the process name to narrow it down to one particular process. Notice below I'm also telling Get-Counter to query the counter five times.

Get-Counter -Counter '\Process(*vmms)\% Processor Time' -MaxSamples 5

One common task when querying performance counters is to export the results to a file like a .csv file. Perhaps this code to check the vmms process is part of some larger script. I only need to pull out the % processor time values for each sample. I can do this by referencing the CounterSamples property. In each of those properties, I'll find the CookedValue property, which contains the actual value as shown below.

Get-Counter -Counter '\Process(*vmms)\% Processor Time' -MaxSamples 5 | ForEach-Object {
    $_.CounterSamples | ForEach-Object {
            Time = $_.TimeStamp
            Path = $_.Path
            Value = $_.CookedValue
} | Export-Csv -Path 'vmmsproctime.csv' -NoTypeInformation

Another handy parameter of the Get-Counter cmdlet is the Continuous parameter. By default, Get-Counter will only take one sample or, as I've done above with the MaxSamples parameter, a predefined number of samples. Using the Continuous parameter allows us to grab samples continually.

The Continuous parameter is great for when you're troubleshooting a particular machine and want to see what values a performance counter returns in real time. Using the Continuous parameter forces Get-Counter to perform one query per second and run indefinitely. To cancel this command, you'll need to use Ctrl-C much like for a continuous ping when troubleshooting network connectivity.

Subscribe to 4sysops newsletter!

If you're troubleshooting one or more servers, building performance reports, or would just rather run a quick command instead of pulling up Resource Monitor, querying performance counters with PowerShell is a great way to do it. The Get-Counter cmdlet is a handy PowerShell command that is your gateway to the internals of your Windows system performance.

  1. Manu Gomez 2 years ago

    Get-Counter -Counter ‘\Process(*vmms)\% Private Bytes’ -MaxSamples 5

    Hi guys why is the above command not working?

    • 10 months ago

      Yes you are right, there is a type in the script, it should be “$_.CounterSamples”, not “$_.CounterExamples”

      Reda DZ


Leave a reply

Your email address will not be published. Required fields are marked *


© 4sysops 2006 - 2023


Please ask IT administration questions in the forums. Any other messages are welcome.


Log in with your credentials


Forgot your details?

Create Account