Windows Management Instrumentation (WMI) provides a wealth of information about computers, but writing code to access that information can give you a headache. Fortunately, WMI calls are generic, so I created a drop-in function named GetWmiProperty that lets you write only one line of code to access WMI data. I designed this function to work with single-instance WMI classes, such as Win32_ComputerSystem or Win32_OperatingSystem.
As Listing 1 shows, GetWmiProperty needs three parameters to run. The first parameter is the name of the computer you want to query. For the local machine, you can use a period (.). The second property is the WMI class name. The third parameter is the name of the property you want to access.
Before you use the GetWmiProperty function, you need to determine which WMI property will provide the information you need. Making this determination might involve some research. You can browse the WMI classes with the free Scriptomatic 2.0 utility, which you can download at http://www.microsoft.com/technet/scriptcenter/tools/scripto2.mspx. You can also check the online WMI documentation at http://www.msdn.microsoft.com/library/en-us/wmisdk/wmi/win32_classes.asp.
After you know which WMI property you need, you can use GetWmi-Property and significantly reduce the amount of time you'll spend writing code to retrieve that property's information. Listing 2 shows some examples of how to use GetWmiProperty.
The Win32_OperatingSystem class exposes many useful properties. For example, if you want to check the local computer's OS version, the best property to use is BuildNumber. As callout A in Listing 2 shows, you need only one line of code to retrieve this information.
Do you need to know what service pack is installed? The code at callout B retrieves this information for a machine named PC01. For example, if PC01 has Windows XP Service Pack 2 (SP2) installed, the property will return a value of 2. If no service packs are installed, the property will return a value of 0.
Do you want to check the local machine's registered user and organization to make sure it's appropriately stamped? As callout C shows, you can retrieve this information with the RegisteredUser and Organization properties.
The properties of the Win32_ComputerSystem class also provide useful information, but sometimes they don't return the information in a userfriendly format. For example, if you want to find out how much physical memory is installed on a PC, you can use the class's TotalPhysicalMemory property. However, this property returns the amount of memory in bytes. On my system, which has 768MB RAM, the property returns 804765696. You can use division to convert the bytes into megabytes, as callout D shows. For example, in my case, the code at callout D returns 767.484375 (804765696/1024/1024).
As this example shows, sometimes there are discrepancies between the returned property value (e.g., 767 .484375) and the value (e.g., 768) displayed on the General tab of Windows' System Properties dialog box. There are two possible reasons for such variations. Some systems don't correctly report their memory in System Management BIOS (SMBIOS), which usually explains small deviations (less than 1MB per module in my experience). Larger differences might appear on systems that use Unified Memory Architecture (UMA) video. If 8MB is reserved for video use on a computer that uses UMA, then Windows doesn't have direct access to that 8MB and won't report it as available system memory. In fact, for determining available resources, you shouldn't consider that 8MB because you can't use it.
Another property that returns less-than-intuitive values is the Win32 _ComputerSystem class's DomainRole property, as callout E shows. You can use this property to determine a machine's role in a domain. However, this property returns an integer ranging from 0 to 5. Fortunately, property values are documented in the online WMI class descriptions, so you just need to look up the information. For example, to learn what the DomainRole integers represent, you can check the Win32_ComputerSystem documentation at http://www.msdn.microsoft.com/library/en-us/wmisdk/wmi/win32_computersystem.asp.
Some WMI properties, such as the Win32_ComputerSystem class's Roles property, return an array. As callout F shows, you can use the Join function to handle arrays. In the WMI documentation, square brackets after a property's name (e.g., Roles \[ \]) indicate that the property returns an array.
GetWmiProperty has given me a lot of mileage, but I designed it to return a single instance of a property value, so it has limitations. Here are the limitations to keep in mind:
- If a computer has no instances of a class, GetWmiProperty returns an empty value. For example, if your machine doesn't have FireWire support, you'll get an empty value if you try to use the function with the Win32_1394Controller class. However, the empty value itself might tell you what you want to know.
- If there is more than one instance of a class, GetWmiProperty returns only one occurrence of the specified property. For example, if a computer has two video cards, the Win32_VideoController class's AdapterRAM property arbitrarily returns the RAM of one card.
When I'm trying to decide whether to use GetWmiProperty, I think about the class I want to access. Are there realistic cases in which a computer might have more or less than one instance of a class? If so, what are the consequences for the script? If those consequences are serious, I write more elaborate code. However, I primarily use single-instance classes, so I often use GetWmiProperty and spend a lot less time writing WMI scripts.