One drawback to the service objects returned from Get-Service is that you can’t see what account the service is running under, often referred to as the service account. This will be something like LocalService or perhaps even a special user account like Mydomain\svcAccount123. You can retrieve this information by querying Windows Management Instrumentation (WMI) and the Win32_Service class. But did you know you can also use ADSI?
First connect to the computer:
PS C:\> [ADSI]$server=”WinNT://$env:computername”
The services will be child objects like users and groups. However, you need a little coding to coax them out into the open.
PS C:\> $server.psbase.children | where {$_.SchemaClassName -eq “Service”}
You should get a list of service objects. But if our goal is to simply retrieve the service account name, how about a script?
#Get-ServiceAccountName.ps1
Param ([string]$computername=$env:computername)
[ADSI]$server="WinNT://$computername"
$server.psbase.children | where {$_.SchemaClassName -eq "Service"} |
select @{name="Computername";Expression={$computername.toUpper()}},`
@{name="Service";Expression={$_.name}},`
@{name="DisplayName";Expression={$_.DisplayName}},`
@{name="AccountName";Expression={$_.ServiceAccountName}},`
@{name="Path";Expression={$_.Path}}
# end of script
The script takes a computer name as a parameter, defaulting to the local computer. The script queries the service objects and returns a custom object like this:
Computername : CHAOS
Service : SQLWriter
DisplayName : SQL Server VSS Writer
AccountName : LocalSystem
Path : “C:\Program Files\Microsoft SQL Server\90\Shared\sqlwriter.exe”
I include the computername so that if you process a list of computers and want to save the output you can keep track of which service is on which computer.
PS C:\> get-content servers.txt | foreach {c:\scripts\get-serviceaccountname.ps1 $_ } | export-csv svcaccounts.csv
Or perhaps you’d this wrapped up in a function:
Function Get-ServiceAccountName {
Param ([string]$computername=$env:computername)
[ADSI]$server="WinNT://$computername"
$server.psbase.children | where {$_.SchemaClassName -eq "Service"} |
select @{name="Computername";Expression={$computername.toUpper()}},`
@{name="Service";Expression={$_.name}},`
@{name="DisplayName";Expression={$_.DisplayName}},`
@{name="AccountName";Expression={$_.ServiceAccountName}},`
@{name="Path";Expression={$_.Path}}
}
Nothing really changes. Or perhaps you’d like a function that accepts pipelined input:
Function Get-ServiceAccountName {
PROCESS {
[string]$computername=$_
[ADSI]$server="WinNT://$computername"
$server.psbase.children | where {$_.SchemaClassName -eq "Service"} |
select @{name="Computername";Expression={$computername.toUpper()}},`
@{name="Service";Expression={$_.name}},`
@{name="DisplayName";Expression={$_.DisplayName}},`
@{name="AccountName";Expression={$_.ServiceAccountName}},`
@{name="Path";Expression={$_.Path}}
}
}
Now you can run expressions like these:
PS C:\> “ServerA”,”ServerB1″ | get-serviceAccountname | Sort Computername,Accountname | format-table computername,Service,Accountname
PS C:\> Get-Content computers.txt | get-serviceAccountname | where {$_.accountname -match “administrator”}
The second example will return all accounts with “administrator” in the name; handy if you want to see which services are running as a domain or local administrator.
This function comes in handy come audit time. By the way, you need administrative rights on any remote computer. There isn’t a way to pass alternate credentials, but even if you have a drive mapped with alternate credentials, that will be sufficient.
Download a text file with all these variations here.
1 comment on “Get ServiceAccount Name with ADSI”
Comments are closed.