We brought on a new client with a lot of servers and as part of our due diligence, we needed to review all of the local administrators on each server. We wanted to make sure the previous MSP’s staff were removed and to provide list of questionable admins to our customer.

powershell export all local admins

To that end we built the script below which queries Active Directory for all member servers (i.e. ignore desktops, printers…):

  • If the “Administrators” group is not found, the server is assumed to be a Domain Controller and skipped, which is noted in the results.SV indicating this.
  • If a “WinRM cannot complete the operation” error occurs, the server is listed with a connection error.
  • The script outputs the server name and the names of the direct members (users and groups) of the local Administrators group on member servers, without expanding nested groups.
  • The results, including skipped DCs and connection errors, are displayed on screen and exported to C:\temp\localadmins.csv.

We just copy paste the script into a Windows Terminal or PowerShell as an Administrator, but you can save it as a .PS1 (like .\Get-MemberServerLocalAdmins.ps1 ) and run it that way.

You can run this script from a domain-joined machine as a domain admin (so you can query Active Directory and connect to remote servers). Note that WinRM must be enabled on the target servers.


param()

# Get the current domain name
$Domain = Get-ADDomain | Select-Object -ExpandProperty NetBIOSName

# Get all computers that appear to be servers based on their OS
$PotentialMemberServers = Get-ADComputer -Filter "OperatingSystem -like '*Server*'" | Select-Object -ExpandProperty Name

# Array to store the results
$Results = @()

# Loop through each potential member server
foreach ($Server in $PotentialMemberServers) {
    Write-Host "Processing server: $Server"

    try {
        # Attempt to get the local Administrators group members
        $LocalAdmins = Invoke-Command -ComputerName $Server -ScriptBlock {
            (Get-LocalGroupMember -Group "Administrators").Name
        } -ErrorAction Stop

        # If successful, add the server name and each admin to the results array
        foreach ($Admin in $LocalAdmins) {
            $Results += [PSCustomObject]@{
                ServerName = $Server
                LocalAdmin = $Admin
            }
        }
    }
    catch {
        if ($_.Exception.Message -like "*Group Administrators was not found*") {
            Write-Host "Skipping $Server as it appears to be a Domain Controller (no local Administrators group)."
            $Results += [PSCustomObject]@{
                ServerName = $Server
                LocalAdmin = "Skipped - Likely a DC"
            }
        } elseif ($_.Exception.Message -like "*WinRM cannot complete the operation*") {
            Write-Warning "Failed to connect to server $Server via WinRM. This often indicates network connectivity issues or firewall rules blocking communication (potentially RPC)."
            $Results += [PSCustomObject]@{
                ServerName = $Server
                LocalAdmin = "Could not connect via WinRM"
            }
        } else {
            # For other errors, display a generic warning
            Write-Warning "Failed to connect to or retrieve local administrators from server: $Server - $($_.Exception.Message)"
        }
    }
}

# Display the results and export to CSV
if ($Results.Count -gt 0) {
    Write-Host "`n--- Local Administrators and Server Status ---"
    $Results | Format-Table -AutoSize

    # Export the results to CSV
    $Results | Export-Csv -Path "C:\temp\localadmins.csv" -NoTypeInformation
    Write-Host "`nData exported to C:\temp\localadmins.csv (including skipped DCs and connection errors)."
} else {
    Write-Host "`nNo member servers found with local administrators."
}

Want To Also Query PC’s?

To include PCs (workstations/clients) in the output while still skipping Domain Controllers, you need to adjust the initial Get-ADComputer filter. Currently, it’s looking for operating systems containing “Server”. You’ll need to broaden this to include typical PC operating system names while explicitly excluding “Domain Controller”.

Here’s the line you need to modify:

Original Line:

PowerShell

$PotentialMemberServers = Get-ADComputer -Filter "OperatingSystem -like '*Server*'" | Select-Object -ExpandProperty Name

Modified Line:

PowerShell

$PotentialMemberServers = Get-ADComputer -Filter * | Where-Object {$_.OperatingSystem


0 Comments

Leave a Reply

Avatar placeholder

Your email address will not be published. Required fields are marked *