Hey, Scripting Guy! Can I Query CPU Information with WMI and Windows PowerShell?

Hey, Scripting Guy! Can I Query CPU Information with WMI and Windows PowerShell?

  • Comments 1
  • Likes

 

Hey, Scripting Guy! Question

Hey, Scripting Guy! I am interested in working with WMI and I would like to query for information from the CPU class. Do you have a script that will show me information about my CPU? I am particularly in need of processor speed and memory because we are trying to do an inventory to plan our upgrade.

-- SV

Hey, Scripting Guy! Answer

Hello SV,

Scripting Guy Ed Wilson here. I am glad you wrote asking about processor information. For one thing it brings me inside into my nice air-conditioned office to put together an answer for you. It is over 100 degrees Fahrenheit (37 degrees Celsius) outside today in Charlotte, North Carolina, in the United States. This does not take into account the 45 percent humidity either. It is, in a word, miserable. I was outside when I got your e-mail message on my Windows Mobile 6.5 Smart Phone and decided to rush right in, fire up Microsoft Office Word, and answer your question. On my way upstairs, I stopped long enough to make a fresh pot of Gunpowder green tea and grab an ANZAC biscuit because I figure it will take me a bit of time to prepare you an intelligible and well thought out answer (besides that, with the high heat and heavy humidity, I am in no rush to get back outside). 

This week we will be reviewing some of the scripts that were submitted during the recently held 2009 Summer Scripting Games. The description of the 2009 Summer Scripting Games details all of the events. Each of the events was answered by a globally recognized expert in the field. There were some cool prizes and winners were recognized from around the world. Additionally, just like at the "real Olympics," because there was a lot going on, an "if you get lost page" was created. Communication with participants was maintained via Twitter, Facebook, and a special forum. The special forum has been taken down, but we still use Twitter and Facebook to communicate with Hey, Scripting Guy! fans. We will be focusing on solutions that used Windows PowerShell. We have several good introduction to Windows PowerShell Hey, Scripting Guy! articles that you will find helpful.

SV, as I was thinking about your problem, it dawned on me I wrote a beginner event for the 2009 Summer Scripting Games that required working with the Win32_Processor WMI class. I rummaged around over at PoshCode and found this entry submitted by KShulte for the Beginner Event 2 Long Jump event. KShulte's answer is seen here.

ScriptingGamesBeginnerEvent2.ps1

set-psdebug -strict
# *** Functions are here ***
function WriteWmiInfo2Host
{
    # Parameters:
    # $eventName:     heading/title of the event (e.g. "speed" or "strength")
    # $wmiObject:     no comment :-)
    # $wmiProperties: an array of interesting properties of my $wmiObject
    # $color:         the foregroundcolor to write with
    # $labelWidth:    the size/width of the label field for my output
Param(
            [string] $eventName,
            [System.Management.ManagementObject] $wmiObject,
            [string[]] $wmiProperties = @("__CLASS"),
            [ConsoleColor] $color = "Black",
            [int] $labelWidth = 20
) #end param

    [string] $label = ""
    if ($wmiObject -ne $null) # is there anything to do?
      {
        Write-Host -fore $color $eventName "..."
        foreach ($wmiProperty in $wmiProperties)
        {
            # truncate and/or pad the property name to the specified length
            $label = "{0,-$($labelWidth)}" -f $wmiProperty.trim()
            if ($label.Length -gt $labelWidth) { $label = $label.Substring(0, $labelWidth) }
            $label += ":"
            Write-Host -fore $color $label $(
                if ($wmiObject.$wmiProperty -eq $null) {"n/a"}
                else { $wmiObject.$wmiProperty.ToString().trim() }
            ) # end Write-Host
        } # end foreach $wmiproperty
    } # end if $wmiObject -ne $null
} # end WriteWmiInfo2Host

# *** Entry point to script ***
cls; $wmiInfo = gwmi Win32_Processor
Write-Host -fore "Green" Strength Evaluation for $(gc env:computername)

# *** Call the WriteWmiInfo2Host function THREE times.
WriteWmiInfo2Host "Speed" $wmiInfo MaxClockSpeed, L2CacheSize, L2CacheSpeed, L3CacheSize, L3CacheSpeed Yellow
WriteWmiInfo2Host "Strength" $wmiInfo NumberOfCores, NumberOfLogicalProcessors, Name Cyan
WriteWmiInfo2Host "Agility" $wmiInfo AddressWidth

The first thing that KShulte does is use the Set-PSDebug cmdlet to configure Windows PowerShell to generate an error if a variable is not declared. This is not exactly the same as in VBScript's Option Explicit command because you do not have to declare each variable on its own line by using the New-Variable cmdlet. In fact, as the script is written, it appears that no variables are created "declared." When a variable is assigned a value it is created and declared. The Set-PSDebug cmdlet will detect typos (typographical errors), and it is easier to use than the Option Explicit command from VBScript. This command is seen here:

set-psdebug –strict

Next, KShulte creates the WriteWmiInfo2Host function. The advantage of creating a function is that it allows the code to be used multiple times. Because the function has a number of parameters, each time the code is called it generates different output. Because the function needs to be passed different input when it is called, the function defines a number of parameters (command-line parameters were discussed in How Can I Use a Named Parameter When Running Scripts? These are seen here:

Param(      [string] $eventName,
            [System.Management.ManagementObject] $wmiObject,
            [string[]] $wmiProperties = @("__CLASS"),
            [ConsoleColor] $color = "Black",
            [int] $labelWidth = 20
) #end param

Inside the function, KShulte checks the WMI object that is passed to the WriteWmiInfo2Host function to see if it is null. If it is null, the remaining code is skipped. Otherwise, it moves to the next section. The check to see if the WMI object is null is seen here:

if ($wmiObject -ne $null) # is there anything to do?

It is now time to display the properties and their associated values. The first thing to do is determine the label width, and trim excess whitespace from it. Next, the property value is retrieved, checked for null, and trimmed as well. Trim is a string method, which means it exists on all instances of string classes. The cool thing about trim is that it will remove white space from both the beginning and end of a string.

In the example seen here, the variable $a is assigned a string that has a single space at the beginning of the line and several spaces at the end of the line. The $b variable does not have any spaces at either the beginning of the line or at the end of the line. There is a space in the middle of the line between the two words. The trim method is used from the string that is contained in the $a variable, and the result trimmed string is stored in the variable $c. The value of $a and $c is then displayed on the Windows PowerShell command line. Next, the value of $a and $b is displayed on the command line. You will note that in the first example there was no space between the word value and the word additional. In the second instance where $a and $b are both displayed, there is a space at the beginning of the sentence, and there are several spaces between the word value and the word additional. This is illustrated here:

PS C:\> $a = " string value     "
PS C:\> $b = "additional value"
PS C:\> $c = $a.Trim()
PS C:\> $c + $b
string valueadditional value
PS C:\> $a + $b
 string value     additional value

The foreach section of the function is seen here:

foreach ($wmiProperty in $wmiProperties)
        {
            # truncate and/or pad the property name to the specified length
            $label = "{0,-$($labelWidth)}" -f $wmiProperty.trim()
            if ($label.Length -gt $labelWidth) { $label = $label.Substring(0, $labelWidth) }
            $label += ":"
            Write-Host -fore $color $label $(
                if ($wmiObject.$wmiProperty -eq $null) {"n/a"}
                else { $wmiObject.$wmiProperty.ToString().trim() }
            ) # end Write-Host
        } # end foreach $wmiproperty

The entry point to the script clears the Windows PowerShell console, and queries WMI for the contents of the Win32_Processor class. This is seen here:

cls; $wmiInfo = gwmi Win32_Processor

As mentioned yesterday, I generally try to avoid the use of aliases in Windows PowerShell scripts. The alias cls is a shortcut name for the Clear-Host function, and gwmi is the alias for the Get-WmiObject cmdlet. In addition, I try to always use the parameter names as well. The semicolon is a command separator, or an end-of-line marker. It is used to designate a separate logical command line in Windows PowerShell. It is often used when working at the Windows PowerShell console line to allow you to type different commands on the same command line. Generally, I avoid it when writing a script because it can make the script more difficult to read. The rewritten command would look like the following:

Clear-Host
$wmiinfo = Get-WmiObject –class Win32_Processor

The next command is pretty cool. KShulte uses a partial parameter name for the foregroundcolor parameter. All that is required is that enough of the parameter be present to uniquely identify the parameter. The interesting thing is that the string that is written by the Write-Host does not need to be inside quotation marks. The subexpression is not required either. In fact the quotation marks around the word green for the foregroundcolor are not required. The code gc env:computername is using the alias for the Get-Content cmdlet to read the value of the computername variable from the environmental drive. The Write-Host command is seen here:

Write-Host -fore "Green" Strength Evaluation for $(gc env:computername)

The Write-Host command could also be written as seen here:

Write-Host –foregroundcolor green Strength Evaluation for (Get-Content env:computername)

The WriteWmiInfo2Host function is called three separate times. Each time the function is called, it relies upon the use of positional parameters. When you have several different parameters, I consider it a best practice to use named parameters. The original section is seen here. The revised one will be seen next.

WriteWmiInfo2Host "Speed" $wmiInfo MaxClockSpeed, L2CacheSize, L2CacheSpeed, L3CacheSize, L3CacheSpeed Yellow
WriteWmiInfo2Host "Strength" $wmiInfo NumberOfCores, NumberOfLogicalProcessors, Name Cyan
WriteWmiInfo2Host "Agility" $wmiInfo AddressWidth

Here is the revision using named parameters:

WriteWmiInfo2Host –eventname "Speed" –wmiobject $wmiInfo –wmiproperties MaxClockSpeed, L2CacheSize, L2CacheSpeed, L3CacheSize, L3CacheSpeed –color yellow
WriteWmiInfo2Host –eventname "strength" –wmiobject $wmiInfo –wmiproperties NumberOfCores, NumberOfLogicalProcessors, Name –color cyan
WriteWmiInfo2Host –eventName "Agility –wmiobject $wmiInfo –wmiProperties addressWidth

When the script is run, the following output is produced on my Windows XP computer:

Image of the output of the script


SV, thank you for your question about working with CPU properties, and KShulte, thank you for writing an awesome script for the 2009 Summer Scripting Games. If you want to be the first to know what is happening on the Script Center, follow us on Twitter or Facebook. If you need assistance with a script, you can post questions to the Official Scripting Guys Forum, or send e-mail to scripter@microsoft.com. The 2009 Summer Scripting Games wrap-up will continue tomorrow. Until then, keep cool. 

Ed Wilson and Craig Liebendorfer, Scripting Guys

 

Your comment has been posted.   Close
Thank you, your comment requires moderation so it may take a while to appear.   Close
Leave a Comment
  • WriteWmiInfo2Host : Cannot convert "System.Object[]" to "System.Management.ManagementObject".

    At C:\wps\test.ps1:42 char:48

    + WriteWmiInfo2Host -eventname "Speed" -wmiobject  <<<< $wmiInfo -wmiproperties MaxClockSpeed, L2CacheSize, L2CacheSpee

    d, L3CacheSize, L3CacheSpeed -color yellow

    WriteWmiInfo2Host : Cannot convert "System.Object[]" to "System.Management.ManagementObject".

    At C:\wps\test.ps1:43 char:51

    + WriteWmiInfo2Host -eventname "strength" -wmiobject  <<<< $wmiInfo -wmiproperties NumberOfCores, NumberOfLogicalProces

    sors, Name -color cyan

    WriteWmiInfo2Host : Cannot convert "System.Object[]" to "System.Management.ManagementObject".

    At C:\wps\test.ps1:44 char:50

    + WriteWmiInfo2Host -eventName "Agility" -wmiobject  <<<< $wmiInfo -wmiProperties addressWidth