- Published on
How to Find a Computer's Last Logon Time in Active Directory (PowerShell Script)
Before decommissioning a computer account you believe is inactive, you want to be sure — and LastLogonDate alone isn't quite enough to be sure. Just like with users, it's the replicated, infrequently-updated version of a value that can lag reality by over a week.
The quick answer
Get-ADComputer -Identity WKS01 -Properties LastLogonDate | Select-Object Name, LastLogonDate
Good enough for a casual check. Not good enough to justify actually deleting the account.
A more useful reporting script
#requires -Modules ActiveDirectory
<#
.SYNOPSIS
Finds a computer's true last logon time by checking every domain controller.
#>
[CmdletBinding()]
param(
[Parameter(Mandatory)]
[string]$ComputerName
)
Import-Module ActiveDirectory -ErrorAction Stop
$identity = $ComputerName.TrimEnd('$')
$computer = Get-ADComputer -Identity $identity -ErrorAction Stop
$domainControllers = Get-ADDomainController -Filter *
$perDcResults = foreach ($dc in $domainControllers) {
try {
$dcComputer = Get-ADComputer -Identity $computer.DistinguishedName -Server $dc.HostName -Properties LastLogon -ErrorAction Stop
$lastLogon = if ($dcComputer.LastLogon) { [DateTime]::FromFileTime($dcComputer.LastLogon) } else { $null }
} catch {
Write-Warning "Could not query $($dc.HostName): $($_.Exception.Message)"
$lastLogon = $null
}
[PSCustomObject]@{ DomainController = $dc.HostName; LastLogon = $lastLogon }
}
$trueLastLogon = $perDcResults | Where-Object { $_.LastLogon } | Sort-Object LastLogon -Descending | Select-Object -First 1
Write-Host "Per-DC last logon for $($computer.Name):" -ForegroundColor Cyan
$perDcResults | Sort-Object DomainController | Format-Table DomainController, LastLogon -AutoSize
if ($trueLastLogon) {
Write-Host "True last logon (max across all DCs): $($trueLastLogon.LastLogon) (on $($trueLastLogon.DomainController))" -ForegroundColor Green
} else {
Write-Host "No DC reported a last logon time for $($computer.Name) — it may have never logged on." -ForegroundColor Yellow
}
Run it with just the computer's SAM account name (WKS01 or WKS01$, either works — the script trims the trailing $ for you) and it queries every DC directly for the maximum.
Why LastLogon instead of LastLogonDate
LastLogon is per-DC and never replicated — every DC only knows about authentication it personally handled. LastLogonDate is the replicated, "good enough for a rough sense" version, updated roughly every 9-14 days by default to limit replication traffic. For a decommission decision, "roughly this long ago" isn't a good enough basis — you want the actual maximum across every DC, which is exactly what querying each one directly and comparing gives you.
Where the manual approach runs out of road
A one-off script is fine for a single check. It starts to hurt once you actually need to run this regularly:
- No scheduling. Cron/Task Scheduler can run the script, but now you own the scheduling, the credentials it runs as, and what happens when it silently fails.
- No history. A CSV export is a snapshot. Was this the same five accounts as last month, or a growing list? A single export can't tell you.
- No distribution. Getting the report to the right people (security, IT ops, compliance) on a schedule means building that plumbing yourself.
- Multi-domain/multi-forest pain. Run it once per domain, reconcile the results yourself, and hope naming/OU conventions are consistent across all of them.
- No alerting. If something changes unexpectedly between runs — an account re-enabled, a privileged group gaining a member — nothing tells you until you happen to run the script again.
None of that is a PowerShell problem. It's what turns a script into a product.
What SysFlint AD does instead
Our SysFlint AD runs the same kind of discovery shown above automatically, on a schedule, entirely inside your own network. No agents on domain controllers, no data leaving your environment. It's free, forever.
- Stale and inactive account detection — Enabled accounts that nobody has logged into for 30, 60, or 90+ days — the ones that are still a live attack surface.
- Scheduled reports by email — Daily, weekly, or monthly runs delivered to the right inbox automatically. No Task Scheduler job for you to babysit.
- Multi-domain and forest coverage — Enumerate every domain in the forest in one pass and get one consolidated report instead of one per domain.
If you're currently doing this with a script on a scheduled task, here's the honest comparison between the two, or go straight to the download page.
Get this script, and the rest of them
The script above is part of awesome-it-scripts, SysFlint's free, open-source library of PowerShell scripts for Active Directory and other IT-admin tasks — no signup, no catch, MIT licensed. Grab this one directly from active-directory/Get-ADComputerLastLogonAllDCs.ps1, or browse the whole thing.
Find every disabled/locked-out/stale/privileged-account script we've published (plus the FAQ that goes with each one) in the repo's active-directory folder. Star it if it's useful — new scripts land there regularly.