三个时间字段别搞混
清理僵尸账号前必须搞清 AD 里三个「最后登录」字段的差异:LastLogon 最精确但不复制,只反映你查询的那台域控上的记录;LastLogonTimestamp 会复制到全林,为了减少复制流量而刻意滞后约 9 到 14 天;PowerShell 的 LastLogonDate 只是把 LastLogonTimestamp 换算成日期的视图字段。用错字段就会把活跃账号判成「从未登录」,然后误停用。
基本信息
| 适用平台 | Windows Server Active Directory(AD 模块、RSAT) |
|---|---|
| LastLogon | 单台域控本地维护、不复制,精确到具体登录时间 |
| LastLogonTimestamp | 复制到全域,新增/更新间隔离散,滞后约 9 到 14 天 |
| LastLogonDate | PowerShell 视图字段,来源是 LastLogonTimestamp |
| 取值范围 | LastLogon 与 LastLogonTimestamp 原始值是 64 位时间戳,需 FromFileTime 转换 |
| 权限要求 | 读取属性需要域账户;批量查询建议使用只读委派账号 |
典型使用场景
- 僵尸账号清理:筛选长期未登录且已启用的账号,交给业务确认后停用
- 许可收敛:统计活跃账号数量,评估许可证与资源占用
- 安全审计:检查长期不动的高权限账号与服务账号
- 离职复核:与人事离职清单交叉核对,确认账号是否已停用
- 巡检基线:周期性导出未登录账号清单,形成趋势数据
常用示例
常用示例
# 用复制属性筛选(推荐):滞后但全域一致;筛选串必须用双引号让变量展开
$cut = (Get-Date).AddDays(-90)
Get-ADUser -Filter "LastLogonDate -lt '$cut' -and Enabled -eq $true" -Properties LastLogonDate, PasswordLastSet, LastLogon |
Select-Object Name, SamAccountName, LastLogonDate, PasswordLastSet, @{n='LastLogon本地';e={[datetime]::FromFileTime($_.LastLogon)}} |
Sort-Object LastLogonDate | Export-Csv D:\audit\stale_users.csv -NoTypeInformation -Encoding UTF8
# 日期格式不匹配导致筛选无效时,先转成固定格式再拼接
$cut2 = (Get-Date).AddDays(-90).ToString('MM/dd/yyyy')
Get-ADUser -Filter "LastLogonDate -lt '$cut2'" -Properties LastLogonDate | Measure-Object # 先确认命中数量
# 内置筛选:不活跃账号
Search-ADAccount -AccountInactive -TimeSpan 90.00:00:00 -UsersOnly | Select-Object Name, SamAccountName, LastLogonDate
Search-ADAccount -PasswordNeverExpires -UsersOnly | Select-Object Name, SamAccountName
Search-ADAccount -AccountDisabled -UsersOnly | Select-Object Name, SamAccountName, LastLogonDate字段取舍对照
| 字段 | 是否复制 | 适用判断 |
|---|---|---|
| LastLogon | 否(单台域控局部) | 精确核验某台域控上的登录,需逐台查询取最大值 |
| LastLogonTimestamp | 是(滞后约 9-14 天) | 全域范围的僵尸账号初筛 |
| LastLogonDate | 是(视图字段) | 脚本与报表使用,本质同 LastLogonTimestamp |
| PasswordLastSet | 是 | 判断口令年龄,与登录活动一起看 |
| whenCreated / whenChanged | 是 | 判断对象创建与属性最后修改时间 |
用 LastLogon 判断「从未登录」时必须查遍所有域控:该属性不复制,你查的那台域控上没有记录不代表用户没登录过,可能只是在别的站点域控上登录。
服务账户与计算机账户的「登录」语义与交互式登录不同:服务启动、计划任务、机器开机都会产生认证记录,判断活跃度要结合事件日志与业务依赖,不能只看时间字段。
审计到处置的流程
审计到处置的流程
# 1. 导出清单(不直接改)
Search-ADAccount -AccountInactive -TimeSpan 180.00:00:00 -UsersOnly |
Select-Object Name, SamAccountName, DistinguishedName, LastLogonDate |
Export-Csv D:\audit\inactive_180.csv -NoTypeInformation -Encoding UTF8
# 2. 与业务确认后先禁用并记录
# Disable-ADAccount -Identity wxm01 -Verbose
# Set-ADUser wxm01 -Description '2026-10-13 停用:长期未登录,待业务确认'
# 3. 观察期内确认无影响,再考虑移动到停用 OU
# Get-ADUser wxm01 -Properties Description, LastLogonDate | Select-Object Name, Description, LastLogonDate清理动作一定先停用、后删除:停用可随时回滚,删除会丢失组成员关系、邮箱与权限关联,且同名的重新创建无法复原原有权限。审计清单必须经业务确认,外派、产假、共享与系统账号都属于典型误判对象。