THE PROBLEM
Account lockouts are one of the most common helpdesk tickets in any Windows environment. User calls in, you spend 10 minutes hunting through Event Logs across multiple domain controllers trying to find which machine caused the lockout. This week we automate the entire detection process — the moment an account locks out, you get an email with the username, source machine, and timestamp. No more hunting.
THE SCRIPT
Save the script below to:
C:\Scripts\LockoutMonitor.ps1PowerShell
# Active Directory Account Lockout Monitor
# Automate & Operate — automateandoperate.com
# Settings — update these
$from = "[email protected]"
$to = "[email protected]"
$smtpServer = "smtp.gmail.com"
$smtpPort = 587
$username = "[email protected]"
$password = ConvertTo-SecureString "yourpassword" -AsPlainText -Force
$credential = New-Object System.Management.Automation.PSCredential($username, $password)
$logFile = "C:\Logs\LockoutMonitor.log"
# How far back to check in minutes (match to Task Scheduler interval)
$checkIntervalMinutes = 15
# Create log folder if missing
if (-not (Test-Path "C:\Logs")) {
New-Item -ItemType Directory -Path "C:\Logs"
}
$timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
$startTime = (Get-Date).AddMinutes(-$checkIntervalMinutes)
try {
# Find PDC Emulator — lockout events are logged here
$pdcEmulator = (Get-ADDomain).PDCEmulator
# Search for lockout events (Event ID 4740)
$lockoutEvents = Get-WinEvent -ComputerName $pdcEmulator -FilterHashtable @{
LogName = "Security"
Id = 4740
StartTime = $startTime
} -ErrorAction SilentlyContinue
if ($lockoutEvents -and $lockoutEvents.Count -gt 0) {
$lockoutDetails = @()
foreach ($event in $lockoutEvents) {
$xml = [xml]$event.ToXml()
$lockedUser = ($xml.Event.EventData.Data | Where-Object { $_.Name -eq "TargetUserName" }).'#text'
$sourceMachine = ($xml.Event.EventData.Data | Where-Object { $_.Name -eq "CallerComputerName" }).'#text'
$eventTime = $event.TimeCreated
$lockoutDetails += [PSCustomObject]@{
Username = $lockedUser
SourceMachine = $sourceMachine
TimeOfLockout = $eventTime
}
Add-Content -Path $logFile -Value "$timestamp — LOCKOUT: $lockedUser locked out from $sourceMachine at $eventTime"
}
# Build email body
$emailBody = "Account Lockout Alert — $timestamp`n"
$emailBody += "Domain Controller: $pdcEmulator`n`n"
$emailBody += "$($lockoutEvents.Count) lockout(s) detected in the last $checkIntervalMinutes minutes:`n"
$emailBody += "=" * 50 + "`n`n"
foreach ($lockout in $lockoutDetails) {
$emailBody += "Username: $($lockout.Username)`n"
$emailBody += "Source Machine: $($lockout.SourceMachine)`n"
$emailBody += "Time: $($lockout.TimeOfLockout)`n"
$emailBody += "-" * 40 + "`n"
}
$emailBody += "`nTo unlock an account run:`n"
$emailBody += "Unlock-ADAccount -Identity USERNAME`n`n"
$emailBody += "Automate & Operate — automateandoperate.com"
Send-MailMessage `
-From $from -To $to `
-Subject "LOCKOUT ALERT: $($lockoutEvents.Count) account lockout(s) detected" `
-Body $emailBody `
-SmtpServer $smtpServer -Port $smtpPort `
-UseSsl -Credential $credential
} else {
Add-Content -Path $logFile -Value "$timestamp — OK: No lockouts detected in last $checkIntervalMinutes minutes"
}
} catch {
Add-Content -Path $logFile -Value "$timestamp — ERROR: $_"
}Update these lines:
$from/$to/$username/$password— your Email details$checkIntervalMinutes— match this to your Task Scheduler repeat interval
SETTING UP TASK SCHEDULER
Press Windows key → type Task Scheduler → open it
Click "Create Basic Task" → name it
Lockout MonitorTrigger: Daily → today → 6:00am → click Next
Action: Start a program → click Next
Program:
powershell.exeArguments:
-ExecutionPolicy Bypass -File "C:\Scripts\LockoutMonitor.ps1"Click Next → Finish
Set it to repeat every 15 minutes:
Right click
Lockout Monitor→ PropertiesClick Triggers tab → Edit
Check "Repeat task every" → set to 15 minutes
Duration: Indefinitely
Click OK → OK
TEST IT
Open PowerShell as administrator and run:
PowerShell
powershell.exe -ExecutionPolicy Bypass -File "C:\Scripts\LockoutMonitor.ps1"To force a test lockout — attempt to log in with a wrong password several times on a test account until it locks. Within 15 minutes you should receive the alert email with the source machine details.
Check C:\Logs\LockoutMonitor.log to confirm it's running correctly.
WHY THIS MATTERS
Lockouts caused by service accounts, cached credentials, or mapped drives can cascade into serious outages. Knowing the source machine immediately cuts your investigation time from 30 minutes to 30 seconds. This script pays for itself the first time a service account locks out at 2am and you already know exactly which server caused it before anyone calls you.
THIS WEEK'S ACTION
Deploy this on your PDC Emulator today. Set it to run every 15 minutes. Next time someone calls the helpdesk about a lockout — you'll already know the answer before they finish explaining the problem.
Reply to this email if you hit any issues — I read every reply.
Automate & Operate — automateandoperate.com
Dictate code. Wispr tags the files.
Speak your PR description, bug reproduction, or Cursor prompt. Wispr Flow auto-tags file names, preserves variable names, and formats everything for immediate paste into GitHub, Jira, or your editor.
No re-typing. No context gaps. No mangled syntax. Works natively inside Cursor, Warp, and every IDE at the system level.
4x faster than typing. 89% of messages sent with zero edits. Used by engineering teams at OpenAI, Vercel, and Clay.

