Automated removal of expired machines in Active Directory

Posted on 2009-07-02
Last Modified: 2013-12-05
I'm looking for a way to automate the removal of expired machines (not logged in > 90 days) to help with asset management.
Question by:Al Caholic
LVL 13

Accepted Solution

Brum07 earned 125 total points
ID: 24763426
LVL 38

Assisted Solution

Shift-3 earned 125 total points
ID: 24763445
If your domain is at the 2003 functional level or higher then you can find inactive computers using the command
dsquery computer -inactive <number of weeks>

Run this from a 2003 server or an XP machine with the adminpak installed.

You could pipe the output of this command to dsrm to delete the accounts, but do so with extreme caution.
LVL 57

Assisted Solution

by:Mike Kline
Mike Kline earned 125 total points
ID: 24763534
I really like old computer by MVP Joe Richards for this
Very nice reports that managment likes too.  
start with
oldcmp -report

LVL 12

Expert Comment

ID: 24763610
I've written vbscripts to query the last logon date of a computer's object (depending on the forest and domain operational level, you might have to query each domain controller or if you are running at 2003 native then you can query AD directly) and then based on the results you can delete the objects that are old - or move them to an expired OU and then delete them once they are really old. It's up to you.

The code for getting last logon is somewhat complex, but I will attach it shortly in a subsequent post.

Deleting the object from AD via vbscript is pretty easy:

strComputer = "atl-pro-040"

set objComputer = GetObject("LDAP://CN=" & strComputer & ",CN=Computers,DC=fabrikam,DC=com")

objComputer.DeleteObject (0)

Open in new window

LVL 12

Assisted Solution

mlongoh earned 125 total points
ID: 24763836
Here's a script that will poll each DC in the domain and determine the most recent last logon date of the computer and output that and whether the computer is enabed or disabled. It expects you to enter the computer name as a command line argument when running the script. You can use pieces of this script and the other small snippet I posted for deleting objects to create one that does the job you want.

On Error Resume Next


strPath = left(wscript.ScriptFullName, len(wscript.ScriptFullName) - len(wscript.ScriptName))

strDom = "fabrikam"


'Find DN

strNTName = strDOM & "\" & wscript.arguments(0) & "$"



Const ADS_NAME_TYPE_1779 = 1

Set objTrans = CreateObject("NameTranslate")

objTrans.Init ADS_NAME_INITTYPE_GC, ""

objTrans.Set ADS_NAME_TYPE_NT4, strNTName

' Use the Get method to retrieve the RPC 1779 Distinguished Name.

strPCDN = objTrans.Get(ADS_NAME_TYPE_1779)

strPCDN = Replace(strPCDN, "/", "\/")

wscript.echo strPCDN

LastLog = #1/1/1601#

'Get TimeZone offsets

strComputer = "."

Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")

Set colTimeZones = objWMIService.ExecQuery("Select * From Win32_TimeZone")

For Each objTimeZone in colTimeZones

intTimeZoneBias = objTimeZone.Bias

intDaylightBias = objTimeZone.DaylightBias


Set objRootDSE = GetObject("LDAP://RootDSE")

strConfigurationNC = objRootDSE.Get("configurationNamingContext")

Set objConnection = CreateObject("ADODB.Connection")

Set objCommand = CreateObject("ADODB.Command")

objConnection.Provider = "ADsDSOObject"

objConnection.Open "Active Directory Provider"

Set objCommand.ActiveConnection = objConnection

objCommand.Properties("Page Size") = 1000

objCommand.Properties("Searchscope") = ADS_SCOPE_SUBTREE 

objCommand.CommandText = _

"SELECT ADsPath FROM 'LDAP://" & strConfigurationNC & "' WHERE objectClass='nTDSDSA'" 

Set objRecordSet = objCommand.Execute


'Get lastlogon from each DC and find newest

Do Until objRecordSet.EOF

Set objParent = GetObject(GetObject(objRecordset.Fields("ADsPath")).Parent)

strDCName = objParent.dnsHostName

Set objUser = GetObject _

("LDAP://" & strDCName & "/" & strPCDN)

Set objLastLogon = objUser.Get("lastLogon")

Set objLastLogonTS = objUser.Get("lastLogonTimestamp")

intLastLogonTime = objLastLogon.HighPart * (2^32) + objLastLogon.LowPart 

intLastLogonTime = intLastLogonTime / (60 * 10000000)

intLastLogonTime = intLastLogonTime / 1440

dtmLastLogon = intLastLogonTime + #1/1/1601#

dtmLastLogon = DateAdd("n", intTimeZoneBias, dtmLastLogon)

dtmLastLogon = DateAdd("n", intDaylightBias, dtmLastLogon)

intLastLogonTimeTS = objLastLogonTS.HighPart * (2^32) + objLastLogonTS.LowPart 

intLastLogonTimeTS = intLastLogonTimeTS / (60 * 10000000)

intLastLogonTimeTS = intLastLogonTimeTS / 1440

dtmLastLogonTS = intLastLogonTimeTS + #1/1/1601#

dtmLastLogonTS = DateAdd("n", intTimeZoneBias, dtmLastLogonTS)

dtmLastLogonTS = DateAdd("n", intDaylightBias, dtmLastLogonTS)

wscript.echo " " & strDCName & " reports " & dtmLastLogon & " as last logon"

wscript.echo " " & strDCName & " reports " & dtmLastLogonTS & " as last logonTimeStamp"

If dtmLastLogonTS > dtmLastLogon Then dtmLastLogon = dtmLastLogonTS

If dtmLastLogon > LastLog Then

LastLog = dtmLastLogon

End If



wscript.echo "Final choice = " & LastLog

If Instr(LastLog, " ") > 0 Then

LLArray=Split(LastLog, " ")


End If



AccountStatus = "disabled"


AccountStatus = "enabled"

End If

wscript.echo wscript.arguments(0) & ";" & strPCDN & ";" & LastLog & ";" & AccountStatus



Function IsAccountDisabled( strDomain, strAccount )

Dim objUser

Set objUser = GetObject("WinNT://" & strDomain & "/" & strAccount & ",user")

IsAccountDisabled = objUser.AccountDisabled

End Function 

Open in new window


Featured Post

PRTG Network Monitor: Intuitive Network Monitoring

Network Monitoring is essential to ensure that computer systems and network devices are running. Use PRTG to monitor LANs, servers, websites, applications and devices, bandwidth, virtual environments, remote systems, IoT, and many more. PRTG is easy to set up & use.

Question has a verified solution.

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

Mapping Drives using Group policy preferences Are you still using old scripts to map your network drives if so this article will show you how to get away for old scripts and move toward Group Policy Preference for mapping them. First things f…
ADCs have gained traction within the last decade, largely due to increased demand for legacy load balancing appliances to handle more advanced application delivery requirements and improve application performance.
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 …

911 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

21 Experts available now in Live!

Get 1:1 Help Now