Summary: Learn how to use Windows PowerShell to simplify collecting performance information from your servers.
Hey, Scripting Guy! We are having performance problems with several of our servers. It is really strange, because if you were to look at the specifications, you would think they are awesome boxes. What I need to do is to collect performance counter information on these things, but I would like to be able to use a script because there are several boxes that need to be analyzed. I really need to find the performance bottleneck, because I do not think the servers are underpowered; I think there is something amiss instead. The thing is that my boss wants to add memory because he says, “With Windows you always need more RAM.” However, if he buys a bunch of expensive RAM and it does not solve the problem, he will blame me. Help, the situation is getting serious.
—AC
Hello AC,
Microsoft Scripting Guy, Ed Wilson, here. Back when I was in consulting I used to do a lot of performance testing on servers, and I thought it was a lot of fun. What is cool is when you find evidence of a particular problem and you solve a serious issue. One thing I found out is that people really want to see the evidence before they will make changes—especially changes that cost money. Therefore, in your case, your boss is a little strange in this regard. Oh well. In the past, the solution for automating performance counters was to use the WMI classes. With Windows PowerShell 2.0, the WMI classes are not required, because there are some excellent cmdlets.
One of the problems with automating performance counters is knowing which counter to add. Windows PowerShell solves that problem by allowing you to use counter sets. To see the available performance counter sets, use the Get-Counter cmdlet with the listset parameter. In the following command I list the names of all the counter sets on my Windows 7 laptop.
PS C:\> Get-Counter -ListSet * | Sort-Object CounterSetName | Select-Object CounterSetName
CounterSetName
————–
.NET CLR Data
.NET CLR Networking
.NET CLR Networking 4.0.0.0
.NET Data Provider for Oracle
.NET Data Provider for SqlServer
.NET Memory Cache 4.0
ASP.NET
ASP.NET Applications
ASP.NET Apps v4.0.30319
ASP.NET State Service
ASP.NET v4.0.30319
Authorization Manager Applications
BranchCache
Browser
Cache
Client Side Caching
Distributed Routing Table
Event Tracing for Windows
Event Tracing for Windows Session
Fax Service
Generic IKEv1, AuthIP, and IKEv2
HTTP Service
HTTP Service Request Queues
HTTP Service URL Groups
ICMP
ICMPv6
Internet Information Services Global
IPHTTPS Global
IPHTTPS Session
IPsec AuthIP IPv4
IPsec AuthIP IPv6
IPsec Driver
IPsec IKEv1 IPv4
IPsec IKEv1 IPv6
IPsec IKEv2 IPv4
IPsec IKEv2 IPv6
IPv4
IPv6
Job Object
Job Object Details
LogicalDisk
Memory
MSDTC Bridge 3.0.0.0
MSDTC Bridge 4.0.0.0
NBT Connection
Netlogon
Network Inspection System
Network Interface
Objects
Offline Files
OpsMgr Connector
Pacer Flow
Pacer Pipe
Paging File
Peer Name Resolution Protocol
Per Processor Network Activity Cycles
Per Processor Network Interface Card Activity
PhysicalDisk
Power Meter
Print Queue
Process
Processor
Processor Information
RAS Port
RAS Total
ReadyBoost Cache
Redirector
Search Indexer
Server
Server Work Queues
ServiceModelEndpoint 3.0.0.0
ServiceModelEndpoint 4.0.0.0
ServiceModelOperation 3.0.0.0
ServiceModelOperation 4.0.0.0
ServiceModelService 3.0.0.0
ServiceModelService 4.0.0.0
SMSvcHost 3.0.0.0
SMSvcHost 4.0.0.0
Synchronization
System
TBS counters
TCPv4
TCPv6
Telephony
Teredo Client
Teredo Relay
Teredo Server
Terminal Services
Terminal Services Session
Thread
UDPv4
UDPv6
USB
WF (System.Workflow) 4.0.0.0
WFP
WFPv4
WFPv6
Windows Media Player Metadata
Windows Workflow Foundation
WSMan Quota Statistics
Suppose I am interested in monitoring memory-related performance counters (something that you should probably consider anyway). I need to supply the path to the specific counter to the Get-Counter Windows PowerShell cmdlet in order to monitor the counter. The nice thing is that I do not have to know the path to the counter, nor do I need to type all of those paths. The reason is that I can retrieve the paths from the memory counter set. To do this I use dotted notation and retrieve the paths. Here is the command to do this.
PS C:\> (get-Counter -ListSet memory).paths
\Memory\Page Faults/sec
\Memory\Available Bytes
\Memory\Committed Bytes
\Memory\Commit Limit
\Memory\Write Copies/sec
\Memory\Transition Faults/sec
\Memory\Cache Faults/sec
\Memory\Demand Zero Faults/sec
\Memory\Pages/sec
\Memory\Pages Input/sec
\Memory\Page Reads/sec
\Memory\Pages Output/sec
\Memory\Pool Paged Bytes
\Memory\Pool Nonpaged Bytes
\Memory\Page Writes/sec
\Memory\Pool Paged Allocs
\Memory\Pool Nonpaged Allocs
\Memory\Free System Page Table Entries
\Memory\Cache Bytes
\Memory\Cache Bytes Peak
\Memory\Pool Paged Resident Bytes
\Memory\System Code Total Bytes
\Memory\System Code Resident Bytes
\Memory\System Driver Total Bytes
\Memory\System Driver Resident Bytes
\Memory\System Cache Resident Bytes
\Memory\% Committed Bytes In Use
\Memory\Available KBytes
\Memory\Available MBytes
\Memory\Transition Pages RePurposed/sec
\Memory\Free & Zero Page List Bytes
\Memory\Modified Page List Bytes
\Memory\Standby Cache Reserve Bytes
\Memory\Standby Cache Normal Priority Bytes
\Memory\Standby Cache Core Bytes
So how do I use all these performance counter paths? The first thing I like to do is to store them into a variable, but that is not completely necessary because I can use the counter paths directly as shown here:
Get-Counter -Counter (get-Counter -ListSet memory).paths
The reason for storing the counter paths in a variable is so I can group them later. For now, I store the memory counter paths in a variable named $memory. I then use the Get-Counter cmdlet to retrieve an instance of the performance information for each of the counters in the variable. Truncated output of the process is shown here:
PS C:\> $memory=(get-Counter -ListSet memory).paths
PS C:\> Get-Counter -Counter $memory
Timestamp CounterSamples
——— ————–
1/22/2011 7:43:18 PM \\edwils1\memory\page faults/sec :
0
\\edwils1\memory\available bytes :
2671661056
\\edwils1\memory\committed bytes :
1656578048
<output truncated>
By default, the Get-Counter Windows PowerShell cmdlet retrieves a single instance of each of the counter’s values. I can tell the cmdlet to retrieve multiple samples, and I can specify the interval between performance snapshots. The minimum interval between samples is one second. The maximum number of samples is 9223372036854775807 because MaxSamples is a datatype of int64. Using the MaxValue static property of the int64 class, I found out the maximum value. The code to do this is shown here:
PS C:\> [int64]::MaxValue
9223372036854775807
Of course, if I really want to monitor a counter on a continuous basis, I use the Continuous parameter. When I monitor a set of counters continuously, I use the Control+C keyboard shortcut to halt performance monitor collection and to return to the Windows PowerShell console. The command to do this is shown here:
PS C:\> Get-Counter -Counter $memory -SampleInterval 1 -Continuous
Timestamp CounterSamples
——— ————–
1/22/2011 8:04:04 PM \\edwils1\memory\page faults/sec :
158.768772415052
<truncated>
If I want to parse the data I collect, I store the results into a variable. The command to take five samples at one-second intervals, using the memory performance counters, is shown here (remember that earlier I stored all the memory performance counter paths in the $memory variable):
PS C:\> $counters = Get-Counter -Counter $memory -SampleInterval 1 -MaxSamples 5
After I have the performance values stored in the $counters variable, I can parse the data by using standard Windows PowerShell techniques. The first thing to do is to find out which type of object I have stored in the variable, and to see which properties it exposes. To do this, I use the Get-Member cmdlet in the manner that appears here:
PS C:\> $counters | Get-Member
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 Property Microsoft.PowerShell.Commands.GetCounter.PerformanceCounterSample[…
Timestamp Property System.DateTime Timestamp {get;set;}
Readings ScriptProperty System.Object Readings {get=$strPaths = “”…
This information tells me two things. The first is that I am dealing with a collection of data (I kind of figured that because I took five different readings at one-second intervals). The second thing I see is more significant, and that is that there is a property called CounterSamples, and it is a rich object as indicated by the Microsoft.PowerShell.Commands.GetCounter.PerformanceCounterSample[… property type information. Because I have a collection to deal with, it means that I will need to select an individual performance sample to work with. I can pipe the $Counters variable to the Foreach-Object cmdlet, or I can use the Foreach statement and walk through the data, or I can index into the collection. While I am still exploring, I will index into the collection and explore the CounterSamples property as illustrated here:
PS C:\> $counters[0].CounterSamples | Get-Member
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;}
The information that appears is standard performance counter type of information. The displayed properties bear a strong resemblance to the properties of the WMI performance counter classes. I like the cooked values, the path, and the time stamp. I sort by the path to group my counters together, and then wrap the table in case any paths are too long. The percentage sign (%) is an alias for the Foreach-Object cmdlet, sort is an alias for the Sort-Object cmdlet, and ft is an alias for the Format-Table cmdlet. The command to select the data I am interested in examining appears here.
$counters | % { $_.counterSamples } | sort path | ft timestamp, path, cookedvalue -Wrap –AutoSize
When the previous command runs, the output shown in the following image appears.
AC, that is all there is to getting started with using the Get-Counter Windows PowerShell cmdlet. Performance Week will continue tomorrow when I will talk about additional ways of using the Get-Counter cmdlet.
I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.
Ed Wilson, Microsoft Scripting Guy
0 comments