PowerShell: Sending password expiration notices via GMail – Part 3
December 20th, 2016 by Charlie Russel and tagged Active Directory, DateTime, Get-Credential, Get-Date, GMail, Here-String, PowerShell
In Part 1 of this series, I showed you how to identify users whose password was about to expire. Then in Part 2 of the series, I took that list of users and sent email to them using gmail-hosted company email. This third part of the series pulls all that together into a single script, complete with comment-based help. As always, this and all my scripts are copyrighted, but you’re welcome to use them as the basis for your own scripts. However, I do appreciate attribution. Thanks, and enjoy.
<# .Synopsis Sends a "Password Expiring" warning email through TreyResearch's gmail. .Description Send-TreyPasswordExpiryNotice first creates a list of accounts whose password will expire in the near future (default is 1 week). It then emails the users to warn them that their password will expire soon. This initial version runs interactively only. .Example Send-TreyPasswordExpiryNotice Sends a warning notice to all TreyResearch users whose password will expire in the next 7 days or less. .Example Send-TreyPasswordExpiryNotice -Logging Sends a warning notice to all TreyResearch users whose password will expire in the next 7 days or less, and creates a log file that is echoed to the console at the end. .Example Send-TreyPasswordExpiryNotice -DaysWarning 14 Sends a warning notice to all TreyResearch users whose password will expire in the next 14 days or less. .Example Send-TreyPasswordExpiryNotice -DaysWarning 5 -Logging -Testing -Verbose Does NOT send a warning notice to TreyResearch users, but rather processes the first user and sends a notice to the admin user(s) and writes to the log file. The -Verbose switch will make it additionally chatty. .Parameter DaysWarning The number of days advanced warning to give users whose passwords are close to expiration. The default is 7 days or less. .Parameter Logging Switch to enable logging. Logs are written to C:\Temp\emaillogs.csv. When this switch is true, Send-TreyPasswordExpiryNotice outputs a table with a list of accounts due to expire as well as writing to a log file. .Parameter Testing Switch to enable testing. When enabled, email is sent to a list of Admin users and only a single account is processed. .Inputs [int] [switch] [Switch] .Notes Author: Charlie Russel ThanksTo: Robert Pearman (WSSMB MVP),Jeffrey Hicks (PS MVP) Copyright: 2016 by Charlie Russel : Permission to use is granted but attribution is appreciated Initial: 06 Sept, 2016 (cpr) : 09 Dec, 2016 (cpr) -(Ver 1.5) -- Reworked: Only process users who need reminding. Formatting changes #> [CmdletBinding()] Param( [Parameter(Mandatory=$False,Position=0)] [int] $DaysWarning = 7, [parameter(Mandatory=$false)] [Switch] $Logging, [parameter(Mandatory=$false)] [switch] $Testing ) #Set parameters for gmail. $smtpServer ="smtp.gmail.com" $SMTPPort = 587 $from = "IT Notification <it-notification@TreyResearch.net>" $AdminUser1 = "Charlie.Russel@TreyResearch.net" $AdminUser2 = "admin.user2@TreyResearch.net" $AdminUser3 = "admin.user3@TreyResearch.net" $externalUser= "external.account@example.com" # Cast this to a list of strings to allow for multiple test recipients [string[]]$testRecipient = $AdminUser1,$AdminUser2,$AdminUser3 <# This uses a stored password sitting on a local hard drive. This is a reasonably secure way to work with passwords in a file, and is ONLY accessible by the user that created it. Create the password with: PSH> Read-Host -AsSecureString | ConvertFrom-SecureString | Out-File $home\Documents\TreyPW.txt See blog post at: http://blogs.msmvps.com/russel/2016/10/04/powershell-get-credential-from-a-file for full details. Alternately, simply prompt for the credentials here with Get-Credential. #> $TreyUsr = "charlie.russel@TreyResearch.net" $TreyPW = Get-Content $Home\Documents\TreyPW.txt | ConvertTo-SecureString $Cred = New-Object System.Management.Automation.PSCredential -ArgumentList $TreyUsr, $TreyPW # Check Logging Settings if ($Logging) { $logFile = "C:\Temp\emaillogs.csv" if (! (Test-Path "C:\Temp") ) { Write-Verbose "No C:\Temp directory, so creating one..." New-Item -Path "C:\" -Name Temp -ItemType Directory } # Remove Logfile if it already exists If ( (Test-Path $logFile)) { Remove-Item $logFile } # Create CSV File and Headers New-Item -Path $logfile -ItemType File Add-Content $logfile "Date,Name,EmailAddress,DaysLeft,ExpiresOn,Notified" } # System Settings $textEncoding = [System.Text.Encoding]::UTF8 $date = Get-Date -format "MM/dd/yyyy" # Explicitly import the Active Directory module, but get rid of the noise if it's already loaded. Import-Module ActiveDirectory 4>$NULL # Use the following to query the domain for who the PDC Emulator role holder is. $TreyDC = (Get-ADDomain -Identity "TreyResearch.net" -Credential $Cred).PDCEmulator # Send a cc: to myself or a list of users $AdminUser = "charlie.russel@TreyResearch.net" $cclist = @($AdminUser) # Do calculations outside the ForEach loop whenever possible $maxPasswordAge = (Get-ADDefaultDomainPasswordPolicy -Server $TreyDC -Credential $Cred).MaxPasswordAge $today = (get-date) # Notice this doesn't get Expired or NeverExpires users. Don't want to send them emails. $TreyUsers = Get-ADUser -filter * ` -properties Name,PasswordNeverExpires,PasswordExpired,PasswordLastSet,EmailAddress ` -Server $TreyDC ` -Credential $Cred ` | where { $_.Enabled -eq $True ` -AND $_.PasswordNeverExpires -eq $False ` -AND $_.passwordexpired -eq $False ` -AND $_.EMailAddress ` -AND (($today - $_.PasswordLastSet).Days -ge ($MaxPasswordAge.Days - $DaysWarning)) } <# Get notification credentials. Prompt with Get-Credential if not using stored creds. $gCred = Get-Credential -UserName "it-notification@TreyResearch.net" ` -Message "Enter Password for IT-Notification account" #> $gUsr = "it-notification@TreyResearch.net" $gPW = Get-Content "$Home\Documents\itnotificationsPW.txt" | ConvertTo-SecureString $gCred = New-Object System.Management.Automation.PSCredential -ArgumentList $gUsr, $gPW # Now, we start to do the work. foreach ($user in $TreyUsers) { Write-Verbose "Processing user $user" $Name = $user.Name $Email = $user.emailaddress $SAM = $user.SAMAccountName $sent = " " $passwordSetDate = $user.PasswordLastSet Write-Verbose "$SAM last set their password on $PasswordSetDate" $expiresOn = $passwordSetDate + $maxPasswordAge $DaysLeft = (New-TimeSpan -Start $today -End $Expireson).Days if (($DaysLeft) -gt "1") { $MessageDays = "in " + "$DaysLeft" + " days." } else { $MessageDays = "today!" } # Email Subject Set Here $subject="Your password will expire $messageDays" Write-Verbose "$Name`'s password will expire $messageDays" # Email Body Set Here, Note You can use HTML, including Images. # This uses PowerShell's here-string. $body =@" Dear $name, <p>Your TreyReseach.net Active Directory Domain credentials <b>will expire $messagedays</b> Please update your credentials as soon as possible! <br> </p> <p>If you are using a Windows domain joined system and are connected to the intranet, press ctrl-alt-delete and select change password. Alternatively, if you are outside of the network, connect to the corporate VPN and reset your password with the same process.<br> </p> <p>If you are not using a Windows based system, ensure you are on the intranet or connected to the corporate VPN. Proceed to https://password.TreyResearch.net <https://password.TreyResearch.net> and reset your password.<br> </p> <p>This process will also sync your newly created AD password to your Gmail password. Please allow up to 5 minutes for replication of the passwords to occur.<br><br> </p> <p><br><b>Problems</b>? <br>Please open a Service Desk request by clicking on the Help Agent icon on your system. If you are NOT running a Help Agent, please contact a member of the IT Team for instructions on how to install the agent. It is a strict TreyResearch company policy that all company-owned systems run the Help Agent. <br></p> <p>Thanks, <br> IT Team </P> "@ # If Testing Is Enabled - Email Administrator if ($testing) { $email = $testRecipient $Subject = "PasswordExpiration Test Message" $cclist = $AdminUser2,$externalUser } # Send Email Message Write-Verbose "$SAM's password is due to expire in $DaysLeft which is less than the " Write-Verbose "DaysWarning Parameter setting of $DaysWarning days." # I've left this as a straight output to the host. If you want it quieter, make it a Write-Verbose "Sending Email Message to $email using $gUsr account" Send-Mailmessage -smtpServer $smtpServer ` -from $from ` -to $email ` -cc $cclist ` -subject $subject ` -body $body ` -bodyasHTML ` -priority High ` -Encoding $textEncoding ` -UseSSL ` -port $SMTPPort ` -Credential $gCred $sent = "Yes" # Used for logging if ($Logging) { Add-Content $logfile "$date,$Name,$email,$DaysLeft,$expiresOn,$Sent" } if ($Testing) { "Sleeping 5, then breaking so we only process a single record" Sleep 5 Break } } If ($Logging) { # Use the logging file to display a table of the accounts about to expire. $expiringAccts = Import-Csv -Path $logfile $expiringAccts | Sort-Object -Property ExpiresOn ` | Format-Table -AutoSize ` @{Expression={$_.DaysLeft};` Label="#Days";` align="Right";` width=7}, ` Name,` @{Expression={(Get-Date -Date $_.ExpiresOn -Format 'MMMM dd')};` Label="Expires On:"} }
ETA: Minor bug fix (-Identity instead of -Identify. Sheesh!)
Posted in Active Directory, Network Administration, PowerShell, PSCredential, Security | Comments Off on PowerShell: Sending password expiration notices via GMail – Part 3