It wasn’t really because they are “deprecated”. Microsoft might treat them this way, but they will for sure be around for quite some time. It’s like VBScript, it still has it’s purpose and it will stick there. You can find a very good Introduction to CIM CmdLets on the Windows PowerShell Blog. For the typical user (so you and me 😉 ) there are often only small differences and for most of the stuff you typically do, they are kind of interchangeable.

What leads to the question, why should one use the new CIM CmdLets?

My personal top three benefits that actually made me use the CIM CmdLets are:

Nr. 3 – The CIM session

On default all CIM CmdLets support the ComputerName parameter that allows you to connect to a remote computer to execute the commands. Pretty much the same as the WMI CmdLets. However they all also have a CimSession parameter, that takes a Session object.

The CimSession allows you to use different credentials and even different authentication methods:

Nr. 2 – Parallel execution – “Fan out”

In my daily job, I often have to work with computers located around the globe. I need to collect information or execute some tasks on multiple of them, preferably in the shortest time possible.

Using the WMI CmdLets you can pass in an array of computer names. However those are processed sequentially. If they are now on a WAN connection, this just sums up. To be able to reduce the total time, you have to implement your own methods to execute it in parallel using e.g. Invoke-Async, Background Jobs, Windows Powershell Workflow with Foreach -Parallel, or similar options. In opposite working with multiple computers using the CIM CmdLets simply works like a charm and is pretty fast.

I did my own very basic speed comparison testing using 5 computers located at 5 different remote locations.

I left out the definition for $Servers as that’s just an array of above mentioned 5 remote computers.

And the results speak for themselve

WMI: 35.40861808 seconds.
CIM: 2.51654976 seconds.

I’ve seen some other speed comparisons that often come to the conclusion, that the WMI CmdLets would be as fast or even faster than the CIM CmdLets. But mostly they were either running hundreds of iterations to the same, sometimes even the local computer. Or they had put it into a custom for-each loop which would then basically disable the built-in capabilities of the CIM CmdLets in terms of doing parallel work.

In case you need to work with Sessions, this works the exact same way as using plain computer names

As you can see while it’s definitely easier than VBScript, it still has the drawback, that you need to supply the method parameters in a certain order. And if you think that this would be the order as specified in the documentation, you might be wrong. The documentation for the InitiateClientOperation method specifies the arguments in the following order:

Type

TargetCollectionID

RandomizationWindow

TargetResourceIDs

However, the method actually expects the arguments in the following order:

RandomizationWindow

TargetCollectionID

TargetResourceIDs

Type

What? Yes!!!

As you can imagine, this makes it pretty cumbersome working with methods sometimes.

The second option would be to get a list of parameters first and then pass them as an object.

I pesonally prefer that way of handling methods and passing in a hashtable that contains the name and values for the method parameters.

For sure there are other interesting aspects as well like the easy serialization/deserialization of objects via Export-CliXML and Import-CliXML, listing of classes using Get-CimClass, the automated conversion of e.g. the WMI DateTime format into the DateTime format used within .Net and PowerShell and a bunch of others.

Drawbacks

There are two issues, that you will run into, when working with the CIM CmdLets epsecially in SCCM. Sooner or later.

you will end up with an error 0x80041089. According to the WMI Error constants, that’s WBEM_E_NO_KEY or better “User attempted to put in an instance with no defined key.” Looking at the definition of SMS_Category_LocalizedProperties again, it gets obvious, that this class doesn’t even have a key property. And now you are stuck. You can’t create an instance of this embedded class as it doesn’t have a key property. But New-CimInstance requires you to use one. And you can’t create a new Category, as LocalizedProperties (which takes an array of SMS_Category_LocalizedProperties) is a mandatory property and can’t be null.

Doh.

2. Working with classes that contain lazy properties

A second thing, that is pretty unique to but also regular within SCCM, is the use of so called lazy properties. As some of the SCCM objects contain pretty large properties or properties that might take quite some time to generate or process, those properties are marked as lazy and will not be loaded on default. E.g. if you are iterating through a list of those objects, all lazy properties will be empty/null.

Using the WMI CmdLets, one has to execute an explicit Get on the WMI object to also load the lazy properties. And this is a necessity if you want to change a value! As if you don’t load the content of the lazy properties and then save the object, those properties will suddenly all be null! You wouldn’t be the first one who accidentally corrupts a ConfigMgr object by simply changing a value 😉

With the CIM CmdLets, this problem isn’t as serious, as the Set-CimInstance CmdLet allows you to supply a list of key-value pairs that you would like to set. So you are no longer getting the object, update the values and then save the whole object. Rather get the object and explicitly set the properties that need to be changed. So no “sideeffect” on the lazy properties. But as there isn’t any Get method on the CimInstance object itself, you simply can’t read the lazy properties. Which might not be a problem, until you need to know the value of any of them.

For sure there are workarounds for those two issues. As this post is already way to large, I’ll give you the solution in a separate post.