PSPasswordExpiryNotifications.psm1

function Find-AllUsers {
    [CmdletBinding()]
    param([string] $AdditionalProperties,
        [hashtable] $WriteParameters)
    $Properties = @('Manager', 'DisplayName', 'GivenName', 'Surname', 'SamAccountName', 'EmailAddress', 'msDS-UserPasswordExpiryTimeComputed', 'PasswordExpired', 'PasswordLastSet', 'PasswordNotRequired'
        if ($AdditionalProperties) {$AdditionalProperties})
    try {
        $Users = Get-ADUser -filter {Enabled -eq $True -and PasswordNeverExpires -eq $False -and PasswordLastSet -gt 0 -and PasswordNotRequired -ne $True} -Properties $Properties -ErrorAction Stop
        $ProcessedUsers = foreach ($_ in $Users) {
            if ($null -ne $_.Manager) {$Manager = Get-ADUser $_.Manager -Properties Mail} else {$Manager = $null}
            if ($AdditionalProperties) {
                $EmailTemp = $_.$AdditionalProperties
                if ($EmailTemp -like '*@*') {$EmailAddress = $EmailTemp} else {$EmailAddress = $_.EmailAddress}
            } else {$EmailAddress = $_.EmailAddress}
            [PSCustomobject] @{UserPrincipalName = $_.UserPrincipalName
                SamAccountName = $_.SamAccountName
                DisplayName = $_.DisplayName
                GivenName = $_.GivenName
                Surname = $_.Surname
                EmailAddress = $EmailAddress
                PasswordExpired = $_.PasswordExpired
                PasswordLastSet = $_.PasswordLastSet
                PasswordNotRequired = $_.PasswordNotRequired
                "Manager" = $Manager.Name
                "ManagerEmail" = $Manager.Mail
                "DateExpiry" = ([datetime]::FromFileTime($_."msDS-UserPasswordExpiryTimeComputed"))
                "DaysToExpire" = (NEW-TIMESPAN -Start (GET-DATE) -End ([datetime]::FromFileTime($_."msDS-UserPasswordExpiryTimeComputed"))).Days
            }
        }
    } catch {
        $ErrorMessage = $_.Exception.Message -replace "`n", " " -replace "`r", " "
        Write-Color @WriteParameters '[e] Error: ', $ErrorMessage -Color White, Red
        Exit
    }
    return $ProcessedUsers
}
$script:WriteParameters = @{ShowTime = $true
    LogFile = ""
    TimeFormat = "yyyy-MM-dd HH:mm:ss"
}
function Set-EmailReplacements {
    [CmdletBinding()]
    param($Replacement,
        $User,
        [System.Collections.IDictionary] $EmailParameters,
        [System.Collections.IDictionary] $FormattingParameters,
        $Day)
    $Replacement = $Replacement -replace "<<DisplayName>>", $user.DisplayName
    $Replacement = $Replacement -replace "<<DateExpiry>>", $user.DateExpiry
    $Replacement = $Replacement -replace "<<GivenName>>", $user.GivenName
    $Replacement = $Replacement -replace "<<Surname>>", $user.Surname
    $Replacement = $Replacement -replace "<<TimeToExpire>>", $Day.Value
    $Replacement = $Replacement -replace "<<ManagerDisplayName>>", $user.Manager
    $Replacement = $Replacement -replace "<<ManagerEmail>>", $user.ManagerEmail
    return $Replacement
}
function Set-EmailReportDetails {
    [CmdletBinding()]
    param([System.Collections.IDictionary] $FormattingOptions,
        [System.Collections.IDictionary] $ReportOptions,
        $TimeToGenerate,
        [int] $CountUsersImminent,
        [int] $CountUsersCountdownStarted,
        [int] $CountUsersAlreadyExpired)
    $DateReport = get-date
    $Report = @(@"
        <p>
            <strong>Report Time:</strong> $DateReport
            <br>
            <strong>Time to generate:</strong> $($TimeToGenerate.Hours) hours, $($TimeToGenerate.Minutes) minutes, $($TimeToGenerate.Seconds) seconds, $($TimeToGenerate.Milliseconds) milliseconds
            <br>
            <strong>Account Executing Report :</strong> $env:userdomain\$($env:username.toupper()) on $($env:ComputerName.toUpper())
            <br>
            <strong>Users expiring countdown started: </strong> $CountUsersCountdownStarted
            <br>
            <strong>Users expiring soon: </strong> $CountUsersImminent
            <br>
            <strong>Users already expired count: </strong> $CountUsersAlreadyExpired
            <br>
        </p>
"@

        foreach ($ip in $ReportOptions.MonitoredIps.Values) {"<li>ip:</strong> $ip</li>"}
        '</ul>'
        '</p>')
    return $Report
}
Function Start-PasswordExpiryCheck {
    [CmdletBinding()]
    param ([System.Collections.IDictionary] $EmailParameters,
        [System.Collections.IDictionary] $FormattingParameters,
        [System.Collections.IDictionary] $ConfigurationParameters)
    $time = [System.Diagnostics.Stopwatch]::StartNew()
    Test-Prerequisits
    $WriteParameters = $ConfigurationParameters.DisplayConsole
    $FieldName = $ConfigurationParameters.RemindersSendToUsers.UseAdditionalField
    $Today = get-date
    $Users = Find-AllUsers -AdditionalProperties $FieldName -WriteParameters $WriteParameters | Sort-Object DateExpiry
    $UsersWithEmail = @($Users | Where-Object {$_.EmailAddress -like '*@*'})
    $UsersExpired = $Users | Where-Object {$_.DateExpiry -lt $Today}
    $EmailBody = Set-EmailHead -FormattingOptions $FormattingParameters
    $EmailReportBranding = Set-EmailReportBranding -FormattingOptions $FormattingParameters
    $EmailBody += Set-EmailFormatting -Template $FormattingParameters.Template -FormattingParameters $FormattingParameters -ConfigurationParameters $ConfigurationParameters -ReportBranding $EmailReportBranding
    $UsersNotified = @(if ($ConfigurationParameters.RemindersSendToUsers.Enable -eq $true) {
            Write-Color @WriteParameters '[i] Starting processing ', 'Users', ' section' -Color White, Yellow, White
            foreach ($Day in $ConfigurationParameters.RemindersSendToUsers.Reminders.GetEnumerator()) {
                $Date = (get-date).AddDays($Day.Value).Date
                foreach ($u in $UsersWithEmail) {
                    if ($u.DateExpiry.Date -eq $Date) {
                        Write-Color @WriteParameters -Text "[i] User ", "$($u.DisplayName)", " expires in ", "$($Day.Value)", " days (", "$($u.DateExpiry)", ")." -Color White, Yellow, White, Red, White, Red, White
                        $TemporaryBody = Set-EmailReplacements -Replacement $EmailBody -User $u -FormattingParameters $FormattingParameters -EmailParameters $EmailParameters -Day $Day
                        $EmailSubject = Set-EmailReplacements -Replacement $EmailParameters.EmailSubject -User $u -FormattingParameters $FormattingParameters -EmailParameters $EmailParameters -Day $Day
                        $u.DaysToExpire = $Day.Value
                        if ($ConfigurationParameters.RemindersSendToUsers.RemindersDisplayOnly -eq $true) {
                            Write-Color @WriteParameters -Text "[i] Pretending to send email to ", "$($u.EmailAddress)", " ...", "Success" -Color White, Green, White, Green
                            $EmailSent = @{}
                            $EmailSent.Status = $false
                            $EmailSent.SentTo = 'N/A'
                        } else {
                            if ($ConfigurationParameters.RemindersSendToUsers.SendToDefaultEmail -eq $false) {
                                Write-Color @WriteParameters -Text "[i] Sending email to ", "$($u.EmailAddress)", " ..." -Color White, Green -NoNewLine
                                $EmailSent = Send-Email -EmailParameters $EmailParameters -Body $TemporaryBody -Subject $EmailSubject -To $u.EmailAddress
                            } else {
                                Write-Color @WriteParameters -Text "[i] Sending email to users is disabled. Sending email to default value: ", "$($EmailParameters.EmailTo) ", "..." -Color White, Yellow, White -NoNewLine
                                $EmailSent = Send-Email -EmailParameters $EmailParameters -Body $TemporaryBody -Subject $EmailSubject
                            }
                            if ($EmailSent.Status -eq $true) {Write-Color -Text "Done" -Color "Green"} else {Write-Color -Text "Failed!" -Color "Red"}
                        }
                        Add-member -InputObject $u -NotePropertyName "EmailSent" -NotePropertyValue $EmailSent.Status
                        Add-member -InputObject $u -NotePropertyName "EmailSentTo" -NotePropertyValue $EmailSent.SentTo
                        $u
                    }
                }
            }
            Write-Color @WriteParameters '[i] Ending processing ', 'Users', ' section' -Color White, Yellow, White
        } else {Write-Color @WriteParameters '[i] Skipping processing ', 'Users', ' section' -Color White, Yellow, White})
    if ($ConfigurationParameters.RemindersSendToManager.Enable -eq $true) {
        Write-Color @WriteParameters '[i] Starting processing ', 'Managers', ' section' -Color White, Yellow, White
        $EmailSubject = $ConfigurationParameters.RemindersSendToManager.ManagersEmailSubject
        $EmailBody = Set-EmailHead -FormattingOptions $FormattingParameters
        $EmailReportBranding = Set-EmailReportBranding -FormattingOptions $FormattingParameters
        $EmailBody += Set-EmailFormatting -Template $FormattingParameters.TemplateForManagers -FormattingParameters $FormattingParameters -ConfigurationParameters $ConfigurationParameters -AddAfter $EmailReportBranding
        $UsersWithManagers = $UsersNotified | Where-Object {$_.ManagerEmail -ne $null}
        $Managers = foreach ($u in $UsersWithManagers) {$u.ManagerEmail}
        $Managers = $Managers | Sort-Object | Get-Unique
        Write-Color @WriteParameters '[i] Preparing package for managers with emails ', "$($UsersWithManagers.Count) ", 'users to process with', ' manager filled in', ' where unique managers ', "$($Managers.Count)" -Color White, Yellow, White, Yellow, White, Yellow
        foreach ($m in $Managers) {
            $ColumnNames = 'UserPrincipalName', 'DisplayName', 'DateExpiry', 'PasswordExpired', 'SamAccountName', 'Manager', 'ManagerEmail', 'PasswordLastSet'
            if ($ConfigurationParameters.RemindersSendToManager.Reports.IncludePasswordNotificationsSent.IncludeNames -ne '') {$UsersNotifiedManagers = $UsersNotified | Where-Object {$_.ManagerEmail -eq $m} | Select-Object $ConfigurationParameters.RemindersSendToManager.Reports.IncludePasswordNotificationsSent.IncludeNames} else {$UsersNotifiedManagers = $UsersNotified | Where-Object {$_.ManagerEmail -eq $m} | Select-Object 'UserPrincipalName', 'DisplayName', 'DateExpiry', 'DaysToExpire', 'SamAccountName', 'Manager', 'ManagerEmail', 'PasswordLastSet', 'EmailSent', 'EmailSentTo'}
            if ($ConfigurationParameters.RemindersSendToManager.Reports.IncludePasswordNotificationsSent.Enabled -eq $true) {foreach ($u in $UsersNotifiedManagers) {Write-Color @WriteParameters -Text '[-] User ', "$($u.DisplayName) ", " Managers Email (", "$($m)", ')' -Color White, Yellow, White, Yellow, White}}
            if ($ConfigurationParameters.RemindersSendToManager.RemindersDisplayOnly -eq $true) {
                Write-Color @WriteParameters -Text "[i] Pretending to send email to manager email ", "$($m)", " ...", "Success" -Color White, Green, White, Green
                $EmailSent = @{}
                $EmailSent.Status = $false
                $EmailSent.SentTo = 'N/A'
            } else {
                $TemporaryBody = $EmailBody
                $TemporaryBody = Set-EmailBodyTableReplacement -Body $TemporaryBody -TableName 'ManagerUsersTable' -TableData $UsersNotifiedManagers
                $TemporaryBody = Set-EmailReplacements -Replacement $TemporaryBody -User $u -FormattingParameters $FormattingParameters -EmailParameters $EmailParameters -Day ''
                if ($ConfigurationParameters.Debug.DisplayTemplateHTML -eq $true) {Get-HTML -text $TemporaryBody}
                if ($ConfigurationParameters.RemindersSendToManager.SendToDefaultEmail -eq $false) {
                    Write-Color @WriteParameters -Text "[i] Sending email to managers email ", "$($m)", " ..." -Color White, Green -NoNewLine
                    $EmailSent = Send-Email -EmailParameters $EmailParameters -Body $TemporaryBody -Subject $EmailSubject -To $m
                } else {
                    Write-Color @WriteParameters -Text "[i] Sending email to managers is disabled. Sending email to default value: ", "$($EmailParameters.EmailTo) ", "..." -Color White, Yellow, White -NoNewLine
                    $EmailSent = Send-Email -EmailParameters $EmailParameters -Body $TemporaryBody -Subject $EmailSubject
                }
                if ($EmailSent.Status -eq $true) {Write-Color -Text "Done" -Color "Green"} else {Write-Color -Text "Failed!" -Color "Red"}
            }
        }
        Write-Color @WriteParameters '[i] Ending processing ', 'Managers', ' section' -Color White, Yellow, White
    } else {Write-Color @WriteParameters '[i] Skipping processing ', 'Managers', ' section' -Color White, Yellow, White}
    if ($ConfigurationParameters.RemindersSendToAdmins.Enable -eq $true) {
        Write-Color @WriteParameters '[i] Starting processing ', 'Administrators', ' section' -Color White, Yellow, White
        $DayHighest = get-HashMaxValue $ConfigurationParameters.RemindersSendToUsers.Reminders
        $DayLowest = get-HashMaxValue $ConfigurationParameters.RemindersSendToUsers.Reminders -Lowest
        $DateCountdownStart = (get-date).AddDays($DayHighest).Date
        $DateIminnent = (get-date).AddDays($DayLowest).Date
        $ColumnNames = 'UserPrincipalName', 'DisplayName', 'DateExpiry', 'PasswordExpired', 'SamAccountName', 'Manager', 'ManagerEmail', 'PasswordLastSet'
        if ($ConfigurationParameters.RemindersSendToAdmins.Reports.IncludePasswordNotificationsSent.IncludeNames -ne '') {$UsersNotified = $UsersNotified | Select-Object $ConfigurationParameters.RemindersSendToAdmins.Reports.IncludePasswordNotificationsSent.IncludeNames} else {$UsersNotified = $UsersNotified | Select-Object $ColumnNames, 'EmailSent', 'EmailSentTo'}
        if ($ConfigurationParameters.RemindersSendToAdmins.Reports.IncludeExpiringImminent.IncludeNames -ne '') {$ExpiringIminent = $Users | Where-Object {$_.DateExpiry -lt $DateIminnent -and $_.PasswordExpired -eq $false} | Select-Object $ConfigurationParameters.RemindersSendToAdmins.Reports.IncludeExpiringImminent.IncludeNames} else {$ExpiringIminent = $Users | Where-Object {$_.DateExpiry -lt $DateIminnent -and $_.PasswordExpired -eq $false} | Select-Object $ColumnNames}
        if ($ConfigurationParameters.RemindersSendToAdmins.Reports.IncludeExpiringCountdownStarted.IncludeNames -ne '') {$ExpiringCountdownStarted = $Users | Where-Object {$_.DateExpiry -lt $DateCountdownStart -and $_.PasswordExpired -eq $false} | Select-Object $ConfigurationParameters.RemindersSendToAdmins.Reports.IncludeExpiringCountdownStarted.IncludeNames} else {$ExpiringCountdownStarted = $Users | Where-Object {$_.DateExpiry -lt $DateCountdownStart -and $_.PasswordExpired -eq $false} | Select-Object $ColumnNames}
        if ($ConfigurationParameters.RemindersSendToAdmins.Reports.IncludeExpired.IncludeNames -ne '') {$UsersExpired = $UsersExpired | Select-Object $ConfigurationParameters.RemindersSendToAdmins.Reports.IncludeExpired.IncludeNames} else {$UsersExpired = $UsersExpired | Select-Object $ColumnNames}
        $EmailBody = Set-EmailHead -FormattingOptions $FormattingParameters
        $EmailBody += "<body>"
        $EmailBody += Set-EmailReportBranding -FormattingOptions $FormattingParameters
        $EmailBody += Set-EmailReportDetails -FormattingOptions $FormattingParameters -ReportOptions $ReportOptions -TimeToGenerate $Time.Elapsed -CountUsersCountdownStarted $($ExpiringCountdownStarted.Count) -CountUsersImminent $($ExpiringIminent.Count) -CountUsersAlreadyExpired $($UsersExpired.Count)
        $time.Stop()
        if ($ConfigurationParameters.RemindersSendToAdmins.Reports.IncludePasswordNotificationsSent.Enabled -eq $true) {
            Write-Color @WriteParameters -Text '[i] Preparing data for report ', 'Password Notifcations Sent' -Color White, Yellow
            $EmailBody += Set-EmailBody -TableData $UsersNotified -TableMessageWelcome "Following users had their password notifications sent" -TableMessageNoData 'No users required nofifications.'
        }
        if ($ConfigurationParameters.RemindersSendToAdmins.Reports.IncludeExpiringImminent.Enabled -eq $true) {
            Write-Color @WriteParameters -Text '[i] Preparing data for report ', 'Users expiring imminent' -Color White, Yellow
            $EmailBody += Set-EmailBody -TableData $ExpiringIminent -TableMessageWelcome "Following users expiring imminent (Less than $DayLowest day(s)" -TableMessageNoData 'No users expiring.'
        }
        if ($ConfigurationParameters.RemindersSendToAdmins.Reports.IncludeExpiringCountdownStarted.Enabled -eq $true) {
            Write-Color @WriteParameters -Text '[i] Preparing data for report ', 'Expiring Couintdown Started' -Color White, Yellow
            $EmailBody += Set-EmailBody -TableData $ExpiringCountdownStarted -TableMessageWelcome "Following users expiring countdown started (Less than $DayHighest day(s))" -TableMessageNoData 'There were no users that had their coundown started.'
        }
        if ($ConfigurationParameters.RemindersSendToAdmins.Reports.IncludeExpired.Enabled -eq $true) {
            Write-Color @WriteParameters -Text '[i] Preparing data for report ', 'Users are already expired' -Color White, Yellow
            $EmailBody += Set-EmailBody -TableData $UsersExpired -TableMessageWelcome "Following users are already expired (and still enabled...)" -TableMessageNoData "No users that are expired and enabled."
        }
        $EmailBody += "</body>"
        if ($ConfigurationParameters.Debug.DisplayTemplateHTML -eq $true) {Get-HTML -text $EmailBody}
        if ($ConfigurationParameters.RemindersSendToAdmins.RemindersDisplayOnly -eq $true) {Write-Color @WriteParameters -Text "[i] Pretending to send email to admins email ", "$($ConfigurationParameters.RemindersSendToAdmins.AdminsEmail) ", "...", 'Success' -Color White, Yellow, White, Green} else {
            Write-Color @WriteParameters -Text "[i] Sending email to administrators on email address ", "$($ConfigurationParameters.RemindersSendToAdmins.AdminsEmail) ", "..." -Color White, Yellow, White -NoNewLine
            $EmailSent = Send-Email -EmailParameters $EmailParameters -Body $EmailBody -Subject $ConfigurationParameters.RemindersSendToAdmins.AdminsEmailSubject -To $ConfigurationParameters.RemindersSendToAdmins.AdminsEmail
            if ($EmailSent.Status -eq $true) {Write-Color -Text "Done" -Color "Green"} else {Write-Color -Text "Failed! Error: $($EmailSent.Error)" -Color "Red"}
        }
        Write-Color @WriteParameters '[i] Ending processing ', 'Administrators', ' section' -Color White, Yellow, White
    } else {Write-Color @WriteParameters '[i] Skipping processing ', 'Administrators', ' section' -Color White, Yellow, White}
}
function Test-Prerequisits {
    [CmdletBinding()]
    param()
    try {$null = get-addomain} catch {
        if ($_.Exception -match "Unable to find a default server with Active Directory Web Services running.") {Write-Color @script:WriteParameters "[-] ", "Active Directory", " not found. Please run this script with access to ", "Domain Controllers." -Color White, Red, White, Red}
        Write-Color @script:WriteParameters "[-] ", "Error: $($_.Exception.Message)" -Color White, Red
        Exit
    }
}
Export-ModuleMember -Function @('Start-PasswordExpiryCheck') -Alias @()