html
In Active Directory (AD), both lastLogon
and lastLogonTimestamp
track authentication events, but with critical technical differences:
- lastLogon:
- Precise real-time recording of every successful authentication
- Not replicated between domain controllers (DC-specific)
- Stored as 64-bit integer representing FILETIME (100-nanosecond intervals since 1601)
- lastLogonTimestamp:
- Replicated across domain controllers with loose consistency
- Updates only when the time difference exceeds 14 days (by default)
- Optimized for cross-DC queries at the expense of precision
For forensic investigations like your terminated employee case:
# PowerShell script to compare both attributes across all DCs
Import-Module ActiveDirectory
$username = "jdoe"
$cutoffDate = [datetime]"2023-10-15"
# Query all DCs for lastLogon (requires admin rights)
$lastLogons = Get-ADDomainController -Filter * | ForEach-Object {
$dc = $_.HostName
Get-ADUser $username -Properties lastLogon -Server $dc |
Select-Object @{Name='DC';Expression={$dc}},
@{Name='lastLogon';Expression={[datetime]::FromFileTime($_.lastLogon)}}
}
# Get the replicated timestamp
$llt = Get-ADUser $username -Properties lastLogonTimestamp |
Select-Object @{Name='lastLogonTimestamp';Expression={[datetime]::FromFileTime($_.lastLogonTimestamp)}}
# Display results
$lastLogons | Sort-Object lastLogon -Descending
$llt
Consider these scenarios:
Situation | lastLogon | lastLogonTimestamp |
---|---|---|
Daily workstation login | Updates every time | Only updates after 14+ days |
Terminated employee | Shows true last access | May show cached value |
Multi-DC environment | Different per DC | Synchronized eventually |
For maximum accuracy:
- Query
lastLogon
from all domain controllers - Check the Security event logs (Event ID 4624) on DCs
- Examine workstation logs if the user had a dedicated machine
- Review VPN authentication logs if remote access was enabled
When monitoring account activity:
# Scheduled task to track true last logons
$scriptBlock = {
$users = Get-ADUser -Filter * -Properties lastLogon
$report = foreach ($u in $users) {
[PSCustomObject]@{
SamAccountName = $u.SamAccountName
LastLogonUTC = if ($u.lastLogon) { [datetime]::FromFileTime($u.lastLogon) } else { $null }
DC = $env:COMPUTERNAME
Timestamp = Get-Date
}
}
$report | Export-Csv -Path "C:\ADAudit\lastLogons_$(Get-Date -Format yyyyMMdd).csv" -Append
}
# Run on each DC via scheduled task
Register-ScheduledJob -Name "AD LastLogon Tracker" -ScriptBlock $scriptBlock -Trigger (New-JobTrigger -Daily -At 3am)
When investigating user login activity in Active Directory, you'll encounter two similar-looking but fundamentally different attributes:
- lastLogon: Records the exact timestamp of the most recent authentication (local to each domain controller)
- lastLogonTimestamp: A replicated attribute with intentional latency (typically 9-14 days behind)
The scenario you described (lastLogon showing pre-termination while lastLogonTimestamp shows post-termination) occurs because:
lastLogon
updates in real-time but isn't replicated across DCslastLogonTimestamp
replicates across the domain but with a built-in delay to prevent replication storms
For accurate forensic investigation, you need to:
# PowerShell script to check lastLogon across all DCs
$user = "username"
$domain = "yourdomain.com"
$dcs = Get-ADDomainController -Filter * | Select-Object HostName
$lastLogons = @()
foreach ($dc in $dcs) {
$userObj = Get-ADUser $user -Properties lastLogon -Server $dc.HostName
$lastLogons += [PSCustomObject]@{
DC = $dc.HostName
LastLogon = if ($userObj.lastLogon) { [datetime]::FromFileTime($userObj.lastLogon) } else { $null }
}
}
$lastLogons | Sort-Object LastLogon -Descending | Select-Object -First 1
Attribute | Best Use Case | Accuracy Window |
---|---|---|
lastLogon | Real-time security investigations | Precise to the second |
lastLogonTimestamp | Account cleanup scripts | ±14 days tolerance |
For routine cleanup (where exact precision isn't critical), use lastLogonTimestamp:
# Find users who haven't logged in for 90+ days
$inactiveThreshold = (Get-Date).AddDays(-90)
Get-ADUser -Filter {Enabled -eq $true} -Properties lastLogonTimestamp |
Where-Object { $_.lastLogonTimestamp -lt $inactiveThreshold.ToFileTime() } |
Select-Object SamAccountName, @{
Name="LastLogonDate";
Expression={[datetime]::FromFileTime($_.lastLogonTimestamp)}
}
- Neither attribute tracks interactive vs network logins specifically
- lastLogonTimestamp may show values up to 14 days older than actual last login
- Some authentication methods (like SSPI) may not update these attributes