Chapter 10. WMI and CIM
We've looked at several kinds of cmdlets so far in Module 1, but until now, each cmdlet has been working with a specific kind of object. In this chapter, we will look at the WMI and CIM cmdlets, which will allow us to look at a seemingly unlimited range of object types. In this chapter, we will cover the following topics:
- What are WMI and CIM?
- A WMI/CIM glossary
- Retrieving objects via WMI and CIM
- Calling methods via WMI and CIM
- The CDXML modules
What is WMI?
Getting objects from cmdlets is what PowerShell is all about. Unfortunately, there are more kinds of objects that we might be interested in than PowerShell has cmdlets for. This was definitely the case during the time of PowerShell 1.0, which only had less than a hundred cmdlets. What do we do about the objects for which PowerShell doesn't have an explicit cmdlet? The answer involves Windows Management Instrumentation (WMI). WMI was introduced as a common interface to manage operating system objects all the way back in Windows NT. WMI provides a uniform way to retrieve objects, which allows us to inspect and even change the state of components, processes, and other objects. Before we look at specific WMI information, it's important to understand how objects are stored in WMI.
WMI organization
The WMI objects are stored in a repository that is local to a computer system. The repository is divided into several namespaces, each of which provides different objects. Inside a namespace there are the WMI classes, each of which describes a certain type of object. Finally, there are the WMI instances, which are specific examples of a WMI class.
An analogy would help to make more sense of this. If we think of the WMI repository like a filing cabinet, the comparison might go something as follows:
- The repository is a filing cabinet
- A namespace is a drawer in the cabinet
- A class is a folder in the drawer
- An instance is a piece of paper in the drawer
The information that you want is found on the piece of paper, that is, in the WMI instance.
Finding WMI classes
The first thing to know about the WMI classes is that there are a ton of them. So many, in fact, that you will almost certainly never need to use most of them. As there are so many classes, finding the class that you want to work with can be interesting. The Get-WMIObject
cmdlet has a parameter called –List
, which lets you get a list of the classes installed on your computer. Combining this cmdlet with Measure-Object
shows that my computer (Windows 7) has over a thousand classes in the default namespace:
You clearly don't want to look through a list of so many items, so you can narrow down the list with the –Class
parameter, which accepts wildcards. For instance, to find classes that deal with the processor, you might do this:
The first two in the list (CIM_Processor
and Win32_Processor
) are the results that are most useful in this case. Depending on what wildcard you use, you may need to look at several classes to find the one that is most appropriate.
Tip
The classes beginning with Win32 are based on the classes beginning with CIM. Generally, I stick with the Win32 classes, but they usually have almost the same information.
Retrieving objects with Get-WMIObject
If you know the name of a class and what namespace that class belongs to, it is simple to retrieve the class using the Get-WMIObject
cmdlet. For instance, there is a class that describes the installed operating system called Win32_OperatingSystem
contained in the default (root\CIMV2
) namespace. To retrieve this class, either of these command-lines will work:
Get-WMIObject –class Win32_OperatingSystem Get-WMIObject –class Win32_OperatingSystem –namespace root\CIMV2
The output here is formatted, so you will probably want to use Select-Object –property *
to see all the properties. In this case, there are 73 properties, which are too many for a screenshot.
Tip
You try it!
Use Get-WMIObject
with the Win32_OperatingSystem
class and look through the properties. You might make a note of the properties that you think would be useful. As you use WMI (and CIM) more and more, you will find a number of classes and properties that you will come back to over and over again. Hence, having a list of "favorites" can be a real life-saver.
One thing you probably noticed with Win32_OperatingSystem
is that only one object (instance) was retrieved by the cmdlet. This makes sense, because there's only one operating system running on a computer at a time (not counting VMs, of course). The other classes might return zero, one, or any number of instances.
A class that should be easy to understand is the Win32_Service
class. This class represents the Windows services that are installed in your operating system. You can see the beginning of the formatted output in the following screenshot:
You might ask why we would use WMI to get information about services when we have a perfectly good cmdlet (Get-Service
) that is designed to do this. Even though we can see only a few properties of each WMI service object in the preceding output, theres enough information to illustrate an important point. The first object in the output, AdobeARMService
, shows six properties. Comparing these properties with the full output of the Get-Service
cmdlet reveals that the Name
and State
properties of the WMI object have analogous properties (Name
and Status
) in the Get-Service
object, but the other four properties (including ProcessID
) are missing from Get-Service
:
Remember that WMI is a very mature technology that has been in use for over 20 years. As WMI is so well established, most aspects of the Windows ecosystem is covered very well by WMI.
Tip
Tip!
In addition to keeping track of the interesting WMI classes, you might also want to make a note of the properties of WMI instances that are missing from the objects output by other PowerShell cmdlets. Often, WMI provides the easiest way to get some information.
Getting the right instance
With Win32_ComputerSystem
, we didn't have to worry about which instance was returned because there was only one. The next class we looked at was Win32_Service
, which returned multiple objects, one for each service on the computer. In order to select specific instances, we can use the –Filter
parameter.
Since WMI covers thousands of different kinds of classes, it would be impossible for Get-WMIObject
to have specific parameters to help us narrow down which objects we would like to see. For instance, if we use Get-Service
to look at services, we can use the –Name
parameter to filter by name. Not all WMI objects have a name property, so it wouldn't make sense to have a parameter to filter by this single property. The solution is to have a query language called WMI Query Language (WQL), similar to SQL, and a single parameter called –Filter
that takes the WHERE clause of the WQL query in order to filter the objects.
WQL syntax
WQL syntax is very simple to use, and is very similar to SQL. In the WQL filter, you can use the property names of classes, constants, and operators to build the conditions you are looking for. For example, to return only the AdobeARMService
instance from the Win32_Service
class, you could use a filter of "Name='AdobeARMService'"
. Note that I have used double quotes around the filter and single quotes around the string value of the Name
property. The full Get-WMIObject
statement and output looks as follows:
Filters can be more complex as well. Consider the Win32_LogicalDisk
class, which contains an instance for each drive on the local computer:
If we wanted to list all the drives that had less than 10GB free and didn't care about the removable, we could use a filter as follows:
-Filter "DriveType=3 and FreeSpace< 10737418240"
Here, you can see that I have calculated the value of 10GB
because WQL doesn't understand units, and also, I have used a variable to hold the filter in order to keep the line shorter.
Tip
Although WQL filters look like SQL syntax, there are crucial differences. You can use comparison operators (=
, <>
, >
, <
. <=
, >=
, LIKE
) in the expressions and can link multiple expressions together with AND and OR. You can also group expressions using parentheses. Another important thing to remember is that the WQL strings use backslash as the escape character. For more details, including how to use the WQL queries, refer to the About_WQL
help topic.
Getting the right instance
With Win32_ComputerSystem
, we didn't have to worry about which instance was returned because there was only one. The next class we looked at was Win32_Service
, which returned multiple objects, one for each service on the computer. In order to select specific instances, we can use the –Filter
parameter.
Since WMI covers thousands of different kinds of classes, it would be impossible for Get-WMIObject
to have specific parameters to help us narrow down which objects we would like to see. For instance, if we use Get-Service
to look at services, we can use the –Name
parameter to filter by name. Not all WMI objects have a name property, so it wouldn't make sense to have a parameter to filter by this single property. The solution is to have a query language called WMI Query Language (WQL), similar to SQL, and a single parameter called –Filter
that takes the WHERE clause of the WQL query in order to filter the objects.
WQL syntax
WQL syntax is very simple to use, and is very similar to SQL. In the WQL filter, you can use the property names of classes, constants, and operators to build the conditions you are looking for. For example, to return only the AdobeARMService
instance from the Win32_Service
class, you could use a filter of "Name='AdobeARMService'"
. Note that I have used double quotes around the filter and single quotes around the string value of the Name
property. The full Get-WMIObject
statement and output looks as follows:
Filters can be more complex as well. Consider the Win32_LogicalDisk
class, which contains an instance for each drive on the local computer:
If we wanted to list all the drives that had less than 10GB free and didn't care about the removable, we could use a filter as follows:
-Filter "DriveType=3 and FreeSpace< 10737418240"
Here, you can see that I have calculated the value of 10GB
because WQL doesn't understand units, and also, I have used a variable to hold the filter in order to keep the line shorter.
Tip
Although WQL filters look like SQL syntax, there are crucial differences. You can use comparison operators (=
, <>
, >
, <
. <=
, >=
, LIKE
) in the expressions and can link multiple expressions together with AND and OR. You can also group expressions using parentheses. Another important thing to remember is that the WQL strings use backslash as the escape character. For more details, including how to use the WQL queries, refer to the About_WQL
help topic.
WQL syntax
WQL syntax is very simple to use, and is very similar to SQL. In the WQL filter, you can use the property names of classes, constants, and operators to build the conditions you are looking for. For example, to return only the AdobeARMService
instance from the Win32_Service
class, you could use a filter of "Name='AdobeARMService'"
. Note that I have used double quotes around the filter and single quotes around the string value of the Name
property. The full Get-WMIObject
statement and output looks as follows:
Filters can be more complex as well. Consider the Win32_LogicalDisk
class, which contains an instance for each drive on the local computer:
If we wanted to list all the drives that had less than 10GB free and didn't care about the removable, we could use a filter as follows:
-Filter "DriveType=3 and FreeSpace< 10737418240"
Here, you can see that I have calculated the value of 10GB
because WQL doesn't understand units, and also, I have used a variable to hold the filter in order to keep the line shorter.
Tip
Although WQL filters look like SQL syntax, there are crucial differences. You can use comparison operators (=
, <>
, >
, <
. <=
, >=
, LIKE
) in the expressions and can link multiple expressions together with AND and OR. You can also group expressions using parentheses. Another important thing to remember is that the WQL strings use backslash as the escape character. For more details, including how to use the WQL queries, refer to the About_WQL
help topic.
Calling methods
When dealing with WMI, there are two kinds of methods that come into play, instance methods and class methods. Calling the WMI instance methods is similar to calling methods on any PowerShell object, that is, using dot-notation. For instance, WMI objects from the Win32_Service
class have a StartService()
method defined in them, which we can verify using Get-Member
:
To call this method, we can store the instance in a variable and use the variable to call the method. Note that the method outputs a structured result type. The ReturnValue
property of the output gives us the outcome of the operation. A value of zero means success. An example of a successful method invocation can be seen in the following screenshot:
Tip
You might notice that the preceding screenshot is an elevated session. If you try to start a service in a non-elevated session, you get a ReturnValue
of 2
, which means "warning".
WMI and CIM
PowerShell 3.0 introduced the Common Information Model (CIM) cmdlets to access WMI repositories. The WMI cmdlets are still present, but they have been superseded by the CIM cmdlets that can perform all the same functions. From a functional level, the CIM cmdlets are similar to the WMI cmdlets. The main difference is the communication that the cmdlets perform with the target computer. The WMI cmdlets use the DCOM protocol, which is a pretty standard thing to do on Windows systems, especially 20 years ago when WMI was created. Unfortunately, DCOM is kind of a mess from a firewall standpoint, as it uses a range of ports (over 16000 ports by default) that need to be open in order to function. In a data center situation, requiring this many ports to be opened in the firewalls is something that network engineers frown upon.
The CIM cmdlets, by default, use Web Services for Management (WS-MAN), the protocol that PowerShell remoting is based on. WS-MAN uses a single port, and has a number of other properties that make it ideal from a networking standpoint. Finally, the CIM cmdlets support sessions, which allow you to reuse a connection to a computer or a set of computers for multiple requests, which can dramatically reduce the network traffic for some workloads.
If you're just looking at the WMI repositories on the local box like we've done in the examples of this chapter, both sets of cmdlets will work fine. If you're looking at the WMI classes across multiple computers in a network, you will need to consider firewall rules and whether WS-MAN is enabled. These are beyond the scope of Module 1, please see Module 2 and 3 for more, but are good to make a note of.
The CIM cmdlets
The two main CIM cmdlets that you will use are Get-CIMClass
and Get-CIMInstance
. Although Get-WMIObject
is used to retrieve both the WMI classes (with –List
) and WMI instances (without –List
), these roles are carried out by separate CIM cmdlets. Using Get-CIMClass
is virtually identical to using Get-WMIObject
with the -List
switch. We can recreate the processor example from earlier in the chapter with Get-CIMClass
as follows:
Retrieving instances is done, of course, with Get-CIMInstance
. Filters work exactly like they do with Get-WMIObject
. Also, the objects output by these two cmdlets are the same, so working with the results will be exactly the same.
The CIM cmdlets
The two main CIM cmdlets that you will use are Get-CIMClass
and Get-CIMInstance
. Although Get-WMIObject
is used to retrieve both the WMI classes (with –List
) and WMI instances (without –List
), these roles are carried out by separate CIM cmdlets. Using Get-CIMClass
is virtually identical to using Get-WMIObject
with the -List
switch. We can recreate the processor example from earlier in the chapter with Get-CIMClass
as follows:
Retrieving instances is done, of course, with Get-CIMInstance
. Filters work exactly like they do with Get-WMIObject
. Also, the objects output by these two cmdlets are the same, so working with the results will be exactly the same.
CDXML modules
One of the drawbacks of using the WMI or CIM cmdlets is that you don't get to use parameters that are specific to the properties of the WMI class you are dealing with. For instance, when we looked at the Win32_LogicalDisk
instances, it would have been really nice to have parameters such as DriveType
or Name
to easily filter the output without having to use a WQL filter statement. In PowerShell 3.0, the concept of a CDXML module was introduced. CDXML modules allow you to create an XML description of the cmdlets and the associated parameters dealing with a WMI class, and the PowerShell engine creates the cmdlets for you when you import the module.
The CDXML modules have two main advantages, as follows:
- The module is XML, so no coding is necessary.
- End users get to use parameters that are specific to the type of object rather than a generic
–Filter
parameter
In PowerShell 4.0, the majority of modules on a server will be CDXML modules, because they are easy to write.
Summary
In this chapter, we have taken a quick look at the basics of using the WMI and CIM cmdlets. It should be clear that there is a lot of information in the WMI repository, and these cmdlets are essential tools for PowerShell scripters. With the introduction of CDXML modules, we're also seeing more cmdlets that are customized to specific WMI classes, making their usage even easier.
In the final chapter, we will look at administering Internet Information Services (IIS).
For further reading
Get-Help about_WMI
Get-Help about_WMI_Cmdlets
Get-Help about_WQL
- WMI Result codes: https://msdn.microsoft.com/en-us/library/aa394574(v=vs.85).aspx
- Get-Help about_CIMSession
- Article summarizing CIM/WMI/OMI/DMTF terminology: http://powershell.org/wp/2015/04/24/management-information-the-omicimwmimidmtf-dictionary/