1. 程式人生 > >如何批量統計AD賬戶最後一次登入時間

如何批量統計AD賬戶最後一次登入時間

在許多IT企業由於管理不善,AD使用者賬號出現大量過期或不在使用中的賬戶,如何有效匯出這些使用者賬戶最後一次登入時間,經過IT部確認之後再刪除這些使用者,而不是直接刪除XX天前未登入的使用者(比如有些賬戶不一定需要登入,但卻非常重要,比如一些郵箱賬戶或資源賬戶),微軟提供了CSDEV工具,這個工具可以匯出使用者屬性的Lastlogon,但是匯出的結果有一個問題,是一串的數字,需要經過多次轉換才能變成相應的日期和時間(轉換方法可以參考:http://www.mcse.org.cn/showtopic-6953.html),有沒有更好的辦法,當然有,而且還不少,比較利用工具truelastlogon,reallastlogon,oldcmp,除此之外還有更好的方法就是VBS指令碼,下面以一個叫lastlogon.vbs

指令碼為例,內容如下:

Option Explicit

Dim objRootDSE, strConfig, adoConnection, adoCommand, strQuery

Dim adoRecordset, objDC

Dim strDNSDomain, objShell, lngBiasKey, lngBias, k, arrstrDCs()

Dim strDN, dtmDate, objDate, objList, strUser

Dim strBase, strFilter, strAttributes, lngHigh, lngLow

' Use a dictionary object to track latest lastLogon for each user.

Set objList = CreateObject("Scripting.Dictionary")

objList.CompareMode = vbTextCompare

' Obtain local Time Zone bias from machine registry.

' This bias changes with Daylight Savings Time.

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

' Determine configuration context and DNS domain from RootDSE object.

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

strConfig = objRootDSE.Get("configurationNamingContext")

strDNSDomain = objRootDSE.Get("defaultNamingContext")

' Use ADO to search Active Directory for ObjectClass nTDSDSA.

' This will identify all Domain Controllers.

Set adoCommand = CreateObject("ADODB.Command")

Set adoConnection = CreateObject("ADODB.Connection")

adoConnection.Provider = "ADsDSOObject"

adoConnection.Open "Active Directory Provider"

adoCommand.ActiveConnection = adoConnection

strBase = "<LDAP://" & strConfig & ">"

strFilter = "(objectClass=nTDSDSA)"

strAttributes = "AdsPath"

strQuery = strBase & ";" & strFilter & ";" & strAttributes & ";subtree"

adoCommand.CommandText = strQuery

adoCommand.Properties("Page Size") = 100

adoCommand.Properties("Timeout") = 60

adoCommand.Properties("Cache Results") = False

Set adoRecordset = adoCommand.Execute

' Enumerate parent objects of class nTDSDSA. Save Domain Controller

' AdsPaths in dynamic array arrstrDCs.

k = 0

Do Until adoRecordset.EOF

    Set objDC = _

        GetObject(GetObject(adoRecordset.Fields("AdsPath").Value).Parent)

    ReDim Preserve arrstrDCs(k)

    arrstrDCs(k) = objDC.DNSHostName

    k = k + 1

    adoRecordset.MoveNext

Loop

adoRecordset.Close

' Retrieve lastLogon attribute for each user on each Domain Controller.

For k = 0 To Ubound(arrstrDCs)

    strBase = "<LDAP://" & arrstrDCs(k) & "/" & strDNSDomain & ">"

    strFilter = "(&(objectCategory=person)(objectClass=user))"

    strAttributes = "distinguishedName,lastLogon"

    strQuery = strBase & ";" & strFilter & ";" & strAttributes _

        & ";subtree"

    adoCommand.CommandText = strQuery

    On Error Resume Next

    Set adoRecordset = adoCommand.Execute

    If (Err.Number <> 0) Then

        On Error GoTo 0

        Wscript.Echo "Domain Controller not available: " & arrstrDCs(k)

    Else

        On Error GoTo 0

        Do Until adoRecordset.EOF

            strDN = adoRecordset.Fields("distinguishedName").Value

            On Error Resume Next

            Set objDate = adoRecordset.Fields("lastLogon").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

            If (objList.Exists(strDN) = True) Then

                If (dtmDate > objList(strDN)) Then

                    objList.Item(strDN) = dtmDate

                End If

            Else

                objList.Add strDN, dtmDate

            End If

            adoRecordset.MoveNext

        Loop

        adoRecordset.Close

    End If

Next

' Output latest lastLogon date for each user.

For Each strUser In objList.Keys

    If (objList.Item(strUser) = #1/1/1601#) Then

        Wscript.Echo strUser & ";Never"

    Else

        Wscript.Echo strUser & ";" & objList.Item(strUser)

    End If

Next

' Clean up.

adoConnection.Close

這個指令碼我們不要直接執行,否則我們只能看到螢幕多次彈出每個使用者最後一次登入時間,我們把這個結果重定向到一個檔案中去,執行下面步驟:

C:\>cscript lastlogon.vbs>lastlogon.csv

執行完畢生成一個CSV檔案,開啟此檔案,可以看到最後1次登入時間,個人測試的結果文件內容如下:

 從上圖很容易看出最後一次登入時間,有些使用者從來沒有登入也會顯示在上面。(如果想把最後一次登入時間作為獨立一列分離出來,用Excel也非常容易實現,在此不再強調。)