PowerShell – Working with CIM – Methods

Originally posted on 2018-08-03 on the old blog

Onward to working with CIM methods!

The data you get from using Get-CIMInstance is rarely directly modifiable as the data returned is usually a snapshot of deeper system settings. To change this you will need to use the methods provided by the Class you are looking at.

Note that that most classes have their own methods unique to them, so depending on what you want to do you will have to read up on the documentation for that class.

There are ways to look up the method names themselves in PowerShell, but the format of the input data is not always obvious. Luckily in most cases you will find what you need for classes made by Microsoft at Microsoft Docs (just search for the class name).

Example

For this article i will mainly use the class Win32_TerminalServiceSettings as an example. This is the class that controls most of the RDP Host settings on the computer.

Here is a snippet that will enable RDP on your local machine (run from an elevated shell):

$Win32TerminalServiceSettings = Get-CimInstance -Namespace root/cimv2/TerminalServices -ClassName Win32_TerminalServiceSetting 
$Win32TerminalServiceSettings | Invoke-CimMethod -MethodName SetAllowTSConnections -Arguments @{AllowTSConnections=1;ModifyFirewallException=1}

So lets break this down a bit.

$Win32TerminalServiceSettings = Get-CimInstance -Namespace root/cimv2/TerminalServices -ClassName Win32_TerminalServiceSetting

This line simply creates a variable containing the CIM Class object. This makes it simple to reuse if you want to invoke several methods, it can also help improve readability of your script.

$Win32TerminalServiceSettings | Invoke-CimMethod -MethodName SetAllowTSConnections -Arguments @{AllowTSConnections=1;ModifyFirewallException=1}

Here we are getting to the meat. We pipe the class object variable into the Invoke-CimMethod cmdlet. Here we first specify the method “SetAllowTSConnections” with the -MethodName parameter. Then we set our arguments with -Arguments, this parameter uses a hashtable to set the properties “AllowTSConnections” to 1 (allow) and “ModifyFirewallException” to 1 (enable firewall rule).

When you execute this command it will usually return a “0” to indicate success. You can check the setting by running the command:

Get-CimInstance -Namespace root/cimv2/TerminalServices -ClassName Win32_TerminalServiceSetting | select AllowTSConnections

It is important to note that calling the variable instead will return stale data, as the variable contains a snapshot of the parameters at the time of creation. This can be useful to compare data, but it is something to be aware of when you check for change.

Vs WMI-Object

For those that are more familiar with WMI this could be done with this command:

(Get-WmiObject -Namespace root/cimv2/TerminalServices -Class Win32_TerminalServiceSetting).SetAllowTsConnections(0,0)

This is an okay way to do it if your method does not have many parameters, but for some methods this can be really finicky.

The reason for this is that the parameter is positional in WMI, meaning that if you have several parameters but you only want to change one you will have to find it's correct position to change it. This is not always easy, as occasionally the parameter position is different that what the documentation says.

By using CIM methods you specify the name of the parameter in you arguments hashtable therefore rendering this issue moot.

Conclusion

As you can see above using CIM methods is fairly easy once you have the basics.

And while you can probably write shorter code with WMI, this can lead to issues when trying to set parameters.

My philosophy when writing scripts is that verbosity (within limits) is good, as it makes the script easier to read and understand and modify when necessary. And CIM cmdles are superior to WMI cmdlets in that way.

Also if you want to use the snippet above to enable RDP, you would probably also want to ensure that “Network Level Authenticaton” is enabled as well. You can do this with this snippet:

$Win32TSGeneralSettings = Get-CimInstance -Namespace root/cimv2/TerminalServices -ClassName Win32_TSGeneralSetting
$Win32TSGeneralSettings| Invoke-CimMethod -MethodName SetUserAuthenticationRequired -Arguments @{UserAuthenticationRequired=1}

Next article in the CIM series will talk about remote connections. Till then have a good one!