Email people via Office 365 from PowerShell when passwords about to expire

I have a demonstration environment where many users have accounts but they never logon to AD directly nor look at this demonstration email mailbox. They only use the environment via Azure AD where they logon at Azure AD via the replicated password hash. Because of this they don’t get password expiry notifications and continue to logon however if they try and access something that does hook into AD and not Azure AD the logon fails.

They wanted to be emailed of upcoming password expiry to their real-email. To accomplish this their real email was stored in extensionAttribute10. I didn’t use the proxyaddresses as this may have SIP information. This attribute could be easily set with:

$aduser | Set-Aduser -Replace @{extensionAttribute10=$AltEmail}

I had a mailbox for a core process I use. Now that user has no other rights so I placed the password in the script but that’s not ideal at all. If this was Azure Automation I could have used a credential object, I could have at least made the password harder to read by creating an encrypted version of the password and then storing that in the file (but its still reversible, just slightly harder to glance at!), e.g.

ConvertFrom-SecureString (ConvertTo-SecureString -AsPlainText -Force 'Password123') #this is run once to generate the value

$securepassword = ConvertTo-SecureString "<the huge value from previous command on one line>" #this is then in script going forward
$cred = new-object System.Management.Automation.PSCredential ("john@savilltech.com", $securepassword)

However the account can’t do anything except email and access to the script location was highly restricted so I left it as text which was also easier to demonstrate below however in my environment I used the alternate approach above just to make it a little harder to get the password on glance :-). Replace this with your own email and password.

The script looks for any password expiring in less than 10 days and emails a simple message. Customize as you like! It has a basic HTML block with a placeholder (MESSAGEHOLDER) that is replaced by a custom string for the user.

$CurrentDate = Get-Date
$Users = Get-ADUser -filter {Enabled -eq $True -and PasswordNeverExpires -eq $False} -Properties msDS-UserPasswordExpiryTimeComputed, PasswordLastSet, CannotChangePassword, extensionAttribute10

$fromEmail = 'fromuser@domain.com'
$fromPass = 'password'
$securePassword = ConvertTo-SecureString $fromPass -AsPlainText -Force
$emailcred = New-Object System.Management.Automation.PSCredential ($fromEmail, $securePassword)  
$SMTPServer = 'smtp.office365.com'
$SMTPPort = '587'

$PasswordNotifyDays = 10

$emailBody = @"
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta content="en-us" http-equiv="Content-Language" />
<meta content="text/html; charset=utf-8" http-equiv="Content-Type" />
</head>
<body>
<p>MESSAGEHOLDER</p>
<p>Please change password at <a href="https://myapps.microsoft.com">https://myapps.microsoft.com</a>.</p>
</body>
</html>
"@

foreach($user in $users)
{
    $userUPN = $user.DistinguishedName
    $userName = $user.Name

        $PasswordLastChanged = $user.PasswordLastSet
        $PasswordExpired = [datetime]::FromFileTime($user."msDS-UserPasswordExpiryTimeComputed")
        
        $PasswordTillExpired = ($PasswordExpired - $CurrentDate).Days
        if($PasswordTillExpired -lt $PasswordNotifyDays)
        {
            if($PasswordTillExpired -lt 0)
            {
                $message = "User $userName ($($user.UserPrincipalName)) password is expired ($PasswordTillExpired days past change time). Last changed $PasswordLastChanged"
            }
            else
            {
                $message = "User $userName ($($user.UserPrincipalName)) password expires in $PasswordTillExpired days. Last changed $PasswordLastChanged"
            }
            Write-Output $message
            $altemail = $user.extensionAttribute10
            if($altemail -ne $null)
            {
                write-output "   Alternate email found and message being sent to $altemail"
                Send-MailMessage -To $altemail -From $fromEmail -Subject "Password Expiry Notification - $($user.UserPrincipalName)" -BodyAsHtml $emailBody.Replace("MESSAGEHOLDER",$message) `
                    -SmtpServer $SMTPServer -Port $SMTPPort -UseSsl -Credential $emailcred
            }
        }
}

Have fun!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: