IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    [原]如何批量统计AD账户最后一次登录时间

    xuhuojun发表于 2011-09-23 02:00:06
    love 0

    在许多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也非常容易实现,在此不再强调。)



沪ICP备19023445号-2号
友情链接