Published on

How to Find Enabled User Accounts in Active Directory (PowerShell Script)

Most account audits focus on the disabled pile, but the enabled list matters just as much — it's your actual attack surface. Every account on this list can authenticate right now. Before a compliance review, an access recertification, or just a sanity check on headcount vs. account count, you need an accurate, current list of exactly who can log in.

The quick answer

Get-ADUser -Filter {Enabled -eq $true} | Select-Object Name, SamAccountName, DistinguishedName

A more useful reporting script

#requires -Modules ActiveDirectory
<#
.SYNOPSIS
    Lists enabled user accounts in Active Directory.
#>

[CmdletBinding()]
param(
    [string]$SearchBase,
    [string]$OutputCsv,
    [switch]$IncludeLastLogon
)

Import-Module ActiveDirectory -ErrorAction Stop

$properties = @('DistinguishedName', 'Description')
if ($IncludeLastLogon) { $properties += 'LastLogonDate' }

$params = @{
    Filter     = { Enabled -eq $true }
    Properties = $properties
}
if ($SearchBase) { $params['SearchBase'] = $SearchBase }

$enabledUsers = Get-ADUser @params |
    Select-Object Name, SamAccountName, DistinguishedName, Description, LastLogonDate |
    Sort-Object Name

if (-not $enabledUsers) {
    Write-Host "No enabled user accounts found." -ForegroundColor Yellow
    return
}

Write-Host "Found $(@($enabledUsers).Count) enabled user account(s)." -ForegroundColor Cyan

if ($IncludeLastLogon) {
    $enabledUsers | Format-Table Name, SamAccountName, LastLogonDate, DistinguishedName -AutoSize
} else {
    $enabledUsers | Format-Table Name, SamAccountName, DistinguishedName -AutoSize
}

if ($OutputCsv) {
    $enabledUsers | Export-Csv -Path $OutputCsv -NoTypeInformation
    Write-Host "Exported results to $OutputCsv" -ForegroundColor Green
}

-IncludeLastLogon adds a LastLogonDate column, which turns this from a headcount list into a starting point for finding enabled accounts nobody's actually using — pair it with -SearchBase to scope a single OU during an access review.

Cross-checking against your HR headcount

The most common use for this report: run it, count the rows, and compare against active headcount from HR. A gap in either direction is worth investigating — more enabled accounts than employees usually means stale contractor or service accounts never disabled; fewer usually means someone's using a shared or generic account instead of their own.

The GUI method (no PowerShell)

In Active Directory Users and Computers, right-click your domain or an OU → NewQueryFindCommon Queries, and leave Disabled accounts unchecked — an unfiltered query already returns everyone, enabled and disabled together, so you'd need to manually exclude the disabled ones from the results. There's no single checkbox for "enabled only" the way there is for "disabled accounts," which is one of the more annoying asymmetries in ADUC's saved queries.

Where the manual approach runs out of road

A one-off script is fine for a single check. It starts to hurt once you actually need to run this regularly:

  • No scheduling. Cron/Task Scheduler can run the script, but now you own the scheduling, the credentials it runs as, and what happens when it silently fails.
  • No history. A CSV export is a snapshot. Was this the same five accounts as last month, or a growing list? A single export can't tell you.
  • No distribution. Getting the report to the right people (security, IT ops, compliance) on a schedule means building that plumbing yourself.
  • Multi-domain/multi-forest pain. Run it once per domain, reconcile the results yourself, and hope naming/OU conventions are consistent across all of them.
  • No alerting. If something changes unexpectedly between runs — an account re-enabled, a privileged group gaining a member — nothing tells you until you happen to run the script again.

None of that is a PowerShell problem. It's what turns a script into a product.

What SysFlint AD does instead

Our SysFlint AD runs the same kind of discovery shown above automatically, on a schedule, entirely inside your own network. No agents on domain controllers, no data leaving your environment. It's free, forever.

  • Disabled account reports Every disabled account, with the OU it lives in, when it was last used, and how long it has been sitting there.
  • Stale and inactive account detection Enabled accounts that nobody has logged into for 30, 60, or 90+ days — the ones that are still a live attack surface.
  • Scheduled reports by email Daily, weekly, or monthly runs delivered to the right inbox automatically. No Task Scheduler job for you to babysit.

If you're currently doing this with a script on a scheduled task, here's the honest comparison between the two, or go straight to the download page.

Get this script, and the rest of them

The script above is part of awesome-it-scripts, SysFlint's free, open-source library of PowerShell scripts for Active Directory and other IT-admin tasks — no signup, no catch, MIT licensed. Grab this one directly from active-directory/Find-EnabledADUsers.ps1, or browse the whole thing.

Find every disabled/locked-out/stale/privileged-account script we've published (plus the FAQ that goes with each one) in the repo's active-directory folder. Star it if it's useful — new scripts land there regularly.