<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Edwin M Sarmiento&gt;Identify password expiration in Active Directory &#8211; Edwin M Sarmiento</title>
	<atom:link href="https://www.edwinmsarmiento.com/identify-password-expiration-in-active-directory/feed/" rel="self" type="application/rss+xml" />
	<link>https://www.edwinmsarmiento.com</link>
	<description>Intentional Excellence</description>
	<lastBuildDate>Mon, 13 Apr 2026 21:00:49 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	
<site xmlns="com-wordpress:feed-additions:1">84283043</site>		<item>
		<title>&gt;Identify password expiration in Active Directory</title>
		<link>https://www.edwinmsarmiento.com/identify-password-expiration-in-active-directory/</link>
		<comments>https://www.edwinmsarmiento.com/identify-password-expiration-in-active-directory/#comments</comments>
		<pubDate>Fri, 09 Nov 2007 06:47:00 +0000</pubDate>
		<dc:creator>Edwin M Sarmiento</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<guid isPermaLink="false">http://bassplayerdoc.wordpress.com/2007/11/09/identify-password-expiration-in-active-directory</guid>

				<description><![CDATA[&#62;If you&#8217;ve got a huge amount of mobile workforce &#8211; people who are always on the go, it would be very difficult to track whether or not they change their passwords. This is very important if your users still access your network thru VPN and use their Active Directory credentials to log on. I see [&#8230;]]]></description>
					<content:encoded><![CDATA[<p>&gt;<span style="font-family:arial;">If you&#8217;ve got a huge amount of mobile workforce &#8211; people who are always on the go, it would be very difficult to track whether or not they change their passwords. This is very important if your users still access your network thru VPN and use their Active Directory credentials to log on. I see a lot of people who rarely log on to their domain, probably once in a month since they are always on the road, probably doing sales calls or out of the country. I wrote a script to check Active Directory for all the user accounts, check for their password expiration, and send them an email if their passwords are set to expire in less than 14 days. In a typical environment, the users will get a prompt if they log in to the domain on a regular basis. This solves the &#8220;not-so-typical&#8221; case of users rarely logging on to a domain.</span><br /><span style="font-family:Arial;"></span><br /><span style="font-family:Courier New;color:#1f497d;"></p>
<p><span style="font-size:85%;"><strong><em>Const ADS_UF_PASSWD_CANT_CHANGE = &amp;H40<br />Const ADS_UF_DONT_EXPIRE_PASSWD = &amp;H10000<br />Const ADS_UF_ACCOUNTDISABLE = &amp;H02</em></strong></span></p>
<p><span style="font-size:85%;"><strong><em>Dim strFilePath, objFSO, objFile, adoConnection, adoCommand<br />Dim objRootDSE, strDNSDomain, strFilter, strQuery, adoRecordset<br />Dim strDN, objShell, lngBiasKey, lngBias, blnPwdExpire,blnAccountDisabled<br />Dim objDate, dtmPwdLastSet, lngFlag, k, oDomain, maxPwdAge, numDays,whenPasswordExpires, strEmailMessage</em></strong></span></p>
<p></p>
<p><span style="font-size:85%;"><strong><em>&#8216;====================================<br />&#8216;Script to change a filename using timestamps<br />Dim strMonth, strDay<br />strMonth = DatePart(&#8220;m&#8221;, Now())<br />strDay = DatePart(&#8220;d&#8221;,Now())</em></strong></span></p>
<p></p>
<p><span style="font-size:85%;"><strong><em>if Len(strMonth)=1 then<br />strMonth = &#8220;0&#8221; &amp; strMonth<br />else<br />strMonth = strMonth<br />end if</em></strong></span></p>
<p></p>
<p><span style="font-size:85%;"><strong><em>if Len(strDay)=1 then<br />strDay = &#8220;0&#8221; &amp; strDay<br />else<br />strDay = strDay<br />end if<br />&#8216;===================================</em></strong></span></p>
<p></p>
<p><span style="font-size:85%;"><strong><em>strFilePath = &#8220;D:users_DOMAIN_&#8221; &amp; DatePart(&#8220;yyyy&#8221;,Now()) &amp; strMonth &amp; strDay &amp; &#8220;.txt&#8221;</em></strong></span></p>
<p></p>
<p><span style="font-size:85%;"><strong><em>Set objFSO = CreateObject(&#8220;Scripting.FileSystemObject&#8221;)</em></strong></span></p>
<p></p>
<p><span style="font-size:85%;"><strong><em>&#8216; Open the file for write access.<br />On Error Resume Next<br />Set objFile = objFSO.OpenTextFile(strFilePath, 2, True, 0)<br />If (Err.Number &lt;&gt; 0) Then<br />On Error GoTo 0<br />Wscript.Echo &#8220;File &#8221; &amp; strFilePath &amp; &#8221; cannot be opened&#8221;<br />Set objFSO = Nothing<br />Wscript.Quit(1)<br />End If<br />On Error GoTo 0</em></strong></span></p>
<p></p>
<p><span style="font-size:85%;"><strong><em>&#8216; Obtain local time zone bias from machine registry.<br />Set objShell = CreateObject(&#8220;Wscript.Shell&#8221;)<br />lngBiasKey = objShell.RegRead(&#8220;HKLMSystemCurrentControlSetControl&#8221; _<br />&amp; &#8220;TimeZoneInformationActiveTimeBias&#8221;)<br />If (UCase(TypeName(lngBiasKey)) = &#8220;LONG&#8221;) Then<br />lngBias = lngBiasKey<br />ElseIf (UCase(TypeName(lngBiasKey)) = &#8220;VARIANT()&#8221;) Then<br />lngBias = 0<br />For k = 0 To UBound(lngBiasKey)<br />lngBias = lngBias + (lngBiasKey(k) * 256^k)<br />Next<br />End If</em></strong></span></p>
<p></p>
<p><span style="font-size:85%;"><strong><em>&#8216; Use ADO to search the domain for all users.<br />Set adoConnection = CreateObject(&#8220;ADODB.Connection&#8221;)<br />Set adoCommand = CreateObject(&#8220;ADODB.Command&#8221;)<br />adoConnection.Provider = &#8220;ADsDSOOBject&#8221;<br />adoConnection.Open &#8220;Active Directory Provider&#8221;<br />Set adoCommand.ActiveConnection = adoConnection</em></strong></span></p>
<p></p>
<p><span style="font-size:85%;"><strong><em>&#8216; Determine the DNS domain from the RootDSE object.<br />Set objRootDSE = GetObject(&#8220;</em></strong></span><a href="//RootDSE/"><span style="font-size:85%;"><strong><em>LDAP://RootDSE</em></strong></span></a><span style="font-size:85%;"><strong><em>&#8220;)<br />strDNSDomain = objRootDSE.Get(&#8220;DefaultNamingContext&#8221;)</em></strong></span></p>
<p></p>
<p><span style="font-size:85%;"><strong><em>&#8216; Filter to retrieve all user objects.<br />strFilter = &#8220;(&amp;(objectCategory=person)(objectClass=user))&#8221;</em></strong></span></p>
<p></p>
<p><span style="font-size:85%;"><strong><em>&#8216; Filter to retrieve all computer objects.<br />&#8216; strFilter = &#8220;(objectCategory=computer)&#8221;</em></strong></span></p>
<p></p>
<p><span style="font-size:85%;"><strong><em>strQuery = &#8220;;&#8221; &amp; strFilter _<br />&amp; &#8220;;displayName,pwdLastSet,userAccountControl,mail;subtree&#8221;</em></strong></span></p>
<p><span style="font-size:85%;"><strong><em>adoCommand.CommandText = strQuery<br />adoCommand.Properties(&#8220;Page Size&#8221;) = 100<br />adoCommand.Properties(&#8220;Timeout&#8221;) = 30<br />adoCommand.Properties(&#8220;Cache Results&#8221;) = False</em></strong></span></p>
<p></p>
<p><span style="font-size:85%;"><strong><em>&#8216; Iterate thru the users collection in Active Directory<br />objFile.WriteLine &#8220;DISPLAY NAME , PASSWORD EXPIRES, ACCOUNT DISABLED, PASSWORD LAST SET , EMAIL, PASSWORD EXPIRES, NUMBER OF DAYS&#8221;</em></strong></span></p>
<p></p>
<p><span style="font-size:85%;"><strong><em>Set oDomain = GetObject(&#8220;</em></strong></span><a href="//dc=DOMAIN,dc=local/"><span style="font-size:85%;"><strong><em>LDAP://dc=DOMAIN,dc=local</em></strong></span></a><span style="font-size:85%;"><strong><em>&#8220;)<br />Set maxPwdAge = oDomain.Get(&#8220;maxPwdAge&#8221;)</em></strong></span></p>
<p></p>
<p><span style="font-size:85%;"><strong><em>numDays = ((maxPwdAge.HighPart * 2 ^ 32) + maxPwdAge.LowPart) / -864000000000</em></strong></span></p>
<p></p>
<p><span style="font-size:85%;"><strong><em>Set adoRecordset = adoCommand.Execute<br />Do Until adoRecordset.EOF</em></strong></span></p>
<p></p>
<p><span style="font-size:85%;"><strong><em>Set objDate = adoRecordset.Fields(&#8220;pwdLastSet&#8221;).Value</em></strong></span></p>
<p></p>
<p><span style="font-size:85%;"><strong><em>lngFlag = adoRecordset.Fields(&#8220;userAccountControl&#8221;).Value<br />blnPwdExpire = True<br />dtmPwdLastSet = Integer8Date(objDate, lngBias)<br />whenPasswordExpires = DateAdd(&#8220;d&#8221;, numDays, dtmPwdLastSet)</em></strong></span></p>
<p></p>
<p><span style="font-size:85%;"><strong><em>If ((lngFlag And ADS_UF_PASSWD_CANT_CHANGE)  0) Then<br />blnPwdExpire = False<br />End If</em></strong></span></p>
<p></p>
<p><span style="font-size:85%;"><strong><em>If ((lngFlag And ADS_UF_DONT_EXPIRE_PASSWD)  0) Then<br />blnPwdExpire = False<br />End If</em></strong></span></p>
<p></p>
<p><span style="font-size:85%;"><strong><em>If (lngFlag And ADS_UF_ACCOUNTDISABLE)  0 Then<br />blnAccountDisabled=True<br />Else<br />blnAccountDisabled=False</p>
<p>If IsNull(adoRecordset.Fields(&#8220;mail&#8221;).Value) or IsEmpty(adoRecordset.Fields(&#8220;mail&#8221;).Value) Then</em></strong></span></p>
<p></p>
<p><span style="font-size:85%;"><strong><em>Else<br />&#8216;check if password expires<br />If blnPwdExpire = True Then<br />If DateDiff(&#8220;d&#8221;, Now, whenPasswordExpires) =0 Then<br />strEmailMessage=&#8221;1&#8243; &#8216;password will expire in less than 14 days<br />objFile.WriteLine adoRecordset.Fields(&#8220;displayName&#8221;).Value &amp; &#8220;,&#8221; &amp; blnPwdExpire &amp; &#8221; , &#8221; &amp; blnAccountDisabled &amp; &#8221; , &#8221; &amp; dtmPwdLastSet &amp; &#8221; , &#8221; &amp; adoRecordset.Fields(&#8220;mail&#8221;).Value &amp; &#8220;,&#8221; &amp; whenPasswordExpires &amp; &#8220;,&#8221; &amp; DateDiff(&#8220;d&#8221;, Now, whenPasswordExpires)<br />Call sendEmail(adoRecordset.Fields(&#8220;mail&#8221;).Value,FormatDateTime(whenPasswordExpires,2),strEmailMessage)<br />ElseIf DateDiff(&#8220;d&#8221;, Now, whenPasswordExpires) &lt;0 Then<br />strEmailMessage=&#8221;0&#8243; &#8216;password has already expired<br />objFile.WriteLine adoRecordset.Fields(&#8220;displayName&#8221;).Value &amp; &#8220;,&#8221; &amp; blnPwdExpire &amp; &#8221; , &#8221; &amp; blnAccountDisabled &amp; &#8221; , &#8221; &amp; dtmPwdLastSet &amp; &#8221; , &#8221; &amp; adoRecordset.Fields(&#8220;mail&#8221;).Value &amp; &#8220;,&#8221; &amp; whenPasswordExpires &amp; &#8220;,&#8221; &amp; DateDiff(&#8220;d&#8221;, Now, whenPasswordExpires)<br />Call sendEmail(adoRecordset.Fields(&#8220;mail&#8221;).Value,FormatDateTime(whenPasswordExpires,2),strEmailMessage)<br />End If<br />End If</em></strong></span></p>
<p></p>
<p><span style="font-size:85%;"><strong><em>End if<br />End If</em></strong></span></p>
<p></p>
<p><span style="font-size:85%;"><strong><em>adoRecordset.MoveNext<br />Loop</em></strong></span></p>
<p></p>
<p><span style="font-size:85%;"><strong><em>adoRecordset.Close</em></strong></span></p>
<p></p>
<p><span style="font-size:85%;"><strong><em>&#8216; Clean up.<br />objFile.Close<br />adoConnection.Close<br />Set objFile = Nothing<br />Set objFSO = Nothing<br />Set objShell = Nothing<br />Set adoConnection = Nothing<br />Set adoCommand = Nothing<br />Set objRootDSE = Nothing<br />Set adoRecordset = Nothing</em></strong></span></p>
<p></p>
<p><span style="font-size:85%;"><strong><em>Wscript.Echo &#8220;Done&#8221;</em></strong></span></p>
<p></p>
<p><span style="font-size:85%;"><strong><em>&#8216;=============================<br />&#8216;Function -Integer8 attribute function courtesy of Richard Mueller &#8211; </em></strong></span><a href="http://www.rlmueller.net/Integer8Attributes.htm"><span style="font-size:85%;"><strong><em>http://www.rlmueller.net/Integer8Attributes.htm</em></strong></span></a><br /><span style="font-size:85%;"><strong><em>Function Integer8Date(ByVal objDate, ByVal lngBias)<br />&#8216; Function to convert Integer8 (64-bit) value to a date, adjusted for<br />&#8216; local time zone bias.<br />Dim lngAdjust, lngDate, lngHigh, lngLow<br />lngAdjust = lngBias<br />lngHigh = objDate.HighPart<br />lngLow = objdate.LowPart<br />&#8216; Account for bug in IADslargeInteger property methods.<br />If (lngLow &lt; 0) Then<br />lngHigh = lngHigh + 1<br />End If<br />If (lngHigh = 0) And (lngLow = 0) Then<br />lngAdjust = 0<br />End If<br />lngDate = #1/1/1601# + (((lngHigh * (2 ^ 32)) _<br />+ lngLow) / 600000000 &#8211; lngAdjust) / 1440<br />Integer8Date = CDate(lngDate)<br />End Function</em></strong></span></p>
<p></p>
<p><span style="font-size:85%;"><strong><em>&#8216;=============================<br />&#8216;Send Email function<br />Sub sendEmail(strEmail, expirationDate, msgFlag)<br />&#8216;Accept input parameters<br />Dim email<br />Dim expirationDate<br />Dim strMessage</em></strong></span></p>
<p></p>
<p><span style="font-size:85%;"><strong><em>email= strEmail<br />expirationDate= expirationDate<br />strMessage= msgFlag</em></strong></span></p>
<p></p>
<p><span style="font-size:85%;"><strong><em>If strMessage=1 then<br />strMessage=&#8221; will expire on &#8220;<br />strMessage2= &#8220;Password Expiration&#8221;<br />ElseIf strMessage=0 then<br />strMessage=&#8221; has already expired last &#8220;<br />strMessage2= &#8220;Expired Password&#8221;<br />End If</em></strong></span></p>
<p></p>
<p><span style="font-size:85%;"><strong><em>Set objMessage = CreateObject(&#8220;CDO.Message&#8221;)<br />objMessage.Subject = &#8220;Message Alert from Domain Administrator: &#8221; &amp; strMessage2<br />objMessage.From = &#8220;</em></strong></span><a href="mailto:admin@domain.local"><span style="font-size:85%;"><strong><em>admin@domain.local</em></strong></span></a><span style="font-size:85%;"><strong><em>&#8220;<br />objMessage.To = email<br />objMessage.TextBody = &#8220;Your domain password &#8221; &amp; strMessage &amp; &#8221; &#8221; &amp; FormatDateTime(expirationDate,1) &amp; &#8220;. This password notification notice is being sent once a week &#8221; &amp; vbCrLF &amp; vbCrLf &amp; &#8220;Please change your password. &#8220;&amp; vbCrlf &amp; vbCrlf &amp; vbCrlf &amp; vbCrlf &amp; &#8220;Domain Administrator&#8221;</em></strong></span></p>
<p></p>
<p><span style="font-size:85%;"><strong><em>&#8216;==This section provides the configuration information for the remote SMTP server.<br />&#8216;==Normally you will only change the server name or IP.<br />objMessage.Configuration.Fields.Item(&#8220;</em></strong></span><a href="http://schemas.microsoft.com/cdo/configuration/sendusing"><span style="font-size:85%;"><strong><em>http://schemas.microsoft.com/cdo/configuration/sendusing</em></strong></span></a><span style="font-size:85%;"><strong><em>&#8220;) = 2 </em></strong></span></p>
<p></p>
<p><span style="font-size:85%;"><strong><em>&#8216;Name or IP of Remote SMTP Server<br />objMessage.Configuration.Fields.Item(&#8220;</em></strong></span><a href="http://schemas.microsoft.com/cdo/configuration/smtpserver"><span style="font-size:85%;"><strong><em>http://schemas.microsoft.com/cdo/configuration/smtpserver</em></strong></span></a><span style="font-size:85%;"><strong><em>&#8220;) = &#8220;smtp.domain.local&#8221;</em></strong></span></p>
<p></p>
<p><span style="font-size:85%;"><strong><em>&#8216;Server port number(typically 25)<br />objMessage.Configuration.Fields.Item(&#8220;</em></strong></span><a href="http://schemas.microsoft.com/cdo/configuration/smtpserverport"><span style="font-size:85%;"><strong><em>http://schemas.microsoft.com/cdo/configuration/smtpserverport</em></strong></span></a><span style="font-size:85%;"><strong><em>&#8220;) = 25 </em></strong></span></p>
<p></p>
<p><span style="font-size:85%;"><strong><em>objMessage.Configuration.Fields.Update</em></strong></span></p>
<p></p>
<p><span style="font-size:85%;"><strong><em>objMessage.Send<br />Set objMessage = Nothing<br />End Sub</em></strong></span></p>
<p><span style="font-family:arial;color:#000000;">The use of ADO was actually not my preference since it requires you to use an additional layer just to connect to ADSI. My original script was actually using the WinNT provider to access Active Directory. But upon further research, I found out that the WinNT provider does not have pointers to access the email attribute in the user object. I need this attribute to send emails to those users whose passwords will be expiring. This prompted me to re-write my script to use the LDAP provider and ADO. </span></p>
<p><span style="font-family:arial;color:#000000;">I have used the following as reference to write this script. Feel free to use it and customize in a way that suites your requirement. </span></p>
<p><a href="http://www.rlmueller.net/"><span style="font-size:85%;">http://www.rlmueller.net/</span></a><br /><a href="http://support.microsoft.com/kb/323750"><span style="font-size:85%;">http://support.microsoft.com/kb/323750</span></a><br /><a href="http://msdn2.microsoft.com/en-us/library/aa772170.aspx"><span style="font-size:85%;">http://msdn2.microsoft.com/en-us/library/aa772170.aspx</span></a></span></p>
<div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/92377218009570869-2126802808134865169?l=bassplayerdoc.blogspot.com' alt='' /></div>
]]></content:encoded>
			

		<wfw:commentRss>https://www.edwinmsarmiento.com/identify-password-expiration-in-active-directory/feed/</wfw:commentRss>
		<slash:comments>12</slash:comments>
				<post-id xmlns="com-wordpress:feed-additions:1">49</post-id>	</item>
	</channel>
</rss>