powershell script for active directory audit​

The Lazy Admin’s Guide to Active Directory Audits with PowerShell (Real Scripts Inside!)

Let’s be honest: manually auditing Active Directory feels like counting grains of sand on a beach. It’s tedious, error-prone, and you *know* there are hidden risks lurking in stale accounts, misconfigured groups, and forgotten permissions.

Enter **PowerShell**.

Forget clicking through endless GUIs. With a few powerful scripts, you can transform AD audits from a quarterly nightmare into an automated, insightful, and *fast* process. Here’s how to become an AD auditing wizard – no magic wand needed, just PowerShell.

Why PowerShell for AD Audits? (Beyond “Because It’s Faster”)

* **Accuracy:** No more human error in manual checks.
* **Depth:** Uncover things the GUI hides (like nested group memberships 10 layers deep).
* **Automation:** Schedule audits to run daily/weekly without lifting a finger.
* **Reporting:** Generate crisp, actionable reports (CSV, HTML, email).
* **Security:** Proactively find vulnerabilities before attackers do.

**Prerequisites (The Boring But Essential Bit):**

1. **Permissions:** Run PowerShell **as an administrator** with an account that has **”Read-All” permissions** in Active Directory (Domain Admins usually work, but least privilege is better!).
2. **Module:** Ensure the `ActiveDirectory` module is installed (it usually is on Domain Controllers or RSAT-enabled machines). Check with:
“`powershell
Get-Module -ListAvailable ActiveDirectory
“`
If missing, install RSAT: Active Directory DS-LDS Tools.

Your PowerShell AD Audit Toolkit (Real-World Scripts)

**1. Find Stale User Accounts (90+ Days Inactive)**

* **The Risk:** Dormant accounts are hacker magnets. Clean them up!
* **The Script:**
“`powershell
# Set your inactivity threshold (e.g., 90 days)
$DaysInactive = 90
$Time = (Get-Date).AddDays(-$DaysInactive)

# Find users enabled but not logged on since threshold

Get-ADUser -Filter {
Enabled -eq $true -and
LastLogonDate -lt $Time -and
LastLogonDate -ne $null
} -Properties LastLogonDate |
Select-Object Name, SamAccountName, UserPrincipalName, LastLogonDate, DistinguishedName |
Export-Csv -Path “C:\Audit\StaleUsers_$(Get-Date -Format yyyyMMdd).csv” -NoTypeInformation

Write-Host “Stale user report generated!” -ForegroundColor Green
“`
* **Real Use:** Run this monthly. Review the CSV, disable accounts (with `Set-ADUser -Identity username -Enabled $false`), and notify owners before deletion.

**2. Audit Privileged Group Memberships (Like “Domain Admins”)**

* **The Risk:** Unauthorized users in admin groups = catastrophic breach.
* **The Script:**
“`powershell
# Define critical groups to audit

$HighRiskGroups = “Domain Admins”, “Enterprise Admins”, “Schema Admins”, “Administrators”

foreach ($Group in $HighRiskGroups) {
Write-Host “Auditing members of: $Group” -ForegroundColor Cyan
Get-ADGroupMember -Identity $Group -Recursive |
Get-ADUser -Properties Name, Title, Department, Enabled, LastLogonDate |
Select-Object @{Name=”Group”; Expression={$Group}}, Name, SamAccountName, Title, Department, Enabled, LastLogonDate
} | Export-Csv -Path “C:\Audit\PrivilegedGroupMembers_$(Get-Date -Format yyyyMMdd).csv” -NoTypeInformation

Write-Host “Privileged group audit complete!” -ForegroundColor Green
“`
* **Real Use:** Run weekly. Scrutinize the CSV. **Question:** Is every member necessary? Is their job title/department aligned? Remove anyone suspicious immediately.

**3. Find Locked-Out Accounts (Helpdesk Hero Script)**

* **The Risk:** Lockouts can indicate brute-force attacks OR frustrated users.
* **The Script:**
“`powershell
# Find all currently locked accounts
Search-ADAccount -LockedOut |
Get-ADUser -Properties Name, Manager, LockedOut, LastBadPasswordAttempt |
Select-Object Name, SamAccountName, UserPrincipalName, Manager, LastBadPasswordAttempt |
Export-Csv -Path “C:\Audit\LockedAccounts_$(Get-Date -Format yyyyMMdd).csv” -NoTypeInformation

Write-Host “Locked accounts report generated!” -ForegroundColor Green
“`
* **Real Use:** Run this **multiple times daily** (or trigger on event logs). Helpdesk uses the CSV to proactively call users/managers before tickets pile up. Security uses it to spot attack patterns.

**4. Audit Users with Password Never Expires**

* **The Risk:** Static passwords are massive security holes (especially for service accounts).
* **The Script:**
“`powershell
Get-ADUser -Filter { PasswordNeverExpires -eq $true } -Properties PasswordNeverExpires, PasswordLastSet |
Where-Object { $_.Enabled -eq $true } | # Ignore disabled accounts
Select-Object Name, SamAccountName, UserPrincipalName, PasswordLastSet, DistinguishedName |
Export-Csv -Path “C:\Audit\PasswordNeverExpires_$(Get-Date -Format yyyyMMdd).csv” -NoTypeInformation

Write-Host “Password Never Expires audit complete!” -ForegroundColor Green
“`
* **Real Use:** Run quarterly. **Justify every entry.** Service accounts might need this, but standard users? Fix it (`Set-ADUser -Identity username -PasswordNeverExpires $false`).

**5. Comprehensive User Account Health Check**

* **The Risk:** Multiple issues compound risk (stale + admin + never expires = disaster).
* **The Script (The Powerhouse):**
“`powershell
# Get ALL enabled users with key properties
$Users = Get-ADUser -Filter { Enabled -eq $true } -Properties *
$Report = @()

foreach ($User in $Users) {
$UserReport = [PSCustomObject]@{
Name = $User.Name
SamAccountName = $User.SamAccountName
UPN = $User.UserPrincipalName
Enabled = $User.Enabled
PasswordNeverExpires= $User.PasswordNeverExpires
PasswordLastSet = $User.PasswordLastSet
LastLogonDate = $User.LastLogonDate
AccountLockedOut = $User.LockedOut
MemberOfAdmins = $null # We’ll check this next
EmailAddress = $User.EmailAddress
Department = $User.Department
DistinguishedName = $User.DistinguishedName
}

# Check if member of any high-risk group (even nested)
$AdminGroups = “Domain Admins”, “Enterprise Admins”, “Schema Admins”
$IsAdmin = $false
foreach ($Group in $AdminGroups) {
if (Get-ADGroupMember -Identity $Group -Recursive | Where-Object { $_.SID -eq $User.SID }) {
$IsAdmin = $true
break # Exit loop early if found in one group
}
}
$UserReport.MemberOfAdmins = $IsAdmin

$Report += $UserReport
}

$Report | Export-Csv -Path “C:\Audit\FullUserAudit_$(Get-Date -Format yyyyMMdd).csv” -NoTypeInformation
Write-Host “Comprehensive User Audit Complete!” -ForegroundColor Green
“`
* **Real Use:** Run this quarterly for deep dives. Filter the CSV in Excel:
* `PasswordNeverExpires = TRUE AND MemberOfAdmins = TRUE` → **Critical Risk!**
* `LastLogonDate < (Get-Date).AddDays(-180)` → Stale Accounts
* `AccountLockedOut = TRUE` → Needs Helpdesk Attention

Pro Tips for Mastering AD Audits with PowerShell

1. **Schedule It:** Use **Task Scheduler** to run scripts nightly/weekly. Example:
“`powershell
# Basic Task Scheduler command to run a script daily
schtasks /create /tn “AD_StaleUserAudit” /tr “powershell.exe -File C:\AuditScripts\StaleUsers.ps1” /sc DAILY /st 02:00
“`
2. **Email Reports:** Add `Send-MailMessage` or use `MailKit` at the end of your scripts to auto-send CSVs to your inbox or security team.
3. **HTML Reports:** Use `ConvertTo-Html` for prettier, browser-viewable reports.
4. **Version Control:** Store scripts in **Git** (Azure DevOps, GitHub) for history and collaboration.
5. **Start Small:** Don’t try to audit everything at once. Tackle one risk area (like stale accounts) first.

### Stop Auditing Manually. Start Scripting.

PowerShell turns Active Directory auditing from a chore into a superpower. These scripts aren’t just theoretical – they’re battle-tested tools that uncover real risks and save hours.

**Your Action Plan:**
1. **Test:** Run these scripts (carefully!) in a **non-production environment** first.
2. **Adapt:** Tweak filters and properties to match *your* AD structure and policies.
3. **Automate:** Schedule your most critical audits.
4. **Review:** Don’t just generate reports – **act on the findings!**

The security of your network hinges on knowing what’s inside AD. Let PowerShell do the heavy lifting. Now go grab that CSV and start cleaning house!

Leave a comment