Public/activedirectory/Get-ADLockedAccount.ps1
|
#Requires -Version 5.1 function Get-ADLockedAccount { <# .SYNOPSIS Finds all currently locked Active Directory user accounts .DESCRIPTION Searches Active Directory for user accounts that are currently locked out. Returns detailed lockout information including lockout time, bad logon count, and last bad password attempt. Results are sorted by most recent lockout first. .PARAMETER SearchBase The distinguished name of the OU to search within. If omitted, searches the entire domain. .PARAMETER Server Specifies the Active Directory Domain Services instance to connect to. .PARAMETER Credential Specifies the credentials to use for the Active Directory query. .EXAMPLE Get-ADLockedAccount Finds all locked accounts in the domain. .EXAMPLE Get-ADLockedAccount -Server 'dc01.contoso.com' Finds all locked accounts from a specific domain controller. .EXAMPLE Get-ADLockedAccount -SearchBase 'OU=Users,DC=contoso,DC=com' Finds locked accounts within a specific OU. .OUTPUTS PSWinOps.ADLockedAccount Returns objects with account identity, lockout time, bad password attempt details, sorted by most recent lockout first. .NOTES Author: Franck SALLET Version: 1.0.0 Last Modified: 2026-04-03 Requires: PowerShell 5.1+ / Windows only Requires: ActiveDirectory module .LINK https://github.com/k9fr4n/PSWinOps .LINK https://learn.microsoft.com/en-us/powershell/module/activedirectory/search-adaccount #> [CmdletBinding()] [OutputType([PSCustomObject])] param( [Parameter()] [ValidateNotNullOrEmpty()] [string]$SearchBase, [Parameter()] [ValidateNotNullOrEmpty()] [string]$Server, [Parameter()] [ValidateNotNull()] [System.Management.Automation.PSCredential]$Credential ) begin { Write-Verbose -Message "[$($MyInvocation.MyCommand)] Starting" try { Import-Module -Name 'ActiveDirectory' -ErrorAction Stop } catch { throw "[$($MyInvocation.MyCommand)] Failed to import ActiveDirectory module: $_" } $adParams = @{} if ($PSBoundParameters.ContainsKey('Server')) { $adParams['Server'] = $Server } if ($PSBoundParameters.ContainsKey('Credential')) { $adParams['Credential'] = $Credential } $searchBaseParam = @{} if ($PSBoundParameters.ContainsKey('SearchBase')) { $searchBaseParam['SearchBase'] = $SearchBase } } process { try { Write-Verbose -Message "[$($MyInvocation.MyCommand)] Searching for locked accounts" $lockedAccounts = Search-ADAccount -LockedOut -UsersOnly @searchBaseParam @adParams -ErrorAction Stop if (-not $lockedAccounts) { Write-Verbose -Message "[$($MyInvocation.MyCommand)] No locked accounts found" return } $results = [System.Collections.Generic.List[object]]::new() foreach ($account in $lockedAccounts) { try { $userDetail = Get-ADUser -Identity $account.SamAccountName ` -Properties 'LockedOut', 'LockoutTime', 'BadLogonCount', 'LastBadPasswordAttempt', 'Description', 'Enabled' ` @adParams -ErrorAction Stop $results.Add([PSCustomObject]@{ PSTypeName = 'PSWinOps.ADLockedAccount' Name = $userDetail.Name SamAccountName = $userDetail.SamAccountName Enabled = $userDetail.Enabled LockoutTime = $userDetail.LockoutTime BadLogonCount = $userDetail.BadLogonCount LastBadPasswordAttempt = $userDetail.LastBadPasswordAttempt Description = $userDetail.Description DistinguishedName = $userDetail.DistinguishedName Timestamp = Get-Date -Format 'o' }) } catch { Write-Error -Message "[$($MyInvocation.MyCommand)] Failed to get details for '$($account.SamAccountName)': $_" continue } } $results | Sort-Object -Property 'LockoutTime' -Descending } catch { Write-Error -Message "[$($MyInvocation.MyCommand)] Search failed: $_" } } end { Write-Verbose -Message "[$($MyInvocation.MyCommand)] Completed" } } |