Skip to content
The Lazy Administrator
  • Home
  • Disclaimer
  • Contact
  • About Me
  • Search Icon

The Lazy Administrator

Finding ways to do the most work with the least effort possible

Email Users If Their Active Directory Password is set to Expire Soon

Email Users If Their Active Directory Password is set to Expire Soon

March 28, 2018 Brad Wyatt Comments 59 comments

Table of Contents

  • User E-Mail Address
  • E-Mail Format
  • SMTP
    • Sending E-Mail
  • Logging
  • Credential
  • The Script

In this article I will show you how PowerShell can automatically send an e-mail notification to end users when their Active Directory password is set to expire soon. I looked over several other similar scripts on TechNet but ended up writing one from scratch to incorporate several features I needed, as well as improve on the overall script flow.

Some of the requirements I needed to meet were as follows:

  1. Get users email addresses from the Email Address value in Active Directory, if it’s empty look at the default address in the proxyaddresses attribute
  2. Send E-mail to users with passwords that were expiring in 7 days or less
  3. Include directions users can follow to reset their Active Directory password
  4. Send E-mail with high priority
  5. Get E-mail notification if sent or failed
  6. Store the credential in a Cred object so it’s secure
  7. Advanced logging on the script for troubleshooting
  8. Send E-mail from Office 365
  9. Set up the script as a scheduled task

User E-Mail Address

One of the key pieces I wanted was to check the users proxyaddresses attribute for a default e-mail address if the E-mail entry in the users Active Directory properties was empty. Many scripts I found online only looked at the E-mail value, so if there was nothing there it would just fail instead of looking at other places. In a lot of environments I have seen that not all users had the E-mail value filled out, but had their default e-mail address and aliases in the proxyaddresses attribute. For Office 365, if you sync your Active Directory this is where it will get the default e-mail address, and any other proxy addresses for Exchange. The script will find the default value by looking at what’s in the proxyaddresses attribute and looking for the value with a capital “SMTP”.

E-Mail Format

In my e-mail I wanted to first greet the user by their Name. This isn’t hard as all we have to do is pass something like their DisplayName value to a variable and add that to the body. Second, I wanted to send the e-mail with high importance, this will show a red exclamation mark next to the e-mail. The subject of the email would tell the user how many days until their password is expired and lastly, if the user wanted to reach to our IT team it would have our contact information followed by our signature.

An e-mail notification would be sent back to the sending address on any failure or any success. This would include the actual e-mail that was sent to the user in an attachment, and the subject of the e-mail. If you have a password portal, on-premise exchange or Office 365 password write-back you could also include a link in the e-mail where users can click and reset their passwords.

SMTP

Since my mail server is Office 365 I want to send mail authenticated, and use SSL. The user I am using to authenticate against the SMTP server must also either be the sending user, or have Send-As rights on the sending user. When the script runs it will search for its credential object, if the credential object is not there it will prompt you for credentials (its best to run this manually first to input and have it store the credentials before setting it up as a scheduled task). As we see in the Get-Credential message it reminds you that this account must be the sender, or have proper permissions.

Sending E-Mail

There are two ways you can go about sending mail with PowerShell. You can use the System.Net.Mail Namespace or use the Send-MailMessage cmdlet. If you want to set this up as a scheduled task I recommend using the System.Net.Mail Namespace (which I use in the script), as you will run into issues trying to use Send-MailMessage unattended.

In the scriptblock below I am calling the Namespace, setting the From, SMTP Host, SSL, Credentials, To, Subject, Delivery Notifications, Priority and Body.

$SmtpClient = new-object system.net.mail.smtpClient
$MailMessage = New-Object system.net.mail.mailmessage

#Who is the e-mail sent from
$mailmessage.From = $FromEmail
#SMTP server to send email
$SmtpClient.Host = $SMTPHost
#SMTP SSL
$SMTPClient.EnableSsl = $true
#SMTP credentials
$SMTPClient.Credentials = $cred
#Send e-mail to the users email
$mailmessage.To.add("$emailaddress")
#Email subject
$mailmessage.Subject = "Your password will expire $daystoexpire days"
#Notification email on delivery / failure
$MailMessage.DeliveryNotificationOptions = ("onSuccess", "onFailure")
#Send e-mail with high priority
$MailMessage.Priority = "High"
$mailmessage.Body = ...

Logging

Using Write-Host and Try/Catch blocks I can log every step of the script and any running errors. The log will be saved at the same $DirPath location which I set at C:\Automation\PasswordExpiry.  In this folder it will store the log as well as the credential object. Here is my log file:

If you run the script manually the shell will also display its progress to you.

 

Credential

The script will store your Office 365 / authentication credentials by using the Export-CLIXML cmdlet. This allows us to store away the entire System.Management.Automation.PSCredential Object as an XML file. the Export-CliXml cmdlet encrypts credential objects using the Windows standard Data Protection API. It’s always best to store credentials of a user with no administrative roles in your Office 365 / Mail environment.

 

The Script

<#	
	.NOTES
	===========================================================================
	 Created on:   	3/27/2018 7:37 PM
	 Created by:   	Bradley Wyatt
	 Version: 	    1.0.0
	 Notes:
	The variables you should change are the SMTP Host, From Email and Expireindays. I suggest keeping the DirPath
	SMTPHOST: The smtp host it will use to send mail
	FromEmail: Who the script will send the e-mail from
	ExpireInDays: Amount of days before a password is set to expire it will look for, in my example I have 7. Any password that will expire in 7 days or less will start sending an email notification 

	Run the script manually first as it will ask for credentials to send email and then safely store them for future use.
	===========================================================================
	.DESCRIPTION
		This script will send an e-mail notification to users where their password is set to expire soon. It includes step by step directions for them to 
		change it on their own.

		It will look for the users e-mail address in the emailaddress attribute and if it's empty it will use the proxyaddress attribute as a fail back. 

		The script will log each run at $DirPath\log.txt
#>

#VARs

#SMTP Host
$SMTPHost = "smtp.office365.com"
#Who is the e-mail from
$FromEmail = "[email protected]"
#Password expiry days
$expireindays = 7

#Program File Path
$DirPath = "C:\Automation\PasswordExpiry"

$Date = Get-Date
#Check if program dir is present
$DirPathCheck = Test-Path -Path $DirPath
If (!($DirPathCheck))
{
	Try
	{
		#If not present then create the dir
		New-Item -ItemType Directory $DirPath -Force
	}
	Catch
	{
		$_ | Out-File ($DirPath + "\" + "Log.txt") -Append
	}
}
#CredObj path
$CredObj = ($DirPath + "\" + "EmailExpiry.cred")
#Check if CredObj is present
$CredObjCheck = Test-Path -Path $CredObj
If (!($CredObjCheck))
{
	"$Date - INFO: creating cred object" | Out-File ($DirPath + "\" + "Log.txt") -Append
	#If not present get office 365 cred to save and store
	$Credential = Get-Credential -Message "Please enter your Office 365 credential that you will use to send e-mail from $FromEmail. If you are not using the account $FromEmail make sure this account has 'Send As' rights on $FromEmail."
	#Export cred obj
	$Credential | Export-CliXml -Path $CredObj
}

Write-Host "Importing Cred object..." -ForegroundColor Yellow
$Cred = (Import-CliXml -Path $CredObj)


# Get Users From AD who are Enabled, Passwords Expire and are Not Currently Expired
"$Date - INFO: Importing AD Module" | Out-File ($DirPath + "\" + "Log.txt") -Append
Import-Module ActiveDirectory
"$Date - INFO: Getting users" | Out-File ($DirPath + "\" + "Log.txt") -Append
$users = Get-Aduser -properties Name, PasswordNeverExpires, PasswordExpired, PasswordLastSet, EmailAddress -filter { (Enabled -eq 'True') -and (PasswordNeverExpires -eq 'False') } | Where-Object { $_.PasswordExpired -eq $False }

$maxPasswordAge = (Get-ADDefaultDomainPasswordPolicy).MaxPasswordAge

# Process Each User for Password Expiry
foreach ($user in $users)
{
	$Name = (Get-ADUser $user | ForEach-Object { $_.Name })
	Write-Host "Working on $Name..." -ForegroundColor White
	Write-Host "Getting e-mail address for $Name..." -ForegroundColor Yellow
	$emailaddress = $user.emailaddress
	If (!($emailaddress))
	{
		Write-Host "$Name has no E-Mail address listed, looking at their proxyaddresses attribute..." -ForegroundColor Red
		Try
		{
			$emailaddress = (Get-ADUser $user -Properties proxyaddresses | Select-Object -ExpandProperty proxyaddresses | Where-Object { $_ -cmatch '^SMTP' }).Trim("SMTP:")
		}
		Catch
		{
			$_ | Out-File ($DirPath + "\" + "Log.txt") -Append
		}
		If (!($emailaddress))
		{
			Write-Host "$Name has no email addresses to send an e-mail to!" -ForegroundColor Red
			#Don't continue on as we can't email $Null, but if there is an e-mail found it will email that address
			"$Date - WARNING: No email found for $Name" | Out-File ($DirPath + "\" + "Log.txt") -Append
		}
		
	}
	#Get Password last set date
	$passwordSetDate = (Get-ADUser $user -properties * | ForEach-Object { $_.PasswordLastSet })
	#Check for Fine Grained Passwords
	$PasswordPol = (Get-ADUserResultantPasswordPolicy $user)
	if (($PasswordPol) -ne $null)
	{
		$maxPasswordAge = ($PasswordPol).MaxPasswordAge
	}
	
	$expireson = $passwordsetdate + $maxPasswordAge
	$today = (get-date)
	#Gets the count on how many days until the password expires and stores it in the $daystoexpire var
	$daystoexpire = (New-TimeSpan -Start $today -End $Expireson).Days
	
	If (($daystoexpire -ge "0") -and ($daystoexpire -lt $expireindays))
	{
		"$Date - INFO: Sending expiry notice email to $Name" | Out-File ($DirPath + "\" + "Log.txt") -Append
		Write-Host "Sending Password expiry email to $name" -ForegroundColor Yellow
		
		$SmtpClient = new-object system.net.mail.smtpClient
		$MailMessage = New-Object system.net.mail.mailmessage
		
		#Who is the e-mail sent from
		$mailmessage.From = $FromEmail
		#SMTP server to send email
		$SmtpClient.Host = $SMTPHost
		#SMTP SSL
		$SMTPClient.EnableSsl = $true
		#SMTP credentials
		$SMTPClient.Credentials = $cred
		#Send e-mail to the users email
		$mailmessage.To.add("$emailaddress")
		#Email subject
		$mailmessage.Subject = "Your password will expire $daystoexpire days"
		#Notification email on delivery / failure
		$MailMessage.DeliveryNotificationOptions = ("onSuccess", "onFailure")
		#Send e-mail with high priority
		$MailMessage.Priority = "High"
		$mailmessage.Body =
		"Dear $Name,
Your Domain password will expire in $daystoexpire days. Please change it as soon as possible.

To change your password, follow the method below:

1. On your Windows computer
	a.	If you are not in the office, logon and connect to VPN. 
	b.	Log onto your computer as usual and make sure you are connected to the internet.
	c.	Press Ctrl-Alt-Del and click on ""Change Password"".
	d.	Fill in your old password and set a new password.  See the password requirements below.
	e.	Press OK to return to your desktop. 

The new password must meet the minimum requirements set forth in our corporate policies including:
	1.	It must be at least 8 characters long.
	2.	It must contain at least one character from 3 of the 4 following groups of characters:
		a.  Uppercase letters (A-Z)
		b.  Lowercase letters (a-z)
		c.  Numbers (0-9)
		d.  Symbols (!@#$%^&*...)
	3.	It cannot match any of your past 24 passwords.
	4.	It cannot contain characters which match 3 or more consecutive characters of your username.
	5.	You cannot change your password more often than once in a 24 hour period.

If you have any questions please contact our Support team at [email protected] or call us at 555.555.5555

Thanks,
The Lazy Administrator
[email protected]
555.555.5555"
		Write-Host "Sending E-mail to $emailaddress..." -ForegroundColor Green
		Try
		{
			$smtpclient.Send($mailmessage)
		}
		Catch
		{
			$_ | Out-File ($DirPath + "\" + "Log.txt") -Append
		}
	}
	Else
	{
		"$Date - INFO: Password for $Name not expiring for $daystoexpire days" | Out-File ($DirPath + "\" + "Log.txt") -Append
		Write-Host "Password for $Name does not expire for $daystoexpire days" -ForegroundColor White
	}
}


 

 

Brad Wyatt
Brad Wyatt

My name is Bradley Wyatt; I am a 5x Microsoft Most Valuable Professional (MVP) in Microsoft Azure and Microsoft 365. I have given talks at many different conferences, user groups, and companies throughout the United States, ranging from PowerShell to DevOps Security best practices, and I am the 2022 North American Outstanding Contribution to the Microsoft Community winner.


Active Directory, PowerShell
Active Directory, Office 365, Passwords, Users

Post navigation

PREVIOUS
[Function] Export Report of Unused Office 365 Licenses Across Multiple Tenants or a Single Tenant Using Friendly License Names
NEXT
Auto License Office 365 Migration Users Prior to Completing the Migration

59 thoughts on “Email Users If Their Active Directory Password is set to Expire Soon”

  1. Ciaran McCarthy says:
    July 1, 2018 at 9:09 am

    Just found your blog through Reddit. This is something I would like to have in place. Will this work if I am using a local installation of office pro 2016 and A local exchange server?

    Thanks
    Ciarán

    Reply
    1. Brad Wyatt says:
      July 1, 2018 at 9:31 am

      The installation of Office doesn’t matter. This will work with local Exchange. You just need to modify the SMTP info to not go to Office 365. (ports, authentication, etc)
      let me know if you’re needing assistance.

      Reply
  2. Ciaran McCarthy says:
    July 2, 2018 at 1:19 pm

    Cheers Brad, I’ll give it a shot!

    Thanks
    Ciarán

    Reply
  3. Ndeye says:
    October 5, 2018 at 6:38 am

    Hello brad thanks for great script!
    But i have an error to sending email I a time out message
    Exception calling “Send” with “1” argument(s): “The operation has timed out.”
    At line:150 char:4
    + $smtpclient.Send($mailmessage)
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : NotSpecified: (:) [], MethodInvocationException
    + FullyQualifiedErrorId : SmtpException

    do you have any idea?
    thanks

    Reply
    1. Brad Wyatt says:
      November 26, 2018 at 4:28 pm

      the SMTP server is not responding

      Reply
  4. Darren Bisbey says:
    December 6, 2018 at 1:54 am

    Brad!

    AWESOME Script nice work!!

    Do you have any tips on how to automate this, I have tried using scheduler but it throws this…

    Exception calling “Send” with “1” argument(s): “The SMTP server requires a secure connection or
    the client was not authenticated. The server response was: 5.7.57 SMTP; Client was not
    authenticated to send anonymous mail during MAIL FROM [AM5PR0402CA0022.eurprd04.prod.outlook.com]”
    At C:\passwordreminder.ps1:173 char:4
    + $smtpclient.Send($mailmessage)
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : NotSpecified: (:) [], MethodInvocationException
    + FullyQualifiedErrorId : SmtpException

    I think its because the SMTP needs auth but can get it when run from Scheduler.

    Any ideas?

    Darren

    Reply
    1. Brad Wyatt says:
      December 7, 2018 at 10:39 am

      Look into this article: https://thelazyadministrator.com/2018/03/28/email-users-when-their-active-directory-password-is-set-to-expire-soon/

      I export the cred as a secure obj and then when the scheduled task runs it will import, and then use it

      Reply
    2. Mattia says:
      July 12, 2019 at 6:08 am

      I encountered this problem and I found the solution.
      User you use to run the ps1 with task scheduler MUST be the same you use to run the task manually. Otherwise the user you use to run the task can’t access to credential file previously created running ps1 manually.
      So I did:
      – rename credential file
      – “run as” ps1 manually with user you plan to use on task scheduler
      – now run the scheduled task and enjoy!

      Reply
      1. Trina Samuels says:
        August 7, 2019 at 7:13 am

        @Mattia this was a great help. Thank you!

        Reply
  5. BC says:
    December 14, 2018 at 1:26 pm

    Brad,
    Nice article. Manually runs perfectly. When I tied to the Schedule throwing an error.
    Would you mind showing the command you used in the Schedule?

    Reply
    1. Brad Wyatt says:
      December 17, 2018 at 12:54 pm

      what is the error, is it regarding the new-timespan? Add verbose logging on your scheduled task to see where it is having issues

      Reply
  6. Darren Bisbey says:
    January 8, 2019 at 6:39 am

    Brad,

    sorry to be a pain… Still get this…

    Exception calling “Send” with “1” argument(s): “The SMTP server requires a secure connection or
    the client was not authenticated. The server response was: 5.7.57 SMTP; Client was not
    authenticated to send anonymous mail during MAIL FROM [LNXP265CA0089.GBRP265.PROD.OUTLOOK.COM]”
    At C:\Automation\PasswordExpiry\passwordreminder.ps1:158 char:4
    + $smtpclient.Send($mailmessage)

    Reply
  7. BC says:
    January 10, 2019 at 8:39 am

    Brad,
    I am also having a similar issue. I can run the script using PowerShell command line it sends email without any problem. when I add it into the schedule the log shows the above error message.
    My Schedule:
    Powershell.exe -File “C:\Automation\PasswordExpiry.ps1”

    Reply
  8. BC says:
    January 11, 2019 at 8:40 am

    The script works running in a PowerShell command – No error message
    I was getting the message running the schedule in the log :
    Exception calling “Send” with “1” argument(s): “The SMTP server requires a secure connection or the client was not authenticated. The server response was: 5.7.57 SMTP; Client was not authenticated to send anonymous mail during MAIL
    FROM [BN6PR19CA0111.namprd19.prod.outlook.com]”
    At C:\Automation\PasswordExpiry.ps1:158 char:1
    + $smtpclient.Send($mailmessage)
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : NotSpecified: (:) [], MethodInvocationException
    + FullyQualifiedErrorId : SmtpException
    *******************
    Found the Issue :
    1. You cannot use running the task as a different user/admin account. I was running the task as a different User account.
    2. Run that schedule under the logged in User/Admin account.
    Mine worked after the change. No more error message.
    Now my settings below:
    Schedule set to:
    Powershell.exe -File “C:\Automation\PasswordExpiry.ps1”
    Under General :
    * When running the task set the user account – Set the current logged in User
    *Run Whether the user is logged on or not- Select
    Brad, Thanks once again Awesome Script. !!

    Reply
  9. Mosharrof says:
    January 23, 2019 at 12:47 am

    You did a great job. It works successfully.
    Thanks a lot bro.

    Reply
  10. Justin says:
    January 29, 2019 at 8:43 am

    Has anyone tried adding an attachment to the email?

    Reply
  11. Jason says:
    April 26, 2019 at 9:18 am

    Thanks so much for this! I’ve been trying for a few days to get this to work with Google G Suite for Business ( G-Mail) for a couple of days now as the log reveals it is unable to send.

    I’ve tried adding $smtpPort = 587 and a number of other things.
    The log doesn’t give me a lot to go on.

    04/26/2019 09:53:35 – INFO: Sending expiry notice email to J Tester
    Exception calling “Send” with “1” argument(s): “Failure sending mail.”
    At line:153 char:1
    + $smtpclient.Send($mailmessage)
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : NotSpecified: (:) [], MethodInvocationException
    + FullyQualifiedErrorId : SmtpException

    Maybe I am not holding my mouth right!

    Reply
    1. Brad Wyatt says:
      April 26, 2019 at 12:02 pm

      https://community.spiceworks.com/topic/2023643-how-to-send-mail-from-gmail-to-another-gmail-using-powershell

      Reply
  12. Saj says:
    April 30, 2019 at 1:57 am

    Hi Brad!

    Thanks for such a nice script.
    Is it possible to send it to some specific OU users?

    Thanks

    Reply
    1. Brad Wyatt says:
      April 30, 2019 at 9:40 am

      Yep! change the $users var to filter for an OU. https://stackoverflow.com/questions/16369994/powershell-active-directory-limiting-my-get-aduser-search-to-a-specific-ou-an

      Reply
  13. Matt Wenger says:
    June 26, 2019 at 3:52 pm

    Just wanted to say thanks, I modified the script to look in a specific OU and it worked perfectly!

    Reply
  14. Mattia says:
    July 12, 2019 at 6:10 am

    Thanks a lot Brad for this script!

    Reply
  15. Trina says:
    July 26, 2019 at 2:09 pm

    You saved my life yet again! Thank you so much

    Reply
  16. Clint says:
    November 22, 2019 at 7:39 am

    This there a way for testing to have the script email all the notices to one certain email address to confirm it is working and to see what the email looks like that the users are getting incase anymore modification is needed?

    Reply
    1. Brad Wyatt says:
      November 22, 2019 at 8:47 am

      yeah you can just change the email variable to send all emails to 1 address

      Reply
  17. name_withheld_4good_reason says:
    December 23, 2019 at 6:48 am

    Thank you for the Christmas present!! Works perfectly! I’m the Net/Sys Admin for a 400 user domain and this will save our Help Desk a lot of useless work – assuming our uses heed the warning – which I’m skeptical of them doing.

    Reply
  18. Simon C. says:
    January 23, 2020 at 3:01 pm

    This is awesome Brad!! OMG!! It’s so a problem solver for me since I manage a pretty large group of user and I constantly have expired acccount since I have my users on the road that are not connected to AD except by VPN, so they apparently don’t have the warning from Windows or it’s pretty random. So if I understand right, I should run this script every 24 hours? In this scenario (24h); if a stubborn user didn’t change his password immediately (on day 7), I assume it will receive a new email again next day (6) and etc.? Thx again!!

    Reply
  19. Josh says:
    April 27, 2020 at 2:17 pm

    Absolute life/time saver! I was manually sending these emails weekly and figured it was time to automate. Great script, thanks so much!

    Reply
  20. Karlin Mayberry says:
    April 28, 2020 at 9:12 am

    Is this compatible with email accounts that are MFA enforced? How does that take affect with the scheduled script and Get-Credential prompt with Modern Authentication?

    Reply
    1. Brad Wyatt says:
      April 28, 2020 at 9:28 am

      for the account that is doing the automation job, create a separate service account

      Reply
  21. Syed says:
    May 21, 2020 at 7:37 am

    Hi Brad,

    First of all thank you so much for the script. I use an in house smtp.server. The script works fine but the result sends no email. It works as sending email but no email is sent at the end.

    Reply
  22. Chris Preti says:
    June 10, 2020 at 2:09 pm

    Brad, the script is throwing an error when it tries to send an email:
    + $smtpclient.Send($mailmessage)
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : NotSpecified: (:) [], MethodInvocationException
    + FullyQualifiedErrorId : SmtpException.

    I’m using Office 365, with an account that has a mailbox and has MFA disabled. Any thoughts?

    Reply
  23. Edgardo Roa Flores says:
    September 24, 2020 at 3:31 pm

    Amigo funciona de maravillas, muchas gracias!!

    Reply
  24. Randy says:
    October 2, 2020 at 2:47 pm

    Works perfectly!
    How could I add a hyperlink in the email body?

    Reply
  25. Bio says:
    November 17, 2020 at 10:00 pm

    This Script works great. Thank you mate…

    Reply
  26. Dan says:
    November 24, 2020 at 3:06 pm

    Hi, I was able to use this script with no credentials – ie sending to a Non-TLS connector set up as an anonymous relay (option 3 of https://docs.microsoft.com/en-us/exchange/mail-flow-best-practices/how-to-set-up-a-multifunction-device-or-application-to-send-email-using-microsoft-365-or-office-365) .
    I did need to run your script manually to have it create the credential file – but I simply put in gibberish (not too clever to remove that dependency to the script). Runs without issue (wanted to come up with a way to work around a third party MFA solution). Thought I would share.

    Reply
  27. Dan says:
    November 24, 2020 at 3:09 pm

    I am curious, I would like the email to be sent to user as outlined in script, but also another email (IT team for example). In a perfect world CC, but will take a regular to. This would be a static email. How would one change the variable? Suggestions?

    Reply
  28. Dan says:
    November 24, 2020 at 4:39 pm

    I was able to determine the CC I was asking about.
    add another variable
    $emailaddress = $user.emailaddress
    ADD $ccemailaddress = “[email protected]”
    Then inserted in the construction of the email section:
    #Send CC e-mail to the ITDeparment email
    $mailmessage.Cc.add(“$ccemailaddress”)

    Reply
  29. Dan says:
    May 12, 2021 at 12:48 pm

    Hi, I noticed a couple of days ago (april 22 for me) another location (april 24) the script which has not been modified, etc. starting failing to send emails with error
    Exception calling “Send” with “1” argument(s): “Failure sending mail.”
    At C:\scripts\365-Hybrid-PasswordExpiry.ps1:185 char:4
    + $smtpclient.Send($mailmessage)

    wondering any thoughts? We did not have a password change (actually we use a transport relay (which is functioning) though we need the cred.file for the script to work, but we used a ‘whatever password’ to complete the process. Wonder if MS has changed something?

    Reply
    1. Nico says:
      July 29, 2021 at 11:39 am

      Did you find a solution for this?

      Reply
  30. Sahi says:
    August 26, 2021 at 9:37 am

    Thank you so much for the script, Brad. I have a quick question. Can you run this script on a Windows 10 active directory joined machine or must it be executed on DC only?

    Reply
  31. dim says:
    October 19, 2021 at 6:50 am

    Hi

    how to make some lines colorful? output email text?

    Reply
  32. Marco says:
    November 11, 2021 at 10:03 am

    Hi Brad,

    The script seems to work, but it has some problems fetching all AD users. In my example it only got 4/10 users which seems a bit weird.
    Any suggestions?

    Best regards

    Reply
  33. Levi says:
    February 15, 2022 at 10:53 am

    Hello, Brad. I’ve been using this script for about a year and a half and it’s been working great until last Thursday when it suddenly stopped sending email.

    Looking through the log, I see this:

    Exception calling “Send” with “1” argument(s): “Failure sending mail.”
    At C:\Automation\PasswordExpiry\PasswordExpireEmailAlert.ps1:177 char:4
    + $smtpclient.Send($mailmessage)
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : NotSpecified: (:) [], MethodInvocationException
    + FullyQualifiedErrorId : SmtpException

    Nothing has changed with our O365 environment, AD, or network. Any idea what could be going on? I was able to get it to work a couple of times for one user only after deleting the log file, but then it would fail again. (There was another user that it never worked on, even if I deleted the log file.)

    Reply
  34. Semo says:
    February 16, 2022 at 4:25 am

    For people with following error:
    + CategoryInfo : NotSpecified: (:) [], MethodInvocationException
    + FullyQualifiedErrorId : SmtpException

    Add at he begining of script following:
    [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12

    to force Tls 1.2

    Source:
    https://office365itpros.com/2021/01/14/powershell-scripts-fail-exchange-online-tls12/

    It worked for me.

    Best regards

    Reply
    1. Bhagawant Singh says:
      June 16, 2023 at 12:54 am

      Hi Semo,

      Can you please help me with complete line where exactly and ho w to add the line. I have tried not working foe me.
      “[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12”

      Reply
    2. Bhagawant Singh says:
      June 26, 2023 at 1:58 am

      Hi Semo,

      This did not work for me. Can you Please share the script where you added the above “Forced Tls 1.2”. This will be great help.

      Reply
    3. Bhagawant Singh says:
      June 26, 2023 at 2:32 am

      Hi Semo,

      Not working for me can you please share where to add the line “[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12”
      Please help.

      Reply
  35. Levi says:
    March 11, 2022 at 10:05 am

    I believe I have the SMTP error taken care of now, thank you Semo. However now I have an issue where it’s only pulling 4 users when we have 40. It’s picking 4 users from the 40, but I don’t know why it’s only picking those 4 and not the other 36.

    Reply
    1. Bhagawant Singh says:
      June 16, 2023 at 12:54 am

      Hi Levi,

      Can you please help me with complete line where exactly and ho w to add the line. I have tried not working foe me.
      “[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12”

      Reply
    2. Bhagawant Singh says:
      June 26, 2023 at 2:27 am

      Hi Levi,

      Can you help how you resolved the SMTP error.

      Reply
  36. Tom York says:
    January 9, 2024 at 12:04 pm

    somehow the script is reading wrong expiration dates for my users. For example a user that just set their password, the script is displaying password expiry date of 179 days when my password expiration policy is only 90 days. anyone have any ideas?

    Thanks!
    Tom

    Reply
  37. Andre says:
    February 21, 2024 at 5:33 am

    Thank you for the awesome script! It works wonderful but the only problem I’m having is that it only checks about 20 users and then it stops. The log file doesn’t show any errors.

    Reply
  38. AP says:
    February 26, 2024 at 5:15 pm

    Hey everyone, I modified it by changing this section like below:

    https://pastebin.com/unTtMaTZ

    Make sure you change the parts I have marked in red here.

    https://imgur.com/a/nwD5bY8

    ——-

    If (($daystoexpire -ge “0”) -and ($daystoexpire -lt $expireindays))
    {
    “$Date – INFO: Sending expiry notice email to $Name” | Out-File ($DirPath + “\” + “LocalPWLog.txt”) -Append
    Write-Host “Sending Password expiry email to $name. Password expiring in $daystoexpire days” -ForegroundColor Yellow

    $EmailParams = @{
    SmtpServer = $SMTPHost
    Port = 587
    UseSsl = $true
    Credential = $cred
    From = $FromEmail
    To = $emailaddress
    Subject = “Your password will expire $daystoexpire days”
    Body = “Dear $Name,
    Your Domain password will expire in $daystoexpire days. Please change it as soon as possible.

    To change your password, follow the method below:

    1. On your Windows computer
    a. If you are not in the office, logon and connect to VPN.
    b. Log onto your computer as usual and make sure you are connected to the internet.
    c. Press Ctrl-Alt-Del and click on “”Change Password””.
    d. Fill in your old password and set a new password. See the password requirements below.
    e. Press OK to return to your desktop.

    The new password must meet the minimum requirements set forth in our corporate policies including:
    1. It must be at least 8 characters long.
    2. It must contain at least one character from 3 of the 4 following groups of characters:
    a. Uppercase letters (A-Z)
    b. Lowercase letters (a-z)
    c. Numbers (0-9)
    d. Symbols (!@#$%^&*…)
    3. It cannot match any of your past 24 passwords.
    4. It cannot contain characters which match 3 or more consecutive characters of your username.
    5. You cannot change your password more often than once in a 24 hour period.

    If you have any questions please contact our Support team at [email protected] or call us at 555.555.5555

    Thanks,
    The Lazy Administrator
    [email protected]
    555.555.5555″
    }
    Write-Host “Sending E-mail to $emailaddress…” -ForegroundColor Green
    Try
    {
    Send-MailMessage @EmailParams
    }
    Catch
    {
    $_ | Out-File ($DirPath + “\” + “Log.txt”) -Append
    }
    }

    Reply
  39. Christy Cain says:
    May 17, 2024 at 6:19 am

    I know this thread is old, but I was able to run this script flawlessly on my WIN11 laptop. I wanted to get in on a Server 2019 in case my laptop ever crashes. However, when I run the same script on the server, it returns a negative date.
    Server:
    Getting e-mail address for User P. Thorny…
    Password for User P. Thorny does not expire for -140 days
    Laptop:
    Getting e-mail address for User P. Thorny…
    Password for User P. Thorny not expiring for 40 days
    Our policy is 180 days so it seems like it is calculating the change backwards on the server.

    Reply
  40. Bill Spencer says:
    October 3, 2024 at 10:20 am

    I’m having trouble with the email portion of this script. I tried the original script and I tried it with AP’s changes and in both instances I get:
    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. Error: 535 5.7.139 Authentication unsuccessful, the request did not meet the criteria to be authenticated successfully. Contact your administrator.

    Please help me with this.

    Reply
    1. Bill Spencer says:
      October 10, 2024 at 2:27 pm

      NM, I used a Graph connection

      Reply
  41. T says:
    March 26, 2025 at 7:48 am

    Apparently as of recent times, Send-Mailmessage doesn’t support modern protocols and authentication which means you can’t use it with Exchange Online. Anyone have the script working with M365 in 2025?

    Running into the SmtpException error and the fix mentioned above doesnt seem to work any more. Another issue I’m finding is I’m getting InvokeMethodOnNull on some users that don’t have an expiring password.

    Reply

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

Subscribe

Email


Categories

  • Active Directory (8)
  • AI (3)
  • API (1)
  • AutoPilot (2)
  • Azure (15)
  • Bicep (4)
  • Connectwise (1)
  • Defender for Cloud Apps (1)
  • Delegated Admin (1)
  • DevOps (6)
  • Graph (6)
  • Intune (15)
  • LabTech (1)
  • Microsoft Teams (6)
  • Office 365 (19)
  • Permissions (2)
  • PowerShell (50)
  • Security (1)
  • SharePoint (3)
  • Skype for Business (1)
  • Terraform (1)
  • Uncategorized (2)
  • Yammer (1)

Recent Comments

  • MD SHARIQUE AKHTAR on Modern Active Directory – An update to PSHTML-AD-Report
  • TommyBoich on How The ConnectWise Manage API Handles Pagination with PowerShell
  • LOTTERY 365 LOGIN on Windows LAPS Management, Configuration and Troubleshooting Using Microsoft Intune
  • SPRUNKI PHASE 6 on Get a New Computer’s Auto Pilot Hash Without Going Through the Out of Box Experience (OOBE)
  • Mohammad Sherbaji on Get a New Computer’s Auto Pilot Hash Without Going Through the Out of Box Experience (OOBE)

1,738,709 People Reached

© 2025   All Rights Reserved.