In the previous article of this series we looked at using WMI in PowerShell to discover service information. The WMI service object offers a few properties missing from the .NET service object. And while we can use Set-Service to modify a service object, there may be situations where you want or need to use WMI.

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.

0 Comments

Leave a reply

Please enclose code in pre tags

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

*

© 4sysops 2006 - 2021

CONTACT US

Please ask IT administration questions in the forums. Any other messages are welcome.

Sending

Log in with your credentials

or    

Forgot your details?

Create Account