Windows IT Pro is the leading independent community for IT professionals deploying Microsoft Windows server and client applications and technologies.
  
  
  Advanced Search 


June 24, 2005

How can I use a script to determine password-expiration dates for users in a domain or an organizational unit (OU) and send an email message to accounts whose passwords expire soon?

RSS
Subscribe to Windows IT Pro | See More Active Directory (AD) Articles Here | Reprints | Or get the Monthly Online Pass—only $5.95 a month!

A. I recently had a client whose users had Active Directory (AD) accounts only for Microsoft Outlook Web Access (OWA); users would never actually log on by using the AD account. Although OWA notifies users that their passwords expire soon, the company wants users to receive an email message letting them know that the account is due to expire.

I wrote the following script, reportpasswordchange.vbs, which you can download at http://www.windowsitpro.com/articles/download/rptpaswdchange.zip, that searches every container and OU for users in the savilltech.com domain and for the number of days that passwords last (your maximum password age). You'll need to enter the root container to search (e.g., dc=savilltech,dc=com), and you'll need to change the sender address and possibly also the subject and message text in the script's SendEmailMessage subroutine. The script expects to run on a server running Microsoft IIS and SMTP, but you can modify this. Doing so would require rewriting parts of the script and is beyond the scope of this Q&A. Save the script as reportpasswordchange.vbs and execute it via CScript. (Because of space limitations, some lines in the script wrap to two lines, so to avoid runtime errors, run the downloaded version.)

'
' John Savill 8th June 2005
' Runs check on last password change date.
'
Option Explicit

Dim objCommand, objConnection, objChild, objUserConnection, strBase, _
  strFilter, strAttributes, strPasswordChangeDate, intPassAge
Dim lngTZBias, objPwdLastSet, strEmailAddress, objMessage
Dim objShell, lngBiasKey, k, PasswordExpiry, strRootDomain
Dim strQuery, objRecordset, strName, strCN

' ********** CHANGE THESE VALUES TO PASSWORD EXPIRY AND ROOT OF
' DIRECTORY WHERE USERS WILL BE SEARCHED ***********

PasswordExpiry=35
strRootDomain="dc=savilltech,dc=com"

' **************************************************************
' **************************************************************

' Obtain local Time Zone bias from machine registry.
Set objShell = CreateObject("Wscript.Shell")
lngBiasKey = _
objShell.RegRead("HKLM\System\CurrentControlSet\Control\" & _
  "TimeZoneInformation\ActiveTimeBias")
If UCase(TypeName(lngBiasKey)) = "LONG" Then
  lngTZBias = lngBiasKey
ElseIf UCase(TypeName(lngBiasKey)) = "VARIANT()" Then
  lngTZBias = 0
  For k = 0 To UBound(lngBiasKey)
    lngTZBias = lngTZBias + (lngBiasKey(k) * 256^k)
  Next
End If

Set objCommand = CreateObject("ADODB.Command")
Set objConnection = CreateObject("ADODB.Connection")
objConnection.Provider = "ADsDSOObject"
objConnection.Open "Active Directory Provider"
objCommand.ActiveConnection = objConnection
strBase = ""

strFilter = "(&(objectCategory=person)(objectClass=user))"
strAttributes = "sAMAccountName,cn,mail,pwdLastSet,distinguishedName"
strQuery = strBase & ";" & strFilter & ";" & strAttributes & ";subtree"
objCommand.CommandText = strQuery
objCommand.Properties("Page Size") = 100
objCommand.Properties("Timeout") = 30
objCommand.Properties("Cache Results") = False
Set objRecordSet = objCommand.Execute

' WScript.echo "Running at " & Date()

Do Until objRecordSet.EOF
  strName = objRecordSet.Fields("sAMAccountName").Value
  strCN = objRecordSet.Fields("cn").value
  strEmailAddress = objRecordSet.Fields("mail").value
  Wscript.Echo "NT Name: " & strName & ", Common Name: " & strCN

  Set objUserConnection = GetObject("LDAP://" & _
    objRecordSet.Fields("distinguishedName").Value)
  Set objPwdLastSet = objUserConnection.pwdLastSet
  strPasswordChangeDate = Integer8Date(objPwdLastSet, lngTZBias)
  WScript.Echo vbTab & "Password last changed at " & _
    strPasswordChangeDate
  intPassAge = DateDiff("d", strPasswordChangeDate, Now)
  WScript.Echo vbTab & "Password changed " & intPassAge & " days ago"

  If intPassAge = (PasswordExpiry-3) Then
    WScript.echo vbTab & "Sending user notification to " & _
      strEmailAddress & " that password expires in 3 days"
  Call SendEmailMessage(strEmailAddress, 3)
  ElseIf intPassAge = (PasswordExpiry-6) Then
    WScript.echo vbTab & "Sending user notification to " & _
      strEmailAddress & " that password expires in 6 days"
    Call SendEmailMessage(strEmailAddress, 6)
  ElseIf intPassAge = (PasswordExpiry-9) Then
    WScript.echo vbTab & "Sending user notification to " & _
      strEmailAddress & " that password expires in 9 days"
    Call SendEmailMessage(strEmailAddress, 9)
  End If

  objRecordSet.MoveNext
Loop

objConnection.Close


Function Integer8Date(objDate, lngBias)
' Function to convert Integer8 (64-bit) value to a date, adjusted for
' local time zone bias.
  Dim lngAdjust, lngDate, lngHigh, lngLow
  lngAdjust = lngBias
  lngHigh = objDate.HighPart
  lngLow = objdate.LowPart
  ' Account for the error in IADslargeInteger property methods.
  If lngLow < 0 Then
    lngHigh = lngHigh + 1
  End If
  If (lngHigh = 0) And (lngLow = 0) Then
    lngAdjust = 0
  End If
  lngDate = #1/1/1601# + (((lngHigh * (2 ^ 32)) _
    + lngLow) / 600000000 - lngAdjust) / 1440
' Trap error if lngDate is overly large.
  On Error Resume Next
  Integer8Date = CDate(lngDate)
  If Err.Number < > 0 Then
    On Error GoTo 0
    Integer8Date = #1/1/1601#
  End If
  On Error GoTo 0
End Function

Sub SendEmailMessage(strDestEmail, strNoOfDays)
  Set objMessage = CreateObject("CDO.Message")
  objMessage.Subject = "Password Expires in " & strNoOfDays & " days"
  objMessage.Sender = "administrator@savilltech.com"
  objMessage.To = strDestEmail
  objMessage.TextBody = "Your password expires in " & strNoOfDays & " _
    days. Please goto http://changepass.com and reset" objMessage.Send
End Sub
To execute the script, run the command
reportpasswordchange.vbs
You'll see output on screen similar to this:
Microsoft (R) Windows Script Host Version 5.6
Copyright (C) Microsoft Corporation 1996-2001. All rights reserved.

NT Name: bwayne, Common Name: Bruce Wayne
Password last changed at 5/7/2005 8:59:01 PM
Password changed 39 days ago
NT Name: CKent, Common Name: Clark Kent
Password last changed at 5/7/2005 9:01:32 PM
Password changed 39 days ago
NT Name: wwest, Common Name: Wally West
Password last changed at 6/8/2005 7:55:47 PM
Password changed 7 days ago
NT Name: krayner, Common Name: Kyle Rayner
Password last changed at 5/7/2005 9:19:52 PM
Password changed 39 days ago

End of Article



Reader Comments
Great script!

Be careful with one thing. Users with non-expiring passwords will also get the warning emails. You can change the strFilter to not include these users:
strFilter = "(&(objectCategory=person)(objectClass=user)(!userAccountControl:1.2.840.113556.1.4.803:=65536))"

Anonymous User June 24, 2005 (Article Rating: )


I had problems with this. The functions wouldn't work

Anonymous User June 28, 2005 (Article Rating: )


This works great. Regarding the first comment, I
also noticed that it checks on disabled accounts.
So I set the strFilter = "(&(objectCategory=person)
(objectClass=user) (!userAccountControl:1.2.840.113556.1.4.803:=2)
(!userAccountControl:1.2.840.113556.1.4.803:=65536))"

Now it won't check disabled accounts or accounts
whose passwords should never expire.

Also, I had to add objMessage.From under
objMessage.Sender (which probably is not needed) so
Exchange would understand who it was from.

Anywho, great script!

Anonymous User July 26, 2005 (Article Rating: )


thank you

Anonymous User July 27, 2005 (Article Rating: )


really great script.
Can someone put final code with some grooming?

Thanks



Anonymous User July 28, 2005 (Article Rating: )


This script looks like exactly what I need - most of my users access email via IMAP - they won't recieve any notification that their password has expired!

However, on running the script I get the following error message:

reportpasswordchange.vbs(46,1) Provider: Table does not exist.

I have changed the strRootDomain as appropriate.

Is this a genuine error message, or is this the message I would get if no users passwords were to expire in the next 9 days?

Anonymous User August 18, 2005 (Article Rating: )


Oops - my problem was that I left the second part of the dc as 'dc=com', whereas it should be 'dc=local' for my system. Is working fine now, but still need to filter out the non-expiring accounts

Anonymous User August 18, 2005 (Article Rating: )


Works well but how come it does not send any email out. Is there a change somewhere that's required?

Anonymous User August 26, 2005 (Article Rating: )


Dudes you all Rock!

Awesome Script and Thanks to those who replied with the filter updates.

Anonymous User August 30, 2005 (Article Rating: )


What should the PasswordExpiry value be set to?

Anonymous User September 09, 2005 (Article Rating: )


 See More Comments  1   2 

You must be a registered user or online subscriber to comment on this article. Please log on before posting a comment. Are you a new visitor? Register now




Top Viewed ArticlesView all articles
Battery Life Issues Almost Certainly Not Windows 7's Fault

While Microsoft is still investigating a notebook battery life issue that was supposedly caused by Windows 7, some interesting trends have emerged. ...

Confirmed: Battery Life Issues Not Windows 7's Fault

Microsoft on Monday issued a lengthy statement about the recent Windows 7 battery controversy, echoing my assessment from earlier in the day, but backing it up with hard, cold evidence. ...

Getting your iPhone to Sync with Exchange 2003

Follow these steps to use an iPhone with Exchange. ...


Related Articles Emailing Users Before Their Passwords Expire

Active Directory (AD) Whitepapers Unleash the Power of Active Directory Groups

Meeting Compliance Objectives in SharePoint

Email Controls and Regulatory Compliance

Related Events The Experts Conference 2010

Troubleshooting Active Directory

Deep Dive into Windows Server 2008 R2 presented by John Savill

Check out our list of Free Email Newsletters!

Active Directory (AD) eBooks The Essentials Series: Active Directory 2008 Operations

Keeping Your Business Safe from Attack: Monitoring and Managing Your Network Security

Windows 2003: Active Directory Administration Essentials

Related Active Directory (AD) Resources Introducing Left-Brain.com, the online IT bookstore
Looking for books, CDs, toolkits, eBooks? Prime your mind at Left-Brain.com

Discover Windows IT Pro eLearning Series!
Clear & detailed technical information and helpful how-to's, all in our trademark no-nonsense format


Windows IT Pro Home Register FAQ for Windows WinInfo News
Europe Edition About Us Contact Us/Customer Service Media Kit Affiliates / Licensing  
SQL Server Magazine Office & SharePoint Pro DevProConnections IT Job Hound
Left-Brain.com Technology Resource Directory asp.netPRO ITTV Windows SuperSite 
 
 Windows IT Pro is a Division of Penton Media Inc.
 © 2010 Penton Media, Inc. Terms of Use | Privacy Statement