Solved

VB script to move and disable Computer accounts that have not logged on for more than a 120 days

Posted on 2008-10-14
6
4,266 Views
Last Modified: 2012-08-14
VB script to move and disable Computer accounts that have not logged on for more than a 120 days
Disable them and move them to another OU
0
Comment
Question by:akmilm
6 Comments
 
LVL 3

Assisted Solution

by:DrunkenELF
DrunkenELF earned 100 total points
Comment Utility
Dear akmilm,

Try this code
Here' s a script that we use to Disable computer objects based on inactivity and move them to a Term OU. If they remain inactive for an additional 30 days, they are deleted from that OU. The script uses both the LastLogonTimestamp and PasswordLastSet attributes to determine inactivity. We disable after 90 days of inactivity and delete after another 30 days (120 total).

I stripped out a couple of company-specific things in the script that we do, so hopefully it still runs without errors.

Edit - I have this setup to run as a scheduled task so it happens automatically. SMS discovery is configured to not query the ' Abandoned Machine Accounts' OU where the disabled computer accounts are located.


' Script to query for the computer password last set and last logon for all computers 

' in the domain and disable all of those who haven' t been used 

' for a specified period and delete those that haven' t been used for a different 

' specified period. 
 

Option Explicit 
 

On Error Resume Next 
 

Dim objFSO, objCommand, objConnection, objRecordSet, objDate, objLog, objComputer, objOU, objShell, objLastLogon 

Dim strBase, strFilter, strQuery, strDN, strDescription, strLine, strCN 

Dim lngDate, lngLastLogon,lngBias 

Dim dtmPwdDate, dtmDisableDate, dtmLastLogon, dtmDeleteDate 
 

Const INFORMATION = 4 
 

Set objFSO = CreateObject(" Scripting.FileSystemObject" ) 

Set objCommand = CreateObject(" ADODB.Command" ) 

Set objConnection = CreateObject(" ADODB.Connection" ) 

Set objShell = CreateObject(" WScript.Shell" ) 
 

' Log an event in the Application log 

objShell.LogEvent INFORMATION, " Computer cleanup.vbs start" 
 

' Create recordset of all computer accounts in domain 

objConnection.Provider = " ADsDSOObject" 

objConnection.Open " Active Directory Provider" 

objCommand.ActiveConnection = objConnection 

strBase = " <LDAP://dc=domaincomponent1,dc=domaincomponent2>" 

strFilter = " (objectCategory=computer)" 

strQuery = strBase & " ;" & strFilter & " ;distinguishedName,pwdLastSet,lastlogonTimestamp,description,cn;subtree" 

objCommand.CommandText = strQuery 

objCommand.Properties(" Page Size" ) = 100 

objCommand.Properties(" Timeout" ) = 30 

objCommand.Properties(" Cache Results" ) = False 

Set objRecordSet = objCommand.Execute 
 

' Set log file 

Set objLog = objFSO.CreateTextFile(" C:\Jobs\ComputerCleanup\Computer cleanup log.txt" , True) 

objLog.Writeline(" Action;Computer;Password last set;Last logon timestamp" ) 
 

' Set target OU for moved accounts 

Set objOU = GetObject(" LDAP://OU=Abandoned Machine Accounts,OU=Term,dc=domaincomponent1,dc=domaincomponent2" ) 
 

lngBias = 300 
 

' Set disable date 

dtmDisableDate = NOW - 90 
 

' Set deletion date 

dtmDeleteDate = NOW - 120 
 

' Loop through computer objects 
 

Do Until objRecordset.EOF 

strDN = objRecordSet.Fields(" distinguishedName" ) 

strCN = objRecordSet.Fields(" CN" ) 

lngDate = objRecordSet.Fields(" pwdLastSet" ) 

lngLastLogon = objRecordset.Fields(" lastLogonTimestamp" ) 
 

' Eliminate all matches for servers in the Domain Controllers or Servers OU hierarchy 

If InStr(strDN," OU=Domain Controllers" ) = 0 And InStr(strDN," OU=Servers" ) = 0 Then 
 

' Call function to format password last set and last logon timestamp attributes 

If IsNull(lngDate) Then 

dtmPwdDate = 0 

Else 

Set objDate = lngDate 

dtmPwdDate = Integer8Date(objDate,lngBias) 

End If 
 

If IsNull(lngLastLogon) Then 

dtmLastLogon = 0 

Else 

Set objLastLogon = lngLastLogon 

dtmLastLogon = Integer8Date(objLastLogon,lngBias) 

End If 
 

' If password last set is older than delete date and 

' the computer account is disabled, delete the account 

If dtmPwdDate < dtmDeleteDate And dtmLastLogon < dtmDeleteDate And Not dtmPwdDate = " 1/1/1601" Then 

Set objComputer = GetObject(" LDAP://" & strDN) 
 

' Delete the account if it is disabled 

If objComputer.AccountDisabled = True Then 

If InStr(strDN," Abandoned Machine Accounts" ) Then 

objComputer.DeleteObject (0) 

objLog.Writeline " Deleted;" & strDN & " ;" & dtmPwdDate & " ;" & dtmLastLogon 

End If 

End If 

End If 
 

' If password last set is older than disable date and " Tombstoned" is in the description, 

' disable the account and move it to the ' Abandoned Machine Accounts' OU 

If dtmPwdDate < dtmDisableDate And dtmLastLogon < dtmDisableDate Then 

Set objComputer = GetObject(" LDAP://" & strDN) 
 

' Disable the account if it isn' t already disabled 

If objComputer.AccountDisabled = False Then 

objComputer.AccountDisabled = True 

objComputer.SetInfo 

objLog.Writeline " Disabled;" & strDN & " ;" & dtmPwdDate & " ;" & dtmLastLogon 

End If 
 

' Move the account to the " Abandoned Machine Accounts" OU if it isn' t already there 

If InStr(strDN," Abandoned Machine Accounts" ) = 0 Then 

objOU.MoveHere " LDAP://" & strDN, vbNullString 

objLog.Writeline " Moved;" & strDN & " ;" & dtmPwdDate & " ;" & dtmLastLogon 

End If 

End If 

End If 
 

objRecordSet.MoveNext 

strDescription = " " 
 

Loop 
 

objLog.Close 
 

' Log an event in the Application log 

objShell.LogEvent INFORMATION, " Computer cleanup.vbs complete" 
 

' Cleanup 

Set objFSO = Nothing 

Set objShell = Nothing 

Set objCommand = Nothing 

Set objConnection = Nothing 

Set objRecordSet = Nothing 

Set objDate = Nothing 

Set objLog = Nothing 

Set objComputer = Nothing 

Set objOU = Nothing 

Set objLastLogon = Nothing 

Set strBase = Nothing 

Set strFilter = Nothing 

Set strQuery = Nothing 

Set strDN = Nothing 

Set strCN = Nothing 

Set strDescription = Nothing 

Set strLine = Nothing 

Set lngDate = Nothing 

Set lngBias = Nothing 

Set lngLastLogon = Nothing 

Set dtmPwdDate = Nothing 

Set dtmDisableDate = Nothing 

Set dtmDeleteDate = Nothing 

Set dtmLastLogon = Nothing 
 

' Function to convert Integer8 (64-bit) value to a date, adjusted for 

' time zone bias. 

Function Integer8Date(objDate, lngBias) 

Dim lngAdjust, lngDate, lngHigh, lngLow 

lngAdjust = lngBias 

lngHigh = objDate.HighPart 

lngLow = objDate.LowPart 

' Account for bug in IADsLargeInteger property methods. 

If (lngHigh = 0) And (lngLow = 0) Then 

lngAdjust = 0 

End If 

lngDate = #1/1/1601# + (((lngHigh * (2 ^ 32)) _ 

+ lngLow) / 600000000 - lngAdjust) / 1440 

Integer8Date = CDate(lngDate) 

End Function 

Open in new window

0
 
LVL 30

Expert Comment

by:LauraEHunterMVP
Comment Utility
Or just download and run oldcmp.exe from www.joeware.net/freetools. Will report on stale computer accounts, disable, move to an alternate OU, and/or delete, as you specify.  There's a -users switch to do the same for stale user accounts as well.
0
 
LVL 18

Expert Comment

by:exx1976
Comment Utility
Man..   ADODB sure is popular around these parts..


The code below should do what you want.  It'll walk through AD and check all computer accounts.  Then it'll simply echo the names out of the ones it's planning to move.  If you want them to actually be moved, then just uncomment out line 16.

This should do what you want, but test test test first!  This was a quick adaptation of a script that I use to prune out inactive user accounts.

Enjoy!
deleteAge = Now - 120

Set rootDSE = GetObject("LDAP://rootDSE")

DomainDN = rootDSE.Get("defaultNamingContext")

DomainADSPath = "LDAP://" & DomainDN

NLEPath = "LDAP://OU=DeadPCs," & DomainDN

checkObj(DomainADSPath)

Function checkObj(oObject)

	Set oObj = GetObject(oObject)

	For Each object In oObj

		If object.class = "organizationalUnit" Or object.class = "container"  Then checkObj(object.ADSpath)

		If object.class = "computer" Then

			PCLastLogin = lastLogin(object.distinguishedName)

			If (PCLastLogin = "Never") Or (PCLastLogin < deleteAge) Then

				If object.whenCreated < createAge Then

					WScript.Echo object.name

					'del object.adspath

				End If

			End If

		End If

	Next

End Function
 

Function del(PCADSPath)

	Set oPC = GetObject(PCADSPath)

	Set TargetOU = GetObject(NLEPath)

	val = oPC.Name & ","

	oOUPath = Replace(PCADSPath,val,"")

	Set oUD = GetObject(oOUPath)

	oPC.accountDisabled = True

	oPC.SetInfo

	TargetOU.MoveHere oPC.adspath, oPC.Name

	End If

End Function
 

Function lastLogin(PCDN)

	On Error Resume Next

	TrueLastLogin = ""

	Set DCs = GetObject("LDAP://OU=Domain Controllers," & DomainDN)

	For Each DC In DCs

		serverLastLogin = ""

		server = Right(dc.name,Len(dc.name)-3)

		Set PC = GetObject("LDAP://" & server & "/" & PCDN)

		serverLastLogin = usr.lastLogin

		If serverLastLogin <> "" Then

			If TrueLastLogin = "" Then 

				TrueLastLogin = serverLastLogin

			Elseif serverLastLogin > TrueLastLogin Then

				TrueLastLogin = serverLastLogin

			End If

		End If

	Next

	If TrueLastLogin = "" Then TrueLastLogin = "Never"

	lastLogin = TrueLastLogin

End Function

Open in new window

0
Enabling OSINT in Activity Based Intelligence

Activity based intelligence (ABI) requires access to all available sources of data. Recorded Future allows analysts to observe structured data on the open, deep, and dark web.

 
LVL 18

Accepted Solution

by:
exx1976 earned 400 total points
Comment Utility
D'oh!  I forgot to remove one of the variables from the old code.   Use this, not the one I just posted..

The line you'll want to uncomment now is line 15.
deleteAge = Now - 16

Set rootDSE = GetObject("LDAP://rootDSE")

DomainDN = rootDSE.Get("defaultNamingContext")

DomainADSPath = "LDAP://" & DomainDN

NLEPath = "LDAP://OU=DeadPCs," & DomainDN

checkObj(DomainADSPath)

Function checkObj(oObject)

	Set oObj = GetObject(oObject)

	For Each object In oObj

		If object.class = "organizationalUnit" Or object.class = "container"  Then checkObj(object.ADSpath)

		If object.class = "computer" Then

			PCLastLogin = lastLogin(object.distinguishedName)

			If (PCLastLogin = "Never") Or (PCLastLogin < deleteAge) Then

				WScript.Echo object.name

				'del object.adspath

			End If

		End If

	Next

End Function
 

Function del(PCADSPath)

	Set oPC = GetObject(PCADSPath)

	Set TargetOU = GetObject(NLEPath)

	val = oPC.Name & ","

	oOUPath = Replace(PCADSPath,val,"")

	Set oUD = GetObject(oOUPath)

	oPC.accountDisabled = True

	oPC.SetInfo

	TargetOU.MoveHere oPC.adspath, oPC.Name

	End If

End Function
 

Function lastLogin(PCDN)

	On Error Resume Next

	TrueLastLogin = ""

	Set DCs = GetObject("LDAP://OU=Domain Controllers," & DomainDN)

	For Each DC In DCs

		serverLastLogin = ""

		server = Right(dc.name,Len(dc.name)-3)

		Set PC = GetObject("LDAP://" & server & "/" & PCDN)

		serverLastLogin = usr.lastLogin

		If serverLastLogin <> "" Then

			If TrueLastLogin = "" Then 

				TrueLastLogin = serverLastLogin

			Elseif serverLastLogin > TrueLastLogin Then

				TrueLastLogin = serverLastLogin

			End If

		End If

	Next

	If TrueLastLogin = "" Then TrueLastLogin = "Never"

	lastLogin = TrueLastLogin

End Function

Open in new window

0
 
LVL 18

Expert Comment

by:exx1976
Comment Utility
Damn..   LOL!!

Make sure to change line 1 to be 120, not 16.  I changed it the first time I posted it, but it's still 16 in my source over here.   Pardon me, it's been a long morning, and I'm only on my second cup of coffee.

:-)
0
 

Expert Comment

by:RISLearner
Comment Utility
Excellent code and many thanks indeed - this is exactly what I have been looking for,  one point though... I believe that line 41 should read;
serverLastLogin = PC.lastLogin

Open in new window

0

Featured Post

Why You Should Analyze Threat Actor TTPs

After years of analyzing threat actor behavior, it’s become clear that at any given time there are specific tactics, techniques, and procedures (TTPs) that are particularly prevalent. By analyzing and understanding these TTPs, you can dramatically enhance your security program.

Join & Write a Comment

This article is the result of a quest to better understand Task Scheduler 2.0 and all the newer objects available in vbscript in this version over  the limited options we had scripting in Task Scheduler 1.0.  As I started my journey of knowledge I f…
Deploying a Microsoft Access application in a Citrix environment is not difficult but takes a few steps. However, Citrix system people are often of little help, as they typically know next to nothing about Access. The script provided here will take …
This tutorial will walk an individual through the steps necessary to join and promote the first Windows Server 2012 domain controller into an Active Directory environment running on Windows Server 2008. Determine the location of the FSMO roles by lo…
This tutorial will walk an individual through the process of configuring their Windows Server 2012 domain controller to synchronize its time with a trusted, external resource. Use Google, Bing, or other preferred search engine to locate trusted NTP …

728 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

11 Experts available now in Live!

Get 1:1 Help Now