Day: April 22, 2026
PowerShell: Audit Local Administrators on Remote Servers

One of the most common security risks in a Windows environment is “Privilege Creep”—where users or service accounts are added to the Local Administrators group and never removed. Manually checking every server is impossible, and Group Policy Preferences don’t always show you the “extra” accounts that might have been added manually.
This PowerShell script allows you to sweep your network, query any local group (Administrators, Remote Desktop Users, etc.), and categorize the members into Local vs. Domain accounts in a clean CSV report.
The PowerShell Script
Save this code as Get-LocalGroupMembers.ps1. It uses the [ADSI] (Active Directory Service Interfaces) provider to connect to the local SAM database of remote computers, which is highly compatible across different Windows versions.
[CmdletBinding()]Param( [Parameter(ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true)] [string[]]$ComputerName = $env:ComputerName, [Parameter()] [string]$LocalGroupName = "Administrators", [Parameter()] [string]$OutputDir = "C:\temp\localadmin\")Begin { # Ensure directory exists and initialize CSV if (!(Test-Path $OutputDir)) { New-Item -ItemType Directory -Path $OutputDir } $OutputFile = Join-Path $OutputDir "LocalGroupMembers.csv" Add-Content -Path $OutPutFile -Value "ComputerName, LocalGroupName, Status, MemberType, MemberDomain, MemberName"}Process { ForEach($Computer in $ComputerName) { Write-Host "Working on $Computer..." -ForegroundColor Cyan If(!(Test-Connection -ComputerName $Computer -Count 1 -Quiet)) { Add-Content -Path $OutputFile -Value "$Computer,$LocalGroupName,Offline" Continue } else { try { $group = [ADSI]"WinNT://$Computer/$LocalGroupName" $members = @($group.Invoke("Members")) if(!$members) { Add-Content -Path $OutputFile -Value "$Computer,$LocalGroupName,NoMembersFound" continue } } catch { Add-Content -Path $OutputFile -Value "$Computer,,FailedToQuery" Continue } foreach($member in $members) { try { $MemberName = $member.GetType().Invokemember("Name","GetProperty",$null,$member,$null) $MemberType = $member.GetType().Invokemember("Class","GetProperty",$null,$member,$null) $MemberPath = $member.GetType().Invokemember("ADSPath","GetProperty",$null,$member,$null) # Determine if member is Local or Domain if($MemberPath -match "^Winnt\:\/\/(?<domainName>\S+)\/(?<CompName>\S+)\/") { $MemberType = if($MemberType -eq "User") { "LocalUser" } else { "LocalGroup" } $MemberDomain = $matches["CompName"] } elseif($MemberPath -match "^WinNT\:\/\/(?<domainname>\S+)/") { $MemberType = if($MemberType -eq "User") { "DomainUser" } else { "DomainGroup" } $MemberDomain = $matches["domainname"] } else { $MemberType = "Unknown"; $MemberDomain = "Unknown" } Add-Content -Path $OutPutFile -Value "$Computer, $LocalGroupName, SUCCESS, $MemberType, $MemberDomain, $MemberName" } catch { Add-Content -Path $OutputFile -Value "$Computer,,FailedQueryMember" } } } }}
How to Use This Script
Audit All Servers from a List
Create a servers.txt file with your hostnames and run:
.\Get-LocalGroupMembers.ps1 -ComputerName (Get-Content C:\temp\servers.txt) -OutputDir C:\temp\Reports\
Query a Specific Group (e.g., Remote Desktop Users)
.\Get-LocalGroupMembers.ps1 -ComputerName "SRV-PROD-01" -LocalGroupName "Remote Desktop Users"
Key Benefits
- Member Classification: The script identifies if an account is a LocalUser or a DomainUser, which is vital for identifying accounts that shouldn’t be there.
- Offline Handling: It pings the computer first to prevent the script from hanging on a dead connection.
- ADSI Speed: Using
[ADSI](WinNT provider) is often faster than using WMI for specific group queries and doesn’t require WinRM to be enabled likeInvoke-Command.