# Sort Windows Active Directory for server 200x by "last logon timestamp"



## shinosuke (May 19, 2007)

Hello,

I am in the process of cleaning up our active directory, a task that has not been done since late 2000, as near as I can tell. 

The old naming structure that a few of the older machines still use makes the cleanup process a bit difficult to perform off name alone. Is there some way to perform a search or sort by "last logon time" or "pwd last set" so that I can delete the computers and users who are no longer in use?

*edit* I forgot to mention that I have 2 windows domain controllers, one with server 2003 and the other with server 2008. */end edit*

Thank you for your time!
Adam


----------



## Squashman (Apr 4, 2003)

JoeWare has alot of cool utilities. I think you will find some of them very useful for your problem.
http://www.joeware.net/freetools/


----------



## StumpedTechy (Jul 7, 2004)

You can also write a custom VBS - I run this one monthly - This one verifies each account vrs a ping to ensure you have nothing in DNS and AD that may be off. Then it disables the account, moves it to a disabled account OU, adds a description of the accounts original location and gives the date it was disabled so you can easily see ones that were disabled for a long time. It also has week variables for both weeks inactive and password not changed. My next incarnation will clean up the disabled accounts OU I use but for now I clean that out manually.

```
' ************************************************************************
' ************************************************************************
' ***								       ***
' ***	This script is to be used to check all currently enabled       ***
' ***   computer accounts in the designated OU and its Sub OUs for     ***
' ***	old/inactive computer accounts.				       ***
' ***	It will check the accounts last active date vrs the date the   ***
' ***	the script is ran and if the difference is over the specified  ***
' ***   number of weeks it will first ping the computer and then, if   ***
' ***	the ping does not reply, the script will then perform the      ***
' ***   following steps -                                              ***
' ***								       ***
' ***  - Put a description in the computer account indicating,         ***
' ***    Number of weeks inactive,				       ***
' ***    Time and date of script run,				       ***
' ***    Where the machines LDAP location was before it was moved.     ***
' ***    (this last bit was implemented to make restoration easy)      ***
' ***  - Disable the computer account.				       ***
' ***  - Move the computer account from the OU it is in to the 	       ***
' ***    designated disabled computer accounts OU.		       ***
' ***								       ***
' ***								       ***
' ***   Lines to be modified -					       ***
' ***	strWeeksInactive = Change this to be the number of weeks not   ***
' ***		active on the domain. Do not make this too short as    ***
' ***		traveling users might not use their machines on the    ***
' ***		domain for a few weeks at a time.		       ***
' ***	strWeeksNoPassChg = Change this to be the number of weeks no   ***
' ***		password has changed on the domain. This number should ***
' ***		be smaller than strWeeksInactive to increase the       ***
' ***		reliability of the script.			       ***
' ***	strMainLDAP = LDAP location of the OU and SubOUs you want to   ***
' ***		scan for old inactive machine accounts.		       ***
' ***	strDisableLDAP = Dump location you want the disabled accounts  ***
' ***           to go into once disabled.		               ***
' ***								       ***
' ***	This scripts is distributed with ensuring that nothing as      ***
' ***   recent as less than 12 weeks inactivity and 8 weeks password   ***
' ***	changes can be changed. The default scan time is 16 weeks      ***
' ***   inactivity and 12 weeks password changes.		       ***
' ***								       ***
' ***  WARNINGS-WARNINGS-WARNINGS-WARNINGS-WARNINGS-WARNINGS-WARNINGS  ***
' ***								       ***
' ***  1) This script does not make any LDAP locations. They have to   ***
' ***	already exist in AD already.				       ***
' ***  2) This script will overwrite existing computer descriptions.   ***
' ***  3) Sometimes there is a slight delay between the script being   ***
' ***  run and when ADUC shows results. This varies depending upon the ***
' ***  server ADUC is pointed to and the where the script runs against.***
' ***								       ***
' ***								       ***
' ***	  Authored by: StumpedTechy 				       ***
' ***     Date:        June 23, 2008                                   ***
' ***     Version:     1.2		                               ***
' ***	  Changes:     1.1 Time variable adjustment made.              ***
' ***		       1.2 Added veification prompt, put vars in msgs  ***
' ************************************************************************
' ************************************************************************

'Variables to change
strWeeksInactive = 16
strWeeksNoPassChg = 12
strMainLDAP = "LDAP://OU=ORL,DC=YOUR,DC=DOMAIN,DC=COM"
strDisableLDAP = "LDAP://OU=Disabled Computers,DC=YOUR,DC=DOMAIN,DC=Com"

strMbox = msgbox ("Are you sure you want to disable all machines that are over "&strWeeksInactive&" Weeks inactive and "&strWeeksNoPassChg&" weeks without password change located "&strMainLDAP&" OU and its Sub OUs? If you need to adjust the times please click Cancel and modify the scripts variables.",1,"Variable account activity and password changed date verification")
If strMbox = "2" Then WScript.Quit

If strWeeksInactive < 12 then 
MsgBox "Warning this script is being ran ouside of the recommended paramters. Please increase the number of inactive weeks." , vbInformation, "Increase Inactive Weeks"
wscript.quit
End If

If strWeeksNoPassChg < 8 then 
MsgBox "Warning this script is being ran ouside of the recommended paramters. Please increase the number of password set weeks." , vbInformation, "Increase Password Set Weeks"
wscript.quit
End If

'Variables not to change
strDate = Replace(Date,"/","-")
strDescTime = Replace(Time,":","-")
strCount = 0

'Queries AD and creates a recordset
Const ADS_SCOPE_SUBTREE = 2
Set objConnection = CreateObject("ADODB.Connection")
Set objCommand =   CreateObject("ADODB.Command")
objConnection.Provider = "ADsDSOObject"
objConnection.Open "Active Directory Provider"
Set objCOmmand.ActiveConnection = objConnection
objCommand.CommandText = _
    "Select Name, ADsPath from '"&strMainLDAP&"' WHERE objectClass='computer' " & _
	   "AND userAccountControl='4096'"
objCommand.Properties("Page Size") = 1000
objCommand.Properties("Timeout") = 30 
objCommand.Properties("Searchscope") = ADS_SCOPE_SUBTREE 
objCommand.Properties("Cache Results") = False 
Err.Clear
On error resume next
Set objRecordSet = objCommand.Execute
If (Err.Number <> 0) Then
		Msgbox "You must have mistyped the LDAP location. "&strMainLDAP&" "& vblf & _
"Please check syntax and rerun script." , vbInformation, "Machine account error notification"
		objRecordSet.MoveNext
		Else
'If recordset is empty
If objRecordSet.EOF then
MsgBox "All machines in "&strMainLDAP&" have been active more than "&strWeeksInactive&" weeks and have had a password changed within "&strWeeksNoPassChg&" weeks." , vbInformation, "Execution completed"
Else
'If recordset is not empty
objRecordSet.MoveFirst
Do Until objRecordSet.EOF
        
        'Gather each records variables
         strADsPath = objRecordSet.Fields("ADsPath").Value
	 strDeviceName = objRecordSet.Fields("Name").Value
	 Set objChange = GetObject(strADsPath)
	 
'Some Machines have old/bad accounts that the query cannot gather information for.
Err.Clear
On error resume next
Set objLastLogon = objChange.Get("lastLogonTimestamp")
		If (Err.Number <> 0) Then
		Msgbox "There was a problem with "&strDeviceName&". The last login cannot be gathered from AD. Machine should be removed from the domain, the account should be deleted, and then lastly readded to the domain." , vbInformation, "Machine account error notification"
		objRecordSet.MoveNext
		Else		
'Manipulate 64 bit interger to a date/time and compares to current date/time.
intLastLogonTime = objLastLogon.HighPart * (2^32) _
+ objLastLogon.LowPart
intLastLogonTime = intLastLogonTime / (60 * 10000000)
intLastLogonTime = intLastLogonTime / 1440
StrTime = intLastLogonTime + #1/1/1601#
dtmEndingDate = strTime
intWeeks = DateDiff("WW",dtmEndingDate,now)
     Set objpwdLastSet = objChange.Get("pwdLastSet")
intpwdLastSetTime = objpwdLastSet.HighPart * (2^32) _
+ objpwdLastSet.LowPart
intpwdLastSetTime = intpwdLastSetTime / (60 * 10000000)
intpwdLastSetTime = intpwdLastSetTime / 1440
StrpwdTime = intLastLogonTime + #1/1/1601#
dtmpwdEndingDate = strpwdTime
intpwdWeeks = DateDiff("WW",dtmpwdEndingDate,now)

'Check and only mainipulate the machine names with the proper date contraints
If CInt(intpwdWeeks) >= CInt(strWeeksNoPassChg) and CInt(intWeeks) >= CInt(strWeeksInactive) then
     If IsAlive(strDeviceName) = False then
     strCount = strCount + 1
     objChange.Put "description" , "Disabled "&strDate&" @ "&strDescTime&" by script. Machine over "&strWeeksInactive&" weeks inactive. Password not set for at least "&strWeeksNoPassChg&" weeks. Moved from "&strADsPath&"."
     objChange.Put "userAccountControl", "4098"
     objChange.SetInfo
     Set objOU = GetObject(""&strDisableLDAP&"")
	 objOU.MoveHere strADsPath, vbNullString
     End if
 End If
 End If
    objRecordSet.MoveNext
	Loop

MsgBox "There were "&strCount&" computers disabled in "&strMainLDAP&" and its SubOUs that were inactive "&strWeeksInactive&" weeks or more and had a password changed over "&strWeeksNoPassChg&" weeks. All machine accounts manipulated have been put in the "&strDisableLDAP&" OU." , vbInformation, "Execution completed"

End If
End If


 Function IsAlive(strDeviceName) 
'---------- Test to see if host or url alive through ping -----------------
' Returns True if Host responds to ping
' 
' Though there are other ways to ping a computer, Win2K,
' XP and different versions of PING return different error
' codes. So the only reliable way to see if the ping
' was sucessful is to read the output of the ping
' command and look for "TTL="
' 
' strRComputer is a hostname or IP 
    Const OpenAsASCII = 0 
     Const FailIfNotExist = 0 
     Const ForReading =  1 
     Dim objShell, objFSO, sTempFile, fFile 
    Set objShell = CreateObject("WScript.Shell") 
     Set objFSO = CreateObject("Scripting.FileSystemObject") 
    sTempFile = objFSO.GetSpecialFolder(2).ShortPath & "\" & objFSO.GetTempName 
    objShell.Run "%comspec% /c ping.exe -n 2 -w 500 " & strDeviceName & " >" & sTempFile, 0 , True 
    Set fFile = objFSO.OpenTextFile(sTempFile, ForReading, FailIfNotExist, OpenAsASCII) 
    Select Case InStr(fFile.ReadAll, "TTL=") 
         Case 0
            IsAlive = False 
         Case Else
            IsAlive = True 
    End Select 
    ffile.close 
     objFSO.DeleteFile(sTempFile)
    Set objFSO = Nothing
    Set objShell = Nothing
End Function
```


----------



## Squashman (Apr 4, 2003)

_Posted via Mobile Device_
That is sweet Stumpy!


----------

