Cyber Security

Monitoring Logon Attempts in Active Directory with PowerShell

Domain-Controllers monitor successful logon attempts by default. All events of all login attempts are logged in the Event Viewer. In this article I will cover how to monitor all logon events with PowerShell. Let’s dive in.

What is it about?

Successful logons are logged with ID 4624. Failed attempts are logged with ID 4771. Furthermore, we should also specify the user name.

https://docs.microsoft.com/en-us/windows/security/threat-protection/auditing/event-4624

Code Samples for successful and failed Logons

Successful Logons – 4624

The following code displays all successful logons of the username f.bizeps (Franz Bizeps) 😉

Get-EventLog -LogName Security -InstanceId 4624 | 
Where-Object Message -match "f.bizeps" | 
Format-Table TimeGenerated,Message -AutoSize -Wrap

A little bit more precise you can use Select-Object to display only the last logon.

Get-EventLog -LogName Security -InstanceId 4624 | 
Where-Object Message -match "f.bizeps" | 
Select-Object -First 1 |
Format-Table TimeGenerated,Message -AutoSize -Wrap

Failed Logons – 4771

Note that failed logons are not enabled by default. This setting must be enabled in the default domain controllers policy.

For showing all failed logons of user f.bizeps run the command below.

Get-EventLog -LogName Security -InstanceId 4771 | 
Where-Object Message -match "f.bizeps" | 
Format-Table TimeGenerated,Message -AutoSize -Wrap

Hope this was helpful!

5 replies »

  1. Hi Patrick,

    Another way is to use Get-WinEvent and better Get-WinEvent with -FilterHashTable for better performance or a better later exploitability.
    Let me show a sample, based on your search.
    $Query = Get-WinEvent -FilterHashtable @{LogName = “Security”
    Id = 4624}
    $Query | Select-Object -Property @{Label = “TimeCreated” ; Expression = {$_.TimeCreated}},
    @{Label = “ID” ; Expression = {$_.ID}},
    @{Label = “MachineName” ; Expression = {$_.MachineName}},
    @{Label = “LevelDisplayName” ; Expression = {$_.LevelDisplayName}},
    @{Label = “TaskDisplayName” ; Expression = {$_.TaskDisplayName}},
    @{Label = “SecurityId” ; Expression = {$_.Properties[4].Value}},
    @{Label = “AccountName” ; Expression = {$_.Properties[5].Value}},
    @{Label = “AccountDomain” ; Expression = {$_.Properties[6].Value}},
    @{Label = “LogonId” ; Expression = {$_.Properties[7].Value}},
    @{Label = “LogonType” ; Expression = {$_.Properties[8].Value}},
    @{Label = “Workstation” ; Expression = {$_.Properties[11].Value}},
    @{Label = “LogonGuid” ; Expression = {$_.Properties[12].Value}} |
    Where-Object -Property AccountName -EQ “Olivier” |
    Format-Table -AutoSize -Wrap

    The output is displayed as an object, not a block string. It’s very boring with eventlogs, a lot of information are located in a unique property called Properties (corresponding to Message). With your previsious code, the output is just a string block for all the Message property.

    In the FilterHasTable, you could also add other parameters like the folowwing, and there is very efficient.
    $StartTime = Get-Date -Year 2020 -Month 10 -Day 7 -Hour 07 -Minute 36 -Second 02
    $EndTime = Get-Date -Year 2020 -Month 10 -Day 7 -Hour 07 -Minute 36 -Second 05
    $Query = Get-WinEvent -FilterHashtable @{
    LogName = ‘Security’
    StartTime = $StartTime
    EndTime = $EndTime
    ID = “4624”
    }
    Nota : I separate the EventLog query from the display. The query takes the longest time. You could also reduced easily the query by Adding the parameter -MaxEvents

    I recognize, however, that in the case showed, Get-EventLog is quite effective.-

    Liked by 2 people

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.