source: https://gallery.technet.microsoft.com/scriptcenter/Get-Last-Logon-for-Users-c8e3eab2
The “lastLogon” Active Directory attribute is a property that is not replicated throughout the Domain Controllers. This attribute is stored on the domain controller that received the authentication request and updated its property accordingly. Because of this behavior, you have have experienced issues where Domain Controllers in other sites have old or empty lastLogon information. This makes it difficult to be sure an account is truly inactive without verifying on each Domain Controller. This can be a problem for environments that have tens or hundreds of Domain Controllers across its enterprise.
I was faced with a problem of writing a script, and like many, developed a seemingly simple solution. The problem was the runtime was very long for the amount of Domain Controllers / User accounts for the environment. I sought out to find the solution to this exceedingly long runtime, and I finally did.
This PowerShell will query each of your Domain Controllers only once and produce the most recent logon date/time.
To protect the informaiton about my directory, lets say my environment is between 5 and 10 Domain Controllers, with between 15 – 25k user accounts. My runtime is between 4-5 minutes for the entire directory! Which is a far cry faster than the hours other methods produce.
By default, this script will return the entire directory ($Username=*) and save to a CSV ($FileName). You may call the function with a -Username to return a single account, and this will output on screen instead of a file.
<###########################################################################
The purpose of this PowerShell script is to collect the last logon
for user accounts on each DC in the domain, evaluate, and return the
most recent logon value.
Author: Jeremy Reeves
Modified: 02/14/2018
Notes: Must have RSAT Tools if running on a workstation
Note: Added enabled true/false to output
###########################################################################>
Import-Module ActiveDirectory
function Get-ADUsersLastLogon($Username="*") {
$FilePath_Prefix = "C:\temp\UserLastLogon-"
function Msg ($Txt="") {
Write-Host "$([DateTime]::Now) $Txt"
}
#Cycle each DC and gather user account lastlogon attributes
$List = @() #Define Array
(Get-ADDomain).ReplicaDirectoryServers | Sort | % {
$DC = $_
Msg "Reading $DC"
$List += Get-ADUser -Server $_ -Filter "samaccountname -like '$Username'" -Properties LastLogon | Select samaccountname,lastlogon,enabled,@{n='DC';e={$DC}}
}
Msg "Sorting for most recent lastlogon"
$LatestLogOn = @() #Define Array
$List | Group-Object -Property samaccountname | % {
$LatestLogOn += ($_.Group | Sort -prop lastlogon -Descending)[0]
}
$List.Clear()
if ($Username -eq "*") { #$Username variable was not set. Running against all user accounts and exporting to a file.
$FileName = "$FilePath_Prefix$([DateTime]::Now.ToString("yyyyMMdd-HHmmss")).csv"
try {
$LatestLogOn | Select samaccountname, lastlogon, @{n='lastlogondatetime';e={[datetime]::FromFileTime($_.lastlogon)}}, Enabled, DC | Export-CSV -Path $FileName -NoTypeInformation -Force
Msg "Exported results. $FileName"
} catch {
Msg "Export Failed. $FileName"
}
} else { #$Username variable was set, and may refer to a single user account.
if ($LatestLogOn) { $LatestLogOn | Select samaccountname, @{n='lastlogon';e={[datetime]::FromFileTime($_.lastlogon)}}, Enabled, DC | FT } else { Msg "$Username not found." }
}
$LatestLogon.Clear()
}