答案1
使用最新的属性。
Lastlogon 仅在执行身份验证的域控制器上更新,并且不会被复制。
LastLogontimestamp 会被复制,但默认情况下,仅当它比之前的值早 14 天或更长时间时才会复制。
答案2
总结- 如果您想要最准确的登录时间,您必须lastLogon
从所有域控制器查询该属性。如果容差±19天是可以接受的,那么您只需lastLogonTimestamp
从最近的域控制器读取即可。
上次登录
此属性不会被复制,而是在域中的每个域控制器上单独维护。要获取用户在域中的上次登录的准确值,必须从域中的每个域控制器检索用户的 Last-Logon 属性。检索到的最大值是该用户的真实上次登录时间。
https://docs.microsoft.com/en-us/windows/desktop/adschema/a-lastlogon#remarks
上次登录时间戳
每当用户登录时,都会从 DC 读取此属性的值。如果该值早于 [ current_time -
msDS-LogonTimeSyncInterval
],则更新该值。域功能级别提升后的初始更新计算为 14 天减去 5 天的随机百分比。
https://docs.microsoft.com/en-us/windows/desktop/adschema/a-lastlogontimestamp
笔记:
- 如果您以编程方式检索这两个日期,则它们都将存储为
FILETIME
(在 .Net/PowerShell 中)。Int64
- PowerShell 还提供了一个
LastLogonDate
属性。我本来希望提供 Microsoft 特定的文档来确认这一点,但大多数消息来源都说并且我的测试也证实它已lastLogonTimestamp
转换为本地DateTime
值。
答案3
其他答案忽略了一个重要细节,但在调查问题中提到的案件时,这个细节至关重要。
上次登录时间戳 可以更新即使未进行实际登录!
例如,您可以亲眼看到在检查“有效权限”对于具有足够旧的 LastLogonTimestamp 值的帐户。
当您遇到如屏幕截图所示的情况时,您会看到某人帐户的 LastLogonTimestamp 相对较新,则您应该检查所有域控制器的 LastLogon 属性值。
如果它们都比 LastLogonTimestamp 旧,那么可能意味着没有“真人进入”,我的意思是有人登录到工作站或远程桌面会话。
但同时,您不能 100% 确定,因此您应该检查所有可用的日志,以确保该帐户未用于任何其他目的(从移动设备同步邮件或类似的东西)...
最后,您应该将 lastLogon 和 lastLogonTimestamp 仅视为查找陈旧帐户的手段。
并且出于安全原因,您必须提前设置所有必要的审计设置,然后使用审计日志进行调查。
不要管最后的登录!
答案4
对于任何想要一个脚本来获取所有启用用户的上次登录时间戳的人来说,这就是我所使用的。
它检查每个 DC 上是否LastLogon
列出了时间戳,如果没有,它将使用LastLogonTimestamp
存在的时间戳,否则将留空。它这样做是因为用户可能没有登录到任何活动的 DC,并且可能是上次登录的旧的已停用的 DC,但该 DC 将同步到LastLogonTimestamp
。
然后它比较各LastLogonCalc
列并获取最新的列。
最后,它会通过电子邮件发送给您。
# Import AD module if not already imported
Import-Module ActiveDirectory
# Get all DCs
$DCs = (Get-ADDomainController -Filter *).Name
# Output to $DCResult for each DC
$DCResult = foreach ($DC in $DCs) {
Get-ADUser -Filter { Enabled -eq $true } -Server $DC -Properties Created, LastLogon, LastLogonDate, LastLogonTimestamp, SamAccountName, GivenName, sn, UserPrincipalName, EmailAddress, mail, Enabled, LockedOut, lockoutTime, LogonWorkstations, Modified, whenChanged, whenCreated, AccountExpirationDate, PasswordExpired, PasswordLastSet, PasswordNeverExpires, CanonicalName, Department, Office, Company, Description, Title, Manager | select Name, Enabled, Created, @{L="LastLogonCalc";E={if ($_.LastLogon -eq "" -or $_.LastLogon -eq $null -or $_.LastLogon -eq 0) { if ($_.LastLogonTimestamp) { [datetime]::FromFileTime($_.LastLogonTimestamp) } else { "" } } else { [datetime]::FromFileTime($_.LastLogon) } }}, @{L="OU";E={$_.CanonicalName.Replace("\/","").substring(0,$_.CanonicalName.Replace("\/","").LastIndexOf("/")+1)}}, @{L="DC";E={$DC}}, SamAccountName, GivenName, sn, UserPrincipalName, EmailAddress, mail, LastLogon, LastLogonTimestamp, LastLogonDate, LockedOut, lockoutTime, LogonWorkstations, Modified, whenChanged, whenCreated, AccountExpirationDate, PasswordExpired, PasswordLastSet, PasswordNeverExpires, CanonicalName, Department, Office, Company, Description, Title, Manager
}
# Convert the results
# Group by Name
# For each group of computer Name's (each Name will have a group)
# Each group will contain one entry for each DC
# If the object has never authenticated against the DC, it'll return None, but that goes to the top of the list, so we need to exlude "None" entries
# Sort by the LastLogon date, and select the last one (most recent date)
$DCOutput = $DCResult | Foreach-Object {$_} | Group-Object Name | Foreach-Object { $_.Group | Sort-Object LastLogonCalc | Select-Object -Last 1 }
$DCOutput = $DCOutput | ForEach-Object { $_ | select Name, Enabled, Created, @{L="LastLogonCalc";E={if ($_.LastLogonCalc -eq "" -or $_.LastLogonCalc -eq $null -or $_.LastLogonCalc -eq 0) { "None" } else { $_.LastLogonCalc } }}, OU, SamAccountName, GivenName, sn, UserPrincipalName, EmailAddress, mail, LastLogon, LastLogonTimestamp, LastLogonDate, LockedOut, lockoutTime, LogonWorkstations, Modified, whenChanged, whenCreated, AccountExpirationDate, PasswordExpired, PasswordLastSet, PasswordNeverExpires, CanonicalName, Department, Office, Company, Description, Title, Manager }
# Set the file name
$DCOutputFilePath = "C:\Temp\UserLastLogonDate$(Get-Date -Format 'yyyy-MM-dd-HHmmss').csv"
# Save the file
$DCOutput | Export-Csv -Path $DCOutputFilePath -NoTypeInformation
# For the email, set the recipents, the Subject, Body and attachments
$EmailRecipients = @("[email protected]")
$EmailSubject = "User Last Login Dates $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')"
$EmailBody = "Attached are the last logon dates for all <B>Enabled</b> AD Users."
$EmailAttachments = @("$DCOutputFilePath")
# Send the email
Send-MailMessage -SmtpServer smtp.MyDomain.uk -Port 25 -From [email protected] -To $EmailRecipients -Subject $EmailSubject -Body $EmailBody -BodyAsHtml -Attachments $EmailAttachments
sleep 10
# Delete the temporary file
Remove-Item -Path $DCOutputFilePath