- This is a copy of Pearlman's original script. I do not support this script; please go to the original author.
- My highly modified verion is here: https://gist.github.com/meoso/3488ef8e9c77d2beccfd921f991faa64 .
-
-
Save meoso/de56bdc68eced50a65d38e99e306ee42 to your computer and use it in GitHub Desktop.
################################################################################################################# | |
# | |
# Version 1.4 February 2016 | |
# Robert Pearman (WSSMB MVP) | |
# TitleRequired.com | |
# Script to Automated Email Reminders when Users Passwords due to Expire. | |
# | |
# Requires: Windows PowerShell Module for Active Directory | |
# | |
# For assistance and ideas, visit the TechNet Gallery Q&A Page. http://gallery.technet.microsoft.com/Password-Expiry-Email-177c3e27/view/Discussions#content | |
# Or Checkout my Youtube Channel - https://www.youtube.com/user/robtitlerequired | |
# | |
################################################################################################################## | |
# Please Configure the following variables.... | |
$smtpServer="mail.server.com" | |
$expireindays = 21 | |
$from = "Company Administrator <support@mycompany.com>" | |
$logging = "Enabled" # Set to Disabled to Disable Logging | |
$logFile = "<log file path>" # ie. c:\mylog.csv | |
$testing = "Enabled" # Set to Disabled to Email Users | |
$testRecipient = "testuser@company.com" | |
# | |
################################################################################################################### | |
# Check Logging Settings | |
if (($logging) -eq "Enabled") | |
{ | |
# Test Log File Path | |
$logfilePath = (Test-Path $logFile) | |
if (($logFilePath) -ne "True") | |
{ | |
# Create CSV File and Headers | |
New-Item $logfile -ItemType File | |
Add-Content $logfile "Date,Name,EmailAddress,DaystoExpire,ExpiresOn,Notified" | |
} | |
} # End Logging Check | |
# System Settings | |
$textEncoding = [System.Text.Encoding]::UTF8 | |
$date = Get-Date -format ddMMyyyy | |
# End System Settings | |
# Get Users From AD who are Enabled, Passwords Expire and are Not Currently Expired | |
Import-Module ActiveDirectory | |
$users = get-aduser -filter * -properties Name, PasswordNeverExpires, PasswordExpired, PasswordLastSet, EmailAddress |where {$_.Enabled -eq "True"} | where { $_.PasswordNeverExpires -eq $false } | where { $_.passwordexpired -eq $false } | |
$DefaultmaxPasswordAge = (Get-ADDefaultDomainPasswordPolicy).MaxPasswordAge | |
# Process Each User for Password Expiry | |
foreach ($user in $users) | |
{ | |
$Name = $user.Name | |
$emailaddress = $user.emailaddress | |
$passwordSetDate = $user.PasswordLastSet | |
$PasswordPol = (Get-AduserResultantPasswordPolicy $user) | |
$sent = "" # Reset Sent Flag | |
# Check for Fine Grained Password | |
if (($PasswordPol) -ne $null) | |
{ | |
$maxPasswordAge = ($PasswordPol).MaxPasswordAge | |
} | |
else | |
{ | |
# No FGP set to Domain Default | |
$maxPasswordAge = $DefaultmaxPasswordAge | |
} | |
$expireson = $passwordsetdate + $maxPasswordAge | |
$today = (get-date) | |
$daystoexpire = (New-TimeSpan -Start $today -End $Expireson).Days | |
# Set Greeting based on Number of Days to Expiry. | |
# Check Number of Days to Expiry | |
$messageDays = $daystoexpire | |
if (($messageDays) -gt "1") | |
{ | |
$messageDays = "in " + "$daystoexpire" + " days." | |
} | |
else | |
{ | |
$messageDays = "today." | |
} | |
# Email Subject Set Here | |
$subject="Your password will expire $messageDays" | |
# Email Body Set Here, Note You can use HTML, including Images. | |
$body =" | |
Dear $name, | |
<p> Your Password will expire $messageDays<br> | |
To change your password on a PC press CTRL ALT Delete and choose Change Password <br> | |
<p>Thanks, <br> | |
</P>" | |
# If Testing Is Enabled - Email Administrator | |
if (($testing) -eq "Enabled") | |
{ | |
$emailaddress = $testRecipient | |
} # End Testing | |
# If a user has no email address listed | |
if (($emailaddress) -eq $null) | |
{ | |
$emailaddress = $testRecipient | |
}# End No Valid Email | |
# Send Email Message | |
if (($daystoexpire -ge "0") -and ($daystoexpire -lt $expireindays)) | |
{ | |
$sent = "Yes" | |
# If Logging is Enabled Log Details | |
if (($logging) -eq "Enabled") | |
{ | |
Add-Content $logfile "$date,$Name,$emailaddress,$daystoExpire,$expireson,$sent" | |
} | |
# Send Email Message | |
Send-Mailmessage -smtpServer $smtpServer -from $from -to $emailaddress -subject $subject -body $body -bodyasHTML -priority High -Encoding $textEncoding | |
} # End Send Message | |
else # Log Non Expiring Password | |
{ | |
$sent = "No" | |
# If Logging is Enabled Log Details | |
if (($logging) -eq "Enabled") | |
{ | |
Add-Content $logfile "$date,$Name,$emailaddress,$daystoExpire,$expireson,$sent" | |
} | |
} | |
} # End User Processing | |
# End |
modify this line: if (($daystoexpire -ge "0") -and ($daystoexpire -lt $expireindays))
with if (($daystoexpire -ge "0") -and ($daystoexpire -lt $expireindays) and ( ($daystoexpire -eq "21") -or ($daystoexpire -eq "14") -or ($daystoexpire -eq "7") -or ($daystoexpire -le "3" ) )
maybe, or something similar, or maybe just work something out not too complex
Can this be set to run against specific OUs?
Can this be set to run against specific OUs?
Research the cmdlet get-aduser
for searchbase
options, then modify your script.
How to put cc to the script?
How to put cc to the script?
https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/send-mailmessage?view=powershell-7.1
tells how to use the cmdlet (-cc
) . just code another variable and mod the Send-Mailmessage line.
but really i dont understand a use-case. the admins receive a report. why CC someone about another users account?
Can we use below script as well for notification alert on password expiry.
##############Variables#################
$verbose = $true
$notificationstartday = 14
$sendermailaddress = "no-reply@contoso.com"
$SMTPserver = "mail.contoso.com"
$DN = "DC=contoso,DC=com"
########################################
##############Function##################
function PreparePasswordPolicyMail ($ComplexityEnabled,$MaxPasswordAge,$MinPasswordAge,$MinPasswordLength,$PasswordHistoryCount)
{
$verbosemailBody = "Below is a summary of the applied Password Policy settings:`r`n`r`n"
$verbosemailBody += "Complexity Enabled = " + $ComplexityEnabled + "`r`n`r`n"
$verbosemailBody += "Maximum Password Age = " + $MaxPasswordAge + "`r`n`r`n"
$verbosemailBody += "Minimum Password Age = " + $MinPasswordAge + "`r`n`r`n"
$verbosemailBody += "Minimum Password Length = " + $MinPasswordLength + "`r`n`r`n"
$verbosemailBody += "Remembered Password History = " + $PasswordHistoryCount + "`r`n`r`n"
return $verbosemailBody
}
function SendMail ($SMTPserver,$sendermailaddress,$usermailaddress,$mailBody)
{
$smtpServer = $SMTPserver
$msg = new-object Net.Mail.MailMessage
$smtp = new-object Net.Mail.SmtpClient($smtpServer)
$msg.From = $sendermailaddress
$msg.To.Add($usermailaddress)
$msg.Subject = "Your password is about to expire"
$msg.Body = $mailBody
$smtp.Send($msg)
}
########################################
##############Main######################
$domainPolicy = Get-ADDefaultDomainPasswordPolicy
$passwordexpirydefaultdomainpolicy = $domainPolicy.MaxPasswordAge.Days -ne 0
if($passwordexpirydefaultdomainpolicy)
{
$defaultdomainpolicyMaxPasswordAge = $domainPolicy.MaxPasswordAge.Days
if($verbose)
{
$defaultdomainpolicyverbosemailBody = PreparePasswordPolicyMail $PSOpolicy.ComplexityEnabled $PSOpolicy.MaxPasswordAge.Days $PSOpolicy.MinPasswordAge.Days $PSOpolicy.MinPasswordLength $PSOpolicy.PasswordHistoryCount
}
}
foreach ($user in (Get-ADUser -SearchBase $DN -Filter * -properties mail))
{
$samaccountname = $user.samaccountname
$PSO= Get-ADUserResultantPasswordPolicy -Identity $samaccountname
if ($PSO -ne $null)
{
$PSOpolicy = Get-ADUserResultantPasswordPolicy -Identity $samaccountname
$PSOMaxPasswordAge = $PSOpolicy.MaxPasswordAge.days
$pwdlastset = [datetime]::FromFileTime((Get-ADUser -LDAPFilter "(&(samaccountname=$samaccountname))" -properties pwdLastSet).pwdLastSet)
$expirydate = ($pwdlastset).AddDays($PSOMaxPasswordAge)
$delta = ($expirydate - (Get-Date)).Days
$comparionresults = (($expirydate - (Get-Date)).Days -le $notificationstartday) -AND ($delta -ge 1)
if ($comparionresults)
{
$mailBody = "Dear " + $user.GivenName + ",`r`n`r`n"
$mailBody += "Your password will expire after " + $delta + " days. You will need to change your password to keep using it.`r`n`r`n"
if ($verbose)
{
$mailBody += PreparePasswordPolicyMail $PSOpolicy.ComplexityEnabled $PSOpolicy.MaxPasswordAge.Days $PSOpolicy.MinPasswordAge.Days $PSOpolicy.MinPasswordLength $PSOpolicy.PasswordHistoryCount
}
$mailBody += "`r`n`r`nYour IT Department"
$usermailaddress = $user.mail
SendMail $SMTPserver $sendermailaddress $usermailaddress $mailBody
}
}
else
{
if($passwordexpirydefaultdomainpolicy)
{
$pwdlastset = [datetime]::FromFileTime((Get-ADUser -LDAPFilter "(&(samaccountname=$samaccountname))" -properties pwdLastSet).pwdLastSet)
$expirydate = ($pwdlastset).AddDays($defaultdomainpolicyMaxPasswordAge)
$delta = ($expirydate - (Get-Date)).Days
$comparionresults = (($expirydate - (Get-Date)).Days -le $notificationstartday) -AND ($delta -ge 1)
if ($comparionresults)
{
$mailBody = "Dear " + $user.GivenName + ",`r`n`r`n"
$delta = ($expirydate - (Get-Date)).Days
$mailBody += "Your password will expire after " + $delta + " days. You will need to change your password to keep using it.`r`n`r`n"
if ($verbose)
{
$mailBody += $defaultdomainpolicyverbosemailBody
}
$mailBody += "`r`n`r`nYour IT Department"
$usermailaddress = $user.mail
SendMail $SMTPserver $sendermailaddress $usermailaddress $mailBody
}
}
}
}
I am getting below error when i run this after making change in my WIn10 systems where i am doing testing before deploying for all user.
Get-ADDefaultDomainPasswordPolicy : The term 'Get-ADDefaultDomainPasswordPolicy' is not recognized as the name of a cmdlet,
function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is
correct and try again.
At C:\passnot.ps1:35 char:17
+ $domainPolicy = Get-ADDefaultDomainPasswordPolicy
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (Get-ADDefaultDomainPasswordPolicy:String) [], CommandNotFoundException
+ FullyQualifiedErrorId : CommandNotFoundException
Get-ADUser : The term 'Get-ADUser' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the
spelling of the name, or if a path was included, verify that the path is correct and try again.
At C:\passnot.ps1:47 char:20
+ foreach ($user in (Get-ADUser -SearchBase -Filter * -properties ...
+ ~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (Get-ADUser:String) [], CommandNotFoundException
+ FullyQualifiedErrorId : CommandNotFoundException
What changes i need to do in this script if want to test for single user.
Thanks
@ALL ,
Thanks,
I used the script but getting below error
#####################################################################
PS C:\Users\XXXXX> C:\Passnotification.ps1
Send-Mailmessage : Error in processing. The server response was: 5.7.3 STARTTLS is required to send mail [PN2PR01CA0019.INDPRD01.PROD.OUTLOOK.COM]
At C:\Passnotification.ps1:122 char:9
+ Send-Mailmessage -smtpServer $smtpServer -from $from -to $ema ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (System.Net.Mail.SmtpClient:SmtpClient) [Send-MailMessage], SmtpException
+ FullyQualifiedErrorId : SmtpException,Microsoft.PowerShell.Commands.SendMailMessage
##########################################################################################
So as suggested in comments added "-UseSsl " in the script
command added:
####################################################################################
# Send Email Message
Send-Mailmessage -smtpServer $smtpServer -from $from -to $emailaddress -subject $subject -body $body -bodyasHTML -priority High -Encoding $textEncoding -UseSsl"
After adding "UseSsl" getting below error :
"PS C:\Users\XXXX> C:\Passnotification.ps1
Send-Mailmessage : The SMTP server requires a secure connection or the client was not authenticated. The server response was: 5.7.57 Client not authenticated to send mail.
[PN1PR01CA0079.INDPRD01.PROD.OUTLOOK.COM]
At C:\Passnotification.ps1:122 char:9
+ Send-Mailmessage -smtpServer $smtpServer -from $from -to $ema ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (System.Net.Mail.SmtpClient:SmtpClient) [Send-MailMessage], SmtpException
+ FullyQualifiedErrorId : SmtpException,Microsoft.PowerShell.Commands.SendMailMessage
##########################################################################
requesting you to please help us and suggest the solution for this.
NOTE: I am testing this from my office system( Win10) on Windows Powershell ISE
Thanks and Best Regards.
I wanted to test this script, it would really a big help for me. may I know if required to provision a Mail Server for the email notification?
Thanks and Best Regards!
I wanted to test this script, it would really a big help for me. may I know if required to provision a Mail Server for the email notification?
Thanks and Best Regards!
Yes you do or a SMTP service
@ALL ,
Thanks,
I used the script but getting below error
[....redacted.....]
Thanks and Best Regards.
Maybe you are not authorized to send mail via that mailsever
How can this code be adjusted to just set this up for one specific user in AD rather than every user?
How can this code be adjusted to just set this up for one specific user in AD rather than every user?
weird request, but you change the filter specs for get-aduser
look at the line with $users = get-aduser -filter * [...]
google cmdlet get-aduser
Can we use below script as well for notification alert on password expiry.
Sorry i was not available to reply for many days. Since this is a completely different script you've posted, you should probably ask the source. It's not really polite to ask about a completely different script, although it is certainly similar.
That said, Get-ADDefaultDomainPasswordPolicy
and Get-ADUser
are not working because you need to import-module activedirectory
.
I hope someone can help. I ran a test after modifying the script on windows server 2019 and got - error: could not send email to me@wlfs.com via smtp.office365.com. I went into the sender's account and unchecked Authenticated SMTP to see if helps but did not.
I hope someone can help. I ran a test after modifying the script on windows server 2019 and got - error: could not send email to me@wlfs.com via smtp.office365.com. I went into the sender's account and unchecked Authenticated SMTP to see if helps but did not.
i would suggest experimenting with simple Send-Mailmessage
test-code using PowerShell ISE
until you find a working result that you could integrate into the script. i suspect authentication is your issue, which is outside of the scope of this gist. here are some resources for Send-Mailmessage
:
Two questions: 1) How do I exclude certain email addresses or groups? 2)How do I stop the email from sending 1 day after the expiration date so it doesn't keep sending an email intermittently? Thank you.
This script is just a copy of Robert Pearman's original script. i prefer not to offer "support" for someone else's work.
However, i do have a highly modified version here: https://gist.github.com/meoso/3488ef8e9c77d2beccfd921f991faa64 which does account for question #2.
As far question #1, i would presume you could resolve this in a number of ways including modifying the original $user = get-aduser -Filter ...
command , or maybe filtering $users by piping to a where-object
filtering by group membership or by an OU. but this is something for you as the end-user to research how.
Hi, How can I modify this code to send out notification to a security group?
Hi, How can I modify this code to send out notification to a security group?
maybe useful: https://activedirectoryfaq.com/2021/02/sending-e-mail-to-members-of-an-ad-group/
Hi, How can I modify this code to send out notification to a security group?
maybe useful: https://activedirectoryfaq.com/2021/02/sending-e-mail-to-members-of-an-ad-group/
Thanks meoso, I know I have to edit this part of the code
Import-Module ActiveDirectory
**$users = get-aduser -filter *** -properties Name, PasswordNeverExpires, PasswordExpired, PasswordLastSet, EmailAddress |where {$.Enabled -eq "True"} | where { $.PasswordNeverExpires -eq $false } | where { $_.passwordexpired -eq $false }
But I am not sure of how to.
I have tried other things like "Get-ADGroupMember".
I want the new code to look in a particular security group and email the users in that security at the times I want them to be notified.
Hi, How can I modify this code to send out notification to a security group?
maybe useful: activedirectoryfaq.com/2021/02/sending-e-mail-to-members-of-an-ad-group
Thanks meoso, I know I have to edit this part of the code Import-Module ActiveDirectory **$users = get-aduser -filter *** -properties Name, PasswordNeverExpires, PasswordExpired, PasswordLastSet, EmailAddress |where {$.Enabled -eq "True"} | where { $.PasswordNeverExpires -eq $false } | where { $_.passwordexpired -eq $false }
But I am not sure of how to. I have tried other things like "Get-ADGroupMember". I want the new code to look in a particular security group and email the users in that security at the times I want them to be notified.
Try some variation of (Get-ADGroup -Identity $GroupName -properties members).Members | Get-ADUser
,
where this format of (Get-ADGroup -Identity $GroupName -properties members).Members
is a workaround for a 5000 user-count limitation existing in Get-ADGroupMember -Identity $GroupName
**Try some variation of [...]
I tried it but it didnt work.
I tried it but it didnt work.
so
$users = (Get-ADGroup -Identity $GroupName -properties members).Members | get-aduser -filter * -properties Name, PasswordNeverExpires, PasswordExpired, PasswordLastSet, EmailAddress |where {$_.Enabled -eq "True"} | where { $_.PasswordNeverExpires -eq $false } | where { $_.passwordexpired -eq $false }
where $GroupName
is set for your group, still fails?
EDIT: do not use -filter *
$users = (Get-ADGroup -Identity $GroupName -properties members).Members | get-aduser -filter * -properties Name, PasswordNeverExpires, PasswordExpired, PasswordLastSet, EmailAddress |where {$_.Enabled -eq "True"} | where { $_.PasswordNeverExpires -eq $false } | where { $_.passwordexpired -eq $false }
Thanks, my bad. I missed something. After fixing it, it runs but it gets notification for everyone not the people in the specific security group I specified.
[...]] it runs but it gets notification for everyone not the people in the specific security group I specified.
try without the -filter *
. This is an interesting use-case. maybe i should do some coding/testing myself.
try without the
-filter *
. This is an interesting use-case. maybe i should do some coding/testing myself.
Thanks! I will try that and let you know.
@Odakolo , i just tested without -filter *
; It works.
$users = (Get-ADGroup -Identity $GroupName -properties members).Members | get-aduser -properties Name, PasswordNeverExpires, PasswordExpired, PasswordLastSet, EmailAddress |where {$_.Enabled -eq "True"} | where { $_.PasswordNeverExpires -eq $false } | where { $_.passwordexpired -eq $false }
where my group had 4 users. 1 of which with a soon to expire password.
seems like there would be a way to simplify this as well, rather than piping, but i'm happy enough with that line.
@Odakolo , i just tested without
-filter *
; It works.
THANKS! it works!
Hi, great script! Is there a possibility to email the user at 21 days, 14 days, 7 days and the last 3 days?