33<#
44. SYNOPSIS
55 Active Directory Password Expiration Notification Script
6-
6+
77. DESCRIPTION
88 Monitors Active Directory users and sends email notifications when passwords are approaching expiration.
99 Supports fine-grained password policies, multilingual messages, and comprehensive logging.
10-
11- . PARAMETER searchBase
12- Distinguished Name of the OU to search for users. If not specified, uses default configured base.
13-
14- . PARAMETER testMode
10+
11+ . PARAMETER SmtpServer
12+ SMTP server address for sending notification emails.
13+
14+ . PARAMETER FromAddress
15+ Email address used as the sender for notifications.
16+
17+ . PARAMETER SearchBase
18+ Distinguished Name of the OU to search for users.
19+
20+ . PARAMETER ExpireInDays
21+ Number of days before expiration to start sending notifications. Default is 10.
22+
23+ . PARAMETER TestMode
1524 Switch to enable test mode. All emails will be sent to the test recipient instead of actual users.
16-
17- . PARAMETER enableLogging
25+
26+ . PARAMETER TestRecipient
27+ Email address to receive all notifications when running in test mode. Default is "admin@company.com".
28+
29+ . PARAMETER EnableLogging
1830 Switch to enable detailed logging to CSV file.
19-
31+
32+ . PARAMETER LogDirectory
33+ Directory path for log files. Default is "C:\Logs\PasswordNotifications".
34+
35+ . PARAMETER Language
36+ Language for email templates. Supported values: EN, PT. Default is EN.
37+
2038. EXAMPLE
21- .\Send-PasswordExpiryNotification.ps1
22- Runs with default configuration
23-
39+ .\Send-PasswordExpiryNotification.ps1 -SmtpServer "mail.company.com" -FromAddress "noreply@company.com" -SearchBase "OU=Users,DC=domain,DC=com"
40+
41+ Runs with specified SMTP server and search base.
42+
2443. EXAMPLE
25- .\Send-PasswordExpiryNotification.ps1 -testMode -enableLogging
26- Runs in test mode with logging enabled
27-
44+ .\Send-PasswordExpiryNotification.ps1 -SmtpServer "mail.company.com" -FromAddress "noreply@company.com" -SearchBase "OU=Users,DC=domain,DC=com" -TestMode -EnableLogging
45+
46+ Runs in test mode with logging enabled.
47+
2848. NOTES
29- File Name : Send-PasswordExpiryNotification.ps1
30- Author : Leonardo Klein Rezende
31- Requires : PowerShell 5.1+, ActiveDirectory Module, SMTP Server Access
32-
49+ File Name : Send-PasswordExpiryNotification.ps1
50+ Author : Leonardo Klein Rezende
51+ Prerequisite : PowerShell 5.1+, ActiveDirectory Module, SMTP Server Access
52+ Creation Date : 2025-09-04
53+
3354. LINK
3455 https://github.com/leonardokr/powershell-scripts
3556#>
3657
58+ [CmdletBinding (SupportsShouldProcess )]
3759param (
38- [string ]$searchBase ,
39- [switch ]$testMode ,
40- [switch ]$enableLogging
41- )
60+ [Parameter (Mandatory = $true )]
61+ [string ]$SmtpServer ,
62+
63+ [Parameter (Mandatory = $true )]
64+ [string ]$FromAddress ,
65+
66+ [Parameter (Mandatory = $true )]
67+ [string ]$SearchBase ,
68+
69+ [Parameter (Mandatory = $false )]
70+ [ValidateRange (1 , 90 )]
71+ [int ]$ExpireInDays = 10 ,
72+
73+ [Parameter (Mandatory = $false )]
74+ [switch ]$TestMode ,
4275
43- $smtpServer = " x.x.x.x"
44- $expireInDays = 10
45- $fromAddress = " noreply@company.com"
46- $testRecipient = " admin@company.com"
47- $language = " EN" # EN or PT
48- $logDirectory = " C:\Logs\PasswordNotifications"
49- $defaultSearchBase = " OU=Users,DC=contoso,DC=local"
76+ [Parameter (Mandatory = $false )]
77+ [string ]$TestRecipient = " admin@company.com" ,
5078
51- if ($searchBase ) { $defaultSearchBase = $searchBase }
52- if ($testMode ) { $testModeEnabled = $true } else { $testModeEnabled = $false }
53- if ($enableLogging ) { $loggingEnabled = $true } else { $loggingEnabled = $false }
79+ [Parameter (Mandatory = $false )]
80+ [switch ]$EnableLogging ,
81+
82+ [Parameter (Mandatory = $false )]
83+ [string ]$LogDirectory = " C:\Logs\PasswordNotifications" ,
84+
85+ [Parameter (Mandatory = $false )]
86+ [ValidateSet (" EN" , " PT" )]
87+ [string ]$Language = " EN"
88+ )
5489
5590$messages = @ {
5691 EN = @ {
@@ -107,7 +142,7 @@ $messages = @{
107142 }
108143}
109144
110- $msg = $messages [$language ]
145+ $msg = $messages [$Language ]
111146function Write-LogMessage {
112147 param (
113148 [string ]$Message ,
@@ -259,8 +294,8 @@ function Send-PasswordExpiryAlert {
259294 $emailBody = Get-PasswordExpiryEmailBody - UserName $User.Name - DaysToExpire $ExpirationData.DaysToExpire
260295
261296 $mailParams = @ {
262- SmtpServer = $smtpServer
263- From = $fromAddress
297+ SmtpServer = $SmtpServer
298+ From = $FromAddress
264299 To = $RecipientEmail
265300 Subject = $msg.EmailSubject
266301 Body = $emailBody
@@ -309,27 +344,22 @@ function Write-LogEntry {
309344
310345try {
311346 Write-LogMessage " === PASSWORD EXPIRATION NOTIFICATION STARTED ===" - Level " INFO"
312- Write-LogMessage " Search Base: $defaultSearchBase " - Level " INFO"
313- Write-LogMessage " Language: $language " - Level " INFO"
314- Write-LogMessage " Test Mode: $testModeEnabled " - Level " INFO"
315- Write-LogMessage " Logging: $loggingEnabled " - Level " INFO"
316-
347+ Write-LogMessage " Search Base: $SearchBase " - Level " INFO"
348+ Write-LogMessage " Language: $Language " - Level " INFO"
349+ Write-LogMessage " Test Mode: $ ( $TestMode .IsPresent ) " - Level " INFO"
350+ Write-LogMessage " Logging: $ ( $EnableLogging .IsPresent ) " - Level " INFO"
351+
317352 $logFilePath = $null
318- if ($loggingEnabled ) {
353+ if ($EnableLogging ) {
319354 $logFileName = " PasswordNotification_$ ( Get-Date - Format ' yyyy-MM-dd' ) .csv"
320- $logFilePath = Join-Path - Path $logDirectory - ChildPath $logFileName
355+ $logFilePath = Join-Path - Path $LogDirectory - ChildPath $logFileName
321356
322357 if (-not (Initialize-LogFile - LogPath $logFilePath )) {
323358 Write-LogMessage " Continuing without logging..." - Level " WARN"
324- $loggingEnabled = $false
359+ $EnableLogging = $false
325360 }
326361 }
327-
328- if (-not (Get-Module - Name ActiveDirectory - ListAvailable)) {
329- throw " Active Directory module not available. Please install RSAT tools."
330- }
331-
332- Import-Module ActiveDirectory - ErrorAction Stop
362+
333363 Write-LogMessage " Active Directory module loaded successfully" - Level " SUCCESS"
334364
335365 $defaultPasswordPolicy = Get-ADDefaultDomainPasswordPolicy - ErrorAction Stop
@@ -342,9 +372,9 @@ try {
342372 $_.PasswordExpired -eq $false
343373 }
344374
345- Write-LogMessage " Searching for users in: $defaultSearchBase " - Level " INFO"
375+ Write-LogMessage " Searching for users in: $SearchBase " - Level " INFO"
346376
347- $adUsers = Get-ADUser - SearchBase $defaultSearchBase - Filter * - Properties Name, PasswordNeverExpires, PasswordExpired, PasswordLastSet, EmailAddress |
377+ $adUsers = Get-ADUser - SearchBase $SearchBase - Filter * - Properties Name, PasswordNeverExpires, PasswordExpired, PasswordLastSet, EmailAddress |
348378 Where-Object $userFilter
349379
350380 Write-LogMessage " Found $ ( $adUsers.Count ) enabled users to process" - Level " INFO"
@@ -363,11 +393,11 @@ try {
363393 try {
364394 $expirationData = Get-PasswordExpirationData - User $user - DefaultMaxAge $maxPasswordAge
365395
366- if ($expirationData.DaysToExpire -ge 0 -and $expirationData.DaysToExpire -lt $expireInDays ) {
367- $recipientEmail = if ($testModeEnabled ) { $testRecipient } else { $user.EmailAddress }
396+ if ($expirationData.DaysToExpire -ge 0 -and $expirationData.DaysToExpire -lt $ExpireInDays ) {
397+ $recipientEmail = if ($TestMode ) { $TestRecipient } else { $user.EmailAddress }
368398
369399 if ([string ]::IsNullOrWhiteSpace($recipientEmail )) {
370- $recipientEmail = $testRecipient
400+ $recipientEmail = $TestRecipient
371401 $stats.NoEmail ++
372402 Write-LogMessage " User without email address: $ ( $user.Name ) " - Level " WARN"
373403 }
@@ -378,7 +408,7 @@ try {
378408 $stats.EmailsSent ++
379409 }
380410
381- if ($loggingEnabled ) {
411+ if ($EnableLogging ) {
382412 Write-LogEntry - LogPath $logFilePath - User $user - ExpirationData $expirationData - Email $recipientEmail - EmailSent $emailSent
383413 }
384414
@@ -401,11 +431,11 @@ try {
401431 Write-LogMessage " Errors: $ ( $stats.Errors ) " - Level " INFO"
402432 Write-LogMessage " Skipped (not expiring): $ ( $stats.Skipped ) " - Level " INFO"
403433
404- if ($testModeEnabled ) {
405- Write-LogMessage " *** TEST MODE ACTIVE - All emails sent to: $testRecipient ***" - Level " WARN"
434+ if ($TestMode ) {
435+ Write-LogMessage " *** TEST MODE ACTIVE - All emails sent to: $TestRecipient ***" - Level " WARN"
406436 }
407437
408- if ($loggingEnabled ) {
438+ if ($EnableLogging ) {
409439 Write-LogMessage " Detailed log saved to: $logFilePath " - Level " INFO"
410440 }
411441
0 commit comments