Password Expiry Email Notification

This script will email a user in the event that their password is due to expire in X number of days. I have now moved it to GitHub -

4.6 Star
86,940 times
Add to favorites
Active Directory
E-mail Twitter Digg Facebook
  • how to test script
    3 Posts | Last post April 17, 2014
    • is there a way to test this script and have it output to a text file before actually running this in production? Id like to see how it looks and who it will be emailing but actually setting it up.
    • Sure, you can change a number of the variables.
       $emailaddress = $user.emailaddress
      If you change the above to:
       $emailaddress = ""
      All emails will go to that one address.
      If you want it to output a list of users who would be emailed you will need to do a little more.
       if ($daystoexpire -lt $expireindays)
          Send-Mailmessage -smtpServer $smtpServer -from $from -to $emailaddress -subject $subject -body $body -bodyasHTML -priority High
      would change to:
       if ($daystoexpire -lt $expireindays)
      That would show each persons name to the screen when running the script.
      Or to output into a text file:
       if ($daystoexpire -lt $expireindays)
          $file = "C:\myusers.txt"
          Add-Content `n
          Add-Content "$name"
      The file would already need to be present, or you could script the creation of a new file if you wanted.
    • thanks!
  • How to add logo in this script
    5 Posts | Last post April 14, 2014
    • This script is working perfect. I need help adding company logo while sending email.Please help!!
    • You can do that with normal HTML but the logo file would need to be accessible wherever the email was opened.
    • Thank you Robert.
      Can you please help me with code to put in your script which will have logo file not as a attachment. It should be in body of email. 
    • img tags are not for attachments, but it will not embed the image into the email. so what i mean is, if you put in a unc path to the image file, that needs to be accessible from where ever someone may open an email. or, it needs to be a logo on a public web server somewhere.
    • Just as an example i added in this line, which appears as an embedded image.
      <img src="""" alt=""logo"" height=""192"" width=""524"">
      Important to note the double quotes ""path""
  • Change date format of $expireson
    3 Posts | Last post April 11, 2014
    • Thanks for this script.
      I have modified the body of the email to include $expireson but a user has complained about the date format. In UK the usual date format is dd/mm/yyyy.
      I'm very new to powershell and don't know how to re-format the date, please can you help.
    • There may be a better way to do this, but this will work.
      $displaydate = Get-Date $expireson -format dd/MM/yyyy
    • Thank you Robert
  • User Friendly Name?
    3 Posts | Last post April 08, 2014
    • Thanks for a great script. Is there any way to get a friendlier format of the username in the body of the email, as opposed to 'Last, First'?
    • Yes, 
      $Name = (Get-ADUser $user | foreach { $_.Name})
      Is the query that returns the users Name field. If in your environment this is 'last, first' simply amend that query to get a better value.
      Without knowing your environment i cannot tell you which value that would be.
    • Thanks, I subbed in $_.givenName and it worked like a charm.
  • 2012R2
    6 Posts | Last post March 08, 2014
    • Hi,
      I'm attempting to execute this script from a 2012R2 server against a 2008R2 domain.  I'm receiving a msDS-AssignedAuthPolicy error.  I'm aware of the possible workaround here
      However I believe my syntax is wrong.
      $users = get-aduser -filter * | get-adobject -properties * | where {$_.Enabled -eq "True"} | where { $_.PasswordNeverExpires -eq $false } | where { $_.passwordexpired -eq $false }
    • Im not aware of the problem, let me look at it and test it and come back to you.
    • You may be able to tweak the filtering like this.
      $users = Get-ADUser -Filter  { (Enabled -eq $true) -and ( PasswordNeverExpires -eq $false) -and (PasswordExpired -eq $false) }
    • Ignore last comment.
      This should solve it.
      $users = Get-ADUser -Filter * -Properties Name, PasswordNeverExpires, PasswordExpired, PasswordLastSet, EmailAddress |where {$_.Enabled -eq "True"} | where { $_.PasswordNeverExpires -eq $false } | where { $_.passwordexpired -eq $false }
    • Thank you for the reply.  E-mails are generated, but the days remaining is blank.
      get-aduser : One or more properties are invalid.
      Parameter name: msDS-AssignedAuthNPolicy
      At C:\Scripts\Password Change Notification.ps1:21 char:23
      +   $passwordSetDate = (get-aduser $user -properties * | foreach { $_.PasswordLast ...
      +                       ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
          + CategoryInfo          : InvalidArgument: (CN=**** ****...=****,DC=com:ADUser) [Get-AD 
         User], ArgumentException
          + FullyQualifiedErrorId : ActiveDirectoryCmdlet:System.ArgumentException,Microsoft.ActiveDire 
      New-TimeSpan : Cannot bind parameter 'End'. Cannot convert the "90.00:00:00" value of type 
      "System.TimeSpan" to type "System.DateTime".
      At C:\Scripts\Password Change Notification.ps1:37 char:52
      +   $daystoexpire = (New-TimeSpan -Start $today -End $Expireson).Days
      +                                                    ~~~~~~~~~~
          + CategoryInfo          : InvalidArgument: (:) [New-TimeSpan], ParameterBindingException
          + FullyQualifiedErrorId : CannotConvertArgumentNoMessage,Microsoft.PowerShell.Commands.NewTim 
    • Mail me the script you are using (with your customisations) and ill see if i can find the issue.
  • Testing it on one user
    2 Posts | Last post January 29, 2014
    • Hello and thanks for you post. I'm currently new to scripting and wanted to know if the script you gave with the following modifications below would work. I Would like to test this script on one user. I want to test this before putting in production.  Sorry for taking up so much space on the post. Also we currently run Exchange 2010
      Thanks again
      #Get Users From AD who are enabled
      Import-Module ActiveDirectory
      $users = get-SearchBase "CN=Lastname\, Firstname,OU=MYOU,OU=MY2nOU,OU=MY3rdOU,DC=domainname,DC=local" -filter * -properties * |where {$_.Enabled -eq "True"} | where { $_.PasswordNeverExpires -eq $false } | where { $_.passwordexpired -eq $false }
    • No i dont think that will work.
      That $users variable, is comprised of a 'Get-ADUser' query which you can find more info on here:
      So for your testing, if you have a user in mind you can Get that user directly,
      $users = Get-ADUser Robert.Pearman -properties *
      We need the extended properties to gather things like email address and password policy so dont remove that portion of the query.
      If you just want to get all the users from a different OU, then do this:
      $users = get-aduser -filter * -properties * -searchbase "OU=TestOU,DC=domain,DC=local" |where {$_.Enabled -eq "True"} | where { $_.PasswordNeverExpires -eq $false } | where { $_.passwordexpired -eq $false }
      Hope that helps.
  • Positional parameter error
    2 Posts | Last post January 24, 2014
    • Hi, Robert.  Thanks for the great script, but I'm having a problem with it.
      I'm trying to use this script to target a Test OU for users who are about to have an expired password.  Per your other answers, I made the following changes to do this:
      #Get Users From AD who are enabled
      Import-Module ActiveDirectory
      $users = get-aduser -filter * -SearchBase 'OU=TestOU,DC=testcorp,DC=com' * -properties * |where {$_.Enabled -eq "True"} | where { $_.PasswordNeverExpires -eq $false } | where { $_.passwordexpired -eq $false }
      When I run this, I get a "A positional parameter cannot be found that accepts argument 'OU=TestOU, DC=testcorp,DC=com".  What am I doing wrong?
    • Actually, it seems to have been a syntax issue.  I changed the line to this:
      $users = get-aduser -SearchBase 'OU=test,DC=testcorp,DC=com' -filter * -properties * |where {$_.Enabled -eq "True"} | where { $_.PasswordNeverExpires -eq $false } | where { $_.passwordexpired -eq $false }
      and it worked with no problem.
      Thank you for the nice script.  
  • Script not running from Task Scheduler
    3 Posts | Last post December 22, 2013
    • Hey Robert. I'm having an interesting situation. I have the script set as I'd like it and I can run it from a powershell window just fine. I tested running it as a scheduled task with the recipient email address as a test account and it worked fine.
      When I changed that email back to the "$Emailaddress" variable, the task ran but no emails were sent. Just to be sure, I ran it from a powershell window separately again and it worked. 
      Any ideas why it wouldn't work from a scheduled task with the $Emailaddress variable in there??
    • Strange!
      Assume they are all local mailboxes, so no issue with relaying mail?
      I think, if it were me, i would be checking the mail server logs to see if the messages are being junked, also use (start-transcript) which can output all of the script to a text file so you can see if you get any errors.
    • Hey Robert. Looks like I've got this resolved. It seemed to be an issue with the service account running the task. I had to change the permissions a bit. I believe it needs all of the Exchange permissions to in order to run properly. 
  • Send-MailMessage Error
    2 Posts | Last post December 21, 2013
    • I get the below message 6 times when the script runs. I do though receive an E-Mail about the password expire. There are 100+ user in the domain. Only about 5 of them have there E-Mail address set in Users and Computers.
      I am trying figure out why i get it 6 times? The E-Mail address are correct in Users and Computers. Is this because maybe the majority of the users do not have an E-Mail set on there account?
      Send-MailMessage : Cannot validate argument on parameter 'To'. The argument is null or empty. Supply an argument that i
      s not null or empty and then try the command again.
      At C:\download\pwscript\PasswordChangeNotification.ps1:43 char:61
      +     Send-Mailmessage -smtpServer $smtpServer -from $from -to <<<<  $emailaddress -subject $subject -body $body -bodya
      sHTML -priority High
          + CategoryInfo          : InvalidData: (:) [Send-MailMessage], ParameterBindingValidationException
          + FullyQualifiedErrorId : ParameterArgumentValidationError,Microsoft.PowerShell.Commands.SendMailMessage
    • If there is no email address set in the properties of their account then there is no email address for the script to find.
      Second, as to why you get 6 emails - who are they addressed to, are there any duplicates?
  • Negative numbers
    8 Posts | Last post December 03, 2013
    • I seem to be getting negative numbers for users that have recently changed their password.  For example: Your Password will expire in -19 days.  Any ideas?
    • I haven't seen that behaviour myself, perhaps you can contact me offline?
    • I had somewhat the same issue before I noticed a typo on line 19 ($PassworldPol - notice the the unwanted 'l' there).
      My guess is that you've implemented fine grained password policies in your domain, with the proper password age set. In the meantime you have a default domain policy set the max password age to 0 ( = no limit, eventhough no user in your domain is affected by this part of the default domain policy hence the fine graind password policies).
      But the If statement on line 19 (corrected in the newest version) is faulty, so the variable maxPasswordAge is based on rules set in the Default Domain Policy.
      So the variable $expireson becomes the same value as $passwordsetdate and the variable $daystoexpire will (if my asumptions are correct) get a negative value.
      Perhaps an overkill reply, but kind of wanted to walk it through myself as well :)..
    • I have tested on several domains with and without FGP and i have not seen a negative value occur.
      Will do some more testing.
    • Try run the following ($maxPasswordAge is set to 0 to represent a Default Domain Password Policy with no restrictions what so ever. If you have a domain with this setting, replace with $maxPasswordAge=(Get-ADDefaultDomainPasswordPolicy).MaxPasswordAge) to get a more precise test scenario).
      $passwordSetDate = (get-aduser SomeUser -properties * | foreach { $_.PasswordLastSet })
      $expireson=$passwordSetDate + $maxPasswordAge
      $today = (Get-Date)
      $daystoexpire=(New-TimeSpan -Start $today -End $Expireson).Days
      echo $daystoexpire
      This gave me a negative value in some cases.
    • I don't know why you would be running this script when you had a password age of 0 - Unless some users were contained within an FGP - in which case it would be easy enough to tweak the script to filter those people out from getting emails. 
    • OK what you could do is this.
      Change Line 41 to:
      if (($daystoexpire -ge "0") -and ($daystoexpire -lt $expireindays))
      This should prevent anyone with a negative value from getting an email.
    • That looks to have fixed the problem.  Thank you for your help and the script.
521 - 530 of 542 Items