Get Local Admin Group Members in a New Old Way

by PowerShell.org Announcer


Yesterday I posted a quick article on getting the age of the local administrator account password. It seemed appropropriate to follow up on a quick and dirty way to list all members of the local administrator group. Normally, I would turn to WMI (and have written about this in the past). But WMI is relatively slow for this task and even using the new CIM cmdlets in PowerShell 3.0 don’t improve performance. Instead I’m going to return to an old school technique using the NET command.

PS C:\> net localgroup administrators
Alias name     administrators
Comment        Administrators have complete and unrestricted access to the computer/domain

Members

-------------------------------------------------------------------------------
Administrator
GLOBOMANTICS\Domain Admins
localadmin
The command completed successfully.

It is very easy to see members. To query a remote computer all I need to do is wrap this in Invoke-Command and use PowerShell remoting.

PS C:\> invoke-command {net localgroup administrators} -comp chi-fp01
Alias name     administrators
Comment        Administrators have complete and unrestricted access to the computer/domain

Members

-------------------------------------------------------------------------------
Administrator
GLOBOMANTICS\Chicago IT
GLOBOMANTICS\Domain Admins
The command completed successfully.

Yes, there is some overhead for remoting but overall performance is pretty decent. And if you already have an established PSSession, even better. For quick and dirty one-liner it doesn’t get much better. Well, maybe it can.

I have no problem using legacy tools when they still get the job done and this certainly qualifies. To make it more PowerShell friendly though, let’s clean up the output by filtering out blanks, that last line and skipping the “header” lines.

PS C:\> invoke-command {
>> net localgroup administrators | 
>> where {$_ -AND $_ -notmatch "command completed successfully"} | 
>> select -skip 4
>> } -computer chi-fp01
>>
Administrator
GLOBOMANTICS\Chicago IT
GLOBOMANTICS\Domain Admins

Boom. Now I only get the member names. Let’s go one more level and write an object to the pipeline and be better at handling output from multiple computers. I came up with a scriptblock like this:

$members = net localgroup administrators | 
 where {$_ -AND $_ -notmatch "command completed successfully"} | 
 select -skip 4
New-Object PSObject -Property @{
 Computername = $env:COMPUTERNAME
 Group = "Administrators"
 Members=$members
 }

This will create a simple object with a properties for the computername, group name and members. Here’s how I can use it with Invoke-Command.

invoke-command {
$members = net localgroup administrators | 
 where {$_ -AND $_ -notmatch "command completed successfully"} | 
 select -skip 4
New-Object PSObject -Property @{
 Computername = $env:COMPUTERNAME
 Group = "Administrators"
 Members=$members
 }
} -computer chi-fp01,chi-win8-01,chi-ex01 -HideComputerName | 
Select * -ExcludeProperty RunspaceID

get-netlocalgroupNow I have objects that I can export to XML, convert to HTML or send to a file. But since I’ve come this far, I might as well take a few more minutes and turn this into a reusable tool.

Function Get-NetLocalGroup {
[cmdletbinding()]

Param(
[Parameter(Position=0)]
[ValidateNotNullorEmpty()]
[object[]]$Computername=$env:computername,
[ValidateNotNullorEmpty()]
[string]$Group = "Administrators",
[switch]$Asjob
)

Write-Verbose "Getting members of local group $Group"

#define the scriptblock
$sb = {
 Param([string]$Name = "Administrators")
$members = net localgroup $Name | 
 where {$_ -AND $_ -notmatch "command completed successfully"} | 
 select -skip 4
New-Object PSObject -Property @{
 Computername = $env:COMPUTERNAME
 Group = $Name
 Members=$members
 }
} #end scriptblock

#define a parameter hash table for splatting
$paramhash = @{
 Scriptblock = $sb
 HideComputername=$True
 ArgumentList=$Group
 }

if ($Computername[0] -is [management.automation.runspaces.pssession]) {
    $paramhash.Add("Session",$Computername)
}
else {
    $paramhash.Add("Computername",$Computername)
}

if ($asjob) {
    Write-Verbose "Running as job"
    $paramhash.Add("AsJob",$True)
}

#run the command
Invoke-Command @paramhash | Select * -ExcludeProperty RunspaceID

} #end Get-NetLocalGroup

This function lets me specify a group of computers or PSSessions as well as the local group name. Today I may need to know who belongs to the local administrator’s group but tomorrow it might be Remote Desktop Users.

PS C:\> Get-NetLocalGroup -Group "remote desktop users" -Computername $sessions

Group        : remote desktop users
Computername : CHI-FP01
Members      : 

Group        : remote desktop users
Computername : CHI-WIN8-01
Members      : 

Computername : CHI-EX01
Members      : 
Group        : remote desktop users

Group        : remote desktop users
Computername : CHI-DC01
Members      : jfrost

Sometimes even old school tools can still be a part of your admin toolkit.