Managing Services with PowerShell and ADSI

In PowerShell v1.0, if you want to manage services on a remote computer, you likely used WMI and the Get-WMIObject cmdlet. But there is another solution using ADSI. If you use the WinNT provider, you can access all of the services on a remote machine in much the same way you would manage local users and groups. Let me show you.

First, connect to the remote computer and specify the service:

PS C:\> [ADSI]$svc=”WinNT://godot/spooler,service”

The $svc object now represents the spooler service on the computer GODOT. There isn’t really valid way to specify alternate credentials. However, if you have an existing secure channel to the remote computer ADSI will use it. In this situation GODOT is a stand alone machine. I mapped a drive to the C$ share using GODOT credentials. My ADSI object will use this connection.

Pipe the object to Select-Object to see all of its properties:

PS C:\> $svc | select *

Path               : {C:\WINDOWS\system32\spoolsv.exe}
LoadOrderGroup     : {SpoolerGroup}
Dependencies       : {RPCSS}
ServiceAccountName : {LocalSystem}
DisplayName        : {Print Spooler}
ServiceType        : {272}
StartType          : {2}
ErrorControl       : {1}
Name               : {spooler}
AuthenticationType : Secure
Children           : {}
Guid               : {C3968E50-4C66-11CF-A995-00AA006BC149}
ObjectSecurity     :
NativeGuid         : {C3968E50-4C66-11CF-A995-00AA006BC149}
NativeObject       : System.__ComObject
Parent             : WinNT://WORKGROUP/godot
Password           :
Properties         : {Path, LoadOrderGroup, Dependencies, ServiceAccountName…}
SchemaClassName    : Service
SchemaEntry        : System.DirectoryServices.DirectoryEntry
UsePropertyCache   : True
Username           :
Options            :
Site               :
Container          :

You might get some error messages about reading object security and the password but that’s ok. Unfortunately one thing you don’t see is the Status property, but its there if you know it exists:

PS C:\> $svc.status
4

A value of 4 indicates the service is running. A value of 1 indicates stopped. You also won’t see this property if you pipe the object to Get-Member. In fact you won’t see much. But there are methods you can use to stop and start the service.

PS C:\> $svc.stop()
PS C:\> $svc.status
1
PS C:\> $svc.start()
PS C:\> $svc.status
4
PS C:\>

Pretty easy if you ask me.
There are a few other values you may want help in decoding. First is the StartType. The integer value can be decoded with a function like this:

function Decode-StartType {
    Param([int]$startType)

    Switch ($startType) {
        0    {“Boot”}
        1    {“System”}
        2    {“Automatic”}
        3    {“Manual”}
        4    {“Disabled”}
       default    {“Unknown”}
    }
}

You can do something similar with the ServiceType:

Function Decode-ServiceType {
    Param([int]$ServiceType)
    Switch ($ServiceType ) {
      1     {“Kernel-Mode Driver”}
      2     {“File System Driver”}
      4     {“Adapter Arguments”}
      8     {“File System Driver Service”}
      16    {“Own Process”}
      32    {“Shared Process”}
      272   {“Own Process – Interactive”}
      288   {“Shared Process – Interactive”}
      default   {“Unknown”}
     }
}

Thus you might do something along these lines:

$svc | select @{name=”Service”;Expression={$_.name.value}},`
@{name=”DisplayName”;Expression={$_.displayname.value}},`
@{name=”Status”;Expression={
    if ($_.status -eq 4) {“Running”}
    elseif ($_.status -eq 1) {“Stopped”}
    else {“Unknown”}
}},`
@{name=”StartType”;Expression={Decode-StartType $_.startType.value}},`
@{name=”ServiceType”;Expression={Decode-ServiceType $_.servicetype.value}},
@{name=”ServiceAccount”;Expression={$_.serviceaccountname.value }}

When executed I get:

Service        : spooler
DisplayName    : Print Spooler
Status         : Running
StartType      : Automatic
ServiceType    : Own Process – Interactive
ServiceAccount : LocalSystem

I’ll be back tomorrow with more fun on this topic.