Send email notification before Active Directory password expired

I am very glad to see there are more than 50,000 views in my blog when starting on counting “total visits” in my blog 7 months ago. Below are the top views from my blog.

Today, I want to share a small IT PowerShell script which is used to send notification to domain users before their password will be expired.

According to MS link (https://learn.microsoft.com/en-us/windows/win32/adschema/a-msds-userpasswordexpirytimecomputed), ms-DS-User-Password-Expiry-Time-Computed attribute is used to contain user password’s expire time in Active Directory. So, using the PowerShell code below to query this value in AD.

Get-ADUser -filter {Enabled -eq $True -and PasswordNeverExpires -eq $False} -Properties DisplayName, EmailAddress, msDS-UserPasswordExpiryTimeComputed

However, the value “133214896056482435” does not have any meaning, so we use [datetime]::FromFileTime($_.”msDS-UserPasswordExpiryTimeComputed”) to convert this value from FromFileTime to DateTime format in PowerShell.

# Query AD user 
$Users = Get-ADUser -filter {Enabled -eq $True -and PasswordNeverExpires -eq $False} -Properties DisplayName, EmailAddress, msDS-UserPasswordExpiryTimeComputed | `
Select-Object -Property DisplayName,  EmailAddress, @{Name="ExpirationDate";Expression={[datetime]::FromFileTime($_."msDS-UserPasswordExpiryTimeComputed")}} | `
Sort-Object "ExpirationDate" 
$users | sort-object ExpirationDate

The PowerShell outputs a list of Domain users corresponding to “Display Name”, “EmailAddress” and “ExpirationDate”.

Next, check if the password will be expired soon (14 days) and send email notification to domain users.

# Query AD user 
$Users = Get-ADUser -filter {Enabled -eq $True -and PasswordNeverExpires -eq $False} -Properties DisplayName, EmailAddress, msDS-UserPasswordExpiryTimeComputed | `
Select-Object -Property DisplayName,  EmailAddress, @{Name="ExpirationDate";Expression={[datetime]::FromFileTime($_."msDS-UserPasswordExpiryTimeComputed")}} | `
Sort-Object "ExpirationDate" 
#$users | sort-object ExpirationDate

# Check if the password will be expired soon and send email notification.
$UserList = foreach ($User in $users) {
if ($User.ExpirationDate -le (Get-Date).AddDays(14) -and $User.ExpirationDate -ge (Get-Date))  
 {
    # Create PSCustomObject to save a list of users whom will have a password expired soon
    [PSCustomObject]@{
        Name       = $User.DisplayName
        EmailAddress = $User.EmailAddress
        ExpiryDate = $User.ExpirationDate
        }
}
}
$userlist | sort-object ExpirationDate

PowerShell outputs a list of domain users who have the domain password will be expired soon.

Now, we will write an entire script to send email notification before AD password will be expired.

Get a password from the console, encrypt it and save into the file C:\Shared\admincred.txt

Read-Host -Prompt "Enter your tenant password" -AsSecureString | ConvertFrom-SecureString | Out-File "C:\Shared\admincred.txt" 
cat C:\Shared\admincred.txt

Below is a full PowerShell script to send email notification.

# PowerShell script that can send email notifications to domain users before their passwords will be expired.

# Query AD user 
$Users = Get-ADUser -filter {Enabled -eq $True -and PasswordNeverExpires -eq $False} -Properties DisplayName, EmailAddress, msDS-UserPasswordExpiryTimeComputed | `
Select-Object -Property DisplayName,  EmailAddress, @{Name="ExpirationDate";Expression={[datetime]::FromFileTime($_."msDS-UserPasswordExpiryTimeComputed")}} | `
Sort-Object "ExpirationDate" 

# Check if the password will be expired soon and send email notification.
$UserList = foreach ($User in $users) {
if ($User.ExpirationDate -le (Get-Date).AddDays(14) -and $User.ExpirationDate -ge (Get-Date))  
 {
    # Create PSCustomObject to save a list of users whom will have a password expired soon
    [PSCustomObject]@{
        Name       = $User.DisplayName
        EmailAddress = $User.EmailAddress
        ExpiryDate = $User.ExpirationDate
        }
    # Send email
    [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
    $SMTP = "smtp-mail.outlook.com"
    $From = "admin@outlook.com"
    $username = "admin@outlook.com"
    #Read-Host -Prompt "Enter your tenant password" -AsSecureString | ConvertFrom-SecureString | Out-File "C:\Shared\admincred.txt" 
    $Pass = Get-Content "C:\Shared\admincred.txt" | ConvertTo-SecureString
    $cred = New-Object System.Management.Automation.PSCredential -argumentlist $username, $Pass
    $Subject = "Password Expiration Warning"
    $Body = "Dear $($User.DisplayName)," + "`n`nYour password will expire in $User.ExpirationDate. Please change your password as soon as possible." + "`n`nRegards," + "`nIT Department"
    $EmailBody = "Hello $($User.DisplayName)," + "`n`n" +
                 "This is a reminder that your password will expire in $($User.ExpirationDate)." + "`n`n" +
                 "Please take a moment to change your password to ensure continued access to your account." + "`n`n" +
                 "Thank you," + "`n" +
                 "IT Team"

   # Try to send the email, catch any exceptions, and log them
    Try {
   #   Send-MailMessage -From $From -To $User.EmailAddress -Subject $Subject -Body $EmailBody -smtpserver $SMTP -usessl -Credential $cred -Port 587
      $EmailMessage = @{
        From = $From
        To = $User.EmailAddress
        Subject = $Subject
        Body = $EmailBody
        SmtpServer = $SMTP
        UseSsl = $True
        Credential = $cred
        Port = 587
        }
      Send-MailMessage @EmailMessage      
    # Log success
      Add-Content -Path "C:\Shared\Logs\EmailSuccess.log" -Value "Email sent successfully to $($User.DisplayName) at $($User.EmailAddress) on $(Get-Date) "
    }
    Catch {
      # Write the error message to the file EmailFailure.log under C:\Shared\Logs.
      Write-Host "Error sending email to $($User.DisplayName) at $($User.EmailAddress): $_"
      Add-Content -Path "C:\Shared\Logs\EmailFailure.Log" -Value "Error sending email to $($User.DisplayName) at $($User.EmailAddress) on $(Get-Date) $_"
    }
}
}
$Userlist | sort-object ExpirationDate

Run the script.

C:\Users\Administrator\passwordnotify.PS1

Checking the EmailSuccess.log file, the script was successfully sent email notification to AD users before their password will be expired.

The script sent an email notification to AD users.

Finally, we can add the script into the Task Scheduler to check domain users’ password expiration and send email notification.

Trigger tab.

Actions tab.

Actions Settings:

Program: %SystemRoot%\system32\WindowsPowerShell\v1.0\powershell.exe

Arguments: -ExecutionPolicy Bypass -File C:\Shared\passwordnotify.PS1

The task was running successfully in Task Scheduler history.

Checking logs in the EmailSuccess.log file to confirm the task scheduler was running successfully.

The email notification was sent to Gmail’s account.