We keep running into the issue where in many networks, some only 5 user and other 150+ user environments, users forget to change their passwords every 90 days. Even though we have the domains configured to start warning them 7 days ahead of time, they seem to ignore the little bubble. Anyone that has ever maintained a directory server, whether it is OpenLDAP or Active Directory, can relate to the few users that continue to forget. After multiple weekends where all hell would rain down Monday morning due to passwords expiring on Friday afternoon, a solution needed to be found.
Do not fret! We have created a great Powershell script, which can be used in a daily scheduled task, to run a report that contains a list of user accounts which will expire soon, while it nags the users to change or update their password before it expires. This report is then also emailed to the IT manager, the IS department, or whomever takes care of password resets.
To keep the script modular, the parameters do not have to be called in the scheduled task so they can be modified before scheduling, as well as makes it easy to call the script for one-off runs. Though, as it can be seen, we have not provided any help files or synopsis for the function, as that may come later.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 |
<# Get-ADUserPasswordExpiryReport By A Tech With a Hammer https://www.techwithahammer.com/?p=31 Created: December 2, 2014 Last Update: December 6, 2014 To do Add in the synopsis so this utility is a little more useful and less #> Function Get-ADUserPasswordExpiryReport { param( # Where to store the reports [parameter(position=0)] [string]$ReportPath = ".\PasswordExpiryReports", # Where in the directory to search user accounts [parameter(position=1)] [string]$SearchBase = "OU=Users,DC=techwithahammer,DC=com", # The number of days to password expire [parameter(position=2)] [string]$Age = 14, # Send the report? I would recommend it [parameter(position=3)] [boolean]$SendReport = $true, # Who to send the expiry report from [parameter(position=4)] [string]$ReportFrom = "justanother@techwithahammer.com", # Where you are sending the password report [parameter(position=5)] [string]$ReportTo = "justanother@techwithahammer.com", # Subject line for the password expiry report to the IT department [parameter(position=6)] [string]$ReportSubject = "Password Expiry Report", # Whether to send the expiry notice or not [parameter(position=7)] [boolean]$SendNotice = $true, # Email address to send the expiry notices from [parameter(position=8)] [string]$NoticeFrom = "justanother@techwithahammer.com", # Email template to be used for expiry notices to users [parameter(position=9)] [string]$NoticePath = ".\PasswordExpiryNotice.html", # Subject line for expiry notice emails sent to user [parameter(position=10)] [string]$NoticeSubject = "Password Expiring", # SMTP Server address [parameter(position=11)] [string]$SMTPServer = "smtp.techwithahammer.com", # #[parameter(position=12)] #[string]$SMTPPort = 25 ) if (!(Test-Path $ReportPath)) { try { New-Item -ItemType Directory $ReportPath } catch { Throw "Report Path does not exist" Exit 5 } } $ReportEmailHeader = @" <style> Table {border-width: 1px; border-style: solid; border-color #000000; border-collapse: collapse;; padding: 2px; } th {border-width: 1px; border-style: solid; border-color #000000; background-color: #000000; color: #ffffff; padding: 2px; } td {border-width: 1px; border-style: solid; border-color #000000; background-color: #ffffff; padding: 2px; } </style>; "@ if ($SendNotice) { if (!(Test-Path $NoticePath)) { Throw "Require valid notice template to send notices. $NoticePath does not exist" Exit 1 } $EmailNotice = (Get-Content $NoticePath) } try { Import-Module ActiveDirectory } Catch { Throw "Unable to load Active Directory module" Exit 1 } $DomainMaxPasswordAge = (Get-ADDefaultDomainPasswordPolicy).MaxPasswordAge if ($DomainMaxPasswordAge -eq $null -or $DomainMaxPasswordAge -le 0) { Throw "Domain does not have a password expiry policy" if ((get-addomain).domainmode -lt 3) { Throw "Unable to continue as domain mode is less than Windows2008Domain" Exit 4 } } $Users = ( get-aduser -searchbase "$SearchBase" -filter {Enabled -eq $true -and PasswordNeverExpires -eq $false} -properties DisplayName,PasswordLastSet,PasswordExpired,EmailAddress,GivenName,sn | where {$_.PasswordLastSet -ne $null} ) If ($Users -eq $null) { Throw "No users found" Exit 2 } else { if ($SendNotice -eq $true -and !(Test-Path $NoticePath)) { Throw "$NoticePath template required for sending notices" Exit 3 } $Results = @() ForEach ($User in $Users) { $UserAccountName = $User.sAMAccountName $UserDisplayName = $User.DisplayName $UserFirstName = $User.GivenName $UserLastName = $User.sn $UserEmailAddress = $User.EmailAddress $Today = (Get-Date -UFormat %c) if ((get-addomain).domainmode -ge 3) { $UserPasswordMaxAge = (Get-ADUserResultantPasswordPolicy $User -erroraction SilentlyContinue).MaxPasswordAge } if ($UserPasswordMaxAge -eq $null) { $UserPasswordMaxAge = $DomainMaxPasswordAge } $UserPasswordExpiry = ($User.PasswordLastSet + $UserPasswordMaxAge) $UserPasswordExpiryDays = (new-timespan -start (get-date) -end $UserPasswordExpiry).Days if ($UserPasswordExpiryDays -le $Age) { $Results += New-Object PSObject -Property @{ 'Account Name' = $UserAccountName 'First Name' = $UserFirstName 'Last Name' = $UserLastName 'Password Expiry Date' = $UserPasswordExpiry 'Days Until Expired' = $UserPasswordExpiryDays } if ($SendNotice -and $UserPasswordExpiryDays -ge 0) { $UserNotice = ($EmailNotice -replace "%Username%","$UserAccountName" | Out-String) $UserNotice = ($UserNotice -replace "%DaysLeft%","$UserPasswordExpiryDays") $UserNotice = ($UserNotice -replace "%DisplayName%","$UserDisplayName") $UserNotice = ($UserNotice -replace "%FirstName%","$UserFirstName") $UserNotice = ($UserNotice -replace "%LastName%,""$UserLastName") $UserNotice = ($UserNotice -replace "%Today%","$Today") Send-MailMessage -From $NoticeFrom -To $UserEmailAddress -SMTPServer $SMTPServer -Subject $NoticeSubject -Body $UserNotice -BodyAsHTML } } } } $Results = ($Results | Sort 'Password Expiry Date') $ReportDateTime = (Get-Date -UFormat %m-%d-%y) $ReportFilePath = "$ReportPath\ADUserPasswordExpiryReport-$ReportDateTime.csv" $Results | Export-CSV $ReportFilePath -NoTypeInformation $Results if ($SendReport) { $ReportEmailBody = ($Results | ConvertTo-HTML -Head $ReportEmailHeader | Out-String) Send-MailMessage -From $ReportFrom -To $ReportTo -SMTPServer $SMTPServer -Subject $ReportSubject -Body $ReportEmailBody -BodyAsHTML -Attachments $ReportFilePath } } |
I had to change the date formats,
line 143 $Today = (Get-Date -UFormat %c )
and
line 182 $ReportDateTime = (Get-Date -UFormat %m-%d-%y )