Hey, Scripting Guy! How Can I Use Windows PowerShell to Retrieve Information About Computer Hardware?

Hey, Scripting Guy! How Can I Use Windows PowerShell to Retrieve Information About Computer Hardware?

  • Comments 1
  • Likes

 

Bookmark and Share

 

Hey, Scripting Guy! Question

Hey, Scripting Guy! I need to use Windows PowerShell to retrieve information about my computer hardware. Specifically I am interested in the make, the model, and the speed of my CPU by using a script. Can this be done?

-- DH

 

Hey, Scripting Guy! AnswerHello DH,

Microsoft Scripting Guy Ed Wilson here. The 2010 Scripting Games had an event that was similar to your requirements. In fact, we recently published the expert commentator solutions for Beginner Event 5 of the 2010 Scripting Games. These solutions include both a VBScript solution and a Windows PowerShell solution. In addition to these resources, you may wish to see the Scripting Wife’s article about Beginner Event 5.

The BEG5_DaleHarris.ps1 script will retrieve CPU information by using Windows Management Instrumentation (WMI). This script works against a local computer as well as against a remote computer (assuming the necessary rights and firewall configuration). It is a pretty cool and useful script, but there are a few areas that can be improved.

The script uses the Write-Host cmdlet to display a welcome message. This is shown here:

Write-Host "Welcome to the 5th Powershell Scripting Games Event for Beginners" `
-foregroundcolor Yellow

Yellow text displays really well if the background is blue. But as seen in the following image, it is nearly invisible when displayed in the Windows PowerShell ISE.

Image of yellow text in the Windows PowerShell ISE

Beginner Event 7 of the 2010 Scripting Games added the requirement to detect if a script was running in the Windows PowerShell ISE. You can easily detect if a script is running in the Windows PowerShell ISE by using a line of code such as this one that examines the name of the host:

If ($Host.Name -match 'ise')
{ "This script must run in the console" ; exit }

Normally, if I want to receive input from a user, I use the Param statement and allow the user to supply the value from the command line. The problem with this approach is that the Windows PowerShell ISE does not have a provision for supplying command-line parameters for a script that is open in the editing pane. Therefore, I generally add a value for the variable to allow me to run and edit the script in the ISE. The other thing that can be done is to use the execution pane, type the full path to the script, and run it from there, which is a bit annoying.

Using the Read-Host cmdlet, the problem of supplying command-line input is avoided because a prompt is generated in the Windows PowerShell console. The dialog box shown in the following image appears when the script is run in the Windows PowerShell ISE.

Image of dialog box shown when script is run in Windows PowerShell ISE

Because the script uses Read-Host to populate the $strComputerName variable that is used with the WMI code, a check is made to see if the user presses ENTER to skip past the prompt. It assigns the localhost to the $strComputerName variable if this happens. The code is shown here:

if ($strComputerName -eq ""){$strComputerName = "."}

The script uses a Try/Catch/Finally syntax to catch any errors that may be generated by the code. Error-handling techniques for Windows PowerShell are discussed in the Getting Started series of Hey, Scripting Guy! posts. The problem with this approach is that it does not work really well. If I type a class name that does not exist, the script returns a line that says my computer cannot be contacted.

If reachability is the primary reason for using the Try/Catch/Finally construction, it should be replaced by a simple Test-Connection command. The Test-Connection command is shown here:

If (Test-Connection -ComputerName $StrComputerName)
{ put your code here }

If you do not want to see errors if the remote computer is unavailable, specify the errorAction of silentlycontinue. There is an alias for the errorAction (EA) that can be used to make the command a bit more compact. In addition, if you are concerned about the speed of the test, change the count to 1 to cause the cmdlet to send one ping. This is required because by default Test-Connection will send four pings. The revised command is shown here:

If (Test-Connection -ComputerName $StrComputerName -ea silentlycontinue -Count 1)
{ put your code here }

We are using the Test-Connection cmdlet as if it were returning a Boolean value, and are suppressing the errors that are produced. This is exactly what the –quiet switch does. We can thus make an additional change and simplify the code one more time. This is shown here:

If (Test-Connection -ComputerName $StrComputerName -Quiet -Count 1)
{ Put your code here }

The reason the Try/Catch/Finally construction was not working in the BEG5_DaleHarris.ps1 has to do with the error action that was specified for the Get-WmiObject cmdlet. It needs to be changed from SilentlyContinue to Stop. This will force the error to be raised, and allow the code to enter the Try/Catch/Finally error handler. This allows the code to be cleaned up quite a bit. The Test-Connection cmdlet will detect if the target computer is unavailable. The Try/Catch/Finally construction will catch any other error. Keep in mind you can have multiple Catch blocks and different handlers for specific types of errors. The revised code is shown here:

If (Test-Connection -ComputerName $StrComputerName -Quiet -Count 1)
{
Try {
$ComputerInfo = gwmi win32_procesor -computername $strComputerName `
-EA stop
$ComputerName = $ComputerInfo.SystemName
$ClockSpeed = $ComputerInfo.MaxClockspeed
$Manufacturer = $ComputerInfo.Manufacturer
"The CPU Speed on $Hostname is $ClockSpeed. The maker is $Manufacturer"
} #end try
Catch [system.exception]
{ "an error occurred" }
Finally{Write-Host "Thanks for trying out this script!"}
} #end if
Else { "Unable to contact $strComputerName" }

The complete BEG5_DaleHarris.ps1 script is shown here.

BEG5_DaleHarris.ps1

#Script to gather information regarding CPU on local or remote computer
#
#3MAY2010
#By Dale Harris
#Soldier currently deployed to Iraq with the U.S. Army
#
#
# Scripting Games: PowerShell Beginner: Event 5
#
#
#
#
#Credit given to Steven Murawski
#http://stackoverflow.com/questions/1142211/try-catch-does-not-seem-to-have-an-effect
#For finding the workaround with Try/Catch/Finally not working on GWMI
#Thanks
#
# HSG-06-04-10
#
# -----------------------------------------------------------------------------
Write-Host "Welcome to the 5th Windows Powershell Scripting Games Event for Beginners" `
-foregroundcolor Yellow
#Input from user required to see if they are doing a remote lookup
$strComputerName = Read-Host "Enter the computer name or IP you are going to
be searching <Hit Enter if Local>"
if ($strComputerName -eq ""){$strComputerName = "."}
Try {
$ComputerInfo = gwmi win32_processor -computername $strComputerName `
-EA SilentlyContinue
if ($?)
{
$ComputerName = $ComputerInfo.SystemName
$ClockSpeed = $ComputerInfo.MaxClockspeed
$Manufacturer = $ComputerInfo.Manufacturer
"The CPU Speed on $Hostname is $ClockSpeed. The maker is $Manufacturer"
}
Else
{
Write-Host "I'm sorry, but your computer cannot be contacted" `
-foregroundcolor Red
} #end if
} #end try
Catch{}
Finally{Write-Host "Thanks for trying out this script!"}

DH, that is all there is to using WMI to detect processor information. Tomorrow, we will have the Weekend Scripter. The 2010 Scripting Games Wrap-Up posts will continue next week.

 

If you want to know exactly what we will be looking at tomorrow, follow us on Twitter or Facebook. If you have any questions, send e-mail to us at scripter@microsoft.com or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

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
  • If a host is not responding to ping, the test-connection -Count 1 -Quiet cmdlet takes 2.4sec to return false.

    If you have to ping 254 hosts and a 100 of them are off-line that's 240 seconds wasted.

    Should it work faster if all 254 test-connection were started as jobs at (almost)the same time?

    Is there a limit on how many jobs can run on a system?

    1..254 | ForEach-Object -Process {

    Start-job -inputobject $_ {$ip = "192.168.5." + $input; if(Test-Connection $ip -Count 1 -Quiet) {$ip}}

    } -End {

    Wait-Job *

    Receive-Job *}

    - GK -