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,338 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
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
6 Comments
 
LVL 3

Assisted Solution

by:DrunkenELF
DrunkenELF earned 100 total points
ID: 22710064
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
ID: 22710380
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
ID: 22731851
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
Efficient way to get backups off site to Azure

This user guide provides instructions on how to deploy and configure both a StoneFly Scale Out NAS Enterprise Cloud Drive virtual machine and Veeam Cloud Connect in the Microsoft Azure Cloud.

 
LVL 18

Accepted Solution

by:
exx1976 earned 400 total points
ID: 22731880
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
ID: 22731904
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
ID: 22905475
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

Free learning courses: Active Directory Deep Dive

Get a firm grasp on your IT environment when you learn Active Directory best practices with Veeam! Watch all, or choose any amount, of this three-part webinar series to improve your skills. From the basics to virtualization and backup, we got you covered.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

This article outlines the process to identify and resolve account lockout in an Active Directory environment.
With User Account Control (UAC) enabled in Windows 7, one needs to open an elevated Command Prompt in order to run scripts under administrative privileges. Although the elevated Command Prompt accomplishes the task, the question How to run as script…
This tutorial will walk an individual through the process of transferring the five major, necessary Active Directory Roles, commonly referred to as the FSMO roles to another domain controller. Log onto the new domain controller with a user account t…
This video shows how to use Hyena, from SystemTools Software, to update 100 user accounts from an external text file. View in 1080p for best video quality.

739 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