Summary: Learn how to get the number of processor cores via WMI and Windows PowerShell.
Hey, 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
Hello 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.
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.
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