Use PowerShell and WMI to Get Processor Information

Use PowerShell and WMI to Get Processor Information

  • Comments 9
  • Likes

Summary: Learn how to get the number of processor cores via WMI and Windows PowerShell.

Hey, Scripting Guy! QuestionHey, Scripting Guy! I need to perform an audit of computers on our network. Specifically, I am tasked with obtaining CPU information. I need the processor speed, number of cores, and number of logical processors. I feel like I should be able to use Windows PowerShell to do this, but I am not certain. Can you help?

—RS

 

Hey, Scripting Guy! AnswerHello RS,

Microsoft Scripting Guy Ed Wilson here. This has been a rather crazy time. This week I am in Seattle, Washington, talking to customers about Windows PowerShell. Later in the week, I will be talking to Windows PowerShell writers on campus at our Microsoft Office in Redmond. I fly back to Charlotte, and then I head north to Canada for a couple of weeks. I really enjoy the opportunity to meet with people who are using Windows PowerShell to solve real world problems. It is cool.

RS, to find out information about the CPU, I use the Windows Management Instrumentation (WMI) class Win32_Processor. In Windows PowerShell, a single line of code that uses the Get-WmiObject cmdlet to do the heavy lifting is all that is required. The syntax of a command to query WMI and return CPU information is shown here:

Get-WmiObject Win32_Processor

And I can shorten that command by using the gwmi alias:

gwmi win32_Processor

In the following figure, I illustrate using the Get-WmiObject command and the default output from the command.

Image of using Get-WmiObject and default output

The Win32_Processor WMI class is documented on MSDN, and the article describes what all of the properties and coded values mean. But RS, for your requirements, I do not need that article. What I do need is a good way to select only the information you require. To do this, I am going to choose which properties I need. I then pipe the returned object to the Select-Object cmdlet. The reason for this is to remove the system properties that are automatically included with the returned WMI object. To avoid typing the properties twice (once for the Get-WmiObject cmdlet and once for the Select-Object cmdlet), I store the array of properties in the $property variable. The revised command is shown here:

$property = "systemname","maxclockspeed","addressWidth",

            "numberOfCores", "NumberOfLogicalProcessors"

Get-WmiObject -class win32_processor -Property  $property |

Select-Object -Property $property 

RS, you mentioned wanting to query computers on your network. The easy way to do this is to use the Active Directory cmdlets. I have an entire series of articles that talk about how to get the Active Directory cmdlets, and how to load and use them. You should refer to that series if you have questions about using Active Directory cmdlets.

RS, I wrote a script called GetAdComputersAndWMIinfo.ps1. The complete text of this script appears here.

GetAdComputersAndWMIinfo.ps1

Import-Module ActiveDirectory

$pingConfig = @{

    "count" = 1

    "bufferSize" = 15

    "delay" = 1

    "EA" = 0 }

$computer = $cn = $null

$cred = Get-Credential

 Get-ADComputer -filter * -Credential $cred |

 ForEach-Object {

                 if(Test-Connection -ComputerName $_.dnshostname @pingconfig)

                   { $computer += $_.dnshostname + "`r`n"} }

$computer = $computer -split "`r`n"

$property = "systemname","maxclockspeed","addressWidth",

            "numberOfCores", "NumberOfLogicalProcessors"

foreach($cn in $computer)

{

 if($cn -match $env:COMPUTERNAME)

   {

   Get-WmiObject -class win32_processor -Property  $property |

   Select-Object -Property $property }

 elseif($cn.Length -gt 0)

  {

   Get-WmiObject -class win32_processor -Property $property -cn $cn -cred $cred |

   Select-Object -Property $property } } 

The first thing to do is to import the ActiveDirectory module. In a script, I recommend using the complete name for the ActiveDirectory module, instead of using a wildcard character pattern such as *AD*. This is because there are many modules available for download from the Internet that would match the *AD* pattern. If this is the case, you cannot be certain you have actually loaded the ActiveDirectory module. To load the ActiveDirectory module, use the Import-Module cmdlet as shown here:

Import-Module ActiveDirectory

Next, I intend to use splatting to simplify using the Test-Connection cmdlet. I wrote an article about splatting last week. Splatting uses a hash table for the parameters and associated values. This hash table is shown here:

$pingConfig = @{

    "count" = 1

    "bufferSize" = 15

    "delay" = 1

    "EA" = 0 }

I then initialize a couple of variables. This helps when running the command multiple times inside the Windows PowerShell ISE. I also retrieve credentials via the Get-Credential cmdlet. These two commands are shown here:

$computer = $cn = $null

$cred = Get-Credential

Now, I use the Get-ADComputer cmdlet to retrieve a listing of computers from Active Directory Directory Services. I use the Foreach-Object cmdlet and pass the host names to the Test-Connection cmdlet to ensure the computer is online. I then create an array of computernames and store the names in the $computer variable. This is shown here:

Get-ADComputer -filter * -Credential $cred |

 ForEach-Object {

                 if(Test-Connection -ComputerName $_.dnshostname @pingconfig)

                   { $computer += $_.dnshostname + "`r`n"} }

The array that gets created is an array of single letters. I split the string based on the carriage return and line feed characters “`r`n” and create a new array that contains the name of each computer in an array element. This process leaves an element at the end of the array; this empty element will be dealt with later in the script. Here is the code that creates the new array of ComputerNames:

$computer = $computer -split "`r`n"

I now define an array of property names that are to be collected from WMI. This is a straightforward value assignment:

$property = "systemname","maxclockspeed","addressWidth",

            "numberOfCores", "NumberOfLogicalProcessors"

The online computers are stored in the $computer variable. I use the foreach statement to walk through the array of computer names. If the computer name matches the local computer name, I do not use credentials because WMI would cause the command to fail. In addition, I check to see if the computer name is greater than 0 in length. This takes care of the empty element at the end of the array. This portion of the code is shown here:

foreach($cn in $computer)

{

 if($cn -match $env:COMPUTERNAME)

   {

   Get-WmiObject -class win32_processor -Property  $property |

   Select-Object -Property $property }

 elseif($cn.Length -gt 0)

  {

   Get-WmiObject -class win32_processor -Property $property -cn $cn -cred $cred |

   Select-Object -Property $property } }

When the script runs, output similar to that shown in the following figure is displayed.

 Image of output when script runs

RS, that is all there is to using the Active Directory module to retrieve computer names, and to use WMI to query for the processor information.

 

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

 

 

Your comment has been posted.   Close
Thank you, your comment requires moderation so it may take a while to appear.   Close
Leave a Comment
  • Hey Scripting Guy,

    I have to caution you on this script.  I have been beating my head against the wall for a while on this very issue.  NumberOfLogicalProcessors vs NumberOfCores changes based on the version of WMI that you have installed.   The only reliable way I have found to pull the actual number is either from the BIOS or ILO/DRAC level.  That way you can also pull the stats on servers that do not have WMI installed such and Nix and AS400 boxes.

    Thanks,

    ScriptWarrior

  • @ScriptWarrior Thank you very much for this caution. As with nearly everything, one must test in ones own environment to ensure that script results are what are expected. The version of WMI is now linked to the version of the Operating System, and so your comments are absolutely correct. For example on Windows XP, this information is not returned at all. On my Windows 7 machine, and on my Windows Server 2008 R2 box, the information is correct. I did not test on Windows Vista or Windows Server 2008.

  • Nice script and thanks for providing clarification on ScriptWarriors comment - your follow-up is insightful for use case scenarios. Cheers.

  • @Craig You are welcome. I am glad you like the script.

  • Hi Ed,

    WMI and the AD cmdlets are great!

    And you showed that these two work together well!

    I've got just a simple question regarding the $computer string / array variable:

    Why did you build a string of dns names joined by CR LF chars in:

    ForEach-Object {

     if(Test-Connection -ComputerName $_.dnshostname @pingconfig)

       { $computer += $_.dnshostname + "`r`n"}

    }

    ... if you split it into an array

    $computer = $computer -split "`r`n"

    afterwards?

    Why that complicated?

    We could define an empty string array before we loop over the AD computernames

    and add the dnsnames directly to the array:

    [string[]] $computer=@()

    Get-ADComputer -filter * -Credential $cred |

       ForEach-Object {

           if(Test-Connection -ComputerName $_.dnshostname @pingconfig)

               { $computer += $_.dnshostname }

       }

    Isn't it simpler than joining the string with CR LF chars and splitting them later on?

    Klaus.

  • @Klaus you are absolutely correct. Creating the array ahead of time, and then directly adding the DNSHostname is a much better way of doing things. I just did not think of it at the time I was writing the script. Once I had something that worked, I quit writing the script, and begin writing the article :-)

  • Hi Ed

    I am making use win32_processor class to extract number of cores and numberoflogicalprocessors and I am able to extract for some servers and for some servers I just get a blank screen, why is it so?

  • @ScriptWarrior: you are absolutely right with your comments to find information related to NumberOfLogicalProcessors vs NumberOfCores, I was unable to find this information for 2003 boxes and can get for 2008 boxes but unable to do so with the help of get-wmiobject. Can you suggest any way to get NumberOfLogicalProcessors and NumberOfCores for 2003 boxes?

  • @ScriptAdmin  there was an Intel utility that showed this information. Not certain about other processors.