WMI is a powerful interface for managing Windows systems. It makes it possible to access things for which there may otherwise be no dedicated PowerShell cmdlets. In some cases, we can retrieve more information than the standard cmdlets provide. This works both locally and remotely.
Deprecated: The old WMI cmdlets
There are a few older cmdlets, but they are not recommended for new development. However, you may still come across them in older scripts, so now you have heard of them at least. They do exist.
| |
CIM cmdlets
Instead, it makes sense to rely on the CIM cmdlets for new development. CIM stands for “Common Information Model” and is essentially the actual technical standard. WMI is Microsoft’s implementation of CIM, which also extends the standard somewhat.
| |
Even though the name only says CIM and not WMI, we can use it to access WMI.
Query WMI data
There are different ways to query information via WMI. For example, with the WMI Query Language, or WQL, which is a kind of SQL. There are simpler ways to query information via WMI, but WMI queries were, for example, commonly used in old VB scripts or in WMI filters for group policies. So if you already have a WMI query, you can simply reuse it in PowerShell.
You can execute a query with a WMI query using the Get-CimInstance cmdlet.
| |
In essence, that means: Show me all properties of all instances of the Win32_BIOS class.
A slightly more PowerShell-like way to query WMI would be this:
| |
Both variants return all properties, even if that is not immediately obvious. With a pipe to | Select-Object *, all properties of the returned object can be made visible. However, the general PowerShell principle is: if it is possible and sensible, filter as far left as possible. This applies both to the selection of objects and to the selection of object properties.
For the selection of object properties, we can use the -Property parameter. For example:
| |
Now I can do all kinds of things with the retrieved properties. For example, store the result in a variable or access individual properties of the result directly.
| |
Filter WMI data
If you want to filter a WMI query more precisely, you can do so either with a complete WMI query or with the -Filter parameter. The syntax of WMI filters is different from PowerShell syntax. In my opinion, it is even a bit more intuitive. But if you use PowerShell all the time, it feels a little unfamiliar.
There are the simple comparison operators:
| Operator | Description |
|---|---|
| = | Equal to |
| < | Less than |
| > | Greater than |
| <= | Less than or equal to |
| >= | Greater than or equal to |
| != or <> | Not equal to |
See also: https://learn.microsoft.com/en-us/windows/win32/wmisdk/wql-operators
And the LIKE operator for wildcard searches. See also: https://learn.microsoft.com/en-us/windows/win32/wmisdk/like-operator
| |
WQL can do much more, but I have not really needed it so far. If you are interested, take a look at the Microsoft documentation: https://learn.microsoft.com/en-us/windows/win32/wmisdk/wql-sql-for-wmi
Associated instances
This can also be useful: related classes, or rather associated instances. For example, I first query all physical network adapters on my device:
| |
Then I pipe that into Get-CimAssociatedInstance to see all related instances:
| |
Based on the data now displayed, I may already see that something interesting is going on. Otherwise, we can also pipe this output to Select-Object to see, for example, only the class names:
| |
Or to see all properties, because they were not all visible before:
| |
If we find out that a particular class is of interest, we can adjust our original query from Get-CimAssociatedInstance to retrieve only that one class:
| |
That allowed me to display the network configuration for a specific network adapter on my computer.
Remote WMI
Remote WMI is easiest if the currently logged in user also has admin rights on the remote system. For example:
| |
Alternatively, we can create a separate CimSession and specify other credentials.
| |
By the way, if you want to perform several WMI actions against a remote system, it is more efficient to create a session first and then run all commands with the -CimSession parameter. If Get-CimInstance uses the -ComputerName parameter, a new connection is created each time, authenticated, the command is executed, and the connection is closed at the end. A CimSession, however, remains active until it is explicitly terminated.
WSMAN and DCOM
WMI remoting with the CIM cmdlets uses the WSMAN protocol in the background by default. If remote WMI does not work directly for you, you can enable it with the Enable-PSRemoting cmdlet. The older WMI cmdlets use DCOM instead of WSMAN, which is blocked by the Windows Firewall by default on modern systems. However, it would also be possible to use DCOM with the CIM cmdlets if necessary. You can find the details in Microsoft Learn.
Multiple remote systems
It is also possible to work with several remote systems at once. To do that, you first need to create several CimSessions and then pass them to Get-CimInstance.
| |
Disconnect
If you have finished your remote work, you should also disconnect the connections again. The easiest way is:
| |
Execute WMI methods
With WMI, we can not only retrieve information, but also execute methods. Some of them overlap in content with regular PowerShell cmdlets or with methods available via .NET. However, it may also be that exactly what you want to do is only available through WMI.
For example, I first retrieve a CIM instance related to a specific printer. Then I pipe that instance to Invoke-CimMethod to define the printer as the default printer.
| |
I had to use two cmdlets here because Invoke-CimMethod does not support the -Filter parameter that is available on Get-CimInstance. However, I could use the -Query parameter and provide a WMI query, which Invoke-CimMethod does support.
| |
But it does not have to be a specific WMI object instance. Some classes also support direct method calls. For example:
| |
Remote WMI method calls
In principle, Invoke-CimMethod also supports the remoting shown earlier. So you could use either -ComputerName or -CimSession here as well.
| |
Important: If processes are started remotely, they do not appear visibly on the desktop. In the Task Manager, or for example via Get-Process, you may still see that the processes are running. For the example notepad.exe, that may not be very useful, but for other processes it can be ✌️
Find WMI methods
If you already have a WMI object instance, you can look directly in PowerShell to see which methods are available:
| |
Delete WMI object instances
There is also the Remove-CimInstance cmdlet, which can be used to delete WMI object instances. This is usually a ⚠️ destructive action ⚠️, because it does not just remove the object’s representation in PowerShell, but actually destroys the underlying object. For example, if I delete the object instance of a running process, the process will be terminated.
| |
What exactly happens depends on the specific class, of course. But the best practice is to use the Remove-CimInstance cmdlet with extreme caution.
Find WMI classes, properties, and methods
To list all WMI classes on the system, you can use the Get-CimClass cmdlet. Depending on the system, there can be quite a lot, but on a modern Windows 11 system there are well over 2000. And some hardware or software adds its own classes.
| |
About the class names:
- Starts with
__: system class - Starts with
MSFT: system class - Starts with
CIM: base CIM class (usually there is a betterWin32class as an alternative) - ⭐ Starts with
Win32: extended WMI class (based on CIM standard classes) - Starts with
Win32_Perf: performance counter class - Starts with
Win32_PnPDevice: Plug and Play device class - ⭐ Starts completely differently: could also be interesting
See also: https://learn.microsoft.com/en-us/windows/win32/wmisdk/wmi-classes
There are sometimes CIM and Win32 classes that overlap in content. In general, the Win32 class is more powerful. For example, the Win32_Process class has 45 properties and 7 methods on my system, while the CIM_Process class has only 18 properties and no methods at all.
The methods and properties of a class are listed in the CimClassMethods and CimClassProperties properties.
| |
However, I prefer to look up the information in the official documentation. If I search for Win32_Process in a search engine, I quickly land on the right documentation. The advantage is that it usually also includes descriptions and examples for the properties and methods.
WMI namespaces
You may have noticed from the output of Get-CimClass: above the list of results there is still: “NameSpace: ROOT/cimv2”.
The classes are organized into namespaces, similar to folders in a file system. Additional hardware or software can sometimes bring their own namespaces containing additional WMI classes. root/cimv2 is simply the default namespace of Windows. And if we call Get-CimClass without further parameters, we will only see the classes in this default namespace. But there are more namespaces.
The definition of namespaces can be retrieved via the system class __Namespace, but we also need to specify that we want to view that definition in the namespace root (without cimv2, which is already a sub-namespace of root):
| |
On a domain controller, I have also seen other namespaces than on a Windows 11 client. For example, my DC has the namespace MicrosoftActiveDirectory.
| |
In fact, namespaces can also contain additional namespaces. For example, the standard namespace root/cimv2 also contains sub-namespaces.
With a small function I wrote myself, we can list all namespaces.
| |
In general, however, a lot of important things also happen in the default namespace root/cimv2, in my opinion. But of course that depends on what you want to do with WMI.
Find WMI classes
If you do not yet know which class you need, you can also search with Get-CimClass. If you suspect that the class name contains a specific word, you can use wildcards and search:
| |
Otherwise, there are also graphical tools that can help, such as the WMI Explorer by Vinay Pamnani.