Public/Get-Lockouts.ps1
Function Get-Lockouts { <# .SYNOPSIS Pipe in distinguishedName or Queries AD for all Domain Controllers Queries the list of DCs to find lockout sources with bad password counts greater then 5 Runs Get-WinEvent with a custom XML formatted around the provided usernames Outputs all lockout events with relevant source information .NOTES Name: Get-LockoutEvents Author: Luke Hagar Version: 1.0 DateCreated: January 20th, 2021 .EXAMPLE Single Search Get-LockoutEvents "Luke.Hagar" Get-LockoutEvents "Luke.Hagar" -Verbose Array Search $LockedOutUsers = {"SamAccountName","EmployeeID","mail"} $LockedOutUsers | Get-LockoutEvents | Format-Table -AutoSize -GroupBy EventDataTargetUserName -Unique Search All Locked out AD User Objects $LockedOutUsers = Search-AdAccount -LockedOut $LockedOutUsers | Get-LockoutEvents | Format-Table -AutoSize -GroupBy EventDataTargetUserName -Unique .LINK #> [CmdletBinding()] param ( [Parameter( ValueFromPipelineByPropertyName = $true )] [string]$distinguishedName ) BEGIN { #get list of Domain Controllers $DomainControllers = Get-ADDomainController -Filter * #XML part 1 to be joined later around username variable $LastHourXMLPart1 = "<QueryList> <Query Id='0' Path='Security'> <Select Path='Security'>*[System[Provider[@Name='Microsoft-Windows-Security-Auditing'] and (Level=4 or Level=0) and (band(Keywords, 13510798882111488)) and (EventID=4740) and TimeCreated[timediff(@SystemTime) < = 604800000]]] and *[EventData[Data[@Name='TargetUserName'] = '" #XML part 2 to be joined later around username variable $LastHourXMLPart2 = "']] </Select> </Query> </QueryList>" } PROCESS { Try { $User = Get-User $distinguishedName -Properties lockedout } Catch { Throw $_.Exception.Message } If ($User.lockedout -eq $true) { $TestingList = @() Write-Verbose "$($User.Name) found" #Merge Queries together around User Search variable [xml]$FinalQuery = "$LastHourXMLPart1" + $User.SamAccountName + "$LastHourXMLPart2" If ($User.lockout -eq $True) { #Test each DCs to find sources Foreach ($DC in $DomainControllers) { Write-Verbose "Checking $($DC.Hostname.ToUpper())" $DCQuery = Get-ADUser -Identity $User.SamAccountName -Server $DC.Hostname -Properties BadPwdCount If ($DCQuery.BadPwdCount -gt 5) { Write-Verbose "$($DCQuery.BadPwdCount) Bad Passwords found on $($DC.Hostname.ToUpper())" $TestingList += $DC.Hostname } } if ($null -ne $TestingList) { Foreach ($TestingDC in $TestingList) { Write-Verbose "" Write-Verbose "Checking $($TestingDC.ToUpper()) for lockout events" Get-WinEvent -ComputerName $TestingDC -FilterXml $FinalQuery -ErrorAction SilentlyContinue | Get-WinEventData | Select-Object TimeCreated, EventDataTargetUserName, EventDataTargetDomainName, EventDataSubjectUserName } } } else { Write-Verbose "No Lockout Events found" return [PSCustomObject]@{ Username = $User.SamAccountName Results = "No Lockout Found / No Bad Passwords Found" } } } } END { } } |