监控密码更改对于维护 Active Directory (AD) 环境的安全性至关重要。Get-ADUser cmdlet 提供访问与密码相关的属性,帮助管理员跟踪用户最后一次更新凭据的时间。此信息对于合规审计、识别密码过期账户以及生成密码过期报告非常重要。通过利用 PowerShell 对特定 AD 属性的支持,管理员可以有效地监控整个组织的密码健康状况。
Active Directory 通过两个相关但不同的属性存储密码更改信息:
pwdLastSet 属性在某些情况下表现出特定行为:
这些特殊情况需要在脚本中谨慎处理,以避免错误并确保报告准确。
使用 Get-ADUser 命令获取 AD 用户的最后密码设置日期:
Get-ADUser -identity robert.allen -properties PwdLastSet | sort Name | ft Name,@{Name='PwdLastSet';Expression={[DateTime]::FromFileTime($_.PwdLastSet)}}
使用 ADManager Plus 获取 AD 用户的最后密码设置日期:
检索特定用户最后一次更改密码的日期,以验证密码策略的合规性。
Get-ADUser -Identity "john.doe" -Properties PasswordLastSet | Select Name,PasswordLastSet
此命令显示指定用户最后一次更改密码的确切日期和时间。
创建 AD 用户密码年龄脚本,以识别密码超过 90 天的用户。
Get-ADUser -Filter {PasswordLastSet -lt (Get-Date).AddDays(-90)} -Properties PasswordLastSet | Select Name,PasswordLastSet
此 PowerShell 最后密码更改查询有助于识别因密码陈旧带来的安全风险。
通过仅筛选已启用用户,聚焦安全审查。
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 | 控制检索大量用户密码报告时的分页。 |
Get-ADUser -Filter * -Properties PasswordLastSet |
Select Name,@{N='PasswordLastSet';E={if($_.PasswordLastSet){$_.PasswordLastSet}else{'Never Set'}}}
Get-ADUser -Identity "user" -Properties PasswordLastSet |
Select Name,@{N='LastSet';E={[DateTime]::FromFileTime($_.PasswordLastSet)}}
$maxPwdAge = (Get-ADDefaultDomainPasswordPolicy).MaxPasswordAge.Days
Get-ADUser -Filter * -Properties PasswordLastSet |
Select Name,@{N='ExpiresOn';E={$_.PasswordLastSet.AddDays($maxPwdAge)}}
Get-ADUser -Identity "user" -Properties PasswordLastSet,msDS-ResultantPSO |
Select Name,PasswordLastSet,"msDS-ResultantPSO"
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 password 于 next 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,它会维护历史数据。