- 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
There are no WMI-based service management cmdlets so we need to use the methods of the service object.
PS C:\> get-wmiobject win32_service -filter "name='lanmanserver'" | get-member -MemberType Method | Select name Name ---- Change ChangeStartMode Delete GetSecurityDescriptor InterrogateService PauseService ResumeService SetSecurityDescriptor StartService StopService UserControlService
Now, it is possible to get a reference to a specific service object and then directly invoke a method.
PS C:\> $service = get-wmiobject win32_service -filter "name='spooler'" PS C:\> $service.state Running PS C:\> $service.StopService() __GENUS : 2 __CLASS : __PARAMETERS __SUPERCLASS : __DYNASTY : __PARAMETERS __RELPATH : __PROPERTY_COUNT : 1 __DERIVATION : {} __SERVER : __NAMESPACE : __PATH : ReturnValue : 0
I directly invoked the StopService() method on the Spooler service object. A return value of 0 indicates success. Any other value indicates an error and you would need to search the MSDN documentation on the Win32_Service class to learn more.
The downside to this method is that there is no –Whatif or other cmdlet benefits. I prefer, and recommend using the Invoke-WmiMethod cmdlet. I find it easiest to get the WMI object and then pipe it to Invoke-WmiMethod.
PS C:\> get-wmiobject win32_service -filter "name='spooler'" | Invoke-WmiMethod-Name StartService -WhatIf What if: Performing operation "Invoke-WmiMethod" on Target "Win32_Service (StartService)". PS C:\> get-wmiobject win32_service -filter "name='spooler'" | Invoke-WmiMethod -Name StartService __GENUS : 2 __CLASS : __PARAMETERS __SUPERCLASS : __DYNASTY : __PARAMETERS __RELPATH : __PROPERTY_COUNT : 1 __DERIVATION : {} __SERVER : __NAMESPACE : __PATH : ReturnValue : 0
In the previous article I found services that were set to auto start but not running. Now I can modify that expression and go ahead and start the services.
PS C:\> get-wmiobject win32_service -filter "startmode='auto' AND state<>'Running'" -comp chi-dc03 | invoke-wmimethod -Name StartService
One downside to this is that the result object only shows the return value. If there are multiple services I have no way of knowing which service goes with which result. To solve that, you can use this variation.
PS C:\> get-wmiobject win32_service -filter "startmode='auto' AND state<>'Running'" -comp chi-dc01,chi-dc02,chi-dc03 | foreach { $svc = $_ ; $_ | Invoke-WmiMethod -Name StartService | Select @{Name="Name";Expression={$svc.name}},@{Name="DisplayName"; Expression={$svc.Displayname}},ReturnValue,@{Name="Computername";Expression={ $svc.Systemname}}} Name DisplayName ReturnValue Computername ---- ----------- ----------- ------------ sppsvc Software Protection 0 CHI-DC01 sppsvc Software Protection 0 CHI-DC02 VMTools VMware Tools Service 7 CHI-DC02 ShellHWDetection Shell Hardware Detection 0 CHI-DC03
In the ForEach scriptblock I save the incoming object to a variable, $svc, so that I can reuse it later as part of a hashtable defining a custom property. As you can see I have one error for a service that I thought I had deleted.
Changing the Start Mode
You can also change the start mode of a service as well. Valid options are Automatic, Disabled or Manual. There is no way with WMI to set the service to Automatic (Delayed).
PS C:\> get-wmiobject win32_service -filter "name='spooler'" | Invoke-WmiMethod -Name ChangeStartMode -ArgumentList "Manual" | Select ReturnValue ReturnValue ----------- 0
The ArgumentList parameter indicates what value to use. This needs to be run with administrator credentials, and if locally, in an elevated PowerShell session.
Setting Service Properties
There aren’t too many properties you can change on a service object. Some WMI objects can be modified with Set-WmiInstance. But with service objects, you need to use the object’s Change() method. The tricky part is that the method takes a large number of parameters:
Change(
string DisplayName,
string PathName,
uint32 ServiceType,
uint32 ErrorControl,
string StartMode,
boolean DesktopInteract,
string StartName,
string StartPassword,
string LoadOrderGroup,
string LoadOrderGroupDependencies,
string ServiceDependencies
)
And you have to include all the parameters up to the one you actually want to change. Use $Null for those you wish to skip. Here’s an example: let’s say I want to change the ErrorControl property of the Spooler service from Normal to Ignore. From researching the class property (http://msdn.microsoft.com/en-us/library/windows/desktop/aa384901(v=vs.85).aspx) I find that Normal has a value of 1 and Ignore is 0. I’ll try this in PowerShell.
PS C:\> Get-WmiObject win32_service -filter "Name='Spooler'" | Invoke-WmiMethod -Name Change -ArgumentList @($null,$null,$null,0) | Select ReturnValue ReturnValue ----------- 0
It looks like it worked, so I’ll verify.
PS C:\> get-wmiobject win32_service -filter "Name='spooler'" | select name,errorcontrol name errorcontrol ---- ------------ Spooler Normal
It did not. It turns out there is a little PowerShell quirk you have to be aware of. Even though the WMI method is expecting parameters in a given order, ErrorControl should have been 4th, when using Invoke-WmiMethod, the order is alphabetical. Don’t ask why. Here’s what I do to figure out the “correct” order.
PS C:\> $svc = Get-WmiObject win32_service -filter "name='spooler'" PS C:\> $svc.GetMethodParameters("change") __GENUS : 2 __CLASS : __PARAMETERS __SUPERCLASS : __DYNASTY : __PARAMETERS __RELPATH : __PROPERTY_COUNT : 11 __DERIVATION : {} __SERVER : __NAMESPACE : __PATH : DesktopInteract : DisplayName : ErrorControl : LoadOrderGroup : LoadOrderGroupDependencies : PathName : ServiceDependencies : ServiceType : StartMode : StartName : StartPassword : PSComputerName :
In this list, ErrorControl is 3rd so I can now re-run my modified Invoke-WmiMethod expression.
PS C:\> Get-WmiObject win32_service -filter "Name='Spooler'" | Invoke-WmiMethod -Name Change -ArgumentList @($null,$null,0)
Checking again, I now see the change I was expecting.
PS C:\> get-wmiobject win32_service -filter "Name='spooler'" | select name,errorcontrol name errorcontrol ---- ------------ Spooler Ignore
Remember, in the argument list you need to include $null for any properties you are skipping up to the one you want to set. There is no need to specify anything for any properties that follow. In an upcoming article we’ll look specifically at working with the service account since that is something you are most likely going to do in PowerShell.
Subscribe to 4sysops newsletter!
Summary
Using WMI to manage services in your environment is very useful, especially for those situations where you can’t use any of the “normal” service cmdlets. Or for those odd scenarios where WMI is the only answer. But if you are running PowerShell 3.0 you also have the option of using the CIM cmdlets, which I’ll cover in the next article.