In a previous article, we began exploring techniques for gathering average processor load numbers. I demonstrated how to use WMI and PowerShell to query the Win32_Processor class. The scenario we are using is a real-world problem that someone posted in a PowerShell forum. Although you might not have this specific problem, I think you might learn a few things along the way.
PowerShell Processor Article Series:
Performance counter data can be accessed through WMI. This type of data if presented in both raw and formatted forms. Personally, I prefer the latter. Let’s find an appropriate class:
I've highlighted the most likely class. I can query it like any other WMI class.
If you try that, then you'll get multiple instances for each processor core as well as a _Total instance. You can simplify the output once you know what to look for:
Because I am interested in an average across all cores, I can filter out the _Total instance and average the rest much as I did in the previous article.
Now that I have the basic concept and syntax worked out, let's scale out to manage a list of computers.
In this example, I'm trying something new. The results of the Get-WmiObject command are piped to Group-Object. This will write a new object to the pipeline. The Name property will be the computername, i.e. PSComputername, because that is what I instructed PowerShell to use for the grouping. The Group property will be the collection of instances. I'm creating a custom property on the fly called Avg%ProcessorTime, which takes the PercentProcessorTime value for each instance in the group and calculates an average.
Using PowerShell's Get-Counter cmdletThe other approach is to get actual performance counter information. Fortunately, PowerShell has a cmdlet that makes this pretty easy called Get-Counter. You can use this cmdlet to access all of the performance counters you would use through the PerfMon management console. The first step is to identify the relevant counters.
We can drill down and get just the list of counters.
Some counters exist for multiple instances as they do with the processor. If you look at the PathsWithInstances property, you'll see a counter for every processor instance.
I am pointing all of this out because you need to specify the counter.
With me so far? For our scenario, I think all I need is the counter for _Total. The Get-Counter cmdlet displays results in an easy-to-read fashion, but not very pipeline friendly for my tastes. I think it helps to see the raw data.
Once you understand this, you can build an expression to display only what you need:
If you read the help for Get-Counter, which you should, you'll see that you can get a number of samples. This might give us a better overall average.
This expression takes a sample every five seconds for about a minute. Do you see where I'm going? We can take these results and average the underlying CookedValue property.
The last step then is to scale this out for multiple servers. One thing to note is that when querying multiple servers the computer name is part of the counter sample. The expression I'm using is a one-line expression, although you could easily break it down into multiple steps.
The first line is getting the processor counter for all the computers in my $computers variable, taking 12 samples over five second intervals. The second line expands the CounterSamples property and groups the results on the Path property. The end result is that all the results will be grouped by computername. On the third line I'm using Select-Object to create a few custom properties. The first is the computer name, which I am pulling out of the Name property, which is really the counter path. The last line creates another value for the average which is calculated by Measure-Object. Once you have your sampling requirements figured out, this would make a good function or script to save yourself a lot of typing. We've looked at a number of techniques for getting an average processor load or utilization, but the original problem had a second requirement, which we'll look at next time.