Hey, Scripting Guy! Your article on accessing performance counters was pretty cool, but it did not really tell me anything. For example, I am interested in getting the same kind of information in Windows PowerShell that I can get in Performance Monitor (PerfMon). Is this possible?
— KB
Hello KB,
Microsoft Scripting Guy Ed Wilson here. I am still convalescing in Murrells Inlet, South Carolina. The Scripting Wife is an absolute genius sometimes, and this was definitely one of her better ideas. The beach, the sand, the cool ocean breeze, and the marshlands are all soothing to the mind. This morning, I am up early with my Thermos of tea, my camera, and my laptop as I head out into the marshlands that form an important part of the Murrells Inlet ecosystem. From my vantage point, I can see a long-legged bird as he stands on a float of sea grass. His reflection on the water adds an abstract quality to the picture I snapped.
Using the Windows PowerShell 2.0 Get-Counter cmdlet, you can retrieve the paths to each of the processor information performance counters, and retrieve three samples of the data. The command to do this is shown here:
(Get-Counter -ListSet ‘processor information’).paths | Get-Counter -MaxSamples 3
The results of running the above command are shown in the following image.
If you wish to wait a certain interval between samples, you can specify the -SampleInterval in seconds:
(Get-Counter -ListSet ‘processor information’).paths | Get-Counter -MaxSamples 5 -SampleInterval 2
Of course, displaying performance counter data on the Windows PowerShell console every two seconds is not much better than watching the performance monitor line scroll across the screen in PerfMon. To really begin to perform any kind of analysis of the data, you need to store the data. The easiest way to do this is to simply store the results in a variable. This is shown here:
$a = (Get-Counter -ListSet ‘processor information’).paths | Get-Counter -MaxSamples 5 -SampleInterval 2
As seen in the following image, the $a variable contains all of the performance counter information that was previously scrolling across the screen.
If we use the Get-Member cmdlet (gm is the alias for the Get-Member cmdlet), we can see that the $a variable contains a PerformanceCounterSampleSet object. The members of the PerformanceCounterSampleSet object are seen here:
PS C:> $a | gm
TypeName: Microsoft.PowerShell.Commands.GetCounter.PerformanceCounterSampleSet
Name MemberType Definition
—- ———- ———-
Equals Method bool Equals(System.Object obj)
GetHashCode Method int GetHashCode()
GetType Method type GetType()
ToString Method string ToString()
CounterSamples Prope
rty Microsoft.PowerShell.Commands.GetCounter.PerformanceCounterSample[] CounterSamples {ge…
Timestamp Property System.DateTime Timestamp {get;set;}
Readings ScriptProperty System.Object Readings {get=$strPaths = “”…
PS C:>
Because the PerformanceCounterSampleSet object is a collection, it is possible to index directly into a single instance of the readings. To do this, use the same technique you would use with an array, as shown in the following image.
The countersamples property returns an instance of the PerformanceCounterSample object, as shown here:
PS C:> $a[0].countersamples | gm
TypeName: Microsoft.PowerShell.Commands.GetCounter.PerformanceCounterSample
Name MemberType Definition
—- ———- ———-
Equals Method bool Equals(System.Object obj)
GetHashCode Method int GetHashCode()
GetType Method type GetType()
ToString Method string ToString()
CookedValue Property System.Double CookedValue {get;set;}
CounterType Property System.Diagnostics.PerformanceCounterType CounterType {get;set;}
DefaultScale Property System.UInt32 DefaultScale {get;set;}
InstanceName Property System.String InstanceName {get;set;}
MultipleCount Property System.UInt32 MultipleCount {get;set;}
Path Property System.String Path {get;set;}
RawValue Property System.UInt64 RawValue {get;set;}
SecondValue Property System.UInt64 SecondValue {get;set;}
Status Property System.UInt32 Status {get;set;}
TimeBase Property System.UInt64 TimeBase {get;set;}
Timestamp Property System.DateTime Timestamp {get;set;}
Timestamp100NSec Property System.UInt64 Timestamp100NSec {get;set;}
PS C:>
The more interesting properties are the path to the counter, the instance name, and the CookedValue. A table displaying this truncated information is shown here (ft is an alias for the Format-Table cmdlet, and wildcards characters are used to reduce the typing requirements for the property names):
PS C:> $a[0].countersamples | ft *path, *instance*, *cook* -AutoSize
Path InstanceName CookedValue
—- ———— ———–
\mred1processor information(_total)processor state flags _total 0
\mred1processor information(0,_total)processor state flags 0,_total 0
\mred1processor information(0,3)processor state flags 0,3
0
\mred1processor information(0,2)processor state flags 0,2 0
\mred1processor information(0,1)processor state flags 0,1 0
\mred1processor information(0,0)processor state flags 0,0 0
\mred1processor information(_total)% of maximum frequency _total 0
\mred1processor information(0,_total)% of maximum frequency 0,_total 0
\mred1processor information(0,3)% of maximum frequency 0,3 0
\mred1processor information(0,2)% of maximum frequency 0,2 0
\mred1processor information(0,1)% of maximum frequency 0,1 0
\mred1processor information(0,0)% of maximum frequency 0,0 0
You can also use the Where-Object cmdlet to filter out counter samples before displaying them in the table. The question mark (?) is an alias for the Where-Object cmdlet and ft is an alias for the Format-Table cmdlet:
PS C:> $a[0].countersamples | ? { $_.cookedvalue -gt 100 } | ft -AutoSize
Path InstanceName CookedValue
—- ———— ———–
\mred1processor information(_total)c1 transitions/sec _total 7180.4703476188
\mred1processor information(0,_total)c1 transitions/sec 0,_total 7180.4703476188
\mred1processor information(0,3)c1 transitions/sec 0,3 1922.74322394713
\mred1processor information(0,2)c1 transitions/sec 0,2 2039.01604283622
\mred1processor information(0,1)c1 transitions/sec 0,1 2147.80348711872
\mred1processor information(0,0)c1 transitions/sec 0,0 1070.90759371672
\mred1processor information(_total)dpcs queued/sec _total 176.155815741847
\mred1processor information(0,_total)dpcs queued/sec 0,_total 176.155815741847
\mred1processor information(_total)interrupts/sec _total 2074.94584094787
\mred1processor information(0,_total)interrupts/sec 0,_total 2074.94584094787
\mred1processor information(0,3)interrupts/sec 0,3 441.138076815277
\mred1processor information(0,2)interrupts/sec 0,2 540.444046596091
\mred1processor information(0,1)interrupts/sec 0,1 535.952821832135
\mred1processor information(0,0)interrupts/sec 0,0 557.410895704371
PS C:>
Because the $a variable contains a collection of performance data, you might be interested in walking through the collection of sample data, and then looking for a cookedvalue that is greater than 3000. When you obtain the inf ormation, you might like to stick with the table output. The percentage sign (%) is an alias for the ForEach-Object Windows PowerShell cmdlet. The question mark (?) is an alias for the Where-Object cmdlet. The –gt is the operator that means greater than and the $_ character is the symbol that refers to the current object on the pipeline. And ft is an alias for the Format-Table cmdlet. The complete one-line command is shown here along with the complete data that was retrieved from my computer:
PS C:> $a | % { $_.countersamples | ? {$_.cookedvalue -gt 3000} } | ft -auto
Path InstanceName CookedValue
—- ———— ———–
\mred1processor information(_total)c1 transitions/sec _total 7180.4703476188
\mred1processor information(0,_total)c1 transitions/sec 0,_total 7180.4703476188
\mred1processor information(_total)c1 transitions/sec _total 7135.11877036386
\mred1processor information(0,_total)c1 transitions/sec 0,_total 7135.11877036386
\mred1processor information(_total)c1 transitions/sec _total 7042.68233293539
\mred1processor information(0,_total)c1 transitions/sec 0,_total 7042.68233293539
\mred1processor information(_total)c1 transitions/sec _total 7256.44182560112
\mred1processor information(0,_total)c1 transitions/sec 0,_total 7256.44182560112
\mred1processor information(_total)c1 transitions/sec _total 7145.0786818399
\mred1processor information(0,_total)c1 transitions/sec 0,_total 7145.0786818399
PS C:>
Because we are using standard Windows PowerShell cmdlets to process the performance information, we can also use the Sort-Object cmdlet to sort the data for us into a more readable output. The revised command that produces sorted information is shown here (note that sort is an alias for the Sort-Object cmdlet):
PS C:> $a | % { $_.countersamples | ? {$_.cookedvalue -gt 3000} } | sort cookedvalue | ft -auto
Path InstanceName CookedValue
—- ———— ———–
\mred1processor information(0,_total)c1 transitions/sec 0,_total 7042.68233293539
\mred1processor information(_total)c1 transitions/sec _total 7042.68233293539
\mred1processor information(0,_total)c1 transitions/sec 0,_total 7135.11877036386
\mred1processor information(_total)c1 transitions/sec _total 7135.11877036386
\mred1processor information(_total)c1 transitions/sec _total 7145.0786818399
\mred1processor information(0,_total)c1 transitions/sec 0,_total 7145.0786818399
\mred1processor information(0,_total)c1 transitions/sec 0,_total 7180.4703476188
\mred1processor information(_total)c1 transitions/sec _total
0 comments