Password Change Reminder PowerShell Script Updated!
May 13, 2014 81 Comments
Back in 2012 i wrote a script to help me remind users about their password expiry, to reduce the number of calls i got on the helpdesk. I decided to share it and published it on the TechNet Gallery,
It has been quite popular since then, with over 8,000 downloads!
Throughout that time i have received a number of questions about how to tweak the script to do various things or fix bugs and errors that people have found.
I have been tweaking it as i go, without much notification to anyone. I have just finished quite a big change, so i thought i would put up a post here, to let people know.
So what’s new?
Comments. Well firstly i added a lot more comments to the script itself. Not very exciting, but for those wanting to tweak it themselves, kind of important.
Logging. I have added logging so any notifications generated can also be outputted into a CSV file.
Testing. A lot of people wanted to be able to test it, but not have users emailed directly, so now you can have all notifications emailed to a separate address. Which you can see in the above image, all the emails going to testuser@company.com .
As always i welcome any comments or suggestions for the script over at the TechNet Gallery.
Hi Robert,
Great script thank you for your time and effort, and for sharing this with us.
Lee.
Nice list of Test Users you got there in your CSV.
Awesome script!
Small grammatical mistake that you may want to fix, should be choose not chose:
To change your password on a PC press CTRL ALT Delete and chose Change Password
I have a feeling i fixed that in the download of the script, i will check!
This is awesome! Thanks much for sharing.
Hi this looks like it could be what we’re after, does it need to run on the exchange server or can it be run on a DC?
Thanks
Should run anywhere you have the Active Directory PowerShell Module available. Does not require Exchange Shell.
Great thanks for this, looks like it’s doing the job nicely. Cheers
Robert – I have tried a few different ways to get the UPN for the username instead of the SamAccountName in both the notice to the IT Admin and the user email, I modified the original Get-QADUser to include -UserPrincipleName but all results came back blank. I also changed the variable $user.LogonName to $user.UserPrincipleName and the results returned 0.
Most of the users on this particular site use the UPN for login, and this is what I need to display to them in the notifications and the admin report. Any ideas?
I just want to say that this script is awesome! It works really well and helps our support staff tremendously! Big thanks to the creator!
Greetings,
Marijn
The Netherlands
Hi there,
I love this script! having an issue where it sends to users *even though they have already changed their password*. Everything else works great, it sends 14 days before expiration and I can BCC myself. A user will change their password but they will still get the notification the next day.
It might be helpful to know that we have two fine grained password policies. One is 90 days for most users, and the rest of the users are on 180. Our default domain policy is *not* used at all, in fact it’s disabled.
That seems odd, you would expect it to update AD straight away with a password set date.
Will investigate, perhaps you can let me know what your infrastructure is like, DC OS etc.
Hi there
Any ideas on how to get this to work on SBS 2008?
It throws an error at Import-Module ActiveDirectory
Import-Module : The specified module ‘ActiveDirectory’ was not loaded because no valid module file was found in any module directory.
Not sure if it is possible to get the ActiveDirectory module installed on SBS 2008?
Thanks
Peter
That module does not exist on Windows 2008, you will need to enable the Active Directory Gateway Service, http://www.microsoft.com/en-gb/download/details.aspx?id=2852, Then as far as I recall you can use any Windows 7 (or newer) machine with the Active Directory PowerShell Module enabled.
Robert i cannot get it to work. I run the Powershell command on a windows 2008 r2 AD and nothing gets emailed or anything ?? any clues or ideas i should be looking for?
Hi Robert,
This isworking really well for us at the moment, we have included a hyperlink to a document on our Extranet in the body of the text, however the link is only clickable from normal Outlook and not OWA? is this a restriction of OWA do you think or is ther a way in powershell to make such links work? the link is https://www.ourdomainname/filelocation .
Thanks for any advice on this
Shaun
Hi Robert,
Edited the configurable items to fit our environment, ran script, .csv was created but had no users data in it. Went to run Line 40 on its own, and realized that it is only pulling data from one OU that only has 5 users in it that fit all critera (none of which are within the expiration scope – hence no results in csv). Nowhere in the script did I filter the get-aduser to only pull from one OU.
Ideas?
When I run “$users = get-aduser -filter * -properties Name, PasswordNeverExpires, PasswordExpired, PasswordLastSet, EmailAddress” I am able to pull all users from all OUs, however, that includes disabled users and service accounts that have passwords that never expired, which is why I liked your refined search.
But as soon as I refine some of those properties, it goes back to pulling from a single OU.
Hi, again thank you for the script. It’s been running great for about 2 months and all of a sudden the other day, the script is empty. I can’t imagine there is nobody in our directory that is scheduled to change their password. If that is true, what could make the report come out empty? Only the headings are in the log file. No data. thanks!
The best way to troubleshoot this is to run the $users query manually in PowerShell and find out, does it select any users? If so, run the rest of the script, minus the email part and see if you get any errors.
When running the $users= query, it returns all users and all information about the user as requested in the command. When commenting the email part, the log file still remains empty. I even tried to run an older version of the script from before we went live with it and that one generate an empty log file. Seems like something may have changed on our side… What else do you think can cause this?
Someone has changed the password policy. Try the below, I have not tested this but it should dump all users from $users out to the file you specify ($logfile) and show you the date their password expires.
$date = Get-Date -format ddMMyyyy
$logFile = “” # ie. c:\mylog.csv
$users = get-aduser -filter * -properties Name, PasswordNeverExpires, PasswordExpired, PasswordLastSet, EmailAddress |where {$_.Enabled -eq “True”} | where { $_.PasswordNeverExpires -eq $false } | where { $_.passwordexpired -eq $false }
$maxPasswordAge = (Get-ADDefaultDomainPasswordPolicy).MaxPasswordAge
foreach ($user in $users)
{
$Name = (Get-ADUser $user | foreach { $_.Name})
$emailaddress = $user.emailaddress
$passwordSetDate = (get-aduser $user -properties * | foreach { $_.PasswordLastSet })
$PasswordPol = (Get-AduserResultantPasswordPolicy $user)
# Check for Fine Grained Password
if (($PasswordPol) -ne $null)
{
$maxPasswordAge = ($PasswordPol).MaxPasswordAge
}
$expireson = $passwordsetdate + $maxPasswordAge
$today = (get-date)
$daystoexpire = (New-TimeSpan -Start $today -End $Expireson).Days
Add-Content $logfile “$date,$Name,$emailaddress,$daystoExpire,$expireson”
}
Thank you for this!!! The reports shows that there isn’t any password ready to expire. So your assumption is correct. The Password Policy was changed from 45 to 90 days. So I can assume the reports are just blank because there aren’t any passwords ready to expire?
Yes, exactly.
Much appreciated for helping us out!
Hi Robert,
I am kishor , basically we are using server 2012 Data center environment. and we are trying to do password expiry notification on mail but how ever we are not able to do this in 2K12.
if do you any solution please revert.
Regards,
Kishor.
What problem are you having?
Hi Robert
We trying to use your script, everything works well, except emails goes directly to junk email to all the users who’s password is about to expired.
We using simple, non-exchange smtp server to send those emails, all our users on O365.
Do you know how we can fix that?
Regards
Marek
You may need to use a transport rule on 365, to change the scl of these messages.
How can I change the script so that it pulls users from a group instead of all of active directory?
Line 40
$users = Get-ADGroupMember GroupName
Hi Robert,
I tried to edit line 40 to point to a group but when I run it I get the error below. I appreciate any help on this as I am new to Powershell scripting and this script of yours is what i am looking for except I am trying to figure out how to tweak it to search through specific AD groups rather than all users. Thank you
New-TimeSpan : Cannot bind parameter ‘End’. Cannot convert the “90.00:00:00” va
lue of type “System.TimeSpan” to type “System.DateTime”.
At C:\admin\Password_Change_Notification-IT2.ps1:59 char:53
+ $daystoexpire = (New-TimeSpan -Start $today -End <<<< $Expireson).Days
+ CategoryInfo : InvalidArgument: (:) [New-TimeSpan], ParameterBi
ndingException
+ FullyQualifiedErrorId : CannotConvertArgumentNoMessage,Microsoft.PowerSh
ell.Commands.NewTimeSpanCommand
what did you put on line 40?
I replaced line 40 with only “$users = Get-ADGroupMember MyGroupName” and kept everything else the same and that is when I got this error.
I am struggling with getting this script scheduled. I can run the script via the AD powershell, but calling the module seems to fail.
When I run this command from a DOS window I get the following error:
C:\Users\ADMINISTRATOR.ADMN>C:\Windows\System32\WindowsPowerShell\v1.0\powershel
l.exe -nologo -noninteractive -command import-module ActiveDirectory -File “c:\
jobfiles\PasswordChangeNotification.ps1”
Import-Module : A parameter cannot be found that matches parameter name ‘File’.
At line:1 char:36
+ import-module ActiveDirectory -File <<<< c:\jobfiles\PasswordChangeNotificat
ion.ps1
+ CategoryInfo : InvalidArgument: (:) [Import-Module], ParameterB
indingException
+ FullyQualifiedErrorId : NamedParameterNotFound,Microsoft.PowerShell.Comm
ands.ImportModuleCommand
After much messing with the command line I finally go it to work as a task. I am running Powershell version 4… I could not get -file to work. The working command line is:
C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe
Then I set the following arguments
-nologo -noninteractive -command “import-module ActiveDirectory;& C:\Jobfiles\PasswordChangeNotification.ps1”
You should not try and run PowerShell Scripts from a CMD window, it is much easier to launch PowerShell directly.
As for the scheduled task, the way I do it is to set the program to launch as ‘PowerShell.exe’ with arguments “-command \Script.ps1”
Hello, How can I get this to only search a specific OU?
Hello, How can I get the script to only search a specific OU?
Look at the -SearchBase parameter.
http://technet.microsoft.com/en-us/library/ee617241.aspx
Get-AdUser Rob -SearchBase "ou=myou,dc=domain,dc=com"
Hi Rob,
Can you please provide an example where this line would be added in your existing script?
Please ignore, managed to fix this
How could this script be modified to put a daily popup to change email??
That is, replace the email part with the popup message??
You don’t have to provide code if you don’t want to, please do suggest what code to comment out so it’s not used and the popup message appears instead.
I want a popup so people can be reminded daily until they do change their pass.
Thank you, Tom
What sort of Popup, like an outlook reminder?
Just a regular Windows popup OK dialog in the center of the screen where they can’t miss it and they have to click it to make it go away. I was thinking like this: http://blogs.technet.com/b/heyscriptingguy/archive/2014/04/04/powertip-use-powershell-to-display-pop-up-window.aspx. It’s called Popup Method, hopefully it will do what I need.
Thank you, Tom
Forgot to say: Email has to be done separately because most people won’t notice an email reminder.
Actually that popup code is not Powershell, I thought it was.
Is there a Powershell way to do the equivalent thing??
I’m not really a programmer but I know how to put things together. :) :)
And I can ask on the Powershell forum…
Thank you, Tom
Final comment: I like your script because it has a testing mode, I forgot to look if it ignores passwords configured not to change or expire.
Robert,
I thought this might be the answer to a requirement that we have but then I saw it wasn’t tested on Server 2012.
Having given it a go it anyway, it looks like the cmdlets have changed now since “The term ‘get-aduser’ is not recognized as the name of a cmdlet, function, script file, or operable program” and I can’t see that in the list of available commands in the right hand pane within Powershell ISE. In fact, it looks like a few other “get-” cmdlets are invalid as well.
Do you have any plans to update this to run on Server 2012? – it’s the future you know!
Thanks.
As far as I know it should work perfectly well in 2012 or 2012 R2.
I would check to make sure your Active Directory PowerShell Module is installed and loaded, if memory serves it should be by default on 2012 if it is a DC but it may not be. You can run Get-Module to see what modules are available, or run Get-WindowsFeature RSAT-AD-PowerShell
Robert:
This script would be great for us. We have multiple users via VPN and based on the config don’t sync to get the alert that the password will expire. My issue is I am not a powershell guy. If I wanted to customize the message and only send this to certain users only in our employees OU, so Service accounts aren’t clicked how would I configure this? Maybe any reference page to customization for this? I saw the test part so running it as a test before hand would be great. Any help would be fantastic and if accepting donations for your work please direct me to a location…..
Nice work!
Is there a way to send the password expiration to users using office365?
Yep,
http://windowsserveressentials.com/2015/01/23/office-365-email-password-reminder/
Robert
Can you please send me a script which will work for gmail server as the smtp server.
i modified the script to do smtpserver : smtp.gmail.com:465 but no email was sent
output was generated saying email was sent.
I using windows 2012 r2 server.
But did not receive any email.
An ideas as to how to setup gmail server for your script so i can test it also.
Hi Robert,
this is really a great script, and it seems it still alive and kinking til 2016..haha just want to ask regarding the test email, is it only for testing purposes? Can I just put in my e-mail? or should I need to create a logfile on where it listed all the staffs name and email address on where system can use as database?
If you enable testing all emails will go to that recipient.
Hi Robert, great script, thank you.
I am having some weird problems with it. We use GMail for business, and I successfully managed to get the script to send using a specific email account with a dedicated app password. Embed this into the script and amend the send-MailMessage command accordingly and it partially worked.
The script required to send email using GMail:
$username = “emailaddress@yourdomain.com”
$pwd = “dedicated app password”
$securepwd = ConvertTo-SecureString $pwd -AsPlainText -Force
$credential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $username, $securepwd
$From = “emailaddress@yourdomain.com”
$To = “testrecipient@yourdomain.com”
$Subject = “Test Notification”
$Body = “Testing script to send emails”
$SMTPServer = “smtp.gmail.com”
$SMTPPort = “587”
Send-MailMessage -From $From -to $To -Subject $Subject -Body $Body -SmtpServer $SMTPServer -port $SMTPPort -UseSsl -Credential $credential
I incorporated the new $ variables into your script:
# Please Configure the following variables….
$smtpServer=”smtp.gmail.com”
$username = “emailaddress@yourdomain.com”
$pwd = “dedicated app password”
$securepwd = ConvertTo-SecureString $pwd -AsPlainText -Force
$credential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $username, $securepwd
$SMTPPort = “587”
$expireindays = 14, 7, 3, 1
$from = “emailaddress@yourdomain.com”
$logging = “enabled” # Set to Disabled to Disable Logging
$logFile = “C:\temp\notification_logs.csv” # ie. c:\mylog.csv
$testing = “disabled” # Set to Disabled to Email Users
$testRecipient = “myemail@mydomain.com”
and amended the Send-EmailMessage line to:
# Send Email Message
Send-MailMessage -From $from -To $emailaddress -Subject $subject -Body $message -dno OnSuccess, OnFailure -SmtpServer $smtpServer -port $SMTPPort -UseSSL -Credential $credential
Start-Sleep -Seconds 10 #Adding a 30sec pause between emails to prevent SPAM block
} # End Send Message
I also had issues with the script acquiring the email address from AD, the way I found to do that was:
$emailaddress = (Get-ADUser $user -properties mail).mail
To use this, I amended your script to bring the mail property as well
$users = get-aduser -SearchBase “OU=MyOU,OU=MyOtherOU,DC=MyDomain,DC=COM” -filter * -properties Name, Mail, PasswordNeverExpires, PasswordExpired, PasswordLastSet, UserPrincipalName |where {$_.Enabled -eq “True”} | where { $_.PasswordNeverExpires -eq $false } | where { $_.passwordexpired -eq $false }
In the log file, I see some weird behaviour. It brings back each user 4 times.
Also, I only ever see a total of 3 emails sent. Never more, never less.
Any advice you can offer would be much appreciated, I am not sure what I have done to cause this.
First thing to do.
$users = get-aduser…
Does this command return the users you think it should?
Do they have the right properties?
Hi Robert, yes, it appears to bring back what I would expect. Certainly the output in the log file contains the right people, but each of them is listed 4 times. I only added the mail property, which seems to work correctly.
How many users do you expect to see?
You should confirm each stage is working correctly.
https://windowsserveressentials.com/2014/09/17/troubleshooting-my-password-change-notification-script/
Hi Robert, I recreated the script using a slightly different (newer) version I downloaded from technet. This one doesn’t use the $triggerdays. I have successfully integrated the GMail part, the trigger days using your suggestion from your troubleshooting page, and everything is working well.
Thank you for your help.
Hi nice script.
i need to filter is on a security group.
in short only members in a specific security group need to recieve the mail.
how would i do that ?
Try this, https://www.youtube.com/watch?v=wad07Th7K8A
Can it be configured to run automatically on a scheduled task so we won’t have to be running it manually every time?
Yes
I’ve done that through GPMC from the following path:
User Configuration / Policies / Windows Settings / Logon Scripts / PowerShell Scripts
Is there any other way you would recommend?
Yes. The trick I have found is to have the scheduled task run a bat file, in the bat file you put the powershell command. Then scheduling works just fine. Also bear in mind server restrictions around running powershell if not from the logged in environment.
Please take a look at this video. https://m.youtube.com/watch?v=zk37X9lH1FE
Thank you for the script it makes my job a little easier. However, I have come across where a user gets an email notification and they change their password that day and the next few days they are still getting email notifications after they have changed their password. I have confirmed/verified that they changed their password in AD and also checking the log file shows they have received the email each day. Any ideas on what could be causing this?
I think in the past this was down to a previous user in the process and the script not resetting a variable, do you know which version you are using?
We are using version 1.3
Ok well i think 1.4 is on the technet site, or if you want to ping me an email id be happy to share a beta version of version 2.0. http://titlerequired.com/support
I am having an issue with the logging. When writing this to a csv it is separating the first and last name into separate columns as my display name has a comma…
I’m not sure what you can do to work around that, in a CSV file.
You could change the value that is logged, to remove the comma from the display name. I don’t know if that would suit your requirements though.
Could you help with an error I’m having with the script ?
It appears that the script can’t find my Fine grained password policy, error message displays…
Get-ADUserResultantPasswordPolicy : Cannot find an object with identity: ‘CN=FGPP-1 …etc
Any ideas why this might be ?
Thanks,
Hi, is it possible to change the word days in Email Subject and body to Tage? nice work!!
Not sure what you mean!
I Rob, how can I exclude one specific OU to not get the password reminder ?
Thanks
Have a look at the Q&A on the technet gallery for one from 11 October 2018, asks the same question hopefully with a good answer!
Great script, works amazingly, thanks.
Reduced so many support calls, thanks to this.