-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathGet-LocalAdminReport.ps1
More file actions
156 lines (132 loc) · 6.6 KB
/
Copy pathGet-LocalAdminReport.ps1
File metadata and controls
156 lines (132 loc) · 6.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
#Requires -Version 5.1
<#
.SYNOPSIS
Local Admin Report - Audits local Administrators group membership across computers.
.DESCRIPTION
Connects to one or multiple remote computers and enumerates all members of the
local Administrators group. Helps detect:
- Unauthorized local admin accounts
- Domain accounts with unexpected local admin rights
- Stale or unrecognized local accounts with elevated privileges
- Computers where too many users have local admin access
.PARAMETER ComputerName One or more computer names. Defaults to local machine.
.PARAMETER OUPath OU distinguished name to pull all computers from AD.
.PARAMETER OutputPath Report directory. Defaults to Desktop.
.PARAMETER FlagDomainUsers Flag any domain user accounts (not groups) found in local admins.
.EXAMPLE
.\21_Get-LocalAdminReport.ps1
.\21_Get-LocalAdminReport.ps1 -ComputerName "PC01","PC02","PC03"
.\21_Get-LocalAdminReport.ps1 -OUPath "OU=Workstations,DC=corp,DC=local"
.\21_Get-LocalAdminReport.ps1 -OUPath "OU=Workstations,DC=corp,DC=local" -FlagDomainUsers
.NOTES
Requires: Remote Registry / WinRM enabled on target machines.
Run as Domain Admin or with local admin rights on targets.
Author : IT Administration Team | Version: 1.0
#>
[CmdletBinding()]
param(
[string[]]$ComputerName = @($env:COMPUTERNAME),
[string]$OUPath = "",
[string]$OutputPath = "$env:USERPROFILE\Desktop",
[switch]$FlagDomainUsers
)
if (-not (Test-Path $OutputPath)) { New-Item -ItemType Directory -Path $OutputPath -Force | Out-Null }
$timestamp = Get-Date -Format "yyyyMMdd_HHmmss"
$logFile = Join-Path $OutputPath "LocalAdminReport_$timestamp.log"
function Write-Log {
param([string]$M, [string]$L = "INFO")
$e = "$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss') [$L] $M"
Add-Content $logFile $e -ErrorAction SilentlyContinue
Write-Host " $e" -ForegroundColor $(switch($L) { "ERROR"{"Red"} "WARN"{"Yellow"} "OK"{"Green"} default{"Gray"} })
}
# Pull computers from AD OU if specified
if ($OUPath) {
try {
Write-Host " Pulling computers from OU: $OUPath" -ForegroundColor Gray
$ComputerName = (Get-ADComputer -Filter * -SearchBase $OUPath -ErrorAction Stop).Name
Write-Host " Found $($ComputerName.Count) computer(s) in OU" -ForegroundColor Cyan
} catch {
Write-Host " [ERROR] Failed to query AD: $($_.Exception.Message)" -ForegroundColor Red
exit 1
}
}
Write-Host "`nLocal Admin Report" -ForegroundColor Green
Write-Host " Scanning $($ComputerName.Count) computer(s)...`n" -ForegroundColor Cyan
$report = [System.Collections.Generic.List[object]]::new()
$reachable = 0
$unreachable = 0
$flagged = [System.Collections.Generic.List[object]]::new()
foreach ($computer in $ComputerName) {
Write-Host " [$computer]" -ForegroundColor Cyan -NoNewline
# Ping check
if (-not (Test-Connection -ComputerName $computer -Count 1 -Quiet -ErrorAction SilentlyContinue)) {
Write-Host " UNREACHABLE" -ForegroundColor Red
Write-Log "UNREACHABLE: $computer" "WARN"
$report.Add([PSCustomObject]@{ Computer=$computer; Member="N/A"; MemberType="N/A"; Domain="N/A"; Status="Unreachable"; Flagged=$false })
$unreachable++
continue
}
try {
# Get local admins via ADSI
$admins = ([ADSI]"WinNT://$computer/Administrators,group").Invoke("Members") |
ForEach-Object {
$member = [ADSI]$_
[PSCustomObject]@{
Name = $member.Name[0]
Path = $member.Path
Class = $member.Class[0]
}
}
Write-Host " $($admins.Count) member(s)" -ForegroundColor $(if ($admins.Count -gt 3) { "Yellow" } else { "Green" })
foreach ($admin in $admins) {
# Parse domain from WinNT path: WinNT://DOMAIN/Username
$parts = $admin.Path -replace "WinNT://","" -split "/"
$domain = if ($parts.Count -ge 2) { $parts[0] } else { "LOCAL" }
$isDomainUser = ($domain -ne $computer -and $admin.Class -eq "User")
$flag = $FlagDomainUsers -and $isDomainUser
if ($flag) {
Write-Host (" *** FLAGGED: {0}\{1} (Domain User with local admin)" -f $domain, $admin.Name) -ForegroundColor Red
$flagged.Add([PSCustomObject]@{ Computer=$computer; Account="$domain\$($admin.Name)" })
} else {
Write-Host (" - {0,-25} Type:{1,-10} Domain:{2}" -f $admin.Name, $admin.Class, $domain)
}
$report.Add([PSCustomObject]@{
Computer = $computer
Member = $admin.Name
MemberType = $admin.Class
Domain = $domain
IsDomainUser = $isDomainUser
Status = "OK"
Flagged = $flag
})
}
Write-Log "Scanned: $computer | $($admins.Count) admin member(s)" "OK"
$reachable++
} catch {
Write-Host " ERROR: $($_.Exception.Message)" -ForegroundColor Red
Write-Log "ERROR on $computer : $($_.Exception.Message)" "ERROR"
$report.Add([PSCustomObject]@{ Computer=$computer; Member="ERROR"; MemberType="N/A"; Domain="N/A"; Status=$_.Exception.Message; Flagged=$false })
$unreachable++
}
}
# Summary
Write-Host "`n ================================================" -ForegroundColor Cyan
Write-Host " SUMMARY" -ForegroundColor Cyan
Write-Host " ================================================" -ForegroundColor Cyan
Write-Host " Computers scanned : $($ComputerName.Count)"
Write-Host " Reachable : $reachable" -ForegroundColor Green
Write-Host " Unreachable : $unreachable" -ForegroundColor $(if($unreachable){"Red"}else{"White"})
Write-Host " Total admin entries: $($report.Count)"
if ($flagged.Count -gt 0) {
Write-Host "`n *** $($flagged.Count) FLAGGED: Domain users with local admin rights ***" -ForegroundColor Red
$flagged | ForEach-Object { Write-Host " - $($_.Computer): $($_.Account)" -ForegroundColor Red }
}
# Computers with unusually high admin count
$highAdmin = $report | Where-Object { $_.Status -eq "OK" } | Group-Object Computer | Where-Object { $_.Count -gt 3 }
if ($highAdmin) {
Write-Host "`n Computers with more than 3 local admins:" -ForegroundColor Yellow
$highAdmin | ForEach-Object { Write-Host " - $($_.Name): $($_.Count) members" -ForegroundColor Yellow }
}
$csv = Join-Path $OutputPath "LocalAdminReport_$timestamp.csv"
$report | Export-Csv $csv -NoTypeInformation
Write-Host "`n [OK] Report exported: $csv" -ForegroundColor Green