Purpose: VB script notifying by email Active directory users when their passwords are about to expire.
Useful for: users who aren't using Windows workstations or not directly connected to an AD domain through a VPN, hence not being able to receive the notification that their password is about to expire and could result in locking their AD account.
What you need to have and do:
- Set the STRFROM variable as the "From" address of the email (usually administrator@yourdomain.com).
- Set the DAYS_FOR_EMAIL variable as the number of days when to start notifying users that their password is about to expire (usually 7).
- Set the ExcludedGroup variable as the AD group name (which you'll have to create) which contains the list of users who don't need to be notified (because they either use a Windows workstation or are connected to the AD domain through something like a VPN).
- Set the ExchangeServerFQN variable as to your Exchange server FQN
- You may also want to amend the email body
- Schedule to run this script every day at midnight using either with Windows AT or better the Windows scheduler
'This program scans all users in the Users container and all organizational units'beneath the HOSTING_OU organizational unit, for users whose passwords have either'already expired or will expire within DAYS_FOR_EMAIL days.''An email is sent, using CDO, via the SMTP server specified as SMTP_SERVER to the'user to tell them to change their password. You should change strFrom to match'the email address of the administrator responsible for password changes.''You will, at a minimum, need to change the SMTP_SERVER, the HOSTING_OU, and the'STRFROM constants. If you run this on an Exchange server, then SMTP_SERVER can'be "127.0.0.1" - and it may be either an ip address or a resolvable name.''If you don't have an OU containing sub-OU's to scan, then set HOSTING_OU to the'empty string ("").
Option Explicit
'Per environment constants - you should change these!Const HOSTING_OU = ""Const SMTP_SERVER = "127.0.0.1"Const STRFROM = "<admin@somecompany.com>"Const DAYS_FOR_EMAIL = 7Const ExcludedGroup = "_Excluded"Const ExchangeServerFQN = "yourexchangeserver@yourdomain.com"
'System Constants - do not changeConst ONE_HUNDRED_NANOSECOND = .000000100 ' .000000100 is equal to 10^-7Const SECONDS_IN_DAY = 86400Const ADS_UF_DONT_EXPIRE_PASSWD = &h10000Const E_ADS_PROPERTY_NOT_FOUND = &h8000500D
'Change to "True" for extensive debugging outputConst bDebug = true
Dim objRootDim numDays, iResultDim strDomainDNDim objContainer, objSubDim UserName, UserExcluded, EmailAddressSet objRoot = GetObject ("LDAP://RootDSE")strDomainDN = objRoot.Get ("defaultNamingContext")Set objRoot = Nothingnumdays = GetMaximumPasswordAge (strDomainDN)dp "Maximum Password Age: " & numDays
If numDays > 0 ThenSet objContainer = GetObject ("LDAP://CN=Users," & strDomainDN)Call ProcessFolder (objContainer, numDays)Set objContainer = NothingIf Len (HOSTING_OU) > 0 ThenSet objContainer = GetObject ("LDAP://OU=" & HOSTING_OU & "," & strDomainDN)For each objSub in objContainerCall ProcessFolder (objSub, numDays)NextSet objContainer = NothingEnd If'Add the number of days to the last time he password was set.' whenPasswordExpires = DateAdd ("d", numDays, oUser.PasswordLastChanged)' WScript.Echo "Password Last Changed: " & oUser.PasswordLastChanged' WScript.Echo "Password Expires On: " & whenPasswordExpiresEnd IfWScript.Echo "Done"
Function GetMaximumPasswordAge (ByVal strDomainDN)Dim objDomain, objMaxPwdAgeDim dblMaxPwdNano, dblMaxPwdSecs, dblMaxPwdDaysSet objDomain = GetObject("LDAP://" & strDomainDN)Set objMaxPWdAge = objDomain.maxPwdAge
If objMaxPwdAge.LowPart = 0 And objMaxPwdAge.Highpart = 0 Then'Maximum password age is set to 0 in the domain'Therefore, passwords do not expireGetMaximumPasswordAge = 0ElsedblMaxPwdNano = Abs (objMaxPwdAge.HighPart * 2^32 + objMaxPwdAge.LowPart)dblMaxPwdSecs = dblMaxPwdNano * ONE_HUNDRED_NANOSECONDdblMaxPwdDays = Int (dblMaxPwdSecs / SECONDS_IN_DAY)GetMaximumPasswordAge = dblMaxPwdDaysEnd IfEnd Function
Function UserIsExpired (objUser, iMaxAge, iDaysForEmail, iRes)Dim intUserAccountControl, dtmValue, intTimeIntervalDim strNameOn Error Resume NextErr.ClearstrName = Mid (objUser.Name, 4)intUserAccountControl = objUser.Get ("userAccountControl")
If intUserAccountControl And ADS_UF_DONT_EXPIRE_PASSWD Thendp "The password for " & strName & " does not expire."UserIsExpired = FalseElseiRes = 0dtmValue = objUser.PasswordLastChangedIf Err.Number = E_ADS_PROPERTY_NOT_FOUND ThenUserIsExpired = Truedp "The password for " & strName & " has never been set."ElseintTimeInterval = Int (Now - dtmValue)dp "The password for " & strName & " was last set on " & _DateValue(dtmValue) & " at " & TimeValue(dtmValue) & _" (" & intTimeInterval & " days ago)"If intTimeInterval >= iMaxAge Thendp "The password for " & strName & " has expired."UserIsExpired = TrueElseiRes = Int ((dtmValue + iMaxAge) - Now)dp "The password for " & strName & " will expire on " & _DateValue(dtmValue + iMaxAge) & " (" & _iRes & " days from today)."If iRes <= iDaysForEmail Thendp strName & " needs an email for password change"UserIsExpired = TrueElsedp strName & " does not need an email for password change"UserIsExpired = FalseEnd IfEnd IfEnd IfEnd IfEnd Function
Sub ProcessFolder (objContainer, iMaxPwdAge)Dim objUser, iResultobjContainer.Filter = Array ("User")Wscript.Echo "Checking company = " & Mid (objContainer.Name, 4)For each objUser in objContainerUserExcluded = 0UserName = ""EmailAddress = ""UserName = LCase(Mid (objUser.Name, 4))EmailAddress = objUser.Maildp "" & vbCRLFdp "User name: " & UserNamedp "Email address: " & EmailAddress'Here we check if the user account is part of excluded groupDim GroupName, Group, IsInExcludedGroup, CheckIfArrayIsInExcludedGroup = 0Group = objUser.memberofCheckIfArray = IsArray(Group)'Checking that the group name is not empty, else skip group checkingIf Not IsEmpty(Group) And CheckIfArray = "True" ThenFor Each GroupName In Group'checking if group string contains the excluded group nameIsInExcludedGroup = InStr (GroupName, ExcludedGroup)If IsInExcludedGroup <> 0 ThenUserExcluded = 1dp "is part of the group: " & ExcludedGroupEnd IfNextEnd if' Checking that the group name is not empty, else skip group checkingIf Not IsEmpty(Group) And CheckIfArray = "False" Then'checking if group string contains the excluded group nameIsInExcludedGroup = InStr (Group, ExcludedGroup)If IsInExcludedGroup <> 0 ThenUserExcluded = 1dp "is part of the group: " & ExcludedGroupEnd IfEnd If'checking if user account begin with a $ or has no mailboxIf (UserExcluded <> 1) And Right (objUser.Name, 1) <> "$" ThenIf IsEmpty (objUser.Mail) or IsNull (objUser.Mail) Thendp "has no mailbox"UserExcluded = 1End IfEnd If' checking if account password is expired or doesnt expireIf UserExcluded <> 1 ThenIf UserIsExpired (objUser, iMaxPwdAge, DAYS_FOR_EMAIL, iResult) ThenWScript.Echo "...sending an email for " & objUser.Maildp "Sending email"Call SendEmail (objUser, iResult)End IfElsedp "...don't send an email"End IfNextEnd Sub
Sub SendEmail (objUser, iResult)Dim objMailSet objMail = CreateObject ("CDO.Message")objMail.Configuration.Fields.Item ("http://schemas.microsoft.com/cdo/configuration/sendusing") = 2objMail.Configuration.Fields.Item ("http://schemas.microsoft.com/cdo/configuration/smtpserver") = SMTP_SERVERobjMail.Configuration.Fields.Item ("http://schemas.microsoft.com/cdo/configuration/smtpserverport") = 25objMail.Configuration.Fields.UpdateobjMail.From = STRFROMobjMail.To = objUser.MailobjMail.Subject = "Your Windows password needs to be changed soon"objMail.Textbody = "Hi," & vbCRLF & vbCRLF & _"Your Windows password will expire soon." & vbCRLF & _"The password for the account: " & objUser.userPrincipalName & _" (" & objUser.sAMAccountName & ")" & vbCRLF & _"will expire in " & iResult & " days. Please change it as soon as possible." & vbCRLF & vbCRLF & _"You can change it from the Internet by login on: " & vbCRLF & _"https://<ExchangeServerFQN>/owa" & vbCRLF & _"(Note: Your Web browser is likely to warn you against using the above Web site, it is because we are using a self-signed certificate and it is safe to continue)" & vbCRLF & vbCRLF & _"If you would prefer not to receive this reminder, just send a reply with the subject line: opt out of password reminder" & vbCRLF & vbCRLF & _"Thank you," & vbCRLF & _"Your email administrator"objMail.SendSet objMail = NothingEnd Sub
Sub dp (str)If bDebug ThenWScript.Echo strEnd IfEnd Sub