Public/Get-MDSADLockoutSource.ps1
Function Get-MDSADLockoutSource { <# .SYNOPSIS Query Active Directory for the lockout source for the most recently lockout event .DESCRIPTION Query Active Directory for the lockout source for the most recently lockout event. If a server is listed the query will be for the last lockout event on that specific server. .EXAMPLE Get-MDSADLockoutSource -SamAccountName $SamAccountName Query a single user's lockout source .EXAMPLE Get-MDSADLockoutSource -SamAccountName SamAccountName1,SamAccountName2 Query multiple users at a time. Also accepts SamAccountNames via the pipeline .EXAMPLE Get-MDSADLockoutSource -SamAccountName $SamAccountName -Server Server.domain.com Accepts a specific server to query assuming the metadata time is the event time for that server .NOTES Written by Rick A., December 2017 #> [CmdletBinding(DefaultParameterSetName='None')] [System.Diagnostics.CodeAnalysis.SuppressMessage('PSAvoidUsingPlainTextForPassword', '')] [System.Diagnostics.CodeAnalysis.SuppressMessage('PSUsePSCredentialType', '')] param( [Parameter( Mandatory = $true, Position = 0, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true )] [Parameter(ParameterSetName="MDSCredential")] [Parameter(ParameterSetName="Credential")] [Parameter(ParameterSetName="None")] [ValidateNotNullOrEmpty()] [string[]]$SamAccountName, [Parameter(Position=1,ParameterSetName="MDSCredential")] [Parameter(Position=1,ParameterSetName="Credential")] [Parameter(Position=1,ParameterSetName="None")] [string]$Server, [parameter(Position=2,ParameterSetName="MDSCredential")] [ValidateNotNullOrEmpty()] [String]$MDSCredential, [parameter(Position=2,ParameterSetName="Credential")] [ValidateNotNullOrEmpty()] [System.Management.Automation.CredentialAttribute()] $Credential ) #requires -Module ActiveDirectory begin {} process { # MDSCredentials If ($PsCmdlet.ParameterSetName -eq "MDSCredential" -and -not [string]::IsNullOrEmpty($MDSCredential)) { Try { $Credential = Get-MDSCredential -Name $MDSCredential } Catch { $PsCmdlet.ThrowTerminatingError($PSItem) } } Try { If ($null -eq $PSBoundParameters.Server) { $PDCEmulator = Get-ADDomain -ErrorAction Stop | Select-Object -Expand PDCEmulator $VerboseString = 'No server specified. Using the PDCEmulator {0}.' -f $PDCEmulator Write-Verbose $VerboseString } } Catch { $PsCmdlet.ThrowTerminatingError($PSItem) } ForEach ($Name in $SamAccountName) { Try { $Events = $ADUser = $null If ($null -eq $PSBoundParameters.Server) { $Server = $PDCEmulator } $VerboseString = 'Performing AD query for {0}.' -f $Name Write-Verbose $VerboseString $getADUserSplat = @{ Filter = {SamAccountName -eq $Name} Properties = 'AccountLockoutTime' Server = $Server ErrorAction = 'Stop' } $ADUser = Get-ADUser @getADUserSplat If ($null -eq $ADUser) { $ErrorString = 'Cannot find object with samaccountname: {0}' -f $SamAccountName Write-Error $ErrorString continue } $VerboseString = 'Querying AD metadata for {0}.' -f $ADUser.DistinguishedName Write-Verbose $VerboseString $MetaData = Get-ADReplicationAttributeMetadata -Server $Server -Object $ADUser.DistinguishedName | Where-Object {'lockoutTime' -eq $_.AttributeName} | Select-Object AttributeName,LastOriginatingChangeTime,LastOriginatingChangeDirectoryServerIdentity $SourceDC = ($Metadata.LastOriginatingChangeDirectoryServerIdentity -Split "CN=")[2] -replace ',' If ($null -eq $MetaData.LastOriginatingChangeTime) { $ErrorString = 'There is no lockout time recorded for {0} in the AD metadata on {1}.' -f $ADuser.SamAccountName,$Server Write-Error $ErrorString continue } If ($null -eq $PSBoundParameters.Server) { $Server = $SourceDC $VerboseString = 'No server specified. Using the LastOriginatingChangeDirectoryServerIdentity {0}.' -f $Server Write-Verbose $VerboseString } $FilterHashtable = @{ LogName = 'Security' ID = 4740 ProviderName = 'Microsoft-Windows-Security-Auditing' StartTime = $MetaData.LastOriginatingChangeTime EndTime = $MetaData.LastOriginatingChangeTime.AddSeconds(1) } $getWinEventSplat = @{ ComputerName = $Server FilterHashtable = $FilterHashtable ErrorAction = 'Stop' Verbose = $False } If ($Credential) {[void]$getWinEventSplat.Add('Credential',$Credential)} Try {[array]$Events = Get-WinEvent @getWinEventSplat} Catch { Write-Error $PSItem Continue } If ($null -eq $Events) {continue} Write-Verbose 'Parsing returned events' ForEach ($Event in $Events) { If($Event | Where-Object {$_.Properties[2].Value -match $ADUser.SID.Value}) { [PSCustomObject] @{ AccountName = $Name EventComputer = $Server LockoutTime = $Event.TimeCreated LockoutSource = $Event.Properties[1].Value } } } } Catch { Write-Error $PSItem } } } end {} } |