Today I wanted to share a script with you that allows you to inform your users per email that their password will expire or even is expired and reminds them about your password policies like complex passwords and how to chose a password. This is a simple VBScript and can easily be adjusted. The email will be generated from a file, in this case a HTML file that you provide. You can adjust the content of this HTML file as you need it. There are sure many commercial solutions out there that can do more then this script, but if you want to save the money and are satisfied with the provided options, this sure can be a good alternative.
Let me mention one thing about passwords first – most of us live with the usual policy that passwords should be changed periodically and need to be of a certain length and complexity. We all live with the daily calls of the help-desk about forgotten passwords, not changed passwords (pretty much why I wrote the script) and so on – what changed was a new recommendation in late 2017 or early 2018 that actually is based on statistics and data and now says – yes – complex passwords and certain lengths – but do not enforce periodic changes of those passwords due to this actually resulting in to less secure passwords while users might only change a number or even write those passwords more likely down and therefor compromising the whole attempt to secure the system.
Anyways – the next few lines will explain the parameters you can adjust in the top section of the VBS script – further below I will post the script and an example HTML file so you can start right away.
The options are between the lines 7 and 61 – don’t be scared – most of them are pretty simple to understand and are actually explained in the script itself. You should not need to modify anything outside those two lines.
About the parameter naming convention and possible values:
- starting with str as strings – those expect text-markers and alphanumeric values “text”
- starting with int as integer values – those are direct numeric values – e.g. 123
- starting with bol are boolean values – those can be either TRUE or FALSE – meaning on or off
Here are the options you can set:
- strSMTPServer: SMTP mail server DNS name or IP address
- intSMTPServerPort: SMTP mail server port – normally 25
- strFrom: SMTP mail from address
- strToAdmin: SMTP mail to address for administrator emails
- strAdminMailSubject: subject for mail to administrators
- strUserMailSubjectExpired: subject for mails to user when password is expired
- strUserMailSubjectWillExpire: subject for mail to user when password will expire – the exact word REPLACEWITHDAYS will be replaced by the days left value so mention it in the subject line if you want to see the value there
- strBodyURL: URL or full file-path (HTML file path e.g. file://) to import for body, the entire content of this URL/FILE will be imported to the body of the email and should explain ways how to change the password
- strAttachment: full file-path to an attachment for the email to the users / leave empty if no attachment
- strLDAPSortColumn: per default: pwdLastSet / sort column for LDAP query
- intStartWithPWexpiresInDays: If the passwords expires in days N or less, the script will inform the user – keep in mind – if you run the script daily, those users will get an email every day once their password will expire in less then the indicated days. 5 is sure a good start.
- bolIgnoreDisabledAccounts: Disabled accounts should always be ignored
- bolInformAdminAboutPWexpires: this will inform the admin about expiring passwords
- bolInformAdminAboutPWisExpired: this will inform the admin about accounts with expired passwords
- bolInformAdminAboutPWneverExpires: this will inform the admin about accounts with password set to never expire
- bolInformAdminAboutUserCantChangePW: this will inform the admin about users who are not allowed to change their password
- bolInformAdminAboutAccountDisabled: this will inform the admin about disabled accounts found – this would have been done in ADS by an administrator
- bolInformAdminAboutExpiredUserAccount: this will inform the admin if the user account has an expiration date and the account is expired
- bolInformAdminAboutAccountWithoutEMail: this will inform the admin about accounts without a set email address
- bolInformAdminAboutStillGoodPasswords: this will inform the admin about users/passwords that are still valid
- bolInformAdminAboutIgnoredUsersExcludedByGroup: this will inform the admin about users that have been ignored by the strGroupsExclude filter
- Please Note: the status account locked will not be checked, this should be corrected automatically by the default security GPO instead (will be in most cases by default)
- strSearchOUs: Filter Priority 1 – only users in those OU paths will be processed. Use LDAP DN like: “OU=Folder,OU=Folder,DC=Domain,DC=local”, you do not need to include the DC=Domain,DC=local – the script will add this information if necessary. Use | (pipe) if you want to add more then one LDAP DN path. Leave empty (“”) to disable this filter
- strGroupsExclude : Filter Priority 2 – if the user object is still not excluded, this group exclude filter will be applied. If the user is member of one of those groups (if multiple groups are defined), he will be ignored. Use | (pipe) if you want to add more then one GroupName. Leave empty (“”) to disable this filter. Example: “Group Number1|GroupNumber2”
- strGroupsInclude: Filter Priority 3 – if the user object is still not excluded, this group Include filter will be applied. The user has to be a member of one of those groups (if multiple groups are defined). Use | (pipe) if you want to add more then one GroupName. Leave empty (“”) to disable this filter. Example: “Group Number1|GroupNumber2”
- bolDebug: set TRUE for script-output, highly recommended to execute the Script in CMD with CSCRIPT <ScriptName> so you see it in a command window instead of dialog boxes.
- bolAttachDebugToAdminMail: the debug output will be attached to the admin-mail (independent from bolDebug)
- bolTestDebugOutputToConsoleOnly: this will disable the mail.send – only output to the CMD will be generated, please enable bolDebug
- bolRedirectMailToAdmin: this will redirect all mails to the admin, instead of sending them to the user – the subject line will include the user-mail address in this case – this allows you to do a real test and actually see what would be send out to whom – without actually sending the emails to the end user
- bolAdminMailOnly: this will send the admin-mail only, no user mail will be generated
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 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 | 'This VBScript will run aggainst the ActiveDirectory Domain the executing User is a Member of. 'The executing User does not need to be an Domain-Administrator of any kind, a simply User is able to read the necessary information from ActiveDirectory ' 'Please configure the following Options - the Script does not accept or expect any Start-Parameter ' 'Version 2.2 - 04/12/2017: Florian Rossmark '---------------------------------- START OPTIONS ---------------------------------- Const strSMTPServer = "relay.domain.com" 'SMTP Mail-Server to use Const intSMTPServerPort = 25 'SMTP Mail-Server connection Port Number Const strFrom = "pwdscript@domain.com" 'SMTP Mail From Address Const strToAdmin = "helpdesk@domain.com" 'SMTP Mail To Address for Administrator Const strAdminMailSubject = "Company Name - User Password Script Results to Admin" 'Subject for Mail to Admin Const strUserMailSubjectExpired = "Your password has expired!" 'Subject for Mail to User when Password is expired Const strUserMailSubjectWillExpire = "Your password will expire in REPLACEWITHDAYS days" 'Subject for Mail to User when Password will expire - the exact word REPLACEWITHDAYS will be replaced by the days left value Const strBodyURL = "file://C:/scripts/PWD/PWDExpire.html" 'URL or full file-path (HTML) to import for Body, the entire content of this URL/FILE will be imported to the Body of the email and should explain ways how to change the password Const strAttachment = "" 'full File-Path to an attachment for the email to the users / leave empty if no attachment Const strLDAPSortColumn = "pwdLastSet" 'per default: pwdLastSet / sort column for LDAP query Const intStartWithPWexpiresInDays = 5 'If the Passwords expires in days N or less, the script will inform the user Const bolIgnoreDisabledAccounts = True 'Disabled accounts should always be ignored Const bolInformAdminAboutPWexpires = True 'This will inform the Admin about expiring passwords Const bolInformAdminAboutPWisExpired = True 'This will inform the Admin about accounts with expired Passwords Const bolInformAdminAboutPWneverExpires = True 'This will inform the Admin about accounts with password set to never expire Const bolInformAdminAboutUserCantChangePW = True 'This will inform the Admin about users who are not allowed to change their password Const bolInformAdminAboutAccountDisabled = True 'This will inform the Admin about disabled accounts found - this would have been done in ADS by an administrator Const bolInformAdminAboutExpiredUserAccount = True 'This will inform the admin if the User Account has an expiration date and the account is expired Const bolInformAdminAboutAccountWithoutEMail = True 'This will inform the Admin about accounts without a set email address Const bolInformAdminAboutStillGoodPasswords = True 'This will inform the Admin about Users/Passwords that are still valid Const bolInformAdminAboutIgnoredUsersExcludedByGroup = True 'This will inform the Admin about Users that have been ignored by the strGroupsExclude filter 'Please Note: Status Account Locked will not be checked, this should be corrected automatically by the Default Security GPO instead (will be in most cases by default) 'Filter Priority 1 - only Users in those OU Paths will be processed 'Use LDAP DN like: "OU=Folder,OU=Folder,DC=Domain,DC=local", you do not need to include the DC=Domain,DC=local - the Script will add this information if necessary 'Use | (pipe) if you want to add more then one LDAP DN Path 'Leave empty ("") to disable this filter Const strSearchOUs = "" '"OU=Users,OU=Site,DC=domain,DC=local" 'Filter Priority 2 - if the User Object is still not excluded, this Group Exclude filter will be applied 'If the user is member of one of those groups (if multiple groups are defined), he will be ignored 'Use | (pipe) if you want to add more then one GroupName 'Leave empty ("") to disable this filter 'Example: "Group Number1|GroupNumber2" Const strGroupsExclude = "No Password notification emails" 'Filter Priority 3 - if the User Object is still not excluded, this Group Include filter will be applied 'The user has to be a member of one of those groups (if multiple groups are defined) 'Use | (pipe) if you want to add more then one GroupName 'Leave empty ("") to disable this filter 'Example: "Group Number1|GroupNumber2" Const strGroupsInclude = "" Const bolDebug = True 'Set TRUE for Script-Output, highly recommended to execute the Script in CMD with CSCRIPT <ScriptName> Const bolAttachDebugToAdminMail = False 'The Debug Output will be attached to the Admin-Mail (independent from bolDebug) Const bolTestDebugOutputToConsoleOnly = False 'This will disable the Mail.Send - only output to the CMD will be generated, please enable bolDebug Const bolRedirectMailToAdmin = True 'This will redirect all Mails to the Admin, instead of sending them to the User - the Subject line will include the User-Mail Address in this case Const bolAdminMailOnly = False 'This will send the Admin-Mail only, no User Mail will be generated '---------------------------------- END OPTIONS ---------------------------------- '---------------------------------- Script starts here ---------------------------------- '---------------------------------- please do not modify after this line ---------------------------------- 'Reference: https://msdn.microsoft.com/en-us/library/aa772300(v=vs.85).aspx Const ADS_UF_DONT_EXPIRE_PASSWD = 65536 Const ADS_UF_PASSWD_CANT_CHANGE = 64 Const ADS_UF_PASSWORD_EXPIRED = 8388608 Const ADS_ACETYPE_ACCESS_DENIED_OBJECT = 6 Const CHANGE_PASSWORD_GUID = "{ab721a53-1e2f-11d0-9819-00aa0040529b}" 'A few Global Variables for the Admin-Mail Dim strAdminPWexpires, strAdminPWisExpired, strAdminPWneverExpires, strAdminUserCantChangePW, strAdminAccountDisabled, strAdminExpiredUserAccount, strAdminAccountWithoutEMail, strAdminPWstillGood, strAdminIgnoredUsersExcludedByGroup Dim strAdminErrorUsers Dim strAdminDebug SearchADS() 'Let's Start the actual process 'starts the actual search procedure - in a sub so it is easier to keep overview of the script Sub SearchADS() Dim objADSRoot, objADSDomain, objADSConnection, objADSCommand, objMaxPWDage, objUser Dim intMaxPWDage, intDaysLeft Dim bolProcessUser Dim cntArray Dim arrSearchOUs, arrGroupsExclude, arrGroupsInclude Dim iADSCommand Dim strFirstFoundGroupMembership arrGroupsExclude = Split(strGroupsExclude, "|") arrGroupsInclude = Split(strGroupsInclude, "|") 'Connect to ADS and get Users Set objADSRoot = GetObject("LDAP://rootDSE") Set objADSDomain = GetObject("LDAP://" & objADSRoot.Get("defaultNamingContext")) Set objMaxPWDage = objADSDomain.Get("maxPwdAge") 'please note, this script can't obey the latest ADS multible password GPO rules, it will only follow the standard with only one password rule intMaxPWDage = CCur((objMaxPWDage.HighPart * 2 ^ 32) + objMaxPWDage.LowPart) / CCur(-864000000000) If Not intMaxPWDage > 0 Then 'Passwords won't expire at all ScriptDebug("intMaxPWDage is set to: " & intMaxPWDage & " - Script stopped") SendEmailNotification True, "", True, 0, "intMaxPWDage is incorrect, please check ADS configuration. Script aborded" 'Inform that there is no expiration configuration in Active Directory Exit Sub 'Stop the Sub / End the Search End If Set objADSConnection = CreateObject("ADODB.Connection") objADSConnection.Open "Provider=ADsDSOObject;" Set objADSCommand = CreateObject("ADODB.Command") objADSCommand.ActiveConnection = objADSConnection If Not Len(strSearchOUs) > 0 Then ReDim arrSearchOUs(0) 'we still need an array to run the For Next arrSearchOUs(0) = "" Else arrSearchOUs = Split(strSearchOUs, "|") End If For iADSCommand = 0 To UBound(arrSearchOUs) 'we already filter OUs if necessary - filter priority 1 If Len(strSearchOUs) > 0 Then 'we need everytime a new objADSDomain to set the Filter based on the OU If Not Right(arrSearchOUs(iADSCommand),Len(objADSRoot.Get("defaultNamingContext"))) = objADSRoot.Get("defaultNamingContext") Then If Not Right(arrSearchOUs(iADSCommand),1) = "'" Then arrSearchOUs(iADSCommand) = arrSearchOUs(iADSCommand) & "," End If arrSearchOUs(iADSCommand) = arrSearchOUs(iADSCommand) & objADSRoot.Get("defaultNamingContext") End If ScriptDebug("Searching LDAP Path: " & arrSearchOUs(iADSCommand)) Set objADSDomain = GetObject("LDAP://" & arrSearchOUs(iADSCommand)) End If 'samAccountType=805306368 / this is the correct value for USERS only - a search for the ObjectClass USER will also list Contacts objADSCommand.CommandText = "<" & objADSDomain.ADsPath & ">;(&(samAccountType=805306368));userAccountControl,sAMAccountName,givenName,sn,mail,distinguishedName,lockoutTime;subtree" objADSCommand.Properties("Sort on") = strLDAPSortColumn Set rs = objADSCommand.Execute If Not rs.EOF Then Do While Not rs.EOF ScriptDebug("") 'Empty Line before each run for easier to read output ScriptDebug("PROCESSING USER: " & NZ(rs("givenName"), "") & " " & NZ(rs("sn"), "") & " (" & NZ(rs("sAMAccountName"), "") & ")") intDaysLeft = 0 bolProcessUser = True 'Priority 2 - Exclude the following groups If Len(strGroupsExclude) > 0 Then strFirstFoundGroupMembership = "" 'just to make sure, lets clean the variable If IsUserInGroup(rs("distinguishedName"), arrGroupsExclude, strFirstFoundGroupMembership) Then 'User is Member of the Group, we ignore him ScriptDebug("..USER IS MEMBER OF EXCLUDED GROUP: " & strFirstFoundGroupMembership & " - IGNORING USER") bolProcessUser = False 'old info - 'We don't inform the Admin in this case, would be done over the Debug Info If bolInformAdminAboutIgnoredUsersExcludedByGroup Then strAdminIgnoredUsersExcludedByGroup = AddAdminInfoTo(strAdminIgnoredUsersExcludedByGroup, NZ(rs("givenName"), "") & "</td><td>" & NZ(rs("sn"), "") & "</td><td>" & NZ(rs("sAMAccountName"), "") & "</td><td class=""right"">" & AdminInfoDaysLeftHTMLFormat((GetPWDaysLeft(rs("distinguishedName"), NZ(rs("givenName"), ""), NZ(rs("sn"), ""), NZ(rs("sAMAccountName"), ""), intDaysLeft, intMaxPWDage) * -1)), True) 'Add to Admin Info End If End If End If 'Priority 3 - Include the following groups If bolProcessUser Then 'do we still go on with this User? If Len(strGroupsInclude) > 0 Then strFirstFoundGroupMembership = "" 'just to make sure, lets clean the variable If Not IsUserInGroup(rs("distinguishedName"), arrGroupsInclude, strFirstFoundGroupMembership) Then 'User is Member of the Group, we ignore him ScriptDebug("..USER IS NOT A MEMBER OF ANY OF THE INCLUDED GROUPS - IGNORING USER") bolProcessUser = False 'old info - 'We don't inform the Admin in this case, would be done over the Debug Info If bolInformAdminAboutIgnoredUsersExcludedByGroup Then strAdminIgnoredUsersExcludedByGroup = AddAdminInfoTo(strAdminIgnoredUsersExcludedByGroup, NZ(rs("givenName"), "") & "</td><td>" & NZ(rs("sn"), "") & "</td><td>" & NZ(rs("sAMAccountName"), "") & "</td><td class=""right"">" & AdminInfoDaysLeftHTMLFormat((GetPWDaysLeft(rs("distinguishedName"), NZ(rs("givenName"), ""), NZ(rs("sn"), ""), NZ(rs("sAMAccountName"), ""), intDaysLeft, intMaxPWDage) * -1)), True) 'Add to Admin Info End If Else 'User will be noramlly proccessed, we still inform about it in the Script-Debug ScriptDebug("..USER IS MEMBER OF INCLUDED GROUP: " & strFirstFoundGroupMembership & " - PROCESSING USER") End If End If End If 'Priority 4 - disabled account? this would have been done by an administrator If bolProcessUser Then 'do we still go on with this User? If IsAccountDisabled(rs("distinguishedName")) Then 'Account is disabled ScriptDebug("..DISABLED USER ACCOUNT FOUND") If bolIgnoreDisabledAccounts Then 'do we ignore this Account? bolProcessUser = False End If If bolInformAdminAboutAccountDisabled Then 'strAdminAccountDisabled = AddAdminInfoTo(strAdminAccountDisabled, NZ(rs("givenName"), "") & " " & NZ(rs("sn"), "") & " (" & NZ(rs("sAMAccountName"), "") & ")") 'Add to Admin Info strAdminAccountDisabled = AddAdminInfoTo(strAdminAccountDisabled, NZ(rs("givenName"), "") & "</td><td>" & NZ(rs("sn"), "") & "</td><td>" & NZ(rs("sAMAccountName"), ""), True) 'Add to Admin Info End If End If End If 'Priority 5 - Will User Account expire? (we only check if it is expired, if yes we take action) If bolProcessUser Then 'do we still go on with this User? If IsUserAccountExpired(rs("distinguishedName"), dtmExpiration) Then bolProcessUser = False ScriptDebug("..USER ACCOUNT IS EXPIRED SINCE: " & dtmExpiration) If bolInformAdminAboutExpiredUserAccount Then 'strAdminExpiredUserAccount = AddAdminInfoTo(strAdminExpiredUserAccount, NZ(rs("givenName"), "") & " " & NZ(rs("sn"), "") & " (" & NZ(rs("sAMAccountName"), "") & ") - User expired since: " & dtmExpiration) 'Add to Admin Info strAdminExpiredUserAccount = AddAdminInfoTo(strAdminExpiredUserAccount, NZ(rs("givenName"), "") & "</td><td>" & NZ(rs("sn"), "") & "</td><td>" & NZ(rs("sAMAccountName"), "") & "</td><td class=""right"">" & AdminInfoDaysLeftHTMLFormat(dtmExpiration), True) 'Add to Admin Info End If End If End If 'Priority 6 - password never expires? this would have been done by an administrator If bolProcessUser Then 'do we still go on with this User? If PasswordDoesExpire(rs("userAccountControl")) Then 'Password does not expire ScriptDebug("..USER WITH PASSWORD WILL NOT EXPIRE FOUND") bolProcessUser = False If bolInformAdminAboutPWneverExpires Then 'strAdminPWneverExpires = AddAdminInfoTo(strAdminPWneverExpires, NZ(rs("givenName"), "") & " " & NZ(rs("sn"), "") & " (" & NZ(rs("sAMAccountName"), "") & ")") 'Add to Admin Info strAdminPWneverExpires = AddAdminInfoTo(strAdminPWneverExpires, NZ(rs("givenName"), "") & "</td><td>" & NZ(rs("sn"), "") & "</td><td>" & NZ(rs("sAMAccountName"), ""), True) 'Add to Admin Info End If End If End If 'Priority 7 - User can't even change the password? this would have been done by an administrator If bolProcessUser Then 'do we still go on with this User? If UserCantChangePassword(rs("distinguishedName")) Then 'User can't change Password ScriptDebug("..USER WITH CAN'T CHANGE PASSWORD FOUND") bolProcessUser = False If bolInformAdminAboutUserCantChangePW Then 'strAdminUserCantChangePW = AddAdminInfoTo(strAdminUserCantChangePW, NZ(rs("givenName"), "") & " " & NZ(rs("sn"), "") & " (" & NZ(rs("sAMAccountName"), "") & ")") 'Add to Admin Info strAdminUserCantChangePW = AddAdminInfoTo(strAdminUserCantChangePW, NZ(rs("givenName"), "") & "</td><td>" & NZ(rs("sn"), "") & "</td><td>" & NZ(rs("sAMAccountName"), ""), True) 'Add to Admin Info End If End If End If 'Priority 8 - User does not have an EMail Address? can't inform User if PW is about to expire what shall we do? If bolProcessUser Then 'do we still go on with this User? If Not Len(NZ(rs("mail"), "")) > 0 Then 'User is missing email address ScriptDebug("..USER WITHOUT EMAIL ADDRESS FOUND") bolProcessUser = False If bolInformAdminAboutAccountWithoutEMail Then 'strAdminAccountWithoutEMail = AddAdminInfoTo(strAdminAccountWithoutEMail, NZ(rs("givenName"), "") & " " & NZ(rs("sn"), "") & " (" & NZ(rs("sAMAccountName"), "") & ") - Days Left: " & (GetPWDaysLeft(rs("distinguishedName"), NZ(rs("givenName"), ""), NZ(rs("sn"), ""), NZ(rs("sAMAccountName"), ""), intDaysLeft, intMaxPWDage) * -1)) 'Add to Admin Info strAdminAccountWithoutEMail = AddAdminInfoTo(strAdminAccountWithoutEMail, NZ(rs("givenName"), "") & "</td><td>" & NZ(rs("sn"), "") & "</td><td>" & NZ(rs("sAMAccountName"), "") & "</td><td class=""right"">" & AdminInfoDaysLeftHTMLFormat((GetPWDaysLeft(rs("distinguishedName"), NZ(rs("givenName"), ""), NZ(rs("sn"), ""), NZ(rs("sAMAccountName"), ""), intDaysLeft, intMaxPWDage) * -1)), True) 'Add to Admin Info End If End If End If 'Priority 9 - now we check the Password Age and take action If bolProcessUser Then 'do we still go on with this User? If PasswordIsExpired(rs("userAccountControl")) Then 'The Password is already expired? We need to take action / this will be double checked later on with a calculation ScriptDebug("..PASSWORD IS EXPIRED") SendEmailNotification False, NZ(rs("mail"), ""), True, 0, "" 'Inform the USER about the expired Password If bolInformAdminAboutPWisExpired Then 'strAdminPWisExpired = AddAdminInfoTo(strAdminPWisExpired, NZ(rs("givenName"), "") & " " & NZ(rs("sn"), "") & " (" & NZ(rs("sAMAccountName"), "") & ")") 'Add to Admin Info strAdminPWisExpired = AddAdminInfoTo(strAdminPWisExpired, NZ(rs("givenName"), "") & "</td><td>" & NZ(rs("sn"), "") & "</td><td>" & NZ(rs("sAMAccountName"), "") & "</td><td class=""right"">" & AdminInfoDaysLeftHTMLFormat((GetPWDaysLeft(rs("distinguishedName"), NZ(rs("givenName"), ""), NZ(rs("sn"), ""), NZ(rs("sAMAccountName"), ""), intDaysLeft, intMaxPWDage) * -1)), True) 'Add to Admin Info End If Else 'Password is not expired yet, how many days does the User have left? Set objUser = GetObject("LDAP://" & rs("distinguishedName")) intDaysLeft = GetPWDaysLeft(rs("distinguishedName"), NZ(rs("givenName"), ""), NZ(rs("sn"), ""), NZ(rs("sAMAccountName"), ""), intDaysLeft, intMaxPWDage) If intDaysLeft <= 0 Then 'we have a number of days left If intStartWithPWexpiresInDays >= (intDaysLeft * -1) Then 'User is to be informed, his days left are less then defined ScriptDebug("..PASSWORD FOR USER WILL EXPIRE IN: " & (intDaysLeft * -1) & " DAYS") SendEmailNotification False, NZ(rs("mail"), ""), False, (intDaysLeft * -1), "" 'Inform the USER that the Password will expire If bolInformAdminAboutPWexpires Then 'strAdminPWexpires = AddAdminInfoTo(strAdminPWexpires, NZ(rs("givenName"), "") & " " & NZ(rs("sn"), "") & " (" & NZ(rs("sAMAccountName"), "") & ") - Days Left: " & (intDaysLeft * -1)) 'Add to Admin Info strAdminPWexpires = AddAdminInfoTo(strAdminPWexpires, NZ(rs("givenName"), "") & "</td><td>" & NZ(rs("sn"), "") & "</td><td>" & NZ(rs("sAMAccountName"), "") & "</td><td class=""right"">" & AdminInfoDaysLeftHTMLFormat((intDaysLeft * -1)), True) 'Add to Admin Info End If Else 'User has more days left then needed by Script Configuration 'we do not need to take action - we do not even send Mail to the Admin ScriptDebug("..USER PASSWORD IS STILL GOOD - DAYS LEFT: " & (intDaysLeft * -1)) If bolInformAdminAboutStillGoodPasswords Then 'strAdminPWstillGood = AddAdminInfoTo(strAdminPWstillGood, NZ(rs("givenName"), "") & " " & NZ(rs("sn"), "") & " (" & NZ(rs("sAMAccountName"), "") & ") - Days Left: " & (intDaysLeft * -1)) 'Add to Admin Info strAdminPWstillGood = AddAdminInfoTo(strAdminPWstillGood, NZ(rs("givenName"), "") & "</td><td>" & NZ(rs("sn"), "") & "</td><td>" & NZ(rs("sAMAccountName"), "") & "</td><td class=""right"">" & AdminInfoDaysLeftHTMLFormat((intDaysLeft * -1)), True) 'Add to Admin Info End If End If Else 'Password is already expired and needs to be changed now / second check, first one might not give the needed information ScriptDebug("..PASSWORD IS EXPIRED FOR: " & (intDaysLeft * -1) & " DAYS") SendEmailNotification False, NZ(rs("mail"), ""), True, 0, "" 'Inform the USER about the expired Password If bolInformAdminAboutPWisExpired Then 'strAdminPWisExpired = AddAdminInfoTo(strAdminPWisExpired, NZ(rs("givenName"), "") & " " & NZ(rs("sn"), "") & " (" & NZ(rs("sAMAccountName"), "") & ") - Days expired: " & (intDaysLeft * -1)) 'Add to Admin Info strAdminPWisExpired = AddAdminInfoTo(strAdminPWisExpired, NZ(rs("givenName"), "") & "</td><td>" & NZ(rs("sn"), "") & "</td><td>" & NZ(rs("sAMAccountName"), "") & "</td><td class=""right"">" & AdminInfoDaysLeftHTMLFormat((intDaysLeft * -1)), True) 'Add to Admin Info End If End If Set objUser = Nothing 'to make sure the Object is release End If End If rs.MoveNext Loop End If Set rs = Nothing Next 'Next from arrSearchOUs Set objADSCommand = Nothing Set objADSConnection = Nothing Set objADSDomain = Nothing Set objADSRoot = Nothing ScriptDebug("") ScriptDebug("SCRIPT ENDED SUCCESSFULLY => Sending Admin Mail") SendEmailNotification True, "", True, 0, GenerateAdminMailBody 'Send the final admin notification with the requested information End Sub 'Function returns days left for Password of User-Object (uses default Value intDaysLeft) Function GetPWDaysLeft(strDistinguishedName, strGivenName, strSN, strsAMAccountName, intDaysLeft, intMaxPWDage) Dim objUser Set objUser = GetObject("LDAP://" & strDistinguishedName) On Error Resume Next 'intDaysLeft will be negative, like a countdown, T minus DAYS intDaysLeft = DateDiff("d", objUser.PasswordLastChanged, Now) - intMaxPWDage If Err Then If Err.Number = &h8000500d Then 'PWD was just changed intDaysLeft = intMaxPWDage ScriptDebug("..USER PASSWORD WAS JUST CHANGED") 'we don't send any Mails about this Else 'unexpexted Error occured - this shouldn't happen at all! ScriptDebug("..UNEXPECTED ERROR (UserPasswordLastChanged)") 'strAdminErrorUsers = AddAdminInfoTo(strAdminErrorUsers, strGivenName & " " & strSN & " (" & strsAMAccountName & ")") 'Add to Admin Info strAdminErrorUsers = AddAdminInfoTo(strAdminErrorUsers, strGivenName & "</td><td>" & strSN & "</td><td>" & strsAMAccountName, True) 'Add to Admin Info End If End If Err.Clear On Error Goto 0 Set objUser = Nothing GetPWDaysLeft = Round(intDaysLeft, 0) End Function Function IsUserAccountExpired(distinguishedName, dtmExpirationDate) Dim bolReturn Dim objUser Dim dtmAccountExpiration bolReturn = False If NZ(distinguishedName, "") <> "" Then Set objUser = GetObject("LDAP://" & distinguishedName) On Error Resume Next dtmAccountExpiration = objUser.AccountExpirationDate If Err.Number = -2147467259 Or dtmAccountExpiration = "1/1/1970" Then 'Account has no expiration date specified 'we do nothing - not even a debug message Else 'Account has expireation date If DateDiff("d", dtmAccountExpiration, Now) > 0 Then bolReturn = True dtmExpirationDate = dtmAccountExpiration End If End If On Error Goto 0 Set objUser = Nothing End If IsUserAccountExpired = bolReturn End Function 'Is the User Member of one of the Groups in the Array? Give back first GroupName found if possible Function IsUserInGroup(distinguishedName, arrGroups, FirstFoundGroupMembership) Dim objUser, objGroup Dim i Dim strGroupName Dim bolFound bolFound = False If NZ(distinguishedName, "") <> "" Then Set objUser = GetObject("LDAP://" & distinguishedName) On Error Resume Next For Each objGroup In objUser.GetEx("memberOf") strGroupName = Split(objGroup,",")(0) strGroupName = Right(strGroupName, (Len(strGroupName)-3)) For i = 0 To UBound(arrGroups) If LCase(strGroupName) = LCase(arrGroups(i)) Then bolFound = True FirstFoundGroupMembership = strGroupName IsUserInGroup = True Exit For End If Next If bolFound Then Exit For End If Next On Error Goto 0 Set objUser = Nothing Else IsUserInGroup = False 'couldn't find User distinguishedName - not really possible End If End Function 'Is the Password Expired? Function PasswordIsExpired(userAccountControl) If NZ(userAccountControl, "") <> "" Then If ADS_UF_PASSWORD_EXPIRED And userAccountControl Then PasswordIsExpired = True Else PasswordIsExpired = False End If Else PasswordIsExpired = False End If End Function 'Is the User able to change to Password? Function UserCantChangePassword(distinguishedName) Dim bolReturn Dim objUser, objSD, objDACL, objACE bolReturn = False If NZ(distinguishedName, "") <> "" Then On Error Resume Next Set objUser = GetObject("LDAP://" & distinguishedName) Set objSD = objUser.Get("nTSecurityDescriptor") Set objDACL = objSD.DiscretionaryAcl For Each objACE in objDACL If objACE.AceType = ADS_ACETYPE_ACCESS_DENIED_OBJECT And LCase(objACE.ObjectType) = CHANGE_PASSWORD_GUID Then bolReturn = True Exit For End If Next Set objDACL = Nothing Set objSD = Nothing Set objUser = Nothing On Error Goto 0 End If UserCantChangePassword = bolReturn End Function 'Does the Account PW expire or not? Function PasswordDoesExpire(userAccountControl) If NZ(userAccountControl, "") <> "" Then If ADS_UF_DONT_EXPIRE_PASSWD And userAccountControl Then PasswordDoesExpire = True Else PasswordDoesExpire = False End If Else PasswordDoesExpire = False End If End Function 'Account Disabled or not Function IsAccountDisabled(distinguishedName) Dim bolReturn Dim objUser bolReturn = False If NZ(distinguishedName, "") <> "" Then On Error Resume Next Set objUser = GetObject("LDAP://" & distinguishedName) bolReturn = objUser.AccountDisabled Set objUser = Nothing On Error Goto 0 End If IsAccountDisabled = bolReturn End Function 'NZ equivalent to VBA Function NZ(Value,alternativeValue) If IsNull(Value) Then NZ = alternativeValue Else NZ = Value End If End Function 'Adds the Information as needed to the specified Variable as a new Line and returns the complete new string Function AddAdminInfoTo(CurrentString, NewTextLine, IsTable) If Not Len(NZ(CurrentString, "")) > 0 Then 'AddAdminInfoTo = NewTextLine If Not IsTable Then AddAdminInfoTo = NewTextLine Else AddAdminInfoTo = CurrentString & "<tr><td>" & Replace(NewTextLine, vbNewLine, "") & "</td></tr>" End If Else 'AddAdminInfoTo = CurrentString & vbNewLine & NewTextLine If Not IsTable Then AddAdminInfoTo = CurrentString & vbNewLine & NewTextLine Else AddAdminInfoTo = CurrentString & "<tr><td>" & Replace(NewTextLine, vbNewLine, "") & "</td></tr>" End If End If End Function 'Reformatts the Days-Left into a special div tag if it is negative/positive Function AdminInfoDaysLeftHTMLFormat(DaysLeft) If DaysLeft > 0 Then AdminInfoDaysLeftHTMLFormat = "<div class=""dayspositive"">" & DaysLeft & "</div>" Else AdminInfoDaysLeftHTMLFormat = "<div class=""daysnegative"">" & DaysLeft & "</div>" End If End Function 'Generates the Mail-Body for the Admin Mail Function GenerateAdminMailBody() Dim strReturn strReturn = "" strReturn = strReturn & "<style>" & vbNewLine strReturn = strReturn & "table { font-family: Calibri; font-size: 11pt; }" & vbNewLine strReturn = strReturn & "th { font: bold; background-color: light-blue; }" & vbNewLine strReturn = strReturn & "th, td { border-bottom: 1px solid black; text-align: left; }" & vbNewLine strReturn = strReturn & "tr:nth-child(even) { background-color: #f2f2f2; }" & vbNewLine strReturn = strReturn & "tr:hover { background-color: #f5f5f5 }" & vbNewLine strReturn = strReturn & "td.right { text-align: right; }" & vbNewLine strReturn = strReturn & "div.dayspositive { }" & vbNewLine strReturn = strReturn & "div.daysnegative { color: #FF0000; font: bold; }" & vbNewLine strReturn = strReturn & "h1 { font: bold; font-size: 12pt; text-decoration: underline; }" & vbNewLine strReturn = strReturn & "</style>" & vbNewLine If Len(NZ(strAdminErrorUsers, "")) > 0 Then 'strReturn = strReturn & "<u>THE FOLLOWING USERS GENERATED SCRIPT ERRORS:</u>" & vbNewLine strReturn = strReturn & "<h1>USERS THAT GENERATED SCRIPT ERRORS:</h1>" & vbNewLine 'strReturn = strReturn & strAdminErrorUsers & vbNewLine strReturn = strReturn & "<table><tr><th>Firstname</th><th>LastName</th><th>Username</th></tr>" & strAdminErrorUsers & "</table><br><br>" strReturn = strReturn & vbNewLine & vbNewLine End If If bolInformAdminAboutPWexpires And Len(NZ(strAdminPWexpires,"")) > 0 Then 'strReturn = strReturn & "<u>THE FOLLOWING PASSWORDS WILL EXPIRE:</u>" & vbNewLine strReturn = strReturn & "<h1>NOTIFIED USERS WITH EXPIRING PASSWORDS:</h1>" & vbNewLine 'strReturn = strReturn & strAdminPWexpires & vbNewLine strReturn = strReturn & "<table><tr><th>Firstname</th><th>LastName</th><th>Username</th><th>Expires in days</th></tr>" & strAdminPWexpires & "</table><br><br>" strReturn = strReturn & vbNewLine & vbNewLine End If If bolInformAdminAboutPWisExpired And Len(NZ(strAdminPWisExpired,"")) > 0 Then 'strReturn = strReturn & "<u>THE FOLLOWING PASSWORDS ARE EXPIRED ALREADY:</u>" & vbNewLine strReturn = strReturn & "<h1>NOTIFIED USERS WITH EXPIRED PASSWORDS:</h1>" & vbNewLine 'strReturn = strReturn & strAdminPWisExpired & vbNewLine strReturn = strReturn & "<table><tr><th>Firstname</th><th>LastName</th><th>Username</th><th>Expires in days</th></tr>" & strAdminPWisExpired & "</table><br><br>" strReturn = strReturn & vbNewLine & vbNewLine End If If bolInformAdminAboutAccountWithoutEMail And Len(NZ(strAdminAccountWithoutEMail,"")) > 0 Then 'strReturn = strReturn & "<u>THE FOLLOWING USER ACCOUNTS DON'T HAVE A VALID EMAIL ADDRESS:</u>" & vbNewLine strReturn = strReturn & "<h1>USER ACCOUNTS WITH NO VALID EMAIL ADDRESS:</h1>" & vbNewLine 'strReturn = strReturn & strAdminAccountWithoutEMail & vbNewLine strReturn = strReturn & "<table><tr><th>Firstname</th><th>LastName</th><th>Username</th><th>Expires in days</th></tr>" & strAdminAccountWithoutEMail & "</table><br><br>" strReturn = strReturn & vbNewLine & vbNewLine End If If bolInformAdminAboutPWneverExpires And Len(NZ(strAdminPWneverExpires,"")) > 0 Then 'strReturn = strReturn & "<u>THE FOLLOWING PASSWORDS NEVER EXPIRE:</u>" & vbNewLine strReturn = strReturn & "<h1>PASSWORD NEVER EXPIRES USERS:</h1>" & vbNewLine 'strReturn = strReturn & strAdminPWneverExpires & vbNewLine strReturn = strReturn & "<table><tr><th>Firstname</th><th>LastName</th><th>Username</th></tr>" & strAdminPWneverExpires & "</table><br><br>" strReturn = strReturn & vbNewLine & vbNewLine End If If bolInformAdminAboutUserCantChangePW And Len(NZ(strAdminUserCantChangePW,"")) > 0 Then 'strReturn = strReturn & "<u>THE FOLLOWING USERS CAN'T CHANGE THEIR PASSWORDS:</u>" & vbNewLine strReturn = strReturn & "<h1>THE FOLLOWING USERS CAN'T CHANGE THEIR PASSWORDS:</h1>" & vbNewLine 'strReturn = strReturn & strAdminUserCantChangePW & vbNewLine strReturn = strReturn & "<table><tr><th>Firstname</th><th>LastName</th><th>Username</th></tr>" & strAdminUserCantChangePW & "</table><br><br>" strReturn = strReturn & vbNewLine & vbNewLine End If If bolInformAdminAboutAccountDisabled And Len(NZ(strAdminAccountDisabled,"")) > 0 Then 'strReturn = strReturn & "<u>THE FOLLOWING USER ACCOUNTS ARE DISABLED:</u>" & vbNewLine strReturn = strReturn & "<h1>DISABLED USER ACCOUNTS:</h1>" & vbNewLine 'strReturn = strReturn & strAdminAccountDisabled & vbNewLine strReturn = strReturn & "<table><tr><th>Firstname</th><th>LastName</th><th>Username</th></tr>" & strAdminAccountDisabled & "</table><br><br>" strReturn = strReturn & vbNewLine & vbNewLine End If If bolInformAdminAboutExpiredUserAccount And Len(NZ(strAdminExpiredUserAccount,"")) > 0 Then 'strReturn = strReturn & "<u>THE FOLLOWING USER ACCOUNTS ARE EXPIRED:</u>" & vbNewLine strReturn = strReturn & "<h1>EXPIRED USER ACCOUNTS:</h1>" & vbNewLine 'strReturn = strReturn & strAdminExpiredUserAccount & vbNewLine strReturn = strReturn & "<table><tr><th>Firstname</th><th>LastName</th><th>Username</th><th>Expires in days</th></tr>" & strAdminExpiredUserAccount & "</table><br><br>" strReturn = strReturn & vbNewLine & vbNewLine End If If bolInformAdminAboutIgnoredUsersExcludedByGroup And Len(NZ(strAdminIgnoredUsersExcludedByGroup,"")) > 0 Then strReturn = strReturn & "<h1>EXCLUDED USER ACCOUNTS (GROUP-FILTER):</h1>" & vbNewLine strReturn = strReturn & "<table><tr><th>Firstname</th><th>LastName</th><th>Username</th><th>Expires in days</th></tr>" & strAdminIgnoredUsersExcludedByGroup & "</table><br><br>" strReturn = strReturn & vbNewLine & vbNewLine End If If bolInformAdminAboutStillGoodPasswords And Len(NZ(strAdminPWstillGood,"")) > 0 Then 'strReturn = strReturn & "<u>THE FOLLOWING USER ACCOUNTS HAVE VALID PASSWORDS:</u>" & vbNewLine strReturn = strReturn & "<h1>THE FOLLOWING USER ACCOUNTS HAVE VALID PASSWORDS:</h1>" & vbNewLine 'strReturn = strReturn & strAdminPWstillGood & vbNewLine strReturn = strReturn & "<table><tr><th>Firstname</th><th>LastName</th><th>Username</th><th>Expires in days</th></tr>" & strAdminPWstillGood & "</table><br><br>" strReturn = strReturn & vbNewLine & vbNewLine End If If bolAttachDebugToAdminMail Then 'strReturn = strReturn & "<u>DEBUG OUTPUT:</u>" & vbNewLine strReturn = strReturn & "<h1>DEBUG OUTPUT:</h1>" & vbNewLine 'strReturn = strReturn & strAdminDebug & vbNewLine strReturn = strReturn & Replace(strAdminDebug, vbNewLine, "<br>") & vbNewLine End If GenerateAdminMailBody = "<div style=""font-family: calibri; font-size: 11pt;"">" & strReturn & "</div>" End Function 'Sends out EMails, to the User (False, UserMailAddress, True or False, DaysLeft for Password, "") or the Admin (TRUE, "", True or False, 0, AdminTextBody) Sub SendEmailNotification(AdminMail, UserMailAddress, IsExpired, DaysLeft, AdminTextBody) Dim objMail Set objMail = CreateObject("CDO.Message") objMail.Configuration.Fields.Item("http://schemas.microsoft.com/cdo/configuration/sendusing") = 2 objMail.Configuration.Fields.Item("http://schemas.microsoft.com/cdo/configuration/smtpserver") = strSMTPServer objMail.Configuration.Fields.Item("http://schemas.microsoft.com/cdo/configuration/smtpserverport") = intSMTPServerPort objMail.Configuration.Fields.Update objMail.From = strFrom If AdminMail Then 'is Admin Mail objMail.Subject = strAdminMailSubject objMail.To = strToAdmin 'objMail.TextBody = AdminTextBody 'objMail.HTMLBody = Replace(AdminTextBody, vbNewLine, "<br>") objMail.HTMLBody = AdminTextBody Else 'is User Mail If Not bolAdminMailOnly Then 'only the Admin Mail will be send If IsExpired Then objMail.Subject = strUserMailSubjectExpired Else objMail.Subject = Replace(strUserMailSubjectWillExpire, "REPLACEWITHDAYS", DaysLeft) End If If bolRedirectMailToAdmin Then 'redirect Mails to Admin - add User Mail Address to Subject objMail.To = strToAdmin objMail.Subject = objMail.Subject & " - REDIRECTED TO ADMIN INSTEAD OF: " & UserMailAddress Else objMail.To = UserMailAddress End If objMail.CreateMHTMLBody strBodyURL End If End If If Not bolTestDebugOutputToConsoleOnly Then If Len(strAttachment) > 0 Then 'we do have an attachment to add? objMail.AddAttachment strAttachment End If If bolAdminMailOnly Then 'only Admin Mail? If AdminMail Then 'Then only if it is the Admin Mail objMail.Send End If Else 'User Mail as well as Admin Mail objMail.Send End If Else ScriptDebug("=>DEBUG ONLY MODE - A EMAIL WOULD HAVE BEEN SEND TO: " & objMail.To & " - Subject: " & objMail.Subject) End If Set objMail = Nothing End Sub 'Any Debug-Information will be proccessed here, easier to do it central and being able to change it to a LogFile or what ever... Sub ScriptDebug(strDebugMessage) If bolDebug Then WScript.Echo strDebugMessage End If If bolAttachDebugToAdminMail Then strAdminDebug = AddAdminInfoTo(strAdminDebug, strDebugMessage, False) End If End Sub |
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 319 320 321 | <html><head><meta http-equiv="Content-Type" content="text/html; charset=windows-1252"> <title>Your password will expire in “X” days</title> <style> <!-- /* Font Definitions */ @font-face {font-family:Verdana; panose-1:2 11 6 4 3 5 4 4 2 4;} /* Style Definitions */ p.MsoNormal, li.MsoNormal, div.MsoNormal {margin:0in; margin-bottom:.0001pt; font-size:12.0pt; font-family:"Times New Roman";} a:link, span.MsoHyperlink {color:blue; text-decoration:underline;} a:visited, span.MsoHyperlinkFollowed {color:purple; text-decoration:underline;} p.sectiontitle, li.sectiontitle, div.sectiontitle {margin-top:12.0pt; margin-right:0in; margin-bottom:12.0pt; margin-left:0in; font-size:12.0pt; font-family:Verdana; font-variant:small-caps; font-weight:bold;} p.sectioncontent, li.sectioncontent, div.sectioncontent {margin-top:0in; margin-right:0in; margin-bottom:0in; margin-left:9.0pt; margin-bottom:.0001pt; font-size:10.0pt; font-family:Verdana;} span.sectiontitlechar {font-family:Verdana; font-variant:small-caps; font-weight:bold;} @page Section1 {size:8.5in 11.0in; margin:81.35pt 1.0in 1.0in 1.0in;} div.Section1 {page:Section1;} /* List Definitions */ ol {margin-bottom:0in;} ul {margin-bottom:0in;} --> </style> </head> <body lang="EN-US" link="blue" vlink="purple"> <div class="Section1"> <table width="100%"><tr><td> <p class="MsoNormal"><b><span style="font-size:10.0pt;font-family:Verdana; color:blue">This is an automated password expiration notification. </span></b></p> <p class="MsoNormal"><b><span style="font-size:10.0pt;font-family:Verdana; color:blue">Please change your password as soon as possible.</span></b></p> </td><td> <div text-align=right> <img src="logo.jpg" width="150px"> </div> </td></tr></table> <p class="MsoNormal"><b><span style="font-size:10.0pt;font-family:Verdana"> </span></b></p> <p class="MsoNormal"><b><u><span style="font-size:10.0pt;font-family:Verdana">Password Policy</span></u></b></p> <p class="MsoNormal"><span style="font-size:10.0pt;font-family:Verdana"> </span></p> <p class="sectioncontent"><b>Password Rules</b></p> <p class="sectioncontent" style="margin-left:45.0pt;text-indent:-.25in">1.<span style="font-size:7.0pt;font-family:"Times New Roman""> </span>Your password must be changed every 90 days</p> <p class="sectioncontent" style="margin-left:45.0pt;text-indent:-.25in">2.<span style="font-size:7.0pt;font-family:"Times New Roman""> </span>The system will remember the last 8 passwords used and will not allow them again</p> <p class="sectioncontent" style="margin-left:45.0pt;text-indent:-.25in">3.<span style="font-size:7.0pt;font-family:"Times New Roman""> </span>Minimum password age is 1 day. A password cannot be changed until it is 1 day old.</p> <p class="sectioncontent" style="margin-left:45.0pt;text-indent:-.25in">4.<span style="font-size:7.0pt;font-family:"Times New Roman""> </span>Account lockout duration is 15 minutes</p> <p class="sectioncontent" style="margin-left:45.0pt;text-indent:-.25in">5.<span style="font-size:7.0pt;font-family:"Times New Roman""> </span>Account lockout threshold is 6 invalid login attempts</p> <p class="sectioncontent" style="margin-left:45.0pt;text-indent:-.25in">6.<span style="font-size:7.0pt;font-family:"Times New Roman""> </span>Reset account lockout counter after 15 minutes</p> <p class="sectioncontent"> </p> <p class="sectioncontent"><b>Complexity Rules</b></p> <p class="sectioncontent" style="margin-left:45.0pt;text-indent:-.25in">1.<span style="font-size:7.0pt;font-family:"Times New Roman""> </span>It must be at least 8 characters in length</p> <p class="sectioncontent" style="margin-left:45.0pt;text-indent:-.25in">2.<span style="font-size:7.0pt;font-family:"Times New Roman""> </span>It cannot contain a significant portion of the username or the person’s full name</p> <p class="sectioncontent" style="margin-left:45.0pt;text-indent:-.25in">3.<span style="font-size:7.0pt;font-family:"Times New Roman""> </span>It cannot contain a complete dictionary word</p> <p class="sectioncontent" style="margin-left:45.0pt;text-indent:-.25in">4.<span style="font-size:7.0pt;font-family:"Times New Roman""> </span>It must contain at least one character from 3 of the 4 following groups:</p> <p class="sectioncontent" style="margin-left:63.0pt;text-indent:-.25in">a.<span style="font-size:7.0pt;font-family:"Times New Roman""> </span>Lower-case alpha character (a-z)</p> <p class="sectioncontent" style="margin-left:63.0pt;text-indent:-.25in">b.<span style="font-size:7.0pt;font-family:"Times New Roman""> </span>Upper-case alpha character (A-Z)</p> <p class="sectioncontent" style="margin-left:63.0pt;text-indent:-.25in">c.<span style="font-size:7.0pt;font-family:"Times New Roman""> </span>Numeric digit (0-9)</p> <p class="sectioncontent" style="margin-left:63.0pt;text-indent:-.25in">d.<span style="font-size:7.0pt;font-family:"Times New Roman""> </span>Special character ( { } [ ] , . < > ; : ' " ? / | \ ` ~ ! @ # $ <br> % ^ & * ( ) _ - + = )</p> <p class="sectioncontent"> </p> <p class="sectioncontent"><b>Suggestions</b></p> <p class="sectioncontent">Use a password that you can remember. One common practice is to model your password after a sentence or a phrase. It can also be useful to replace letter with numbers. </p> <p class="sectioncontent"> </p> <p class="sectioncontent">Steve might use the well-known statement, “I can eat sushi for lunch every day” to come up with the following password:</p> <p class="sectioncontent" style="text-indent:27.0pt">Ic3s4led!</p> <p class="sectioncontent"> </p> <p class="sectioncontent">Ray might use “My motorcycle is way too fast for you!”</p> <p class="sectioncontent" style="text-indent:27.0pt">MmiW2f4u!</p> <p class="MsoNormal"><span style="font-size:10.0pt;font-family:Verdana"> </span></p> <p class="MsoNormal"><span style="font-size:10.0pt;font-family:Verdana"> </span></p> <p class="MsoNormal"><b><u><span style="font-size:10.0pt;font-family:Verdana">How to Change Your Password</span></u></b></p> <p class="MsoNormal"><span style="font-size:10.0pt;font-family:Verdana"> </span></p> <p class="MsoNormal"><b><span style="font-size:10.0pt;font-family:Verdana">Method 1 – Directly From Windows</span></b></p> <p class="MsoNormal"><span style="font-size:10.0pt;font-family:Verdana"> </span></p> <p class="MsoNormal"><span style="font-size:10.0pt;font-family:Verdana">If you have a computer with direct connectivity to corporate network, changing your password is very easy. </span></p> <p class="MsoNormal"><span style="font-size:10.0pt;font-family:Verdana"> </span></p> <ol style="margin-top:0in" start="1" type="1"> <li class="MsoNormal"><span style="font-size:10.0pt;font-family:Verdana">After you are logged into your computer, enter the keyboard combination “Ctrl + ALT + Del” (this is the same combination used when logging onto your computer)</span></li> <li class="MsoNormal"><span style="font-size:10.0pt;font-family:Verdana">In the Windows Security popup window click “Change Password”</span></li> <li class="MsoNormal"><span style="font-size:10.0pt;font-family:Verdana">The 1<sup>st</sup> two fields will be auto-filled. Please enter your current “OLD” password followed by your “NEW” password in the last two fields.</span></li> </ol> <p class="MsoNormal" style="margin-left:.25in"><span style="font-size:10.0pt; font-family:Verdana"> </span></p> <table class="MsoNormalTable" border="0" cellspacing="0" cellpadding="0" width="289" style="width:216.6pt;margin-left:41.4pt;border-collapse:collapse"> <tbody><tr> <td width="136" valign="top" style="width:102.0pt;border:solid windowtext 1.0pt; padding:0in 5.4pt 0in 5.4pt"> <p class="MsoNormal"><b><span style="font-size:10.0pt;font-family:Verdana">Description</span></b></p> </td> <td width="153" valign="top" style="width:114.6pt;border:solid windowtext 1.0pt; border-left:none;padding:0in 5.4pt 0in 5.4pt"> <p class="MsoNormal"><b><span style="font-size:10.0pt;font-family:Verdana">Your Answer</span></b></p> </td> </tr> <tr> <td width="136" valign="top" style="width:102.0pt;border:solid windowtext 1.0pt; border-top:none;padding:0in 5.4pt 0in 5.4pt"> <p class="MsoNormal"><span style="font-size:10.0pt;font-family:Verdana">Username</span></p> </td> <td width="153" valign="top" style="width:114.6pt;border-top:none;border-left: none;border-bottom:solid windowtext 1.0pt;border-right:solid windowtext 1.0pt; padding:0in 5.4pt 0in 5.4pt"> <p class="MsoNormal"><span style="font-size:10.0pt;font-family:Verdana">Your userID e.g. jsmith</span></p> </td> </tr> <tr> <td width="136" valign="top" style="width:102.0pt;border:solid windowtext 1.0pt; border-top:none;padding:0in 5.4pt 0in 5.4pt"> <p class="MsoNormal"><span style="font-size:10.0pt;font-family:Verdana">Log on to</span></p> </td> <td width="153" valign="top" style="width:114.6pt;border-top:none;border-left: none;border-bottom:solid windowtext 1.0pt;border-right:solid windowtext 1.0pt; padding:0in 5.4pt 0in 5.4pt"> <p class="MsoNormal"><span style="font-size:10.0pt;font-family:Verdana">Company Name</span></p> </td> </tr> <tr> <td width="136" valign="top" style="width:102.0pt;border:solid windowtext 1.0pt; border-top:none;padding:0in 5.4pt 0in 5.4pt"> <p class="MsoNormal"><span style="font-size:10.0pt;font-family:Verdana">Old password</span></p> </td> <td width="153" valign="top" style="width:114.6pt;border-top:none;border-left: none;border-bottom:solid windowtext 1.0pt;border-right:solid windowtext 1.0pt; padding:0in 5.4pt 0in 5.4pt"> <p class="MsoNormal"><span style="font-size:10.0pt;font-family:Verdana">Your OLD password</span></p> </td> </tr> <tr> <td width="136" valign="top" style="width:102.0pt;border:solid windowtext 1.0pt; border-top:none;padding:0in 5.4pt 0in 5.4pt"> <p class="MsoNormal"><span style="font-size:10.0pt;font-family:Verdana">New password</span></p> </td> <td width="153" valign="top" style="width:114.6pt;border-top:none;border-left: none;border-bottom:solid windowtext 1.0pt;border-right:solid windowtext 1.0pt; padding:0in 5.4pt 0in 5.4pt"> <p class="MsoNormal"><span style="font-size:10.0pt;font-family:Verdana">Your NEW password</span></p> </td> </tr> <tr> <td width="136" valign="top" style="width:102.0pt;border:solid windowtext 1.0pt; border-top:none;padding:0in 5.4pt 0in 5.4pt"> <p class="MsoNormal"><span style="font-size:10.0pt;font-family:Verdana">Confirm new password</span></p> </td> <td width="153" valign="top" style="width:114.6pt;border-top:none;border-left: none;border-bottom:solid windowtext 1.0pt;border-right:solid windowtext 1.0pt; padding:0in 5.4pt 0in 5.4pt"> <p class="MsoNormal"><span style="font-size:10.0pt;font-family:Verdana">Your New Password</span></p> </td> </tr> </tbody></table> <p class="MsoNormal"><span style="font-size:10.0pt;font-family:Verdana"> </span></p> <ol style="margin-top:0in" start="4" type="1"> <li class="MsoNormal"><span style="font-size:10.0pt;font-family:Verdana">Click OK </span></li> </ol> <p class="MsoNormal" style="margin-left:.25in"><span style="font-size:10.0pt; font-family:Verdana">Your new password is now set and will be valid for 90 days</span></p> <p class="MsoNormal"><span style="font-size:10.0pt;font-family:Verdana"> </span></p> <p class="MsoNormal"><b><span style="font-size:10.0pt;font-family:Verdana">Method 2 – Contact the Helpdesk</span></b></p> <p class="MsoNormal"><span style="font-size:10.0pt;font-family:Verdana"> </span></p> <p class="MsoNormal"><span style="font-size:10.0pt;font-family:Verdana">If you require assistance in changing your password, please submit a help desk request and we will be more than happy to help you out. </span></p> <p class="MsoNormal"><span style="font-size:10.0pt;font-family:Verdana"> </span></p> <ol style="margin-top:0in" start="1" type="1"> <li class="MsoNormal"><span style="font-size:10.0pt;font-family:Verdana">Create a helpdesk ticket </span></li> <ol style="margin-top:0in" start="1" type="a"> <li class="MsoNormal"><span style="font-size:10.0pt;font-family:Verdana">Open your web browser and type <a href="http://helpdesk.domain.com/">http://helpdesk.domain.com</a></span></li> <li class="MsoNormal"><span style="font-size:10.0pt;font-family:Verdana">Create a new ticket and label it “I Need Help”</span></li> <li class="MsoNormal"><span style="font-size:10.0pt;font-family:Verdana">In the Notes field, please provide a phone number and the best time to reach you</span></li> </ol> <li class="MsoNormal"><span style="font-size:10.0pt;font-family:Verdana">An IT associate will contact you to assist in changing your password</span></li> </ol> <p class="MsoNormal" style="margin-left:.25in"><span style="font-size:10.0pt; font-family:Verdana">NOTE: If you are unable to access helpdesk website, please call 888-888-8888 or x8888</span></p> </div> </body></html> |
As always – feel free to reach out to me if you have any questions or comments.