Hey, Scripting Guy! Question

I would like to determine the average processor utilization for my computer over a certain period of time. If I could run this remotely, it would be even better. Can this be done?

- MP

SpacerHey, Scripting Guy! Answer

Hi MP,

We can certainly do this. In fact, it can be done both locally and remotely. But you do need to be careful of the Heisenberg uncertainty principle.

There are a couple of ways we can query for performance information. We can use the Get-WmiObject cmdlet, which is very easy to use and understand. We can also use the System.Management.Management .NET Framework class directly. This is perhaps a bit easier to do than it might seem because of the existence of the [WMI] type accelerator. Before choosing our approach, let's examine each potential solution to see which code is the best to use.

For our test, let's obtain the total processor utilization time for the first CPU in our machine. Let's print this value out ten times. This command is one logical command and uses the line continuation character at the end of the first line to allow for multiline entry. This command uses the [WMI] type accelerator. The command begins by using a for statement that begins counting at 1, continues until the value of $i is less than or equal to 10, and increments the value of $i by one. The code block, which is demarked by the curly brackets, uses the [WMI] type accelerator to return a specific instance of the Win32_PerfFormattedData_PerfOS_Processor WMI class. These instances are seen in the WbemTest tool when you choose the instances button from the class page:

Image of instances of the Win32_PerfFormattedData_PerfOS_Processor WMI class

 

You will notice that each instance is referenced by the name of the class, the name property, and then a value for the name property. The name property is the key property for the Win32_PerfFormattedData_PerfOS_Processor WMI class. When you are using the [WMI] type accelerator, you always need to give it a value for the key property of the class. This process of using the [WMI] type accelerator to connect to a specific instance of a class is similar to the VBScript Get method. The Get method of the sWbemServices object is talked about on this page. After we have the specific instance of the Win32_PerfFormattedData_PerfOS_Processor WMI class, we can return the percentProcessorTime property value:

for($i = 1 ; $i -le 10 ; $i++) `
{ 
 ([wmi]"Win32_PerfFormattedData_PerfOS_Processor.name='0'").percentProcessorTime
}

When it is run, it prints out the current processor utilization 10 different times.

If you were to use Get-WmiObject , the code would be very similar in concept. The Get-WmiObject cmdlet takes the –class parameter, which allows it to query a specific WMI class. This is similar to using the ExecQuery method from the sWbemServices object. The ExecQuery method is documented here. To keep the cmdlet from returning information from all the processors, the –filter parameter is used to limit the amount of information that is returned. This is similar to using a where clause in a VBScript WMI query. Because only one instance of the class is returned, we can also use the dotted notation to retrieve a specific property from the object. This code is shown here:

for($i = 1 ; $i -le 10 ; $i++) `
{ 
 (Get-WmiObject -class Win32_PerfFormattedData_PerfOS_Processor –filter "name='0'").percentProcessorTime 
}

If we use the measure-command cmdlet to see if one approach is faster than the other, we would see that both commands take approximately five seconds to execute. There is no appreciable difference in the performance of the two commands. So the choice is the syntax with which you are the most familiar.

So here it is, the GetWmiPerformanceData.ps1 script.

Function GetWmiPerformanceData()
{
 For($i = 1 ; $i -le $reps ; $i++)
  {
   ([wmi]"\\$computer\root\cimv2:$class.$key='$instance'").$Property
   Start-Sleep -Seconds $delay
  } #end for
}#end GetWmiPerformanceData

$computer = "vista"
$delay = 1
$reps = 2
$class = "Win32_PerfFormattedData_PerfOS_Processor"
$key = "name"
$instance = "_Total"
$property = "PercentProcessorTime"

GetWmiPerformanceData

The GetWmiPerformanceData.ps1 script begins by declaring a function that is named GetWmiPerformanceData. This function is used to query the WMI class a certain number of times, and to return a specific property from a specific instance on a specific computer. The cool thing about the function is that everything is abstracted. This follows the prime directive for scripting which means do not mess with the worker section of the script. The four parts of a script are detailed in the Microsoft VBScript Step by Step book. The for statement begins with the value of $i equal to 1, and continues until it is less than or equal the value set in the variable $reps. It is incremented by one on each loop. This is seen here:

For($i = 1 ; $i -le $reps ; $i++)

Inside the code block, the [WMI] type accelerator is used to connect to the root\cimv2 WMI namespace on the computer that is specified in the $computer variable. The WMI class that will be queried is stored in the $class variable and the key property name is in the $key variable. The particular instance to return is defined in the $instance variable, and the property we are interested in is stored in the $property variable. Although this particular syntax is a bit complicated, the fact that it is stored in a function with everything abstracted into a variable means it can be used over again without requiring any changes. This line of code is shown here:

([wmi]"\\$computer\root\cimv2:$class.$key='$instance'").$Property

Because you might want to pause the script between polling cycles, the start-sleep cmdlet is used to halt script execution. The specified time is supplied in seconds, although milliseconds could have been used. This line of code is shown here:

Start-Sleep -Seconds $delay

The bulk of the script is supplying values for the variables. The computer variable holds the name of the computer to query. This could be a local or a remote computer. The $delay variable controls the time between polling, and the $reps variable controls how many times the script will poll. The $class variable holds a WMI performance counter class, and the $key variable holds the key property for the class. Note that this script will not work on a WMI class that contains a composite key (more than one key property). The $instance variable is used to supply the name of the particular instance to query. This is seen is seen here:

$computer = "vista"
$delay = 1
$reps = 2
$class = "Win32_PerfFormattedData_PerfOS_Processor"
$key = "name"
$instance = "_Total"
$property = "PercentProcessorTime"

Once all the variables have been supplied values, the last thing to do is to actually call the function. This is easily done by simply placing the function name on a line by itself as seen here:

GetWmiPerformanceData

When we run the script, the results are not all that impressive. It is just a list of numbers displayed on the console.

MP, this should move you closer to using the WMI performance counter classes. Tomorrow, we will see what we can do about processing the numbers that are written to the screen. See ya!

Ed Wilson and Craig Liebendorfer, Scripting Guys