Using PowerShell to generate a Password Expiration email for users


I am looking for a script that will address the needs of remotely based staff and others so they can get notified via email prior to the passwords expiring. I found a script here However I want to be sure this will work in our environment. We are running in hybrid mode with an exchange server running Exchange 2013 on a server running 2012 R2 on premise and using Office 365 with Exchange online.

I also want to test this with a few users before putting in place for the domain. What is the best way to safely do this?


A virtual test environment would be the one and only way to safely test anything that you’ve downloaded, unless you are certain you 100% understand what the code is doing.

But the Exchange components really shouldn’t matter, assuming everything’s authenticating based on your internal Active Dirctory. It’s AD that tracks password expiration, obviously. You just need a means of sending email, which your internal Exchange Server can obviously do via SMPT for you, regardless of their version. It does rely on the ActiveDirectory module, which is present in 2008R2 and beyond.

I’ll note that this isn’t a particular well-written script from a Patterns/Practices perspective. The use of Write-Output to produce what is essentially verbose output, for example, suggests a less-than-complete understanding of how PowerShell works. It’s also poorly modularized, which means it’s definitely going to take longer to understand and to test on your part. But it doesn’t look inimical, at first glance.

Also, it’s “on-premises” [grin]. “On-premise” actually means something else.

My Script i use

# Specify number of days. Any users whose passwords expire within
# this many days after today will be processed.
$intDays = 14

# Retrieve Domain maximum password age policy, in days.
$D = [System.DirectoryServices.ActiveDirectory.Domain]::GetCurrentDomain()
$Domain = [ADSI]"LDAP://$D"
$MPA = $Domain.maxPwdAge.Value
# Convert to Int64 ticks (100-nanosecond intervals).
$lngMaxPwdAge = $Domain.ConvertLargeIntegerToInt64($MPA)
# Convert to days.
$MaxPwdAge = -$lngMaxPwdAge/(600000000 * 1440)

# Determine the password last changed date such that the password
# would just now be expired. We will not process any users whose
# password has already expired.
$Now = Get-Date
$Date1 = $Now.AddDays(-$MaxPwdAge)

# Determine the password last changed date such the password
# will expire $intDays in the future.
$Date2 = $Now.AddDays($intDays - $MaxPwdAge)

# Convert from PowerShell ticks to Active Directory ticks.
$64Bit1 = $Date1.Ticks - 504911232000000000
$64Bit2 = $Date2.Ticks - 504911232000000000

$Searcher = New-Object System.DirectoryServices.DirectorySearcher
$Searcher.PageSize = 100
$Searcher.SearchScope = "subtree"

# Filter on user objects where the password expires between the
# dates specified, the account is not disabled, password never
# expires is not set, password not required is not set.
# and password cannot change is not set.
$Searcher.Filter = "(&(objectCategory=person)(objectClass=user)" `
    + "(pwdLastSet>=" + $($64Bit1) + ")" `
    + "(pwdLastSet $Null
$Searcher.PropertiesToLoad.Add("name") > $Null
$Searcher.PropertiesToLoad.Add("Company") > $Null
$Searcher.PropertiesToLoad.Add("pwdLastSet") > $Null
$Searcher.PropertiesToLoad.Add("mail") > $Null

# Only search the specified OU.
$Searcher.SearchRoot = "LDAP://OU=Projectwise External Users,OU=Extranet,DC=global,DC=Domain,DC=com"

$Results = $Searcher.FindAll()
ForEach ($Result In $Results)
    # Retrieve attribute values for this user.
    $Samaccountname = $Result.Properties.Item("sAMAccountName")
    $PLS = $Result.Properties.Item("pwdLastSet")
    $Mail = $Result.Properties.Item("mail")
    $Displayname = $Result.Properties.Item("name")
    $Company = $Result.Properties.Item("Company")

    If ($PLS.Count -eq 0)
        $Date = [DateTime]0
        # Interpret 64-bit integer as a date.
        $Date = [DateTime]$PLS.Item(0)
    # Convert from .NET ticks to Active Directory Integer8 ticks.
    # Also, convert from UTC to local time.
    $PwdLastSet = $Date.AddYears(1600).TolocalTime()
    # Determine when password expires.
    $PwdExpires = $PwdLastSet.AddDays($MaxPwdAge)
    # Convert to UK Date Format
    $PWDRES = $PwdExpires.ToLongDateString()
    #Get Total Days Remaining
    $Remaining = $PwdExpires - (get-date) | Select days -ExpandProperty days

    #Get Subject Date
    $SubjectDate = $Pwdres

    # Output information for this user.

    $text = "BODY{font-family:'Times New Roman'};P{font-family:'Times New Roman'};TABLE{font-family:'Times New Roman'}"
    $text = $text + "Dear Sir/Madam,"

    $text = $text + "You are currently mobilised to access the Domain ProjectWise system, however your account password is due to expire in $Remaining days."
    $text = $text + "To continue using ProjectWise, YOU MUST RESET YOUR PASSWORD BEFORE THE EXPIRE DATE."

    $text = $text + "To do this, please visit the web site:"
    $text = $text + "Instructions:"
    $text = $text + "
    " $text = $text + "
  1. At the 'Extranet Logon page', enter your Username: $Samaccountname and existing password. Click the Sign in button. Note: DO NOT enter the 'global\' prefix to your account name.
  2. " $text = $text + "
  3. At the 'Change Your Password' page, enter your existing password into the Old Password field, and create your new password ensuring it complies with the requirements noted. Click the Change Password button.
  4. " $text = $text + "
" $text = $text + "Note:  The password change needs time to replicate across the Domain IT system. This may take up to one hour BEFORE you can regain access to ProjectWise." $text = $text + "If you don't change your password before the expiry period, your account will automatically become inactive and you will no longer be able to acces ProjectWise" $text = $text + "If you need assistance, please email Can you please include in your email the following details so we can assist you:" $text = $text + "
    " $text = $text + "
  • Name of project
  • " $text = $text + "
  • Your name
  • " $text = $text + "
  • Your company name
  • " $text = $text + "
  • Nature of problem
  • " $text = $text + "
  • Links to documents or screen shots if applicable to your problem.
" $text = $text + "Kind Regards," $text = $text + "ProjectWise Support" ##Variables $smtpServer = "" $From = "" $SubjectCPY = "Your Domain Account Password is Due to Expire on $SubjectDate" $Body = "$text" $prior = "" #Email Content ## -cc $mail will mail user account Send-Mailmessage -smtpServer $smtpServer -from $from -to $mail -bcc $prior -subject $subjectCPY -priority High -Body $Body -BodyAsHtml }

For your reference, you can find useful script here: