-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathPasswordChangeNotification.ps1
318 lines (307 loc) · 13.1 KB
/
PasswordChangeNotification.ps1
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
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
<#
.Synopsis
Script to Automated Email Reminders when Users Passwords due to Expire.
.DESCRIPTION
Script to Automated Email Reminders when Users Passwords due to Expire.
Robert Pearman / WindowsServerEssentials.com
Version 2.9 August 2018
Requires: Windows PowerShell Module for Active Directory
For assistance and ideas, visit the TechNet Gallery Q&A Page. http://gallery.technet.microsoft.com/Password-Expiry-Email-177c3e27/view/Discussions#content
Alternativley visit my youtube channel, https://www.youtube.com/robtitlerequired
Videos are available to cover most questions, some videos are based on the earlier version which used static variables, however most of the code
can still be applied to this version, for example for targeting groups, or email design.
Please take a look at the existing Q&A as many questions are simply repeating earlier ones, with the same answers!
.EXAMPLE
PasswordChangeNotification.ps1 -smtpServer mail.domain.com -expireInDays 21 -from "IT Support <[email protected]>" -Logging -LogPath "c:\logFiles" -testing -testRecipient [email protected]
This example will use mail.domain.com as an smtp server, notify users whose password expires in less than 21 days, send mail from [email protected]
Logging is enabled, log path is c:\logfiles
Testing is enabled, and test recipient is [email protected]
.EXAMPLE
PasswordChangeNotification.ps1 -smtpServer mail.domain.com -expireInDays 21 -from "IT Support <[email protected]>" -reportTo [email protected] -interval 1,2,5,10,15
This example will use mail.domain.com as an smtp server, notify users whose password expires in less than 21 days, send mail from [email protected]
Report is enabled, reports sent to [email protected]
Interval is used, and emails will be sent to people whose password expires in less than 21 days if the script is run, with 15, 10, 5, 2 or 1 days remaining untill password expires.
#>
param(
# $smtpServer Enter Your SMTP Server Hostname or IP Address
[Parameter(Mandatory=$True,Position=0)]
[ValidateNotNull()]
[string]$smtpServer,
# Notify Users if Expiry Less than X Days
[Parameter(Mandatory=$True,Position=1)]
[ValidateNotNull()]
[int]$expireInDays,
# From Address, eg "IT Support <[email protected]>"
[Parameter(Mandatory=$True,Position=2)]
[ValidateNotNull()]
[string]$from,
[Parameter(Position=3)]
[switch]$logging,
# Log File Path
[Parameter(Position=4)]
[string]$logPath,
# Testing Enabled
[Parameter(Position=5)]
[switch]$testing,
# Test Recipient, eg [email protected]
[Parameter(Position=6)]
[string]$testRecipient,
# Output more detailed status to console
[Parameter(Position=7)]
[switch]$status,
# Log file recipient
[Parameter(Position=8)]
[string]$reportto,
# Notification Interval
[Parameter(Position=9)]
[array]$interval
)
###################################################################################################################
# Time / Date Info
$start = [datetime]::Now
$midnight = $start.Date.AddDays(1)
$timeToMidnight = New-TimeSpan -Start $start -end $midnight.Date
$midnight2 = $start.Date.AddDays(2)
$timeToMidnight2 = New-TimeSpan -Start $start -end $midnight2.Date
# System Settings
$textEncoding = [System.Text.Encoding]::UTF8
$today = $start
# End System Settings
# Load AD Module
try{
Import-Module ActiveDirectory -ErrorAction Stop
}
catch{
Write-Warning "Unable to load Active Directory PowerShell Module"
}
# Set Output Formatting - Padding characters
$padVal = "20"
Write-Output "Script Loaded"
Write-Output "*** Settings Summary ***"
$smtpServerLabel = "SMTP Server".PadRight($padVal," ")
$expireInDaysLabel = "Expire in Days".PadRight($padVal," ")
$fromLabel = "From".PadRight($padVal," ")
$testLabel = "Testing".PadRight($padVal," ")
$testRecipientLabel = "Test Recipient".PadRight($padVal," ")
$logLabel = "Logging".PadRight($padVal," ")
$logPathLabel = "Log Path".PadRight($padVal," ")
$reportToLabel = "Report Recipient".PadRight($padVal," ")
$interValLabel = "Intervals".PadRight($padval," ")
# Testing Values
if($testing)
{
if(($testRecipient) -eq $null)
{
Write-Output "No Test Recipient Specified"
Exit
}
}
# Logging Values
if($logging)
{
if(($logPath) -eq $null)
{
$logPath = $PSScriptRoot
}
}
# Output Summary Information
Write-Output "$smtpServerLabel : $smtpServer"
Write-Output "$expireInDaysLabel : $expireInDays"
Write-Output "$fromLabel : $from"
Write-Output "$logLabel : $logging"
Write-Output "$logPathLabel : $logPath"
Write-Output "$testLabel : $testing"
Write-Output "$testRecipientLabel : $testRecipient"
Write-Output "$reportToLabel : $reportto"
Write-Output "$interValLabel : $interval"
Write-Output "*".PadRight(25,"*")
# Get Users From AD who are Enabled, Passwords Expire and are Not Currently Expired
# To target a specific OU - use the -searchBase Parameter -https://docs.microsoft.com/en-us/powershell/module/addsadministration/get-aduser
# You can target specific group members using Get-AdGroupMember, explained here https://www.youtube.com/watch?v=4CX9qMcECVQ
# based on earlier version but method still works here.
$users = get-aduser -filter {(Enabled -eq $true) -and (PasswordNeverExpires -eq $false)} -properties Name, PasswordNeverExpires, PasswordExpired, PasswordLastSet, EmailAddress | where { $_.passwordexpired -eq $false }
# Count Users
$usersCount = ($users | Measure-Object).Count
Write-Output "Found $usersCount User Objects"
# Collect Domain Password Policy Information
$defaultMaxPasswordAge = (Get-ADDefaultDomainPasswordPolicy -ErrorAction Stop).MaxPasswordAge.Days
Write-Output "Domain Default Password Age: $defaultMaxPasswordAge"
# Collect Users
$colUsers = @()
# Process Each User for Password Expiry
Write-Output "Process User Objects"
foreach ($user in $users)
{
# Store User information
$Name = $user.Name
$emailaddress = $user.emailaddress
$passwordSetDate = $user.PasswordLastSet
$samAccountName = $user.SamAccountName
$pwdLastSet = $user.PasswordLastSet
# Check for Fine Grained Password
$maxPasswordAge = $defaultMaxPasswordAge
$PasswordPol = (Get-AduserResultantPasswordPolicy $user)
if (($PasswordPol) -ne $null)
{
$maxPasswordAge = ($PasswordPol).MaxPasswordAge.Days
}
# Create User Object
$userObj = New-Object System.Object
$expireson = $pwdLastSet.AddDays($maxPasswordAge)
$daysToExpire = New-TimeSpan -Start $today -End $Expireson
# Round Expiry Date Up or Down
if(($daysToExpire.Days -eq "0") -and ($daysToExpire.TotalHours -le $timeToMidnight.TotalHours))
{
$userObj | Add-Member -Type NoteProperty -Name UserMessage -Value "today."
}
if(($daysToExpire.Days -eq "0") -and ($daysToExpire.TotalHours -gt $timeToMidnight.TotalHours) -or ($daysToExpire.Days -eq "1") -and ($daysToExpire.TotalHours -le $timeToMidnight2.TotalHours))
{
$userObj | Add-Member -Type NoteProperty -Name UserMessage -Value "tomorrow."
}
if(($daysToExpire.Days -ge "1") -and ($daysToExpire.TotalHours -gt $timeToMidnight2.TotalHours))
{
$days = $daysToExpire.TotalDays
$days = [math]::Round($days)
$userObj | Add-Member -Type NoteProperty -Name UserMessage -Value "in $days days."
}
$daysToExpire = [math]::Round($daysToExpire.TotalDays)
$userObj | Add-Member -Type NoteProperty -Name UserName -Value $samAccountName
$userObj | Add-Member -Type NoteProperty -Name Name -Value $Name
$userObj | Add-Member -Type NoteProperty -Name EmailAddress -Value $emailAddress
$userObj | Add-Member -Type NoteProperty -Name PasswordSet -Value $pwdLastSet
$userObj | Add-Member -Type NoteProperty -Name DaysToExpire -Value $daysToExpire
$userObj | Add-Member -Type NoteProperty -Name ExpiresOn -Value $expiresOn
# Add userObj to colusers array
$colUsers += $userObj
}
# Count Users
$colUsersCount = ($colUsers | Measure-Object).Count
Write-Output "$colusersCount Users processed"
# Select Users to Notify
$notifyUsers = $colUsers | where { $_.DaysToExpire -le $expireInDays}
$notifiedUsers = @()
$notifyCount = ($notifyUsers | Measure-Object).Count
Write-Output "$notifyCount Users with expiring passwords within $expireInDays Days"
# Process notifyusers
foreach ($user in $notifyUsers)
{
# Email Address
$samAccountName = $user.UserName
$emailAddress = $user.EmailAddress
# Set Greeting Message
$name = $user.Name
$messageDays = $user.UserMessage
# Subject Setting
$subject="Your password will expire $messageDays"
# Email Body Set Here, Note You can use HTML, including Images.
# examples here https://youtu.be/iwvQ5tPqgW0
$body ="
<font face=""verdana"">
Dear $name,
<p> Your Password will expire $messageDays<br>
To change your password on a PC press CTRL ALT Delete and choose Change Password <br>
<p> If you are using a MAC you can now change your password via Web Mail. <br>
Login to <a href=""https://mail.domain.com/owa"">Web Mail</a> click on Options, then Change Password.
<p> Don't forget to Update the password on your Mobile Devices as well!
<p>Thanks, <br>
</P>
IT Support
<a href=""mailto:[email protected]""?Subject=Password Expiry Assistance"">[email protected]</a> | 0123 456 78910
</font>"
# If Testing Is Enabled - Email Administrator
if($testing)
{
$emailaddress = $testRecipient
} # End Testing
# If a user has no email address listed
if(($emailaddress) -eq $null)
{
$emailaddress = $testRecipient
}# End No Valid Email
$samLabel = $samAccountName.PadRight($padVal," ")
try{
# If using interval paramter - follow this section
if($interval)
{
$daysToExpire = [int]$user.DaysToExpire
# check interval array for expiry days
if(($interval) -Contains($daysToExpire))
{
# if using status - output information to console
if($status)
{
Write-Output "Sending Email : $samLabel : $emailAddress"
}
# Send message - if you need to use SMTP authentication watch this video https://youtu.be/_-JHzG_LNvw
Send-Mailmessage -smtpServer $smtpServer -from $from -to $emailaddress -subject $subject -body $body -bodyasHTML -priority High -Encoding $textEncoding -ErrorAction Stop
$user | Add-Member -MemberType NoteProperty -Name SendMail -Value "OK"
}
else
{
# if using status - output information to console
# No Message sent
if($status)
{
Write-Output "Sending Email : $samLabel : $emailAddress : Skipped - Interval"
}
$user | Add-Member -MemberType NoteProperty -Name SendMail -Value "Skipped - Interval"
}
}
else
{
# if not using interval paramter - follow this section
# if using status - output information to console
if($status)
{
Write-Output "Sending Email : $samLabel : $emailAddress"
}
Send-Mailmessage -smtpServer $smtpServer -from $from -to $emailaddress -subject $subject -body $body -bodyasHTML -priority High -Encoding $textEncoding -ErrorAction Stop
$user | Add-Member -MemberType NoteProperty -Name SendMail -Value "OK"
}
}
catch{
# error section
$errorMessage = $_.exception.Message
# if using status - output information to console
if($status)
{
$errorMessage
}
$user | Add-Member -MemberType NoteProperty -Name SendMail -Value $errorMessage
}
$notifiedUsers += $user
}
if($logging)
{
# Create Log File
Write-Output "Creating Log File"
$day = $today.Day
$month = $today.Month
$year = $today.Year
$date = "$day-$month-$year"
$logFileName = "$date-PasswordLog.csv"
if(($logPath.EndsWith("\")))
{
$logPath = $logPath -Replace ".$"
}
$logFile = $logPath, $logFileName -join "\"
Write-Output "Log Output: $logfile"
$notifiedUsers | Export-CSV $logFile
if($reportTo)
{
$reportSubject = "Password Expiry Report"
$reportBody = "Password Expiry Report Attached"
try{
Send-Mailmessage -smtpServer $smtpServer -from $from -to $reportTo -subject $reportSubject -body $reportbody -bodyasHTML -priority High -Encoding $textEncoding -Attachments $logFile -ErrorAction Stop
}
catch{
$errorMessage = $_.Exception.Message
Write-Output $errorMessage
}
}
}
$notifiedUsers | select UserName,Name,EmailAddress,PasswordSet,DaysToExpire,ExpiresOn | sort DaystoExpire | FT -autoSize
$stop = [datetime]::Now
$runTime = New-TimeSpan $start $stop
Write-Output "Script Runtime: $runtime"
# End