Get AD User Password Expiration
0
PEOPLE
Last week I came across a post on the Microsoft Active Directory team blog about finding when a user password expires. The blog posted a PowerShell script that uses the ActiveDirectory cmdlets. The function takes a user name you pass it, get's password information and lets you know if the password has expired or when it is going to expire. It works and gets the job done. However, I decided to take it a step further.
One of my concerns with the original version is that it can't be used in the pipeline. What if you want to get password information for a group of users, but sort them by the password expiration date or only select those that will expire within a certain number of days? The existing function can't do any of that since all it does is write a string message to the pipeline. There is no object. So I revised the function to write a custom object to the pipeline that shows the user name, distinguishedname, whether the password is expired, when it will expire, if it can expire, the password age and when it was last set. Yes, I could probably write an expression using Get-ADUser to return the same results, but since the AD post was already written I decided to start with it. I always encourage people to think "object"-ively. Here's ;my version with a slightly different name.
function Get-ADUserPwdExpiration{
#requires -version 2.0
[cmdletbinding()]
Param ([Parameter(Mandatory=$true,
Position=0,
ValueFromPipeline=$true,
HelpMessage="Identity of the User Account")]
[Alias("name")]
[string] $accountIdentity)
PROCESS {
Trap {
Write-warning "An error occured on this account"
write-warning $accountObj
#$accountobj | select *
write-warning $_.exception.Message
continue
}
$accountObj = Get-ADUser $accountIdentity -properties PasswordExpired, PasswordNeverExpires, PasswordLastSet
#enable the following line for debugging
#$accountobj | select *
#verify an account was found
if ($accountObj) {
#set some default values
$NeverExpires=$False
#default value indicates the account has expired
[datetime]$ExpiresOn="1/1/0001"
if ($accountObj.PasswordExpired) {
$expired=$True
}
else {
$Expired=$False
}
#verify there is a PasswordLastSet value
if ($accountObj.PasswordLastSet) {
$pwdLastSet=$accountObj.PasswordLastSet
}
else {
#password has likely never been set
$pwdLastSet=$False
[timespan]$passwordAge=0
#Write-warning "password last set is null"
}
If ($pwdLastSet) {
#get password details
#get password age
[timespan]$passwordAge=(get-date) - $pwdLastSet
if ($accountObj.PasswordNeverExpires) {
$NeverExpires=$True
[datetime]$ExpiresOn="9/9/9999"
}
else {
#get dfl
$maxPasswordAgeTimeSpan = $null
$dfl = (get-addomain).DomainMode
if ($dfl -ge 3) {
## Greater than Windows2008 domain functional level
$accountFGPP = Get-ADUserResultantPasswordPolicy $accountObj
if ($accountFGPP -ne $null) {
$maxPasswordAgeTimeSpan = $accountFGPP.MaxPasswordAge
}
else {
$maxPasswordAgeTimeSpan = (Get-ADDefaultDomainPasswordPolicy).MaxPasswordAge
}
} #if $dfl -ge 3
else {
$maxPasswordAgeTimeSpan = (Get-ADDefaultDomainPasswordPolicy).MaxPasswordAge
}
if ($maxPasswordAgeTimeSpan -eq $null -or $maxPasswordAgeTimeSpan.TotalMilliseconds -eq 0) {
write-warning "MaxPasswordAge is not set for the domain or is set to zero!"
} else {
$pwdLastSet=$accountObj.PasswordLastSet
[datetime]$ExpiresOn=$pwdLastSet + $maxPasswordAgeTimeSpan
}
} #else get dfl
}
#Write a custom object to the pipeline
new-object PSObject -Property @{
Name=$accountObj.name
DN=$accountObj.DistinguishedName
SAM=$accountObj.SAMAccountName
NeverExpires=$neverExpires
Expired=$expired
ExpiresOn=$expiresOn
PasswordLastSet=$pwdLastSet
PasswordAge=$passwordAge
Enabled=$accountobj.Enabled
}
} #end If $accountobj
else {
write-warning "Failed to find a user account for $accountIdentity"
}
} #end Process
} #end function
My version also includes some error handling so that if you specify a user account that doesn't exist, a warning message is displayed. After you download the script file you can dot source it in your PowerShell session. The script also defines an alias, gupe, for the function which makes it easier to use.
PS S:\> . .\Get-ADUserPwdExpiration.ps1
PS S:\> gupe a.beebe
PasswordLastSet : 3/4/2010 1:26:04 PM
SAM : A.Beebe
ExpiresOn : 4/15/2010 1:26:04 PM
Enabled : True
Name : Ann Beebe
NeverExpires : False
DN : CN=Ann Beebe,OU=HR,OU=Employees,DC=jdhlab,DC=local
Expired : False
PasswordAge : 6.01:26:29.9648862
I'll be the first to admit it isn't a perfect script or function. But it can be used in the pipeline so you can sort, filter, export, group or do whatever you want with the resulting object. I changed some values to True/False or other values that can be sorted or at least consisten. When I work with PowerShell, this is what I'm after. You'll have to let me know what you think.,
Replies
None, yet.









