'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ' Stale_Accounts.vbs ' ' Author Emmanuel Dreux ' email : edreux At ilinfo.fr ' http://www.ilinfo.fr/tools/Stale_Accounts.vbs.txt ' Last Modified: 2 Février 2009 ' ' Liste les comptes inactifs de l'AD. ' Sauvegarde dans un fichier ' Ignore comptes de services, comptes SSO, comptes admin et builtin ' List stale Accounts in Active Directory ' Save to file ' Ignore Service accounts, SSO accounts (utilisteurs de keytab) , admin accounts ' '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ' History: ' ' Version 1.0 : Initial Release. '---------------------------------------------------------------------------- ' Scripting constants '---------------------------------------------------------------------------- Option Explicit Const ADS_UF_ACCOUNTDISABLE = 2 ' Path to Log File Const strPathtoTextFile = "C:\temp" Const strLogFilePrefix = "StaleAccounts" Dim FSO Dim DateTimeStamp Dim strLogFile Dim oLogFile Dim logline Dim objHash ' Const Dictionnary Dim oConnection 'As ADODB.Connection Dim oCmd 'As ADODB.Command Dim oRecordset 'As ADODB.Recordset Dim strQuery 'As String Dim strFilter 'As String Dim intTFD Dim key Dim cInActiveAccounts 'Counter of objects found matching criteria Dim strDN Dim strfqdn Dim Environnement, strEnvironnement Dim ObjectTypes, strObjectTypes Dim strDescription, strLine Dim straccountname ,bMustlog, bMustskip Dim objDate Dim dtmDate, nowdate Dim lngBias, lngBiasKey,lngHigh,lngLow Dim objShell Dim objUser Dim strpwdlastchange Dim strPwdOld strEnvironnement = NULL strObjectTypes = NULL Main '---------------------------------------------------------------------------- ' Main '---------------------------------------------------------------------------- Sub Main() nowdate = Now ' Obtain local Time Zone bias from machine registry. Set objShell = CreateObject("Wscript.Shell") lngBiasKey = objShell.RegRead("HKLM\System\CurrentControlSet\Control\" _ & "TimeZoneInformation\ActiveTimeBias") If (UCase(TypeName(lngBiasKey)) = "LONG") Then lngBias = lngBiasKey ElseIf (UCase(TypeName(lngBiasKey)) = "VARIANT()") Then lngBias = 0 For k = 0 To UBound(lngBiasKey) lngBias = lngBias + (lngBiasKey(k) * 256^k) Next End If Set objShell = Nothing if (IsNull(strObjectTypes)) Then ObjectTypes = InputBox("Choisissez le type d'objets (User,Computer)", "Choix des objets","User") If ObjectTypes = "" Then MsgBox("Aucun objet sélectionné") WScript.Quit Else strObjectTypes = ObjectTypes End If End If Select case LCASE(strObjectTypes) case "user" strFilter = "(&(ObjectCategory=Person)(objectClass=user))" case "computer" strFilter = "(objectClass=computer)" end select ' Ouvre les fichiers de log Set FSO = CreateObject("scripting.filesystemobject") call GetDateTimeStamp() strLogFile = strLogFilePrefix + "_" + DateTimeStamp +".csv" Set oLogFile= FSO.CreateTextFile(strLogFile,TRUE) logline="Domain;Account Disabled;Last Logon;Inactive days;Password Last Set; Password Age;Display Name;User Name;Description" Call LogToFile(oLogFile,logline) Set objHash = CreateObject("Scripting.Dictionary") objHash.Add "ADS_UF_ACCOUNTDISABLE", ADS_UF_ACCOUNTDISABLE Call ProcessDomain("dc=mondomaine,dc=local","mondomaine.local",strObjectTypes) Call ProcessDomain("dc=child1,dc=mondomaine,dc=local","child1.mondomaine.local",strObjectTypes) Call ProcessDomain("dc=child2,dc=mondomaine,dc=local","child2.mondomaine.local",strObjectTypes) Set oRecordset = Nothing Set oConnection = Nothing WScript.Quit(0) End Sub '--------------------------------------------------------------------------------------------- ' Function ProcessDomain(strDN,strfqdn,ObjectTypes) ' ' Process Domain '--------------------------------------------------------------------------------------------- Function ProcessDomain(strDN,strfqdn,ObjectTypes) ' RAZ des compteurs cInactiveAccounts = 0 bMustlog = 0 bMustskip = 0 ' Set up the ADO Connection Set oConnection = CreateObject("ADODB.Connection") Set oCmd = CreateObject("ADODB.Command") oConnection.Provider = "ADSDsOObject" oConnection.Open "ADs Provider" oCmd.ActiveConnection = oConnection ' Set the page size to the default server limit oCmd.Properties("Page Size") = 1000 ' Use the filter and return the operating system information strQuery = ";" & strFilter & ";Description,samAccountName,name,userAccountControl,ADsPath,lastlogontimestamp;subtree" ' Execute the query and loop through the result set oCmd.CommandText = strQuery Set oRecordset = oCmd.Execute While Not oRecordset.EOF strDescription = "" logline = UCASE(strfqdn) straccountname = LCASE(oRecordset.Fields("samAccountName").Value) if ( LCASE(ObjectTypes) ="user") Then 'Ignore service accounts if ( Instr(1,straccountname, "svc", 1) > 0) Then bMustskip = 1 WScript.Echo straccountname & " skipped" End If 'Ignore SSO accounts if ( Instr(1,straccountname, "sso", 1) > 0) Then bMustskip = 1 WScript.Echo straccountname & " skipped" End if 'Ignore builtin admin accounts if ( Instr(1,straccountname, "adm", 1) > 0) Then bMustskip = 1 WScript.Echo straccountname & " skipped" End If 'Ignore builtin admin accounts if ( Instr(1,straccountname, "krbtgt", 1) > 0) Then bMustskip = 1 WScript.Echo straccountname & " skipped" End If 'Ignore admin accounts if ( Instr(1,straccountname, "ENT", 1) > 0) Then bMustskip = 1 WScript.Echo straccountname & " skipped" End If 'Ignore trusts if ( Instr(1,straccountname, "$", 1) > 0) Then bMustskip = 1 WScript.Echo straccountname & " skipped" End If 'Ignore generic accounts if ( Instr(1,straccountname, "generiq", 1) > 0) Then bMustskip = 1 WScript.Echo straccountname & " skipped" End If if ( Instr(1,straccountname, "guest", 1) > 0) Then bMustskip = 1 WScript.Echo straccountname & " skipped" End If if ( Instr(1,straccountname, "invité", 1) > 0) Then bMustskip = 1 WScript.Echo straccountname & " skipped" End If End if if ( bMustskip = 0 ) Then intTFD = oRecordset.Fields("userAccountControl") On Error Resume Next Set objDate = oRecordset.Fields("lastLogonTimeStamp").Value If (Err.Number <> 0) Then On Error GoTo 0 dtmDate = #1/1/1601# Else On Error GoTo 0 lngHigh = objDate.HighPart lngLow = objDate.LowPart If (lngLow < 0) Then lngHigh = lngHigh + 1 End If If (lngHigh = 0) And (lngLow = 0 ) Then dtmDate = #1/1/1601# Else dtmDate = #1/1/1601# + (((lngHigh * (2 ^ 32)) _ + lngLow)/600000000 - lngBias)/1440 End If End If For Each Key In objHash.Keys If objHash(Key) And intTFD Then logline = logline & ";" & "VRAI" Else logline = logline & ";" & "FAUX" end if next If (dtmDate = #1/1/1601#) Then logline = logline & ";" & "Never;;" Else logline = logline & ";" & dtmDate & ";" & DateDiff("d",dtmDate,nowdate) End If ' Password Last Change On Error Resume Next Set objUser = GetObject(oRecordset.Fields("ADsPath")) strpwdlastchange = objUser.PasswordLastChanged If Err.Number = 0 Then strPwdOld = DateDiff("d",strpwdlastchange ,nowdate) logline = logline & ";" & strpwdlastchange & ";" & strPwdOld Else logline = logline & ";" & "Never"& ";;" End If logline = logline & ";" & oRecordset.Fields("name") & ";" & oRecordset.Fields("samAccountName") if Not IsNull(oRecordset.Fields("description").Value) Then For Each strLine in oRecordset.Fields("description").Value strDescription = strDescription & strLine Next end if logline = logline & ";" & strDescription Call LogToFile(oLogFile,logline) end if bMustLog =0 bMustskip = 0 oRecordset.MoveNext Wend WScript.Echo WScript.Echo "Domaine : " & strfqdn WScript.Echo "Total Number of objects found: " & oRecordset.RecordCount WScript.Echo "Total Number of stale accounts: " & cInactiveAccounts End Function '--------------------------------------------------------------------------------------------- ' Function LogToFile(ofile,strline) ' ' Log entry to file specified in input '--------------------------------------------------------------------------------------------- Function LogToFile(ofile, strline) ofile.WriteLine strline End Function '--------------------------------------------------------------------------------------------- ' Function: GetDateTimeStamp ' This function is responsible for getting the unique Date / Time stamp used for ' creating unique directory / file names. '--------------------------------------------------------------------------------------------- Function GetDateTimeStamp() On Error Resume Next Dim Seconds Dim Minutes Dim Hours Dim theDay Dim theMonth Hours = Hour(Now) Minutes = Minute(Now) Seconds = Second(Now) theDay = Day(Now) theMonth = Month(Now) If Len(Hours) = 1 Then Hours = "0" & Hours If Len(Minutes) = 1 Then Minutes = "0" & Minutes If Len(Seconds) = 1 Then Seconds = "0" & Seconds If Len(theDay) = 1 Then theDay = "0" & theDay If Len(theMonth) = 1 Then theMonth = "0" & theMonth DateTimeStamp = theMonth & "-" & theDay & "-" & Year(Now) & "_" & Hours & "-" & Minutes & "-" & Seconds End Function