Active Directory Hygiene Is Not Optional
Active Directory is the most important database in most organisations that nobody maintains. It accumulates stale accounts, orphaned groups, broken trust relationships, and configuration drift at a rate that would terrify any DBA. But because AD "just works," nobody cleans it up until a security audit demands it — at which point it's an emergency.
The state of most AD environments
The average mid-size AD environment I walk into has:
- Disabled accounts from employees who left years ago. Some are still members of distribution groups, so former employees are getting internal email if nobody removed them.
- Service accounts with passwords that haven't changed since 2015. The person who knew that password left in 2017. If that service account breaks, nobody knows how to fix it without resetting it, and resetting it might break whatever it runs.
- Empty groups. Created for projects that ended years ago. Clutter that makes the real groups harder to find.
- Users with "Password never expires" set. Usually senior executives or legacy service accounts. Both are exactly the accounts an attacker wants.
- Orphaned OUs. Organisational units from reorganisations that happened three org charts ago. Contain some objects. Nobody knows which ones.
- Schema extensions from software that was uninstalled in 2014. The attributes remain forever. Schema modifications are irreversible.
The cleanup process
I approach AD cleanup methodically. The order matters because some objects depend on others.
Step 1: Disabled accounts older than 90 days. These get deleted. Not moved to a "disabled users" OU — deleted. If you're worried about losing something, export to CSV first. In 15 years, I've never needed to restore a disabled account that was older than 90 days.
Step 2: Stale computer accounts. Domain controllers automatically disable computer accounts that haven't changed their password in 60 days (by default). These get deleted after 90 days of being disabled. A computer account that hasn't authenticated in three months isn't coming back.
Step 3: Empty groups. Groups with no members get documented and deleted. Empty distribution groups just clutter the GAL. Empty security groups are leftover from projects. If nobody claims an empty group, it doesn't need to exist.
Step 4: Service account audit. Every service account gets documented: what it runs, who manages it, when the password was last changed, what the recovery process is. Service accounts with unknown purpose get disabled for 30 days. If nothing breaks, they get deleted.
Step 5: Privileged group membership. Domain Admins, Enterprise Admins, Schema Admins — these groups should have the absolute minimum membership. I've seen Domain Admins groups with 47 members. There is no legitimate reason for 47 people to be Domain Admins. The target is 4-5 maximum, with just-in-time elevation for everyone else.
Step 6: Password policy review. Fine-grained password policies are underused. The default domain policy applies to everyone, which means your service accounts have the same password requirements as your users. Split them. Service accounts should have longer, more complex passwords that change less frequently. User accounts should have reasonable complexity with regular rotation.
The automation
Most of this is scriptable. I have a PowerShell module I've refined over years:
# Find all disabled accounts older than 90 days
Search-ADAccount -AccountDisabled -UsersOnly |
Where-Object {$_.LastLogonDate -lt (Get-Date).AddDays(-90)}
# Find empty groups
Get-ADGroup -Filter * -Properties Members |
Where-Object {$_.Members.Count -eq 0}
# Find users with PasswordNeverExpires
Get-ADUser -Filter {PasswordNeverExpires -eq $true}
Each of these produces a CSV for review before taking action. The review is important — scripts do what you tell them, not what you mean. A script that deletes disabled accounts will happily delete the break-glass admin account you disabled on purpose. Human review is the safety net.
The ongoing discipline
AD cleanup isn't a project. It's a recurring task. I run the hygiene scripts monthly and review the output. The first cleanup is always the biggest — years of accumulated cruft. After that, it's maintenance: a few disabled accounts, a handful of empty groups, the occasional service account that's no longer needed. Fifteen minutes a month.
The alternative is waiting for the auditors to find the problems first. They will. And then you'll be doing the same cleanup, but with a deadline and an angry CISO watching.