• 首页
  • PowerShell
  • 如何使用 PowerShell 检查 Active Directory 中的最后密码更改日期

如何使用 PowerShell 检查 Active Directory 中的最后密码更改日期

监控密码更改对于维护 Active Directory (AD) 环境的安全性至关重要。Get-ADUser cmdlet 提供访问与密码相关的属性,帮助管理员跟踪用户最后一次更新凭据的时间。此信息对于合规审计、识别密码过期账户以及生成密码过期报告非常重要。通过利用 PowerShell 对特定 AD 属性的支持,管理员可以有效地监控整个组织的密码健康状况。

理解 PasswordLastSet 和 pwdLastSet

Active Directory 通过两个相关但不同的属性存储密码更改信息:

  • pwdLastSet 是 Active Directory 中实际存储的 LDAP 属性。该属性包含一个 64 位整数,表示自 1601 年 1 月 1 日以来的 100 纳秒间隔数(Windows FileTime 格式)。每当密码更改时,无论是用户、管理员还是通过密码重置过程触发,该值都会自动更新。
  • PasswordLastSetGet-ADUser cmdlet 暴露的 PowerShell 属性。当查询此属性时,PowerShell 会自动将原始的 pwdLastSet 值转换为更易读的 DateTime 对象。此转换简化了脚本和报告中对数据的处理,无需手动进行 FileTime 转换。

特殊情况和空值

pwdLastSet 属性在某些情况下表现出特定行为:

  • 对于尚未设置初始密码的新创建账户,返回 null。
  • 当启用 用户下次登录时必须更改密码 选项时,值变为 null。
  • 设置为 0(零)以强制密码过期。
  • 在任何密码更改操作期间更新为当前时间戳。

这些特殊情况需要在脚本中谨慎处理,以避免错误并确保报告准确。

PowerShell

使用 Get-ADUser 命令获取 AD 用户的最后密码设置日期:

  1. 确定要检索报告的域。
  2. 确定需要获取报告的 LDAP 属性。
  3. 编写脚本。
  4. 在 Windows PowerShell 中执行脚本。
  5. 报告将以请求的格式导出。
  6. To obtain the report in a different format, modify the script accordingly to the needs of the user.
    Get-ADUser -identity robert.allen -properties PwdLastSet | sort Name | ft Name,@{Name='PwdLastSet';Expression={[DateTime]::FromFileTime($_.PwdLastSet)}}
ADManager Plus

使用 ADManager Plus 获取 AD 用户的最后密码设置日期:

  1. 导航至 Reports > Password Reports > Password Changed Users
  2. 选择所需的 domainOU 和期望的 time period 来筛选用户。
  3. 点击 Generate
  4. 报告生成后,点击 Export As 以 HTML、CSV、XLS 或 PDF 格式下载。

示例用例和脚本

示例 1:获取特定用户的最后密码设置日期。

检索特定用户最后一次更改密码的日期,以验证密码策略的合规性。

Get-ADUser -Identity "john.doe" -Properties PasswordLastSet | Select Name,PasswordLastSet

此命令显示指定用户最后一次更改密码的确切日期和时间。

示例 2:查找 90 天内未更改密码的用户。

创建 AD 用户密码年龄脚本,以识别密码超过 90 天的用户。

Get-ADUser -Filter {PasswordLastSet -lt (Get-Date).AddDays(-90)} -Properties PasswordLastSet | Select Name,PasswordLastSet

此 PowerShell 最后密码更改查询有助于识别因密码陈旧带来的安全风险。

示例 3:仅检查已启用账户的密码最后更改时间。

通过仅筛选已启用用户,聚焦安全审查。

Get-ADUser -Filter {Enabled -eq $true} -Properties PasswordLastSet,PasswordNeverExpires | Select Name,PasswordLastSet,PasswordNeverExpires

此命令有助于识别可能需要执行密码策略的活跃账户。

支持的参数

参数 描述
-Identity 通过区分名称、GUID、安全标识符或 SAM 账户名指定 AD 用户对象。
-Filter 使用 PowerShell 表达式语言指定查询字符串,以基于 PasswordLastSet 检索多个对象。
-SearchBase 指定 AD 路径以搜索具有特定密码更改日期的用户。
-Properties 必须包含 PasswordLastSet 才能检索密码更改信息(默认不返回)。
-LDAPFilter 使用 LDAP 语法进行复杂的基于日期的密码查询。
-ResultPageSize 控制检索大量用户密码报告时的分页。

常见密码最后设置查询问题的故障排除

错误:PasswordLastSet 属性返回为空或 null。

  • 原因:用户从未设置密码或查询中未指定属性。
  • Solution: Include the property explicitly and handle null values:
    Get-ADUser -Filter * -Properties PasswordLastSet |
    Select Name,@{N='PasswordLastSet';E={if($_.PasswordLastSet){$_.PasswordLastSet}else{'Never Set'}}}

错误:日期显示为大数字而非可读日期。

  • 原因:PasswordLastSetFileTime 格式(Int64)存储。
  • Solution: Convert to 日期时间 format:
    Get-ADUser -Identity "user" -Properties PasswordLastSet |
    Select Name,@{N='LastSet';E={[DateTime]::FromFileTime($_.PasswordLastSet)}}

错误:PowerShell 密码过期报告显示错误日期。

  • 原因:未考虑域的 MaxPasswordAge 策略。
  • Solution: Calculate expiration using domain policy:
    $maxPwdAge = (Get-ADDefaultDomainPasswordPolicy).MaxPasswordAge.Days
    Get-ADUser -Filter * -Properties PasswordLastSet |
    Select Name,@{N='ExpiresOn';E={$_.PasswordLastSet.AddDays($maxPwdAge)}}

错误:Get-ADUser PasswordLastReset 对细粒度密码策略无效。

  • 原因:细粒度密码策略(FGPP)需要不同的计算方法。
  • Solution: Check for applicable Password Settings Object (PSO):
    Get-ADUser -Identity "user" -Properties PasswordLastSet,msDS-ResultantPSO |
    Select Name,PasswordLastSet,"msDS-ResultantPSO"

避免问题的最佳实践

  • 始终指定 -Properties 参数:默认不返回 PasswordLastSet。
  • 高效处理空值在日期操作前检查 $null
  • 先用小数据集测试:使用 -ResultSetSize 限制初始结果。
  • 使用正确的日期比较:始终使用 DateTime 对象,而非字符串。
  • 考虑服务账户:过滤或特殊处理带有 PasswordNeverExpires 的账户。

使用 PowerShell 查找密码最后设置日期的限制

  • 复杂的日期计算:将 PasswordLastSet 从 FileTime 格式转换需要 DateTime 操作,且空值可能导致错误。
  • 无自动年龄计算:必须手动使用日期运算计算每个用户的密码年龄。
  • 可视化有限:无附加模块无法创建显示密码年龄分布的图表。
  • 空值处理:从未设置密码的用户返回空值,需特殊处理以避免脚本错误。
  • 大数据集性能:未正确过滤时,获取数千用户的 Get-ADUser PasswordLastSet 可能很慢。
  • 无自动告警:无计划任务时无法自动发送密码过期通知。

使用 ADManager Plus 获取 AD 用户密码年龄的亮点

  • 即时密码年龄计算:无需脚本即可查看自动计算的密码年龄(天)。
  • 预置密码报告访问专门的密码过期、永不过期和最近更改密码报告。
  • 合规报告支持即时生成符合 SOX、HIPAA 和 PCI DSS 的密码审计报告。
  • 批量密码管理:直接从报告结果重置多个用户密码。
  • 实时密码监控:通过预配置报告跟踪密码变更。
  • 导出灵活性以多种格式导出密码报告,包含格式化日期和计算年龄。

使用 ADManager Plus 查找 AD 用户的密码最后设置日期

常见问题解答

PasswordLastSet 在 Active Directory 中以 FileTime 值存储(64 位整数,表示自 1601 年 1 月 1 日起的 100 纳秒间隔)。需要转换为可读的 DateTime 格式:

错误:显示原始 FileTime 值

Get-ADUser -Identity "john.doe" -Properties PasswordLastSet | Select PasswordLastSet

正确:转换为可读日期

Get-ADUser -Identity "john.doe" -Properties PasswordLastSet |
Select Name, @{Name='PasswordLastSet';Expression={[DateTime]::FromFileTime($_.PasswordLastSet)}}

对于 PowerShell 3.0 及以上版本,正确使用 -Properties 参数时,PasswordLastSet 属性会自动转换为 DateTime

创建 PowerShell 密码过期报告时,需要将 PasswordLastSet 日期与域的 MaxPasswordAge 策略结合:

获取域密码策略:

$maxPwdAge = (Get-ADDefaultDomainPasswordPolicy).MaxPasswordAge

计算所有用户的过期时间:

Get-ADUser -Filter {Enabled -eq $true} -Properties PasswordLastSet, PasswordNeverExpires |
Select Name, PasswordLastSet,
@{Name='PasswordExpires';Expression={
if($_.PasswordNeverExpires -or $_.PasswordLastSet -eq $null) {
"Never"
} else {
$_.PasswordLastSet.AddDays($maxPwdAge.Days)
}
}},
@{Name='DaysUntilExpiry';Expression={
if($_.PasswordNeverExpires -or $_.PasswordLastSet -eq $null) {
"N/A"
} else {
(New-TimeSpan -Start (Get-Date) -End $_.PasswordLastSet.AddDays($maxPwdAge.Days)).Days
}
}} | Sort DaysUntilExpiry

某些账户的 PasswordLastSet 值可能为空,表示密码从未设置或账户是在启用 User must change passwordnext logon 选项时创建的。

查找未设置密码的用户:

Get-ADUser -Filter * -Properties PasswordLastSet |
Where-Object {$_.PasswordLastSet -eq $null} |
Select Name, SamAccountName, Enabled

在报告中包含适当的处理:

Get-ADUser -Filter * -Properties PasswordLastSet, whenCreated |
Select Name,
@{Name='PasswordStatus';Expression={
if($_.PasswordLastSet -eq $null) {
"Never Set (Created: $($_.whenCreated))"
} else {
"Last Changed: $($_.PasswordLastSet)"
}
}}

FGPPs 会覆盖默认的域策略。您需要检查适用的 PSO。

检查用户是否应用了特定 PSO:

Get-ADUser -Identity "john.doe" -Properties PasswordLastSet, "msDS-ResultantPSO", "msDS-UserPasswordExpiryTimeComputed" |
Select Name, PasswordLastSet,
@{Name='PasswordPolicy';Expression={
if($_."msDS-ResultantPSO") {
(Get-ADObject $_."msDS-ResultantPSO" -Properties name).name
} else {
"Default Domain Policy"
}
}},
@{Name='ExpiryDate';Expression={
[DateTime]::FromFileTime($_."msDS-UserPasswordExpiryTimeComputed")
}}

获取所有具有 FGPPs 的用户及其过期日期:

Get-ADUser -Filter * -Properties PasswordLastSet, "msDS-UserPasswordExpiryTimeComputed", "msDS-ResultantPSO" |
Where-Object {$_."msDS-ResultantPSO" -ne $null} |
Select Name, PasswordLastSet,
@{Name='ExpiryDate';Expression={[DateTime]::FromFileTime($_."msDS-UserPasswordExpiryTimeComputed")}}

此差异通常由于时区差异或工具计算密码年龄的方式不同导致。

确保一致的时区处理:

Get-ADUser -Identity "john.doe" -Properties PasswordLastSet |
Select Name,
@{Name='PasswordLastSet (UTC)';Expression={$_.PasswordLastSet.ToUniversalTime()}},
@{Name='PasswordLastSet (Local)';Expression={$_.PasswordLastSet.ToLocalTime()}},
@{Name='Password Age (Days)';Expression={
[Math]::Round(((Get-Date) - $_.PasswordLastSet).TotalDays, 2)
}}

为了与 Active Directory Users and Computers 精确匹配,请使用相同的计算方法:

Get-ADUser -Identity "john.doe" -Properties PasswordLastSet, pwdLastSet |
Select Name,
@{Name='PasswordLastSet';Expression={$_.PasswordLastSet}},
@{Name='Exact Age';Expression={
$now = [DateTime]::Now
$age = $now - $_.PasswordLastSet
"$($age.Days) days, $($age.Hours) hours, $($age.Minutes) minutes"
}}

创建全面的 AD 用户密码年龄脚本,以便对多个组织单位进行安全审计。

定义目标 OU:

$OUs = @(
"OU=Sales,DC=contoso,DC=com",
"OU=IT,DC=contoso,DC=com",
"OU=Finance,DC=contoso,DC=com"
)

生成全面的密码审计报告:

$Report = foreach ($OU in $OUs) {
Get-ADUser -Filter {Enabled -eq $true} -SearchBase $OU -Properties PasswordLastSet, PasswordNeverExpires,LastLogonDate |
Select @{Name='OU';Expression={$OU.Split(',')[0].Replace('OU=','')}},
Name,
SamAccountName,
@{Name='PasswordLastSet';Expression={
if($_.PasswordLastSet) {$_.PasswordLastSet} else {"Never"}
}},
@{Name='PasswordAge';Expression={
if($_.PasswordLastSet) {
[Math]::Round(((Get-Date) - $_.PasswordLastSet).TotalDays)
} else {"N/A"}
}},
PasswordNeverExpires,
LastLogonDate,
@{Name='Risk Level';Expression={
if($_.PasswordNeverExpires) {"High - Never Expires"}
elseif(-not $_.PasswordLastSet) {"High - Never Set"}
elseif(((Get-Date) - $_.PasswordLastSet).TotalDays -gt 180) {"High - Very Old"}
elseif(((Get-Date) - $_.PasswordLastSet).TotalDays -gt 90) {"Medium - Old"}
else {"Low"}
}}
}

带时间戳导出报告:

$Report | Export-CSV "C:\PasswordAudit_$(Get-Date -Format 'yyyyMMdd_HHmmss').csv" -NoTypeInformation
# Create summary statistics
$Report | Group-Object 'Risk Level' | Select Name, Count

使用 PowerShell 最后密码更改脚本设置主动监控即将过期的密码。

获取默认域密码策略:

$maxPwdAge = (Get-ADDefaultDomainPasswordPolicy).MaxPasswordAge
# Find users with passwords expiring within 7 days
$ExpiringUsers = Get-ADUser -Filter {Enabled -eq $true -and PasswordNeverExpires -eq $false} -Properties PasswordLastSet, EmailAddress, Manager |
Where-Object {$_.PasswordLastSet -ne $null} |
Select Name, EmailAddress,
@{Name='Manager';Expression={(Get-ADUser $_.Manager -ErrorAction SilentlyContinue).Name}},
PasswordLastSet,
@{Name='ExpiryDate';Expression={$_.PasswordLastSet.Add($maxPwdAge)}},
@{Name='DaysUntilExpiry';Expression={
($_.PasswordLastSet.Add($maxPwdAge) - (Get-Date)).Days
}} |
Where-Object {$_.DaysUntilExpiry -le 7 -and $_.DaysUntilExpiry -ge 0} |
Sort DaysUntilExpiry

显示结果:

$ExpiringUsers | Format-Table -AutoSize

PowerShell 无法直接访问密码历史,但您可以使用 AdminSDHolder 或通过比较 PasswordLastSet 随时间的变化来跟踪密码更改频率。

检查当前密码年龄并估算更改频率:

Get-ADUser -Filter * -Properties PasswordLastSet, whenCreated |
Where-Object {$_.PasswordLastSet -ne $null} |
Select Name,
@{Name='AccountAge(Days)';Expression={((Get-Date) - $_.whenCreated).Days}},
@{Name='PasswordAge(Days)';Expression={((Get-Date) - $_.PasswordLastSet).Days}},
@{Name='EstimatedChangesPerYear';Expression={
$accountAge = ((Get-Date) - $_.whenCreated).Days
$passwordAge = ((Get-Date) - $_.PasswordLastSet).Days
if($accountAge -gt 365) {
[Math]::Round(365 / $passwordAge, 2)
} else {
"Account less than 1 year old"
}
}} |
Sort 'PasswordAge(Days)' -Descending

对于括号或其他特殊字符,请使用单引号并根据需要转义。

注意:对于实际的密码历史和详细的更改跟踪,建议使用 ADManager Plus,它会维护历史数据。

Active Directory管理与报告的一站式解决方案
电子邮件下载链接 Email the ADManager Plus download link