We help IT Professionals succeed at work.

Check out our new AWS podcast with Certified Expert, Phil Phillips! Listen to "How to Execute a Seamless AWS Migration" on EE or on your favorite podcast platform. Listen Now

x

Enumerating User Accounts in AD for Password Age

wtm
wtm asked
on
Medium Priority
3,107 Views
Last Modified: 2012-06-27
My scripting skills are weak so I need some help on this one. I have a script that would search the Users container in AD and then create an output text file of the password age for each user. Last Name, First Name and password age. We have since divided our AD by Practice and within each Practice container there are sub containers which have user accounts. I am trying to adjust my existing script to enumerate all users from the root of the domain down but am having no success. I have found reference to 'subtree' but am unfamiliar  with its use. The script that I used in the past is pasted below.

Thanks
Option Explicit
 
Dim objDSE, strDefaultDN, strDN, objContainer, objChild, dtmValue, intAge, strFileName
dim objFSO, objFile, objTextFile, strReportName
Const ForAppending = 8
 
'**** OPEN OBJECTS
Set objDSE = GetObject("LDAP://rootDSE") 'open Active Directory
strDefaultDN = "OU=Users,OU=Insurance,OU=SABC," & objDSE.Get("defaultNamingContext") 'full path to users folder
'strDefaultDN = "OU=Users," & objDSE.Get("defaultNamingContext") 'full path to users folder
 
'**** ARE YOU SURE?
strDN = 	InputBox("Enter the distinguished name of a container" & _
	vbCrLf & "(e.g. " & strDefaultDN & ")", , strDefaultDN) 'allow user to change folder
 
If strDN = "" Then WScript.Quit(1) 'user clicked Cancel = exit script
 
'******** NAME REPORT
strReportName = InputBox("Enter Report File Name:", , "PasswordReport") 'allow user to name report
 
'***** CREATE AND OPEN TEXT FILE
Set objContainer = GetObject("LDAP://" & strDN) 'open users folder
objContainer.Filter = Array("user") 'only read users
strFileName = "C:\Documents and Settings\maunw\Desktop\Password Age Checker\Report\" & strReportName & ".txt"
Set objFSO = CreateObject("Scripting.FileSystemObject") 'create file system object
Set objFile = objFSO.CreateTextFile(strFileName) 'create report file
objFile.close 'close report file
Set objTextFile = objFSO.OpenTextFile(strFileName, ForAppending, True) 'open report file to edit
 
'**** PROCESS
on error resume next 'if there is a bad record, move to the next
For Each objChild In objContainer 'process each user
	dtmValue = objChild.PasswordLastChanged 'date password was changed
	intAge = Int(Now - dtmValue) 'Today - password last changed = age
	objTextFile.WriteLine(objChild.FullName & vbtab & intAge) 'write line to file
Next
objTextFile.Close 'close file
WScript.Echo "END" 'notify that processing is done

Open in new window

Comment
Watch Question

Henrik JohanssonSystems engineer
Top Expert 2008

Commented:
Open a recordset with objRS.Open as showed in the snippet below and loop through the recordset.
strQuery has three parts separated by ; (from, criteria and fields)

I see I missed to save output to file, but it can either be done by using scripting.filesystemobject as used in question or by executing the script with the following command

cscript //NoLogo script.vbs > filename.txt
Option Explicit
On Error Resume Next
 
Dim objDSE,strDomain,strDN,strFields,strFrom,strWhere,strQuery,objRS,objConn,fld,strSeparator,strLine,objUser
 
Set objDSE=GetObject("LDAP://rootDSE") 
strDomain=objDSE.Get("defaultNamingContext")
 
strDN=InputBox("Enter OU in current domain")
If strDN<>"" And Right(strDN,1)<>"," Then strDN=strDN & ","
strFields="samAccountName,sn,givenName,pwdLastSet,adsPath"
strFrom="<LDAP://" & strDN & objDSE.Get("defaultNamingContext") &">"
strWhere="(&(objectClass=user)(objectClass=Person)(samAccountName=*)(userprincipalname=*))"
strQuery= strFrom & ";" & strWhere & ";" & strFields
 
Set objRS=CreateObject("ADODB.RecordSet")
Set objConn=CreateObject("ADODB.Connection")
Call objConn.Open("Provider=ADSDSOObject")
Call objRS.Open(strQuery,objConn)
 
strLine=""
strSeparator=vbTab
For Each fld in objRS.Fields
	Select Case fld.Name
		Case "sn" strLine=strLine & "Last name" & strSeparator
		Case "givenName" strLine=strLine & "First name" & strSeparator
		Case "samAccountName" strLine=strLine & "Username" & strSeparator
		Case "pwdLastSet" strLine=strLine & "Password age" & strSeparator
	End Select
Next
wscript.echo strLine
 
Do While Not objRS.EOF
	strLine=""
	Set objUser=GetObject(objRS("adsPath"))
	For Each fld in objRS.Fields
		If fld.Name="pwdLastSet" Then
			If Not IsNull(objUser.PasswordLastChanged) Then 
				strLine=strLine & CStr(DateDiff("h",objUser.PasswordLastChanged,Now))
			End IF
			strLine=strLine & strSeparator
		ElseIf fld.Name<>"adsPath" Then
			If Not isNull(fld) Then strLine=strLine & CStr(fld) 
			strLine=strLIne & strSeparator
		End IF
	Next
	Set objUser=Nothing
	wscript.echo strLine
	objRS.moveNext
Loop
objRS.Close: Set objRS=Nothing
objConn.Close: Set objConn=Nothing

Open in new window

Chris DentPowerShell Developer
CERTIFIED EXPERT
Top Expert 2010

Commented:
wtm,

If you have no existing experience with VbScript you might consider PowerShell for these kind of tasks. It needs these two installed:

http://www.microsoft.com/windowsserver2003/technologies/management/powershell/default.mspx
http://www.quest.com/activeroles-server/arms.aspx

But once you have those open up the version from the Quest folder in the start menu and all you need to do to generate this report is this:

Get-QADUser -IncludedProperties PwdLastSet | `
  Select-Object FirstName, LastName, sAMAccountName, PwdLastSet

If you want to pop that into a file it's:

Get-QADUser -IncludedProperties PwdLastSet | `
  Select-Object FirstName, LastName, sAMAccountName, PwdLastSet | `
  Export-CSV "SomeFile.csv"

The ` above just lets it carry the command onto the next line. Easier to read. It could just be written on a single line.

It can also sort, or easily include any other attributes. To see what could be included run:

Get-QADUser "You" | Format-List *

Sorting would be:

Get-QADUser -IncludedProperties PwdLastSet | `
  Select-Object FirstName, LastName, sAMAccountName, PwdLastSet | `
  Sort-Object PwdLastSet | `
  Export-CSV "SomeFile.csv"

Those tools can be installed wherever you like, it doesn't have to be on your Domain Controller or anywhere silly like that.

Chris
wtm

Author

Commented:
henjoh09:

Thank you for your help. Hoping you can point me in the right direction. I don't need the pop up for each user account info. I just need the information dumped into a text file. I am not able to follow what you did or how you did it. Why the case statement?
wtm

Author

Commented:
What I am looking for is just the code to allow the present script to enumerate through my AD.

Thanks
Systems engineer
Top Expert 2008
Commented:
Unlock this solution with a free trial preview.
(No credit card required)
Get Preview
wtm

Author

Commented:
Thank you henjoh09 for the redue. Works as expected.
wtm

Author

Commented:
henjoh09,

One last thing. After testing, the scrip works great with the exception of enumerating through one of my OU's. If I give the entire path to the OU i.e OU=Commercial A and A,OU=SFACTS, it works fine. But if I only give the root OU i.e. OU=SFACTS, I get a script failure on line 55 char 4 source (null). Under the SFACTS OU there are several sub OU's with OU's under that. Under my SABC OU I have only one sub layer of OU's. Enumerating through the SABC OU works Fine. Any Ideas?

Thanks Again
Henrik JohanssonSystems engineer
Top Expert 2008

Commented:
I commented out the 'On Error Resume Next' on line 2 for debugging and forgot to change it back when posting.
wtm

Author

Commented:
That did it. Thanks for all your help.
Unlock the solution to this question.
Thanks for using Experts Exchange.

Please provide your email to receive a free trial preview!

*This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.

OR

Please enter a first name

Please enter a last name

8+ characters (letters, numbers, and a symbol)

By clicking, you agree to the Terms of Use and Privacy Policy.