Get-LockoutBlame

Searchs Windows Event logs about Locked Accounts. Defaults to 1 hour.

Hint: If the computer name is blank, that means it was locked out remotely. Check for open RDP(3389) ports.

Get-Lockoutblame.ps1
<#
.SYNOPSIS
Gets a Windows Event about Locked Accounts.
.DESCRIPTION
Script to get a Windows Event about Locked Accounts, including the host which caused the lockout.
By default only events triggered in the last hour are returned, but a different time frame can be provided with the PastHours parameter or overridden with the All switch.
.EXAMPLE
Get-LockoutBlame
Returns all account lockout events that were triggered in the past hour.
.EXAMPLE
Get-LockoutBlame -PastHours 24
Returns all account lockout events that were triggered in the last 24 hours.
.EXAMPLE
Get-LockoutBlame -All
Returns all account lockout events present in the event log.
.EXAMPLE
Get-LockoutBlame -UserName johnd
Returns all account lockout events for the user johnd in the past hour
.EXAMPLE
Get-LockoutBlame -UserName johnd -All
Returns all account lockout events for the user johnd present in the event log.
.NOTES
The default value for the ComputerName parameter uses a cmdlet from the ActiveDirectory module, if you don't have this installed (why?) you can either provide a domain controller at runtime or hardcode it as the default.
#>
 
[CmdletBinding(DefaultParameterSetName='Filtered')]
[OutputType('System.Diagnostics.Eventing.Reader.EventLogRecord')]
param
(
    [Parameter(Position = 0)]
    [ValidateNotNullOrEmpty()]
    [string] $UserName,
 
    [Parameter(ParameterSetName='Filtered')]
    [ValidateNotNullOrEmpty()]
    [int] $PastHours = 1,
 
    [Parameter(ParameterSetName='Unfiltered')]
    [switch] $All,
 
    [Parameter()]
    [ValidateNotNullOrEmpty()]
    [string] $ComputerName = ((Get-ADDomainController -Discover -Service PrimaryDC).HostName)
)
 
process
{
    try
    {
        $filter = '*[System[EventID=4740'
 
        if (!$all) {
            $PastMilliseconds = $PastHours * 3600000
            $filter += " and TimeCreated[timediff(@SystemTime) <= $PastMilliseconds]]"
        } else {
            $filter += ']'
        }
 
        if ($username) {
            $filter += " and EventData[Data[@Name='TargetUserName']='$UserName']]"
        } else {
            $filter += ']'
        }
 
        $Events = Get-WinEvent -ComputerName $ComputerName -Logname Security -FilterXPath $filter
        $Events | Select-Object TimeCreated,
                                @{Name='User Name';Expression={$_.Properties[0].Value}},
                                @{Name='Source Host';Expression={$_.Properties[1].Value}}
    }
    catch
    {
        Throw $_.Exception
    }
}