Security/Get-LocalAdmins.ps1
|
<#
.SYNOPSIS Reports members of the local Administrators group on one or more computers. .DESCRIPTION Retrieves all members of the local Administrators group, including nested group membership. Works on local or remote computers. Useful for security baseline checks, compliance audits, and identifying unauthorized admin access. No external modules required. Uses built-in CIM/WMI for remote queries. .PARAMETER ComputerName One or more computer names to query. Defaults to the local computer. Accepts pipeline input. .PARAMETER Credential Credential for remote computer access. Not needed for the local computer. .PARAMETER OutputPath Optional path to export results as CSV. .EXAMPLE PS> .\Security\Get-LocalAdmins.ps1 Lists local Administrators group members on the current computer. .EXAMPLE PS> .\Security\Get-LocalAdmins.ps1 -ComputerName 'SERVER01','SERVER02' Lists local admins on multiple remote computers. .EXAMPLE PS> Get-Content .\servers.txt | .\Security\Get-LocalAdmins.ps1 -OutputPath '.\local-admins.csv' Reads server names from a file and exports all local admin members to CSV. .EXAMPLE PS> .\Security\Get-LocalAdmins.ps1 -ComputerName 'SERVER01' -Credential (Get-Credential) Queries a remote server using alternate credentials. #> [CmdletBinding()] param( [Parameter(ValueFromPipeline, ValueFromPipelineByPropertyName)] [Alias('CN')] [string[]]$ComputerName = @($env:COMPUTERNAME), [Parameter()] [PSCredential]$Credential, [Parameter()] [string]$OutputPath ) begin { $allResults = [System.Collections.Generic.List[PSCustomObject]]::new() } process { foreach ($computer in $ComputerName) { Write-Verbose "Querying local Administrators on $computer" try { if ($computer -eq $env:COMPUTERNAME -and -not $Credential) { # Local computer - use Get-LocalGroupMember directly $members = Get-LocalGroupMember -Group 'Administrators' foreach ($member in $members) { $allResults.Add([PSCustomObject]@{ ComputerName = $computer Name = $member.Name ObjectClass = $member.ObjectClass PrincipalSource = $member.PrincipalSource }) } } else { # Remote computer - use CIM $cimSession = $null $cimParams = @{ ComputerName = $computer } if ($Credential) { $sessionParams = @{ ComputerName = $computer Credential = $Credential } $cimSession = New-CimSession @sessionParams $cimParams = @{ CimSession = $cimSession } } $query = "SELECT * FROM Win32_GroupUser WHERE GroupComponent=`"Win32_Group.Domain='$computer',Name='Administrators'`"" $members = Get-CimInstance -Query $query @cimParams foreach ($member in $members) { $partComponent = $member.PartComponent $memberName = "$($partComponent.Domain)\$($partComponent.Name)" $objectClass = if ($partComponent.CimClass.CimClassName -eq 'Win32_UserAccount') { 'User' } else { 'Group' } $allResults.Add([PSCustomObject]@{ ComputerName = $computer Name = $memberName ObjectClass = $objectClass PrincipalSource = 'N/A' }) } if ($cimSession) { Remove-CimSession -CimSession $cimSession } } } catch { Write-Warning "Failed to query $computer`: $_" $allResults.Add([PSCustomObject]@{ ComputerName = $computer Name = "ERROR: $_" ObjectClass = 'Error' PrincipalSource = 'N/A' }) } } } end { if ($OutputPath) { $allResults | Export-Csv -Path $OutputPath -NoTypeInformation -Encoding UTF8 Write-Output "Exported $($allResults.Count) entries from $($ComputerName.Count) computer(s) to $OutputPath" } else { Write-Output $allResults } } |