RE: Scavanging retired machine accounts
From: Ron Rosenkoetter (RonRosenkoetter_at_discussions.microsoft.com)
Date: 08/06/04
- Next message: Carlos: "Re: Using the script"
- Previous message: Ron Rosenkoetter: "Re: remote system information"
- In reply to: Rully Kusuma: "Scavanging retired machine accounts"
- Messages sorted by: [ date ] [ thread ]
Date: Fri, 6 Aug 2004 14:37:02 -0700
Here's a script I wrote a while back that does exactly what you want.
On Error Resume Next
'Set Log File Name
LogFileName = "c:\CheckComputerAccountsInAD.log"
'Set File Constants
Const ForReading = 1
Const ForWriting = 2
Const ForAppending = 8
'Setting the Arguments
Set objArgs = Wscript.Arguments
If ObjArgs.Count > 0 Then
Arg1 = objArgs(0)
Else
wscript.echo "Please specify all required arguments. Run this script
again "
wscript.echo "with a /? as the first argument to see the help file"
Wscript.Quit
End If
'Checking if Help file is needed
HELP = 0
If Arg1 = "help" Then HELP = 1
If Arg1 = "/?" Then HELP = 1
If Arg1 = "?" Then HELP = 1
' Doubles as Help document and Purpose of script REMARKS
If HELP = 1 then
wscript.echo " ******************************"
wscript.echo " * Script: CheckComputerAccountsInAD.vbs"
wscript.echo " * Creation Date: 5-7-2003"
wscript.echo " * Date Last Modified: 2-12-2004"
wscript.echo " * Author: Ron Rosenkoetter"
wscript.echo " * E-mail: Ronald.Rosenkoetter@gentiva.com"
wscript.echo " *"
wscript.echo " * Description: This script will query the specified"
wscript.echo " * domain (will default to the current domain if none"
wscript.echo " * is specified), looking for computer accounts that"
wscript.echo " * haven't been modified in the specified number of
months"
wscript.echo " * or weeks (will default to 3 months if none is
specified)"
wscript.echo " * This script will either list, disable, or move these"
wscript.echo " * accounts depending on which option is chosen"
wscript.echo " *"
wscript.echo " * Note: Computer accounts change their passwords every
30 days"
wscript.echo " * After 60 days, the computer account will not be able "
wscript.echo " * to authenticate on the domain until its password is
reset"
wscript.echo " *"
wscript.echo " * Limitations: "
wscript.echo " * List: This script will only list disabled computers"
wscript.echo " * if weeks are chosen as a timeframe. "
wscript.echo " * Disable: This script will not disable a computer
account"
wscript.echo " * based on weeks inactive. An account must be
inactive"
wscript.echo " * for at least 2 months before this script will
disable it"
wscript.echo " * Move: This script will move an account to the
DeletePending OU"
wscript.echo " * (It will created it if it doesn't already exist)
based on the "
wscript.echo " * number of weeks or months the computer has been
DISABLED."
wscript.echo " * This script will not move a computer account that
isn't"
wscript.echo " * already disabled."
wscript.echo " *"
wscript.echo " * Usage: CheckComputerAccountsInAD.vbs [options]"
wscript.echo " *"
wscript.echo " * /l: List"
wscript.echo " * /ds: Disable"
wscript.echo " * /move: Move (This script will only move disabled
computers)"
wscript.echo " * [one of these is required]"
wscript.echo " *"
wscript.echo " * /d: Domain (ADsPath form)"
wscript.echo " * [defaults to current domain]"
wscript.echo " * /m: Number of Months of inactivity to check for"
wscript.echo " * /w: Number of Weeks of inactivity to check for"
wscript.echo " * [defaults to 3 months]"
wscript.echo " *"
wscript.echo " * Example: CheckComputerAccountsInAD.vbs /l:"
wscript.echo " * This will list all computers in the current domain"
wscript.echo " * that haven't been modified in 3 months"
wscript.echo " *"
wscript.echo " * Example: CheckComputerAccountsInAD.vbs /m:4 /ds:"
wscript.echo " * This will disable all computers in the current domain"
wscript.echo " * that haven't been modified in 4 months"
wscript.echo " *"
wscript.echo " * Example: CheckComputerAccountsInAD.vbs /w:2 /move:"
wscript.echo " * This will move all computers in the current domain"
wscript.echo " * that have been DISABLED for 2 weeks to the
DeletePending OU"
wscript.echo " *"
wscript.echo " ******************************"
Wscript.Quit
End If
'Make sure required options are specified
If (NOT Wscript.Arguments.Named.Exists("l")) and (NOT
Wscript.Arguments.Named.Exists("ds")) _
and (NOT Wscript.Arguments.Named.Exists("move")) Then
wscript.echo "Please specify all required arguments. Run this script
again "
wscript.echo "with a /? as the first argument to see the help file"
Wscript.Quit
End If
'Set Option Variables
Domain = Wscript.Arguments.Named("d")
MonthsSpecified = CInt(Wscript.Arguments.Named("m"))
WeeksSpecified = CInt(Wscript.Arguments.Named("w"))
'Create the File System Object
Set objFSO = CreateObject("Scripting.FileSystemObject")
'Open a log file for printing results
Wscript.Echo "Opening Log File"
Set LogFile = objFSO.OpenTextFile(LogFileName,ForWriting,True)
If Err.Number <> 0 then
Wscript.Echo "Unable to open the " & LogFileName
Wscript.Quit
End If
'Dimension Array Variables
Dim arrUserList()
'Set Number of Months if not specified
If (NOT Wscript.Arguments.Named.Exists("m")) AND (NOT
Wscript.Arguments.Named.Exists("w")) Then
MonthsSpecified = 3
End If
'Get Domain name if not specified
If NOT Wscript.Arguments.Named.Exists("d") Then
Set RootDSE = GetObject("LDAP://rootDSE")
Domain = RootDSE.Get("DefaultNamingContext")
End If
'Searching Active Directory
'Create the Connection object and open it
Set objConnection = CreateObject("ADODB.Connection")
objConnection.Open "Provider=ADsDSOObject;"
'Create the Command object and set its ActiveConnection to the Connection
object
Set objCommand = CreateObject("ADODB.Command")
objCommand.ActiveConnection = objConnection
'Set the CommandText property of the Command object. Start at the domain
level, and
'pull back a list of every user's account name and distinguished name
objCommand.CommandText = _
"<LDAP://" & Domain & ">;(objectCategory=Computer);" & _
"Name,ADsPath,DistinguishedName,whenChanged;subtree"
'To search for more than 1000 records, add the following line. This will
return ALL objects
'in the search.
objCommand.Properties("Page Size") = 1000
'Sort by name
objCommand.Properties("Sort On") = "whenChanged"
'Execute the Command and place the results in the RecordSet object
Message "Retrieving a list of all computer accounts in " & Domain
Set objRecordSet = objCommand.Execute
CheckForErrorQuit
Message vbCrLf
'Check to see which action the script should perform (List, Disable, Delete)
'***************
'List PCs that match the criteria
If (Wscript.Arguments.Named.Exists("l")) AND (NOT
Wscript.Arguments.Named.Exists("ds")) _
AND (NOT Wscript.Arguments.Named.Exists("move")) Then
'Check to see if we're working with weeks or months
If Wscript.Arguments.Named.Exists("w") Then
ListComputers WeeksSpecified, "w", "weeks"
Else
ListComputers MonthsSpecified, "m", "months"
End If
End If
'Subrountine ListComputers
Sub ListComputers (TimeSpecified, TimeCheck, TimePeriod)
'Loop through the RecordSet and compare the dates
Do Until objRecordSet.EOF
DateDifference =
DateDiff(TimeCheck,objRecordSet.Fields("whenChanged"), Now)
'If the computer account has not been modified in several months, then it has
'been off-line or disabled all that time (Computer accounts change their
'passwords every 30 days)
If DateDifference >= TimeSpecified Then
'Object has not modified in the time period specified. Check to see if it's
disabled
'or just hasn't checked in"
Set objComp = GetObject(objRecordSet.Fields("ADsPath"))
If objComp.UserAccountControl AND 2 Then
Message objRecordSet.Fields("name") & " has been disabled for
" & _
DateDifference & " " & TimePeriod
DisabledCount = DisabledCount + 1
Else
'How long a computer has been off-line (not updated its password) is really
only
'relevant when talking about months. If we're using a number of weeks as a
'comparison, we're probably only interested in the disabled computer accounts
If TimeCheck = "m" Then
Message objRecordSet.Fields("name") & " has not updated " & _
"its password in " & DateDifference & " " & TimePeriod
OfflineCount = OfflineCount + 1
End If
End If
End If
objRecordSet.MoveNext
Loop
Message vbCrLf
Message "Number of PCs that have been disabled for " & _
TimeSpecified & " " & TimePeriod & ": " & DisabledCount
If TimeCheck = "m" Then
Message "Number of PCs that have been off-line for " & _
TimeSpecified & " " & TimePeriod & ": " & OfflineCount
End If
objRecordSet.MoveFirst
DisabledCount = 0
OffLineCount = 0
End Sub
'***************
'****************
'Disable PCs that match criteria
If Wscript.Arguments.Named.Exists("ds") Then
'There is no point disabling PCs based on how many weeks it's been since the
'computer changed its password. This is something that should be set at the
'month time period (2 at the very least, 3 is better as a minimum)
If Wscript.Arguments.Named.Exists("w") Then
Message "Disabling Computers based on weeks is not supported"
QuitProgram
End If
If MonthsSpecified < 2 Then
Message "Disabling Computers for less than 2 months of inactivity is
not supported"
QuitProgram
End If
'Loop through the RecordSet and compare the dates
Do Until objRecordSet.EOF
NumberOfMonths = DateDiff("m",objRecordSet.Fields("whenChanged"), Now)
'If the computer account has not been modified in several months, then it has
'been off-line all the time (Computer accounts change their passwords every
30 days)
If NumberOfMonths >= MonthsSpecified Then
Set objComp = GetObject(objRecordSet.Fields("ADsPath"))
Select Case DisableComputerAccount (objComp)
Case 0
Message "Disabled " & objRecordSet.Fields("DistinguishedName")
Message " Password has not been updated in " & NumberofMonths
& _
" months" & vbCrlf
Count = Count + 1
Case 1
Message "Unable to disable " &
objRecordSet.Fields("DistinguishedName") & " <------"
Message " Password has not been updated in " & NumberofMonths
& _
" months" & vbCrlf
Case 2
Message objRecordSet.Fields("DistinguishedName") & " already
disabled"
End Select
End If
objRecordSet.MoveNext
Loop
Message "Number of PCs that have been disabled: " & Count
objRecordSet.MoveFirst
Count = 0
End If
'***************
'****************
'Move PCs that match criteria
If Wscript.Arguments.Named.Exists("move") Then
'Check to see if we're working with weeks or months
If Wscript.Arguments.Named.Exists("w") Then
DeleteComputers WeeksSpecified, "w", "weeks"
Else
DeleteComputers MonthsSpecified, "m", "months"
End If
End If
'Subrountine DeleteComputers
Sub DeleteComputers (TimeSpecified, TimeCheck, TimePeriod)
'Make sure that deletion is desired
Wscript.Echo "Are you SURE you want to move all computers that have been
disabled"
Wscript.Echo "for more than " & TimeSpecified & " " & TimePeriod & "?"
Wscript.StdOut.Write "Enter Yes if you do, anything else to cancel: "
Input = Wscript.StdIn.ReadLine
If ucase(Input) = "YES" Then
'Create (if it doesn't already exist), a DeletePending OU
Set objDomain = GetObject("LDAP://" & Domain)
Select Case CreateOU(objDomain,"DeletePending", _
"An OU that holds disabled computers before they are deleted")
Case 0
Message vbCrLf & "Created DeletePending OU"
Case 2
'Already exists, do nothing
Case Else
Message vbCrLf & "Unable to create DeletePending OU"
QuitProgram
End Select
'Loop through the RecordSet and compare the dates
Do Until objRecordSet.EOF
DateDifference =
DateDiff(TimeCheck,objRecordSet.Fields("whenChanged"), Now)
'If the computer account has not been modified in several months, then it has
'been off-line all the time (Computer accounts change their passwords every
30 days)
If DateDifference >= TimeSpecified Then
Set objComp = GetObject(objRecordSet.Fields("ADsPath"))
'Check to see if Computer account is disabled. This script will not delete any
'computer accounts that are enabled.
If objComp.UserAccountControl AND 2 Then
Select Case MoveAccountToOU("OU=DeletePending," & Domain,objComp)
Case 0
Message "Moved " & objRecordSet.Fields("DistinguishedName")
& vbCrLf
Count = Count + 1
Case Else
Message "Unable to move " &
objRecordSet.Fields("DistinguishedName") & " <------" & _
vbCrLf
End Select
End If
End If
objRecordSet.MoveNext
Loop
Message "Number of PCs that have been moved to the DeletePending OU: "
& Count
objRecordSet.MoveFirst
Count = 0
Else
QuitProgram
End If
End Sub
'***************
QuitProgram
'#############################
'Function DisableComputerAccount
'Variables
'objComputerName - object referencing the ComputerName
'Returns
'0 if account is disabled successfully
'1 if function was unable to disable the account
'2 if account was already disabled.
Function DisableComputerAccount(objComputerName)
On Error Resume Next
'Create a Shell object in order to retrieve the username of the user
'running this script.
Set objWS = WScript.CreateObject("WScript.Shell")
'Access Environment variables using ExpandEnvironmentStrings()
UserName = objWS.ExpandEnvironmentStrings("%USERNAME%")
'UserAccountControl returns a bitmask that references many user account
'settings
UAC = objComputerName.userAccountControl
'2 (0010) is the bit that is set to indicate a disabled account
If UAC AND 2 Then
DisableComputerAccount = 2 'already disabled
Else
'Set the (0010) bit in order to disable the account
objComputerName.Put "userAccountControl", UAC OR 2
objComputerName.Put "Description", "Disabled by " & UserName & " on "
& Date
objComputerName.SetInfo
If Err.Number = 0 Then
DisableComputerAccount = 0
Else
DisableComputerAccount = 1
Err.Clear
End If
End If
End Function
'#############################
'#############################
'Function MoveAccountToOU
'Variables
'OUDN = Distinugished Name Path (i.e. OU=OUName,DC=domain,DC=com)
'objAccountName (User object or Computer object)
'Returns
'0 if account is moved to the specified OU successfully
'1 if function is unable to move the account to the specified OU
Function MoveAccountToOU(OUDN,objAccountName)
Set objOU = GetObject("LDAP://" & OUDN)
objOU.MoveHere objAccountName.ADsPath, "cn=" & objAccountName.cn
If Err.Number = 0 Then
MoveAccountToOU = 0
Else
MoveAccountToOU = 1
Err.Clear
End If
End Function
'#############################
'#############################
'Function CreateOU
'Variables
'objParent - Parent Object (Domain or another OU)
'OUName
'OUDescription
'Returns
'0 if the OU is created successfully
'1 if function is unable to create the OU
'2 if the OU already exists.
Function CreateOU(objParent,OUName,OUDescription)
'Check to see if the OU already exists
For Each OU in objParent
If ucase(OU.name) = ucase("OU=" & OUName) Then
CreateOU = 2
NoMatch = 1
End If
Next
If NoMatch <> 1 Then
Set NewOU = objParent.Create("organizationalUnit", "OU=" & OUName)
NewOU.Description = OUDescription
NewOU.SetInfo
If Err.Number = 0 Then
CreateOU = 0
Else
CreateOU = 1
Err.Clear
End If
End If
End Function
'#############################
'#############################
'Function CheckForErrorQuit
Function CheckForErrorQuit()
If Err.Number <> 0 then
Message "Error #" & Err.Number & " - " & Err.Description
CheckForErrorQuit = Err.Description
QuitProgram
End If
End Function
'#############################
'Function CheckForErrorClear
Function CheckForErrorClear()
If Err.Number <> 0 then
Message "Error # " & Err.Number & " - " & Err.Description
CheckForErrorClear = Err.Description
Err.Clear
End If
End Function
'#############################
'Subroutine Message
Sub Message (Text)
Wscript.Echo Text
LogFile.WriteLine Text
End Sub
'#############################
'Subrountine QuitProgram
Sub QuitProgram
LogFile.Close
Wscript.Echo " "
Wscript.Echo "****************************************************"
Wscript.Echo "* Use notepad " & LogFileName & " to see a log of these
results"
Wscript.Echo "****************************************************"
Wscript.Quit
End Sub
'############################
"Rully Kusuma" wrote:
> Is there any scripts that would scavange retired machine accounts based on
> their last contact with active directory?
>
> Thank you in advance.
>
>
>
- Next message: Carlos: "Re: Using the script"
- Previous message: Ron Rosenkoetter: "Re: remote system information"
- In reply to: Rully Kusuma: "Scavanging retired machine accounts"
- Messages sorted by: [ date ] [ thread ]
Relevant Pages
|