Find out when your Password Expires


Few weeks ago I came across this question “How to find out an account’s password expiration date” in one of our internal mailing-list. This looks like a simple question, but when we tried to find the answer we realized it is not a trivial task. One of my colleagues pointed to this 22-printed page detailed MSDN article that describes how to find a user account’s password expiration date. The steps described in this article are a bit outdated. It does not take Fine-Grained Password policy (a new feature added in Windows 2008) into account while calculating the maximum password age. With the addition of fine grained password policy, this becomes an even more daunting task to do. Using AD Powershell this task can be achieved with ~40 lines of script-code. Here is function that calculates the password expiration date of a user object given its samAccountName, security identifier or DistinguishedName.

function Get-XADUserPasswordExpirationDate() {

Param ([Parameter(Mandatory=$true, Position=0, ValueFromPipeline=$true, HelpMessage="Identity of the Account")]
[Object] $accountIdentity)
PROCESS {
$accountObj = Get-ADUser $accountIdentity -properties PasswordExpired, PasswordNeverExpires, PasswordLastSet
if ($accountObj.PasswordExpired) {
echo ("Password of account: " + $accountObj.Name + " already expired!")
} else {
if ($accountObj.PasswordNeverExpires) {
echo ("Password of account: " + $accountObj.Name + " is set to never expires!")
} else {
$passwordSetDate = $accountObj.PasswordLastSet
if ($passwordSetDate -eq $null) {
echo ("Password of account: " + $accountObj.Name + " has never been set!")
} else {
$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
}
} else {
$maxPasswordAgeTimeSpan = (Get-ADDefaultDomainPasswordPolicy).MaxPasswordAge
}
if ($maxPasswordAgeTimeSpan -eq $null -or $maxPasswordAgeTimeSpan.TotalMilliseconds -eq 0) {
echo ("MaxPasswordAge is not set for the domain or is set to zero!")
} else {
echo ("Password of account: " + $accountObj.Name + " expires on: " + ($passwordSetDate + $maxPasswordAgeTimeSpan))
}
}
}
}
}
}

Here are some sample usages of this function:

PS AD:\> Get-XADUserPasswordExpirationDate testuser1
Password of account: testuser1 already expired!

PS AD:\> Get-XADUserPasswordExpirationDate JohnDoe
Password of account: John Doe expires on: 02/25/2010 13:03:20

Since the MSDN article explains the algorithm using a flow diagram, I too have tried creating a flow diagram that explains the logic used to compute the password expiration date of an account:

clip_image002

 

Hope you find this useful. Please leave a comment if you have any feedback on this topic or would like to see any other topic discussed in our blog.

 

Enjoy,

Swami

Comments (26)

  1. Anonymous says:

    Will this script work on both 2003 and 2008?

  2. Anonymous says:

    Hello again,

    Having problems getting this to run on a Windows 2003 server.

    -> Have upgraded Powershell:

    PS C:Documents and SettingsAdministrator.EX2K3Desktop> $PSVersionTable

    Name                           Value

    —-                           —–

    CLRVersion                     2.0.50727.3082

    BuildVersion                   6.0.6002.18111

    PSVersion                      2.0

    WSManStackVersion              2.0

    PSCompatibleVersions           {1.0, 2.0}

    SerializationVersion           1.1.0.1

    PSRemotingProtocolVersion      2.1

    • >Have set exectionpolicy to Unrestricted

    -> When trying to run the script it seems that the script doesn't run. How's that?:

    PS C:Documents and SettingsAdministrator.EX2K3Desktop> .GET-XADUserPasswordExpirationDate user1

    PS C:Documents and SettingsAdministrator.EX2K3Desktop>

    /G

  3. M. Ali says:

    @Greg B

    The Active Directory module for Powershell is only supported on Windows Server 2008 R2 or Windows 7 OS. Please see the following for the installation details:

    blogs.msdn.com/…/installation

  4. Anonymous says:

    You can also read the (new in 2008) account attribute msDS-UserPasswordExpiryTimeComputed. This will tell you the password expiration date.

  5. Anonymous says:

    If the password is already expired, checking the "Password Never Expires" checkbox will un-expire the password until the user is located on a site with a DC.

    If the DC to be reachable over the VPN (which is a requirement for the lock/unlock suggestion that you have), why not just go ahead and change the password? Doing the change password will still cache the new password, so cached logons will work fine.

    http://www.lepide.com/

  6. Anonymous says:

    Or just start a command prompt and type "net user <username>"

    (Or "net user <username> /domain" if it's a domain account…

    ~1 line of code…

  7. Anonymous says:

    The net user command won't take note of fine grained password policies in a 2008r2 native domain. The attributes added to the schema that account for the functionality of fine grained password policies came after net user. That application has nothing that can account for those new attributes.

  8. Anonymous says:

    How do we use this in powershell?  I create a test4.ps1 file with the code from above pasted.  Then in powershell i run .Test4.ps1 Get-XADUserPasswordExpirationDate USERNAME and nothing shows up.  Am i running this correctly?

    Thanks

  9. Anonymous says:

    Thank you, This is an awesome scriptfunction, I'm most certainly adding this to my arsenal of scripts!

    Cheers,

    Matthew Kerfoot

    http://www.matthewkerfoot.com

  10. Anonymous says:

    Yours is too long. I just use old dos command on powershell

    net user username <Enter> (for local user)

    net user username /domain <Enter> (for domain user)

    They will give you the same result.

  11. Anonymous says:

    Hi Swami,

    Thank you, the script is very useful and others for sharing ideas. If you wish to check password/ account expiration using GUI, you can checkout JiJi Password Expiration Notification Tool.

    Regards,

    Gopi

    http://www.jijitechnologies.com

  12. Anonymous says:

    Go to boot from Windows CD, then go to command mode

  13. Anonymous says:

    Change the last else statement as follows:

    $expiryDate = Get-Date ($passwordSetDate + $maxPasswordAgeTimeSpan) -format D

                           echo ("Password of account: " + $accountObj.Name + " expires on: " + $expiryDate)

    This returns the expiry date in a non-ambiguous format.

  14. Anonymous says:

    Powershell script just to find a password expiry? Seriously? Thi is so much easier:

    http://www.dolejarz.com/how-to-find-password-age-in-active-directory

  15. Anonymous says:

    Brum…. What can I say, I laughed my head off when I saw you last comment… The "net" command worked perfectly for my needs, no messing with AS PowerShell! Thanks

  16. Anonymous says:

    Even though I was able to obtain the password expiration via a dos command/prompt, I do appreciate this PowerShell function. I had no issues getting it to light up, since we run a Windows 2008 R2 infrastructure. In addition, I am able to re-purpose much of the code.

    Thanks again M.Ali!

  17. Anonymous says:

    I have a strange situation where every now and again the if ($maxPasswordAgeTimeSpan -eq $null -or $maxPasswordAgeTimeSpan.TotalMilliseconds -eq 0) evaluates true.  not sure why.  Is there a way to manually set the $maxPasswordAgeTimeSpan equal to a 60 day time span as a work around?

  18. Anonymous says:

    Found this script to be extremely helpful during an implementation of FGPP.  I was having a problem with LDAP calls to active directory from an application that was returning results based off of the domain GPO rather than the FGPP.  When trying to identify the problem, the net user command was also misleading as it does not report values based off of the FGPP's.  This script was useful in finding and verifying the actual password expiration date for accounts with an FGPP applied.

    Thanks!

  19. Anonymous says:

    One liner : Get-ADUser $user -Properties "msDS-UserPasswordExpiryTimeComputed"

    Then, just convert to datetime.

  20. Clint Wills says:

    Really Very good blog post, thanks for the useful  information about password expiration notification and find out all users who have password never expires via PowerShell command. I  also found good information from password-expiration-notification.blogspot.in whose provide the script to notify  users through email notification about their impending AD password expiry and get the complete  reports on the delivery status of password change reminder.

  21. Anonymous says:

    Kindly have a look at adsysnet ad inactive account tracker,. This tool notify the password and account expiration info . And options for scheduling actions on those ad user accounts.

    try this link, adsysnet.com/asn-active-directory-inactive-account-tracker-download.aspx

  22. JOhn says:

    How do you run this script in powershell?

  23. Someguy says:

    Steve – thanks for the one-liner.  The way powershell should work for something so simple!

  24. Improvement on the one-liner says:

    Automatically computes the date and time, assigns it to column named PasswordExpirationDate

    get-aduser -filter {Enabled -eq $True -and PasswordNeverExpires -eq $False -and Name -notlike "*$*" -and Mail -like "*@*"} -Properties msDS-UserPasswordExpiryTimeComputed,mail | select givenname,surname,samaccountname,@{name="PasswordExpirationDate";expression={([datetime]::FromFileTime($_."msDS-UserPasswordExpiryTimeComputed"))}} | sort PasswordExpirationDate | ft

    Or this to save to .csv file

    get-aduser -filter {Enabled -eq $True -and PasswordNeverExpires -eq $False -and Name -notlike "*$*" -and Mail -like "*@*"} -Properties msDS-UserPasswordExpiryTimeComputed,mail | select givenname,surname,samaccountname,@{name="PasswordExpirationDate";expression={([datetime]::FromFileTime($_."msDS-UserPasswordExpiryTimeComputed"))}} | sort PasswordExpirationDate | export-csv -path passwordsexpiring.csv

    Want to know how many passwords expire tomorrow in a one liner?

    get-aduser -filter {Enabled -eq $True -and PasswordNeverExpires -eq $False -and Name -notlike "*$*" -and Mail -like "*@*"} -Properties msDS-UserPasswordExpiryTimeComputed,mail | select givenname,surname,samaccountname,mail,@{name="PasswordExpirationDate";expression={([datetime]::FromFileTime($_."msDS-UserPasswordExpiryTimeComputed"))}} | where {(($_.PasswordExpirationDate).toshortdatestring()) -like (((get-date).adddays(1)).ToShortDateString())} | ft

  25. Updated improvement on one-liner says:

    Automatically computes the date and time, assigns it to column named PasswordExpirationDate.  Previous post would only display if they had an email address in AD.  Used the previous to send expiration notice to end user.  

    get-aduser -filter {Enabled -eq $True -and PasswordNeverExpires -eq $False -and Name -notlike "*$*"} -Properties msDS-UserPasswordExpiryTimeComputed | select givenname,surname,samaccountname,@{name="PasswordExpirationDate";expression={([datetime]::FromFileTime($_."msDS-UserPasswordExpiryTimeComputed"))}} | sort PasswordExpirationDate | ft

    Or this to save to .csv file

    get-aduser -filter {Enabled -eq $True -and PasswordNeverExpires -eq $False -and Name -notlike "*$*"} -Properties msDS-UserPasswordExpiryTimeComputed | select givenname,surname,samaccountname,@{name="PasswordExpirationDate";expression={([datetime]::FromFileTime($_."msDS-UserPasswordExpiryTimeComputed"))}} | sort PasswordExpirationDate | export-csv -path passwordsexpiring.csv

    Want to know how many passwords expire tomorrow in a one liner?

    get-aduser -filter {Enabled -eq $True -and PasswordNeverExpires -eq $False -and Name -notlike "*$*"} -Properties msDS-UserPasswordExpiryTimeComputed | select givenname,surname,samaccountname,mail,@{name="PasswordExpirationDate";expression={([datetime]::FromFileTime($_."msDS-UserPasswordExpiryTimeComputed"))}} | where {(($_.PasswordExpirationDate).toshortdatestring()) -like (((get-date).adddays(1)).ToShortDateString())} | ft

    Hope it helps someone else,

  26. AD-Admin says:

    Hey Swami,

    your scripts is gr8 and working.

    I'll like to have this script sending the email to user about password expire and it should be automated whereas above we need t manually run the Get-XADUserPasswordExpirationDate username command to get the details.

    Can you update the script and provide as i'm stuck up on it.

    Appreciate your help.

    Thanks,

    Admin