Active Directory User Lockout and Password Report

Published: May 30, 2024 | Last Modified: May 13, 2025

Tags: powershell active-directory security automation reporting user-management

Categories: PowerShell Active Directory



This PowerShell script generates an HTML diagnostics report for user lockouts in the Active Directory. The script imports the Active Directory module and retrieves all user accounts that are not disabled. It fetches password-related properties and calculates the password age and expiration details for each user. The results are filtered, sorted, and converted into an HTML report with CSS styling for better readability. The final HTML report is saved to a file and opened in the default web browser.

# Import the Active Directory module
Import-Module ActiveDirectory

# Get all users who are not disabled
$users = Get-ADUser -Filter * -Property pwdLastSet, Enabled, LockedOut, PasswordExpired, WhenCreated, LastLogonDate

# Get the result of `net accounts`
$netAccounts = net accounts
$maxPwdAgeLine = $netAccounts | Select-String -Pattern "Maximum password age"
$maxPwdAgeValue = ($maxPwdAgeLine -split "\s+")[4] # Extract the value from the line

# Handle the "Unlimited" case
if ($maxPwdAgeValue -eq "Unlimited") {
    $maxPwdAge = [int]::MaxValue
} else {
    $maxPwdAge = [int]$maxPwdAgeValue
}

# Create a custom object to store the results
$results = @()

foreach ($user in $users) {
    # Convert pwdLastSet to a readable date if it is greater than 0
    if ($user.pwdLastSet -gt 0) {
        $pwdLastSetDate = [datetime]::FromFileTimeUtc($user.pwdLastSet)
        $daysSincePwdLastSet = [math]::Round(((Get-Date) - $pwdLastSetDate).TotalDays)
        $daysUntilPwdExpiration = $maxPwdAge - $daysSincePwdLastSet
    } else {
        $pwdLastSetDate = $null
        $daysSincePwdLastSet = $null
        $daysUntilPwdExpiration = $null
    }
    $results += [PSCustomObject]@{
        UserName                  = $user.SamAccountName
        pwdLastSet                = $pwdLastSetDate
        DaysSincePwdLastSet       = $daysSincePwdLastSet
        DaysUntilPwdExpiration    = $daysUntilPwdExpiration
        Enabled                   = $user.Enabled
        LockedOut                 = $user.LockedOut
        PasswordExpired           = $user.PasswordExpired
        WhenCreated               = $user.WhenCreated
        LastSignIn                = $user.LastLogonDate
    }
}

# Filter out users with pwdLastSet set to null
$filteredResults = $results | Where-Object { $_.pwdLastSet -ne $null }

# Sort the results by pwdLastSet in descending order
$sortedResults = $filteredResults | Sort-Object -Property pwdLastSet -Descending

# Convert the results to HTML
$html = $sortedResults | ConvertTo-Html -Property UserName, pwdLastSet, DaysSincePwdLastSet, DaysUntilPwdExpiration, Enabled, LockedOut, PasswordExpired, WhenCreated, LastSignIn -Title "User Password Status" -PreContent "<h1>User Password Status</h1>"

# Add CSS for table styling
$style = @"
    <style>
        table {
            width: 100%;
            border-collapse: collapse;
        }
        table, th, td {
            border: 1px solid black;
        }
        th, td {
            padding: 1px;
            text-align: left;
        }
        th {
            background-color: #f2f2f2;
        }
        tr:nth-child(even) {
            background-color: #f9f9f9;
        }
    </style>
"@

$htmlContent = "$style$html"

# Save the HTML file
$htmlPath = "pwdLastSet.html"
$htmlContent | Out-File -FilePath $htmlPath

# Open the HTML file in the default browser
Start-Process "powershell.exe" -ArgumentList "Start-Process $htmlPath"