Lead Image © andresr, fotolia.com

Lead Image © andresr, fotolia.com

Retrieving Windows performance data in PowerShell

Taking Precautions

Article from ADMIN 26/2015
By
The software market offers numerous solutions for tracking the status of Windows computers. However, if you only need to monitor individual computers outside the domain, you can use PowerShell to collect basic health and performance data.

Basic performance data and health status of Windows computers can be collected and evaluated very easily and conveniently using PowerShell. The scripting language is an ideal candidate both for local and remote machines because it is familiar with a variety of interfaces in different Windows subsystems.

The number of interfaces and connection points increases steadily with each new version of a Microsoft product. For example, Windows performance, process, registry, and network information is easily understood using Windows Management Instrumentation (WMI). Data from Windows server roles and from the operating system's advanced configuration do not pose any obstacles, either.

In this article, I show you how to use PowerShell to access WMI and performance data on local or remote computers, how to find relevant WMI objects, and how to look at the performance of individual computers and check for violations of threshold values. The scripts shown here are intended for Windows installations starting from Windows 7 and Windows Server 2008 R2.

Collecting WMI Object Data

Much of the information available via a computer can be accessed or controlled as objects automatically via the WMI interface. The interface publishes information about the computer, the operating system, and objects, which can be queried in the form of classes and attributes. WMI also can control your computer remotely. Some classes implement methods that can be used to shut down the computer or configure operating system components.

WMI is a good candidate for a general inventory of machine properties because of the extensive amount of data provided. Of course, PowerShell provides the necessary tool to collect the data. To access WMI objects, you use the Get-WMIObject cmdlet with the WMI object to be queried as a parameter (Listing 1).

Listing 1

Get-WMIObject Cmdlet

# Get-WMIObject Win32_OperatingSystem
SystemDirectory: C:\Windows\system32
Organization:
BuildNumber:     9600
RegisteredUser:  johndoe@outlook.com
SerialNumber:    00282-30340-00000-AB9A5
Version:         6.3.9600

The information you read from the operating system can also be formatted and customized. For example, normally only the operating system's most important attributes are displayed. If you want to discover its Name attribute, you can explicitly request it using PowerShell (Listing 2).

Listing 2

Getting the Operating System Name

# Get-WMIObject Win32_OperatingSystem | fl Name, BuildNumber, Version
Name:        Microsoft Windows 8.1 Enterprise|C:\Windows|\Device\Harddisk0\Partition4
BuildNumber: 9600
Version:     6.3.9600

The command return value also can be saved in a variable that can be used to address individual attributes specifically, such as the Name and the Caption attribute (Listing 3). The requests issued to WMI previously all ran on the local computer. However, WMI is network-capable, meaning you can also send WMI requests to remote computers. The prerequisite, of course, is that you have the necessary permissions. The ComputerName parameter takes the name of the remote computer (Listing 4).

Listing 3

Saving the Command Return Value

# $os = Get-WMIObject Win32_OperatingSystem
# $os.Name
Microsoft Windows 8.1 Enterprise|C:\Windows|\Device\Harddisk0\Partition4
# $os.Caption
Microsoft Windows 8.1 Enterprise

Listing 4

Sending WMI Request to Remote Computer

# Get-WMIObject Win32_OperatingSystem -ComputerName web-2008R2 | fl Name, BuildNumber, Version
Name:        Microsoft Windows Server 2008 R2 Standard|C:\Windows|\Device\Harddisk0\Partition2
BuildNumber: 7601
Version:     6.1.7601

If you need to specify different logon information because the target computer is not in the same domain or is not a standalone computer, the Credential parameter can get the username and password. The smartest way to do this is to retrieve the logon information in a password mask and use it as a secure character string (Listing 5).

Listing 5

Getting Logon Information

# $c = Get-Credential
# Get-WMIObject Win32_OperatingSystem -ComputerName web-2008R2 -Credential $c | fl Name, BuildNumber, Version
Name:         Microsoft Windows Server 2008 R2 Standard|C:\Windows|\Device\Harddisk0\Partition2
BuildNumber : 7601
Version:      6.1.7601

For those of you who don't like typing, the cmdlet has an alias – a short form – designed to take some typing out of the rather long cmdlet command line: Instead of Get-WMIObject, you can write gwmi.

Failing to set up the WMI configuration on Windows Firewall is a well-known pitfall when querying WMI on remote computers. WMI must be configured for remote queries before the data can be retrieved. If this is not the case, the cmdlet fails and displays the error message RPC server unavailable. A new firewall rule that allows Windows Management Instrumentation (WMI) (Figure 1) provides a remedy. You can enable this firewall exception either manually on the target computers or through Group Policy.

Figure 1: WMI requests require an exception in Windows Firewall.

Finding Relevant WMI Objects

The WMI subsystem in Windows provides information about all hardware and software in more than 600 classes, each with several attributes. Murphy's law thus dictates that you will quickly lose track of, or not be able to find, the right class.

The Microsoft Developer Network [1] is a good place to start. WMI Code Creator [2], a program that Microsoft provides for free, offers further clues as to the available classes and their attributes. The software, which was actually designed for programmers, randomly generates sample code for WMI in the languages C#, Visual Basic, .NET, and Visual Basic Scripting (VBS).

With the drop-down menu, you can create program snippets. It lists all available classes in a pick list sorted by name. If you select a class, the available attributes are displayed (Figure 2). What's more, if you find an interesting attribute, a script can be run on the local computer at the push of a button to display the value of the attribute for the local computer.For example, you can see whether the class found with the attribute combination is correct and whether the attribute contains the correct value in the desired format. Table 1 lists a selection of important WMI classes.

Figure 2: The WMI Code Creator is ideal to search for WMI objects and attributes for scripted queries.

Table 1

Important WMI Classes

WMI Class Description
Win32_ComputerSystem Computer system information, such as name, hardware type, start mode, status of the domain accession.
Win32_DiskDrive Information about the hard disks and their sizes.
Win32_Environment Overview of environment variables.
Win32_FileSpecification Information about data on the filesystem; file information (e.g., size, version number).
Win32_GroupUser Information on local groups and group members.
Win32_LogicalDisk Overview of the logical drives and partitions.
Win32_NTDomain Active Directory domain or workgroup information.
Win32_OperatingSystem CAS proxy information about the Windows operating system (e.g., name, version, service packs, owners).
Win32_NetworkAdapter Information about network cards.
Win32_Product Software repository and installed applications information.
Win32_UserAccount Query local user accounts.
Win32_Volume Find volume data.

Assembling Complex Queries

The selection in Table 1 provides valuable information about individual data from target computers. Automatic querying of these items is demonstrated in a small script named get-serverinfos.ps1 (Listing 6).

Listing 6

get-serverinfos.ps1

01 ##Load server list. A text file containing one server name per line.
02 $serverList = Get-Content -Path C:\temp\server.txt
03 $logfile = "C:\temp\logfile.txt"
04 Add-Content $logfile -value "..................................................."
05 Add-Content $logfile -value "New log file $(Get-Date)"
06 $c = Get-Credential
07 ##A loop that is run for each server foreach ($server in $serverList)
08 {
09     ##check whether the server answer via ping.
10     if (Test-Connection -ComputerName $server -Quiet -Count 1)
11     {
12     ##If the server can be reached via ping, then:
13       Add-Content $logfile -value "...Server $($server)..."
14       $computerInfo = Get-WMIObject Win32_ComputerSystem \
           -computerName $server -Credential $c
15       $osInfo = Get-WMIObject Win32_OperatingSystem -computername \
           $server -Credential $c
16       $bootTime = [string]$osInfo.ConvertToDateTime ($osInfo.LastBootUpTime)
17       #If the manufacturer is Microsoft or VMWare
18       if($computerInfo.Manufacturer -eq "Microsoft Corporation" \
            -and $computerInfo.Model -eq "Virtual Machine")
19       {
20         $type = "Hyper-V Virtual Machine"
21       }
22       elseif($computerInfo.Manufacturer -eq "VMware, Inc." \
                -and $computerInfo.Model -eq "VMware Virtual Platform")
23       {
24         $type = "VMWare Virtual Machine"
25       }
26       else
27       {
28         $type = "physical machine"
29       }
30       ##Computer Info
31       Add-Content $logfile -value "Member of $($computerInfo.Domain). \
           Made by $($computerInfo.Manufacturer)."
32       Add-Content $logfile -value "It is a $($type)."
33       Add-Content $logfile -value "RAM: $\
          ($computer Info.TotalPhysicalMemory/1024/1024) MByte"
34       ##OSInfo
35       Add-Content $logfile -value "Running on $($osInfo.Caption), \
           build $($osInfo.BuildNumber) - with $($osInfo.OSArchitecture)"
36       Add-Content $logfile -value \
          "Installed on $($osInfo.ConvertToDateTime($osInfo.Install Date))"
37       Add-Content $logfile -value \
          "Registered user: $($osInfo.RegisteredUser)"
38      Add-Content $logfile -value "Last started $($bootTime)"
39     }
40     else
41    {
42       Write host "The server $($server) cannot be reached. \
           We proceed with the next..."
43    }
44 }

The sample script reads server names from a text file and tries to ping the server online. The server names are stored one per line in the server.txt file. If the server responds to the ping, the data is collected using previously retrieved logon information. The formatted information is then written to a second text file named logs.txt. Of course, you can change the file names at the beginning of the script file.

Another distinction is made between physical and virtual machines. If the manufacturer is Microsoft or VMware and the model is Virtual Machine or VMware Virtual Platform , the target can hardly be physical hardware. The script implements the case distinction and outputs the knowledge it gleans. A distinction is made between virtual machines on Hyper-V or VMware and physical hardware. The script can be extended easily for additional hypervisors.

Other data from the WMI repository can be queried, depending on whether Java is installed on the computer. The class to use is Win32_Product (Listing 7). To narrow down the selection of objects, you can use a filter with the Get-WMIObject cmdlet. Up to know, all the available results that have been output have been re-used in PowerShell. However, that is not entirely useful for a search against all possible software packages; the result list from Win32_Product is usually very long because target computers typically have a large quantity of installed software.

Listing 7

Win32_Product

# Get-WMIObject Win32_Product -Filter "Vendor like 'Oracle%'"
IdentifyingNumber: {26A24AE4-039D-4CA4-87B4-2F83217051FF}
Name:              Java 7 Update 51
Vendor:            Oracle
Version:           7.0.510
Caption:           Java 7 Update 51

If the WMI interface can perform the necessary filtering, you can save time by searching and processing the results list within PowerShell. Both variants – filtering via WMI or filtering in PowerShell – are target oriented. You need to add two lines of code to the existing script to embed the Java query. The lines would look like this:

# $java = get-wmiobject Win32_Product -Filter "Vendor like 'Oracle%'"
# if($java -ne $null) { Add-Content $logfile -value "Java is installed." }

By looking at other attributes of repository software packages, you can create a small software inventory. Even the software version is available, which allows you to check whether individual computers are using obsolete programs. All packages installed with Windows Installer (MSI files) are in Win32_Product. It provides information about versions of Office or other business applications on personal computers or workstations.

Buy this article as PDF

Express-Checkout as PDF
Price $2.95
(incl. VAT)

Buy ADMIN Magazine

SINGLE ISSUES
 
SUBSCRIPTIONS
 
TABLET & SMARTPHONE APPS
Get it on Google Play

US / Canada

Get it on Google Play

UK / Australia

Related content

comments powered by Disqus
Subscribe to our ADMIN Newsletters
Subscribe to our Linux Newsletters
Find Linux and Open Source Jobs



Support Our Work

ADMIN content is made possible with support from readers like you. Please consider contributing when you've found an article to be beneficial.

Learn More”>
	</a>

<hr>		    
			</div>
		    		</div>

		<div class=