Wysyłanie email przypominającego o terminie zmiany hasła

Poniżej skrypt wysyłający powiadomienia dla użytkowników o terminie zmiany hasła. Skrypt wyszukuje użytkowników którym hasło wygaśnie w terminie 7 lub mniej dni. W przypadku terminu krótszego niż 24 godziny zmieniany jest temat. W przypadku gdy hasło wygasa w sobotę lub w niedzielę dodatkowo dodawana jest taka informacja.

# Ustawienia SMTP
$SmtpServer = "mail.domena.local"
$From       = "Administrator AD <[email protected]>"

# Pobranie wszystkich włączonych użytkowników AD z potrzebnymi właściwościami
$Users = Get-ADUser -Filter {Enabled -eq $true} -Properties "DisplayName","msDS-UserPasswordExpiryTimeComputed","PasswordLastSet","PasswordNeverExpires","Mail"
#$Users = $Users|where {$_.samaccountname -eq "login"}  #odblokować do testów dla jednego użytkownika

# Utworzenie listy użytkowników z datą wygaśnięcia hasła i adresem e-mail
$UsersWithExpiry = foreach ($user in $Users) {

    if ($user.PasswordNeverExpires) { continue }   #tylko użytkownicy z ustawioną polityką zmiany hasła

    $ExpiryFileTime = $user."msDS-UserPasswordExpiryTimeComputed"
    if (-not $ExpiryFileTime -or $ExpiryFileTime -eq 0) { continue }

    try {
        $ExpiryDate = [datetime]::FromFileTime($ExpiryFileTime)
    } catch {
        continue
    }

    [PSCustomObject]@{
        DisplayName    = $user.DisplayName
        SamAccountName = $user.SamAccountName
        Email          = $user.Mail
        PasswordLastSet= $user.PasswordLastSet
        ExpiryDate     = $ExpiryDate
    }
}

# Obecna data
$Today = Get-Date

function Get-DayNameHtml([datetime]$date) {
    $dayName = $date.ToString('dddd', [cultureinfo]'pl-PL')
    if ($dayName -in @('sobota', 'niedziela')) {
        return "<span style='color:red;font-weight:bold'>$dayName</span>"
    } else {
        return $dayName
    }
}

# Funkcja wysyłki emaili do użytkowników w danym dniu (0..7)
function Send-ExpiryEmail($UsersList, [int]$DayBucket) {
    foreach ($u in $UsersList) {
        # Obliczenia różnicy czasu
        $ts = $u.ExpiryDate - (Get-Date)
        if ($ts.TotalSeconds -le 0) { continue } # hasło już wygasło – pomijamy

        $dayNameHtml = Get-DayNameHtml($u.ExpiryDate)

        # Dostosowanie tematu i treści dla < 24h
        if ($DayBucket -eq 0) {
            $hoursLeft = [math]::Ceiling($ts.TotalHours)
            $Subject = "$($u.DisplayName) – Twoje hasło wygaśnie za mniej niż 24 godziny (ok. $hoursLeft godzin)."
            $Body = @"
<html>
<body>
<p style="font-family:Tahoma; font-size:12pt"><b>$($u.DisplayName), Twoje hasło do konta AD wygaśnie $($u.ExpiryDate.ToString('dd.MM.yyyy HH:mm')) ($dayNameHtml).
Pamiętaj o zmianie hasła jak najszybciej. Pozostało około $hoursLeft godzin.</b></p>
<p style="font-family:Tahoma; font-size:10pt">Wiadomość wygenerowana automatycznie. Proszę nie odpowiadać.</p>
</body>
</html>
"@
        } else {
            $Subject = "$($u.DisplayName) – Twoje hasło wygasa za $DayBucket dni."
            $Body = @"
<html>
<body>
<p style="font-family:Tahoma; font-size:12pt"><b>$($u.DisplayName), Twoje hasło do konta AD wygaśnie $($u.ExpiryDate.ToString('dd.MM.yyyy HH:mm')) ($dayNameHtml).
Pamiętaj o zmianie hasła przed tą datą.</b></p>
<p style="font-family:Tahoma; font-size:10pt">Wiadomość wygenerowana automatycznie. Proszę nie odpowiadać.</p>
</body>
</html>
"@
        }

        Write-Host $Subject
        # Zakomentuj poniższą linię jeśli chcesz przetestować do kogo zostanie wysłana informacja
        # w poniższym poleceniu zakładamy, że serwer przyjmie wysyłkę bez autoryzacji (serwer z którego wykonujemy skrypt jest dodany do wyjątków)
        Send-MailMessage -SmtpServer $SmtpServer -From $From -To $u.Email -Subject $Subject -Body $Body -BodyAsHtml -Encoding UTF8
    }
}

# Grupowanie według liczby pełnych dni do wygaśnięcia: Floor(TotalDays) ∈ {0..7}
for ($i = 7; $i -ge 0; $i--) {
    $UsersForDay = @(
        $UsersWithExpiry |
        Where-Object {
            $ts = $_.ExpiryDate - $Today
            # pomijamy ujemne (wygasłe)
            if ($ts.TotalSeconds -le 0) { return $false }
            [int][math]::Floor($ts.TotalDays) -eq $i
        }
    )

    if ($UsersForDay.Count -gt 0) {
        Send-ExpiryEmail -UsersList $UsersForDay -DayBucket $i
    }
}

Tak przygotowany skrypt dodajemy do harmonogramu jako cykliczne zadanie wykonywane codziennie