- Use PowerShell splatting and PSBoundParameters to pass parameters - Wed, Nov 9 2022
- Using PowerShell with $PSStyle - Mon, Jan 24 2022
- Clean up user profiles with PowerShell - Mon, Jun 9 2014
Stopping and Starting with CIM cmdlets
One important distinction with a CIM-derived object compared to “pure” WMI, is that the resultant object has no methods. This means you cannot directly invoke a method like StopService(). Instead, you have to use Invoke-CimMethod. Here’s the spooler service on the local computer.
PS C:\> get-ciminstance win32_service -filter "Name='spooler'" ProcessId Name StartMode State Status ExitCode --------- ---- --------- ----- ------ -------- 0 Spooler Manual Stopped OK 1077
As with WMI, I find the easiest approach is to pipe the object to the Invoke-CimMethod cmdlet.
PS C:\> get-ciminstance win32_service -filter "Name='spooler'" | Invoke-CimMethod -Name StartService ReturnValue PSComputerName ----------- -------------- 0
The cmdlet works pretty much the same way as Invoke-WmiMethod. A return value of 0 indicates success. Let’s revisit an earlier query to find all services that are set to autostart but are not running and then start them.
PS C:\> get-ciminstance win32_service -filter "startmode='auto' and state<>'running'" -computer $computers | Invoke-CimMethod -Name StartService –WhatIf
The $computers variable is an array of computernames. Using Whatif indicates what the command would do if I had allowed it as you can see in the screenshot.
To effect the change I can re-run the command without –WhatIf.
PS C:\> get-ciminstance win32_service -filter "startmode='auto' and state<>'running'" -computer $computers | Invoke-CimMethod -Name StartService
As you can see in the next screenshot I can see where I was successful, although I can’t tell which service was changed.
Let’s turn to a variation of something I did in a previous article using Invoke-WmiMethod. In this case, because I’m running PowerShell 3.0, I can take each service object, start it and create a custom object to display the results.
get-ciminstance win32_service -filter "startmode='auto' and state<>'running'" -computer $computers | foreach { $result = $_ | Invoke-CimMethod -Name StartService #create a custom object [pscustomobject]@{ Result=$Result.ReturnValue Name=$_.Name DisplayName=$_.Displayname Computername=$Result.PSComputername } } | Sort Computername,Name
Don’t you think the screenshot below is easier to understand?
Of course you can add any other information you need such as the date and time. Or filter this further to only display errors. All I need to do is take my previous expression and filter on the result value.
... | Sort Computername,Name | Where {$_.result -gt 0} Result Name DisplayName Computername ------ ---- ----------- ------------ 7 VMTools VMware Tools Service chi-dc02 2 gpsvc Group Policy Client chi-win8-01
Changing the StartMode
Changing a service property such as the Startmode is equally easy. I don’t need the Remote Access Connection Manager service running on my network, so I’m going to disable it where ever it is found.
PS C:\> get-ciminstance win32_service -filter "name='rasman'" -comp $computers | Invoke-CimMethod -methodname ChangeStartmode -Arguments @{startmode='Disabled'} ReturnValue PSComputerName ----------- -------------- 0 chi-win8-01 0 chi-dc03 0 chi-db01 0 chi-ex01
One slight difference here compared to Invoke-WmiMethod is that the list of arguments must be presented as a dictionary object. The tricky part is identifying the key, which in this case is StartMode. The best thing to do is look at documentation for the WMI method and look at the name of the parameter. Astute readers may also notice that I used –MethodName whereas earlier I used –Name. From what I can gather –Name is an undocumented alias to the –MethodName parameter.
Because we use a dictionary object for method parameters, it is easier to invoke the service object’s Change method. In a previous article I set the ErrorControl property of the Spooler service to Ignore. Let’s set it back to Normal using the CIM cmdlets.
PS C:\> get-ciminstance win32_service -filter "name='spooler'" | Invoke-CimMethod -MethodName Change -Arguments @{ErrorControl=1} ReturnValue PSComputerName ----------- -------------- 0
This is so much easier. No more trying to figure out the position and adding $Null values. Set the specific method parameter and be done with it!
Summary
Using the CIM cmdlets can make remote management very easy and firewall friendly. Yes, it does require PowerShell 3.0 but hopefully you are headed in that direction anyway. Any service management that you could have done with WMI you can also do with the CIM cmdlets, and sometimes with less effort.
I have also stumbled upon another quirk with the CIM cmdlets. Under normal conditions the remote computer must also be running PowerShell 3.0. This holds true when querying all instances of a given class. But when you use a filter, as I’ve done often in this article, then I can query using Get-CimInstance even if the remote computer is running PowerShell 2.0! I’m still investigating why this seems to be happening. But in any case you should be testing everything I demonstrated in this series in a non-production environment any way.
Next up we’ll look specifically at managing the credentials a service is running under.
Has been useful for me today. Thanks!