The other day I showed you how to use ADSI and PowerShell to manage services on remote computers. Since the ADSI type adapter is admittedly “kludgy” at times, I put together a script that you could use like a cmdlet to retrieve service information via ADSI.
1: #Get-RemoteService.ps1
2:
3: param([string]$computername=$env:computername,
4: [string]$service=$(Throw "You must enter a service name like spooler")
5: )
6:
7: function Decode-StartType {
8: Param([int]$startType)
9:
10: Switch ($startType) {
11: 0 {"Boot"}
12: 1 {"System"}
13: 2 {"Automatic"}
14: 3 {"Manual"}
15: 4 {"Disabled"}
16: default {"Unknown"}
17: }
18: }
19:
20: Function Decode-ServiceType {
21: Param([int]$ServiceType)
22:
23: Switch ($ServiceType ) {
24: 1 {"Kernel-Mode Driver"}
25: 2 {"File System Driver"}
26: 4 {"Adapter Arguments"}
27: 8 {"File System Driver Service"}
28: 16 {"Own Process"}
29: 32 {"Shared Process"}
30: 272 {"Own Process - Interactive"}
31: 288 {"Shared Process - Interactive"}
32: default {"Unknown"}
33: }
34: }
35:
36: [ADSI]$svc="WinNT://$computername/$service,service"
37:
38: if ($svc.name)
39: {
40: #connection made to valid service
41: if ($svc.status -eq 4) {$status="Running"}
42: elseif ($svc.status -eq 1) {$status="Stopped"}
43: else {$status="Unknown"}
44:
45: $obj=New-Object PSobject
46:
47: $obj | Add-Member NoteProperty "Computername" $computername.toUpper()
48: $obj | Add-Member NoteProperty "Service" $svc.name.value
49: $obj | Add-Member NoteProperty "DisplayName" $svc.displayname.value
50: $obj | Add-Member NoteProperty "Status" $status
51: $obj | Add-Member NoteProperty "StartType" (Decode-StartType $svc.startType.value)
52: $obj | Add-Member NoteProperty "ServiceType" (Decode-ServiceType $svc.servicetype.value)
53: $obj | Add-Member NoteProperty "ServiceAccount" $svc.serviceaccountname.value
54: $obj | Add-Member NoteProperty "Path" $svc.Path.Value
55:
56: write $obj
57: }
58: else
59: {
60: Write-Warning ("Failed to find the {0} service on {1}" -f $service,$computername.ToUpper())
61: }
62:
The script creates custom object that uses more admin friendly values.
PS C:\> c:\scripts\posh\get-remoteservice -computer godot -service remoteregistry
Computername : GODOT
Service : remoteregistry
DisplayName : Remote Registry
Status : Running
StartType : Automatic
ServiceType : Shared Process
ServiceAccount : NT AUTHORITY\LocalService
Path : C:\WINDOWS\system32\svchost.exe -k LocalService
But what about finding all the services? You can use ADSI for this as well. Try these commands
PS C:\> [ADSI]$server=”WinNT://$env:computername”
PS C:\> $server.psbase.children | Where {$_.class -eq “service”} | format-table Name,Displayname,Status -autosize
You can substitute any computername you want. $env:computername will resolve to your computername. Of course the output leaves a little to be desired. Ergo, another script.
1: #Get-AllRemoteService.ps1
2:
3: param([string]$computername=$env:computername)
4:
5: function Decode-StartType {
6: Param([int]$startType)
7:
8: Switch ($startType) {
9: 0 {"Boot"}
10: 1 {"System"}
11: 2 {"Automatic"}
12: 3 {"Manual"}
13: 4 {"Disabled"}
14: default {"Unknown:$starttype"}
15: }
16: }
17:
18: Function Decode-ServiceType {
19: Param([int]$ServiceType)
20:
21: Switch ($ServiceType ) {
22: 1 {"Kernel-Mode Driver"}
23: 2 {"File System Driver"}
24: 4 {"Adapter Arguments"}
25: 8 {"File System Driver Service"}
26: 16 {"Own Process"}
27: 32 {"Shared Process"}
28: 272 {"Own Process - Interactive"}
29: 288 {"Shared Process - Interactive"}
30: default {"Unknown:$servicetype"}
31: }
32: }
33:
34: [ADSI]$server="WinNT://$computername"
35:
36: if ($server.name)
37: {
38: #connection made to valid server
39: #filter child objects and get services
40: $services=$server.psbase.children | where {$_.class -eq "service"}
41:
42: foreach ($svc in $services) {
43: if ($svc.status -eq 4) {$status="Running"}
44: elseif ($svc.status -eq 1) {$status="Stopped"}
45: else {$status="Unknown"}
46:
47: $obj=New-Object PSobject
48:
49: $obj | Add-Member NoteProperty "Computername" $computername.toUpper()
50: $obj | Add-Member NoteProperty "Service" $svc.name.value
51: $obj | Add-Member NoteProperty "DisplayName" $svc.displayname.value
52: $obj | Add-Member NoteProperty "Status" $status
53: $obj | Add-Member NoteProperty "StartType" (Decode-StartType $svc.startType.value)
54: $obj | Add-Member NoteProperty "ServiceType" (Decode-ServiceType $svc.servicetype.value)
55: $obj | Add-Member NoteProperty "ServiceAccount" $svc.serviceaccountname.value
56: $obj | Add-Member NoteProperty "Path" $svc.Path.Value
57:
58: write $obj
59: } #end foreach
60: } #end if
61: else
62: {
63: Write-Warning ("Failed to connect to {0}" -f $computername.ToUpper())
64: }
This script merely needs a computername as a parameter. It will default to the localhost.
PS C:\Scripts> .\get-allremoteservice FILE02
You’ll get my custom service object for every service on that computer. Of course, because the script is writing an object to the pipeline you can sort, filter, group, export and anything else you’d like to do.
PS C:\scripts> .\get-allremoteservice | where {$_.status -eq “running”} | sort ServiceAccount | format-table -groupby ServiceAccount service,Displayname,StartType,ServiceType
Eventually you’ll be able to use Get-Service everywhere (in PowerShell v2.0), but this might be a valuable alternative until then.
Get both scripts here in a convenient zip file.