PowerShell – WMI and CIM

So for my fist post on this blog i’ll write some musings about PowerShell and using the WMI and CIM cmdlets.

WMI is the backbone of most PowerShell cmdlets that interact with system settings (and C# as well).
And they are a powerful tool for collecting data and making system changes.

WMI itself  is based upon the standard called Common Information Model (CIM) created by the Distributed Management Task Force (DMTF).
Originally PowerShell v 1.0 was shipped with the following cmdlets for working with WMI:

These are common workhorses for a lot of scripts around.
But they are lacking a critical part of the PowerShell experience; discoverability.

These cmdlets does not allow for autocomplete of classes and namespaces, meaning you would have to dig into the documentations to discover them.

This was resolved with the release of PowerShell 3.0 and the CIM cmdlets:


These cmdlets support autocomplete and makes it much easier to script without searching through documentation to find your classes and namespaces.

Now writing about this in-depth would get really long, so i’ll just link to Microsoft’s documentation on these:
WMI: https://msdn.microsoft.com/en-us/library/aa384642(v=vs.85).aspx
CIM\MI: https://msdn.microsoft.com/en-us/library/jj819829(v=vs.85).aspx

Documentation on WMI classes included in Windows can be found here:

And Microsoft Docs is an excellent reference for PowerShell cmdlets (and everything else Microsoft):

WMI vs CMI cmdlets

I will focus on the CIM cmdlets, for a few reasons:

Fist is auto-complete, which makes it much faster to create scripts in various editors (ISE primarily, but also VSCode), but also when you are just working in the console.

Second reason is that CIM is much faster when trying to query multiple computers.
This is because it will execute the commands in parallel, and also because it uses WSMan as the backend for remote management (same as PowerShell).
One of the really nifty features of using WSMan as backend, is that you can create CIMSessions as well (more in a later post).

And the third reason CIM is the way forward for PowerShell Core (PS v6.0), and will be supported on all platforms that PSCore is working on.
Meaning you can reuse a lot of the knowledge from CIM on both Linux and MacOS as well.

Here is a little snippet to show what i mean.
This will use both WMI and CIM to get some information about the computers in the $ComputerList array.
This will return hostname, Windows version and install date in a table.
It will also do a measure with the same commands to show how much time each command takes to complete.

$ComputerList = "Computer1","Computer2","Computer3"

Get-CimInstance CIM_OperatingSystem -ComputerName $ComputerList | Select CSName,Version,InstallDate
Get-WmiObject Win32_OperatingSystem -ComputerName $ComputerList | Select CSName,Version,InstallDate 

Measure-Command {Get-CimInstance CIM_OperatingSystem -ComputerName $ComputerList} 

Measure-Command {Get-WmiObject Win32_OperatingSystem -ComputerName $ComputerList}

Now querying 3 computers on the same network does not have a  really significant delay (both are likely below 1 second).
But this quickly scales, and if one computer is slower than the others the Get-WMIObject will likely hang until it gets an response.

The CIM cmdlet also shows another nice feature here.
Date values will automatically be shown with the user’s own time and date format (the PS object itself is unchanged).
No need to do any additional step to understand the time and dates returned in CIM objects.

This will be the first post about PowerShell and CIM in an ongoing series.
So please check in later for more posts!

Have a any feedback, suggestions, corrections and the like?
Please do leave a comment!

This is my first proper blog post (of hopefully many), and good feedback is the best way to improve!

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.