Auditing Logon Events in Windows

Every so often we’re asked to look into logon events to determine who logged into a device and when, be it a server or a PC. While there are commercial tools which can provide this information, they tend to be out of reach for smaller organisations leaving us with parsing the Security Event Log.

This post is designed to provide a crash course in what events are relevant, and a quick guide on what to look for.

The content below is specific to Server 2012 R2, and there are large differences in logging between 2008, 2012, and 2016 when it comes to RDP. There is a fantastic in depth write up at PureRDS.org on the topic.

Where do we look?

In both AD and non-domain environments, we need to look at the logs of the device in question - not the domain controllers. Specifically, we’re looking at the Security log,

Successful logon events

Here we’re looking for Event ID 4624. However, this ID is also logged when other authentication events occur, such as a user connecting to a share on a file server - event 4624 would be logged on the file server.

The different types of logon events are identified with the Logon Type field. There is a great article on the different logon types at Techgenix, but here is a quick reference for the types we’re interested in.

Type Name Description
2 Interactive These are the normal logon events you would expect to see when a user logs onto their PC, or onto the console session of a server
3 Network These are logons such as accessing a share, IIS, etc. In specific circumstances type 3 will also be logged for RDP connections - more on this later
7 Unlock The device was unlocked (i.e., screensaver with a password)
10 RemoteInteractive This typically indicates a login via RDP, though with some exceptions described below

There is a also official documentation at Microsoft.

Based on the above, if we’re looking for a user that logged onto a PC, or a server via the console session, we’re looking for Event ID 4624, with a Logon Type of 2.

Event ID 4624 Interactive Logon

If we’re also looking for RDP logons (typically to servers), we would be looking for Event ID 4624, with a Logon Type of 10.

Event ID 4624 Interactive Logon

It’s worth noting that this also gives us the IP address the user was connecting from, under the Network Information heading.

If we only care about RDP logons, another log to check is Microsoft-Windows-TerminalServices-LocalSessionManager/Operational. Here are RDP logons are logged, and in a much cleaner way than what is provided by the Security log.

We would be looking for Event ID 21, logged by TerminalServices-LocalSessionManager.

Event ID 21 RDP Logon

Incorrect username or password

When a user attempts to log on and gets the username or password wrong, this will be logged as an Audit Failure with Event ID 4625 in the Logon Task Category.

Event ID 4625

There is one caveat to this with RDP logons that use NLA (Network Layer Authentication). Failed logon attempts here are logged as Event ID 4624, with a Logon Type of 3.

Extracting relevant logon data

So now we know what we’re looking for, but short of clickity clacking through 100,000 Security event log entries all way to the RSI clinic, how do we extract the data we want?

Here are two examples, one using the Event Viewer, and one using PowerShell. We’ll be looking for Security Log Event Id 4624 with a Logon Type of 10. Modifying the examples to meet your specific needs should be easy.

I won’t go into too much detail here as both of these could be their own standalone posts.

Using Event Viewer

Event logs can be represented as XML documents, if you view any log entry and select the Details tab, there will be an option to display the log in XML View. This is fantastic because it brings structure to our data and makes querying easy.

To create a filter using XML, select Filter Current Log, select the XML tab, tick the Edit Query Manually checkbox, and enter your query.

Here is a sample query for our current example:

<QueryList>
  <Query Id="0" Path="Security">
    <Select Path="Security">
        *[System[(EventID=4624)] and EventData[Data[@Name='LogonType'] and Data=10]]    </Select>  </Query>
</QueryList>

The highlighted lines are the key elements. If you look at the XML representation of the event log, you’ll notice that the EventID property is a child of System, and that the LogonType value is a Data property under the EventData root.

Some more information on XPath / XML queries can be found here.

Using PowerShell

Firstly, what not to do. Do not pull the entire event log and then use Where-Object to filter the logs you want. This is the least performant way to achieve our goal.

What we’re going to do instead is write a hashtable filter that will return only what we need (as usual, with a caveat or two).

PowerSell 6+

PowerShell 6+ introduced <named-data> keys which, if you’re fortunate enough to be running PowerShell 6+, makes you life much easier.

There is great example already on the linked page, but here would be our version of that.

Get-WinEvent -FilterHashtable @{LogName='Security'; ID=4624; 'LogonType'=10}

PowerShell 5.x and earlier

Using a Hashtable

Unfortunately <named-data> is not available to us and there is no structured way to query exactly what we want using a hashtable. What I’ve found tends to work fairly well is to use the Data key and, if we return more than what were after, at that point use Where-Object to do our filtering.

Get-WinEvent -FilterHashtable @{LogName='Security'; ID=4624; Data=10}

Using XPath

I tend to prefer the above method as it usually gets me very close to what I want, and hashtables are easy compared to XML queries. But if we want accuracy with no further filtering required, we can go down the XPath route.

This is the same XML query format we used in the Event Viewer example.

Get-WinEvent -LogName Security -FilterXPath "*[System[(EventID=4624)] and EventData[Data[@Name='LogonType'] and Data=10]]"

That’s it for now, happy hunting!