IanN1990

Active Directory - Cant find expired users

24 posts in this topic

#1 ·  Posted (edited)

Good Evening, 

Last AD question for now :)

I am pulling down alot of information from ad using the following ;

#include <AD.au3>
#include <array.au3>

sOU = _AD_Open()

$Results = _AD_GetObjectsInOU($sOU, "(name=*)", 2, "name,accountexpires")
_Arraydisplay($Results)

_AD_Close()

It pulls down all the names in colum one but colum 2 is empty

If i did

$Result = _AD_GetObjectProperties("ian.1990,"accountexpires")
_ArrayDisplay($Result)

It would bring down when my account expires

 

*Note i am trying to avoid using the function _GetExpiredAccounts as i want to understand why GetObjectsinOU is not working

 

Kind regards

Ian

Edited by IanN1990

Share this post


Link to post
Share on other sites



You get the expiration date by _AD_GetObjectsInOU but in a format you can't read. So I suggest to use function _AD__GetAccountsExpired.


My UDFs and Tutorials:

Spoiler

UDFs:
Active Directory (NEW 2017-02-03 - Version 1.4.7.0) - Download - General Help & Support - Example Scripts - Wiki
OutlookEX (NEW 2017-02-03 - Version 1.2.4.0) - Download - General Help & Support - Example Scripts - Wiki
ExcelChart (2015-04-01 - Version 0.4.0.0) - Download - General Help & Support - Example Scripts
Excel - Example Scripts - Wiki
Word - Wiki
Tutorials:
ADO - Wiki

 

Share this post


Link to post
Share on other sites

#3 ·  Posted (edited)

So is it the case that colum 2 is not empty and has pulled down the expiry date but because of the format it is not being displayed?

Does that also mean in theory i could do something like

consolewrite(ConvertExpiretoReadable($Results[1][1]))

  Func ConvertExpiretoReadable($ArrayExpireResult)
    Something...
    Something..
    Return $Expire
  Endfunc

 

Edited by IanN1990

Share this post


Link to post
Share on other sites

Correct.
Check function _AD_GetObjectsInOU to see how it translates property "accountexpires". But be warned: It's a bit complex :)


My UDFs and Tutorials:

Spoiler

UDFs:
Active Directory (NEW 2017-02-03 - Version 1.4.7.0) - Download - General Help & Support - Example Scripts - Wiki
OutlookEX (NEW 2017-02-03 - Version 1.2.4.0) - Download - General Help & Support - Example Scripts - Wiki
ExcelChart (2015-04-01 - Version 0.4.0.0) - Download - General Help & Support - Example Scripts
Excel - Example Scripts - Wiki
Word - Wiki
Tutorials:
ADO - Wiki

 

Share this post


Link to post
Share on other sites

#5 ·  Posted (edited)

I have the source code for _AD_GetObjectsinOU open in a different tab but i admit i am not sure what i am looking for. I cant find any related to "accountexpires" in the function itself?

Edited by IanN1990

Share this post


Link to post
Share on other sites

Ops, my bad.
_AD_GetObjectsInOU returns the data "as is". I was talking about _AD_GetObjectProperties which returns the data in readable form.


My UDFs and Tutorials:

Spoiler

UDFs:
Active Directory (NEW 2017-02-03 - Version 1.4.7.0) - Download - General Help & Support - Example Scripts - Wiki
OutlookEX (NEW 2017-02-03 - Version 1.2.4.0) - Download - General Help & Support - Example Scripts - Wiki
ExcelChart (2015-04-01 - Version 0.4.0.0) - Download - General Help & Support - Example Scripts
Excel - Example Scripts - Wiki
Word - Wiki
Tutorials:
ADO - Wiki

 

Share this post


Link to post
Share on other sites

#7 ·  Posted (edited)

Ah that makes sense. Looking into _AD_GetObjectProperties i see what you mean.

Thanks for givng me a lead to work with as previously i had drawn a blank. Tomorrow i will look into this function in more detail and see what i can glimmer. :)

 

 

 

Edited by IanN1990

Share this post


Link to post
Share on other sites

So I have looked into the function but as you said, it is complex.

I am only asking you this next question because from what I can see, AD.au3 is something you have created :) 

ElseIf $oItem.ADsType = $ADSTYPE_LARGE_INTEGER Then
                    If $oItem.Name = "pwdLastSet" Or $oItem.Name = "accountExpires" Or $oItem.Name = "lastLogonTimestamp" Or $oItem.Name = "badPasswordTime" Or $oItem.Name = "lastLogon" Or $oItem.Name = "lockoutTime" Then
                        If $vPropertyValue.LargeInteger.LowPart = 0 And $vPropertyValue.LargeInteger.HighPart = 0 Then
                            $aObjectProperties[$iCount3][1] = "1601/01/01 00:00:00"
                        Else
                            Local $sTemp = DllStructCreate("dword low;dword high")
                            DllStructSetData($sTemp, "Low", $vPropertyValue.LargeInteger.LowPart)
                            DllStructSetData($sTemp, "High", $vPropertyValue.LargeInteger.HighPart)
                            Local $sTemp2 = _Date_Time_FileTimeToSystemTime(DllStructGetPtr($sTemp))
                            Local $sTemp3 = _Date_Time_SystemTimeToTzSpecificLocalTime(DllStructGetPtr($sTemp2))
                            $aObjectProperties[$iCount3][1] = _Date_Time_SystemTimeToDateTimeStr($sTemp3, 1)
                        EndIf
                    Else
                        $aObjectProperties[$iCount3][1] = __AD_LargeInt2Double($vPropertyValue.LargeInteger.LowPart, $vPropertyValue.LargeInteger.HighPart)
                    EndIf

Is the code that seams to refer to expired details but I don't seam to be able convert the data gathered from OU

 

Share this post


Link to post
Share on other sites

The problem is that _AD_GetObjectsInOU does not return property objects but only strings. So you can't use $oItem.ADsType or $vPropertyValue.LargeInteger.LowPart.

The function processes a large integer (https://msdn.microsoft.com/de-de/library/windows/desktop/aa383710(v=vs.85).aspx) and returns a date/time string.
As you now have a string you could fill the DllStruct (DllStuctSetData) with the high and low 4 bytes and then call the _Date* functions.

Never tried it myself and can't test at the moment.


My UDFs and Tutorials:

Spoiler

UDFs:
Active Directory (NEW 2017-02-03 - Version 1.4.7.0) - Download - General Help & Support - Example Scripts - Wiki
OutlookEX (NEW 2017-02-03 - Version 1.2.4.0) - Download - General Help & Support - Example Scripts - Wiki
ExcelChart (2015-04-01 - Version 0.4.0.0) - Download - General Help & Support - Example Scripts
Excel - Example Scripts - Wiki
Word - Wiki
Tutorials:
ADO - Wiki

 

Share this post


Link to post
Share on other sites

Here is what I tired following your advice

#include <AD.au3>
#include <array.au3>

$sOU = _AD_Open()

$Array = _AD_GetObjectsInOU($Domain, "(name=*)", 2, "name, accountexpires", "")
For $i=1 to 1000
_AD_GetObjectProperties1($Array[$i][1])
Next

_AD_Close()

Exit

Func _AD_GetObjectProperties1($vPropertyValue)
 Local $sTemp = DllStructCreate("dword low;dword high")
 DllStructSetData($sTemp, "Low", $vPropertyValue.LargeInteger.LowPart)
 DllStructSetData($sTemp, "High", $vPropertyValue.LargeInteger.HighPart)
 Local $sTemp2 = _Date_Time_FileTimeToSystemTime(DllStructGetPtr($sTemp))
 Local $sTemp3 = _Date_Time_SystemTimeToTzSpecificLocalTime(DllStructGetPtr($sTemp2))
 ConsoleWrite(_Date_Time_SystemTimeToDateTimeStr($sTemp3, 1) &  @crlf)
EndFunc   ;==>_AD_GetObjectProperties

It produces a 1,000 list of 1601/01/01 00:00:00 which from testing is the same if I ran the command with ""

Share this post


Link to post
Share on other sites

I have also gone through the list and AD manually to confirm there are defo expired accounts in there :) 

Share this post


Link to post
Share on other sites

I'm sure

$vPropertyValue.LargeInteger.LowPart

doesn't work as $vPropertyValue is not an object.
What do you get when you run

ConsoleWrite(StringLen($vPropertyValue) & @CRLF)

in your function?


My UDFs and Tutorials:

Spoiler

UDFs:
Active Directory (NEW 2017-02-03 - Version 1.4.7.0) - Download - General Help & Support - Example Scripts - Wiki
OutlookEX (NEW 2017-02-03 - Version 1.2.4.0) - Download - General Help & Support - Example Scripts - Wiki
ExcelChart (2015-04-01 - Version 0.4.0.0) - Download - General Help & Support - Example Scripts
Excel - Example Scripts - Wiki
Word - Wiki
Tutorials:
ADO - Wiki

 

Share this post


Link to post
Share on other sites

Thanks for sticking with this water :) and sorry for the delayed response.

I remoted into my work pc and added the line. The result was

0
1601/01/01 01:00:00

I fear this means for me to get the expired information, it will mean rewritting or editing the _AD_GetObjectsInOU function :( as i imagine as that would provide the objects we need?

 

Share this post


Link to post
Share on other sites

#14 ·  Posted (edited)

I would do it this way:

$aArray = _AD_GetObjectsInOU($sDomain, "(name=*)", 2, "samaccountname,name", "")
For $i=1 to $aArray[0][0]
    $aExpires = _AD_GetObjectProperties($aArray[$i][0], "accountexpires")
    ConsoleWrite("User " & $aArray[$i][0] & " expires on " & $aExpires[1][0])
Next

I will check if I can make this a bit faster.

Edited by water

My UDFs and Tutorials:

Spoiler

UDFs:
Active Directory (NEW 2017-02-03 - Version 1.4.7.0) - Download - General Help & Support - Example Scripts - Wiki
OutlookEX (NEW 2017-02-03 - Version 1.2.4.0) - Download - General Help & Support - Example Scripts - Wiki
ExcelChart (2015-04-01 - Version 0.4.0.0) - Download - General Help & Support - Example Scripts
Excel - Example Scripts - Wiki
Word - Wiki
Tutorials:
ADO - Wiki

 

Share this post


Link to post
Share on other sites

#15 ·  Posted (edited)

I tired your function but as you say it is very slow :( In some instances, taking almost minutes to complete.

I tired to dig a little into my previous idea to see if it was to much of a long shot and here is what i found

 

Func _AD_GetObjectsInOU($sOU = "", $sFilter = "(name=*)", $iSearchScope = 2, $sDataToRetrieve = "sAMAccountName", $sSortBy = "sAMAccountName", $bCount = False, $vReturnNull = True)

    If $sOU = "" Then
        $sOU = $sAD_DNSDomain
    Else
        If _AD_ObjectExists($sOU, "distinguishedName") = 0 Then Return SetError(1, 0, "")
    EndIf
    Local $sReturnNull = ""
    If Not IsBool($vReturnNull) Then
        $sReturnNull = $vReturnNull
        $vReturnNull = False
    EndIf
    Local $iCount2, $aDataToRetrieve, $aTemp
    If $sDataToRetrieve = "" Then $sDataToRetrieve = "sAMAccountName"
    $sDataToRetrieve = StringStripWS($sDataToRetrieve, 8)
    $__oAD_Command.Properties("Searchscope") = $iSearchScope
    $__oAD_Command.CommandText = "<LDAP://" & $sAD_HostServer & "/" & $sOU & ">;" & $sFilter & ";" & $sDataToRetrieve
    $__oAD_Command.Properties("Sort On") = $sSortBy
    Local $oRecordSet = $__oAD_Command.Execute
    If @error Or Not IsObj($oRecordSet) Then Return SetError(2, @error, "")
    Local $iCount1 = $oRecordSet.RecordCount
    If $iCount1 = 0 Then
        If $bCount Then Return SetError(3, 0, 0)
        Return SetError(3, 0, "")
    EndIf
    If $bCount Then Return $iCount1
    If StringInStr($sDataToRetrieve, ",") Then
       ConsoleWrite("A")
        $aDataToRetrieve = StringSplit($sDataToRetrieve, ",")
        Local $aObjects[$iCount1 + 1][$aDataToRetrieve[0]]
        $aObjects[0][0] = $iCount1
        $aObjects[0][1] = $aDataToRetrieve[0]
        $iCount2 = 1
        $oRecordSet.MoveFirst
        Do
            For $iCount1 = 1 To $aDataToRetrieve[0]
                If IsArray($oRecordSet.Fields($aDataToRetrieve[$iCount1]).Value) Then

                    $aTemp = $oRecordSet.Fields($aDataToRetrieve[$iCount1]).Value
                    $aObjects[$iCount2][$iCount1 - 1] = _ArrayToString($aTemp)
                 Else

                    $aObjects[$iCount2][$iCount1 - 1] = $oRecordSet.Fields($aDataToRetrieve[$iCount1]).Value
                    If Not $vReturnNull And IsKeyword($aObjects[$iCount2][$iCount1 - 1]) = $KEYWORD_NULL Then $aObjects[$iCount2][$iCount1 - 1] = $sReturnNull
                EndIf
            Next
            $oRecordSet.MoveNext
            $iCount2 += 1
        Until $oRecordSet.EOF
     Else
        Local $aObjects[$iCount1 + 1]
        $aObjects[0] = UBound($aObjects) - 1
        $iCount2 = 1
        $oRecordSet.MoveFirst
        Do
            If IsArray($oRecordSet.Fields($sDataToRetrieve).Value) Then
                $aTemp = $oRecordSet.Fields($sDataToRetrieve).Value
                $aObjects[$iCount2] = _ArrayToString($aTemp)
     Else
                     $aTemp = $oRecordSet.Fields($sDataToRetrieve).Value
                           Local $sTemp = DllStructCreate("dword low;dword high")
                            DllStructSetData($sTemp, "Low", $aTemp.LargeInteger.LowPart)
                            DllStructSetData($sTemp, "High", $aTemp.LargeInteger.HighPart)
                            Local $sTemp2 = _Date_Time_FileTimeToSystemTime(DllStructGetPtr($sTemp))
                            Local $sTemp3 = _Date_Time_SystemTimeToTzSpecificLocalTime(DllStructGetPtr($sTemp2))
                            ConsoleWrite(_Date_Time_SystemTimeToDateTimeStr($sTemp3, 1) &  @crlf)

                $aObjects[$iCount2] = $oRecordSet.Fields($sDataToRetrieve).Value

            EndIf
            $oRecordSet.MoveNext
            $iCount2 += 1
        Until $oRecordSet.EOF
    EndIf
    $__oAD_Command.Properties("Sort On") = "" ; Reset sort property
    Return $aObjects

EndFunc   ;==>_AD_GetObjectsInOU

I found where the code runs when processing accountexpires, we have the code that converts it into an expired date, we have the code processing objects but now finding what object to use doesn't seam to be working :(

Edited by IanN1990

Share this post


Link to post
Share on other sites

#16 ·  Posted (edited)

Another idea is to play with the brushed up version of _AD_GetObjectsInOU written by JoshuaBarnette. Unfortunately it is not faster then the code I posted above.

 

Edited by water

My UDFs and Tutorials:

Spoiler

UDFs:
Active Directory (NEW 2017-02-03 - Version 1.4.7.0) - Download - General Help & Support - Example Scripts - Wiki
OutlookEX (NEW 2017-02-03 - Version 1.2.4.0) - Download - General Help & Support - Example Scripts - Wiki
ExcelChart (2015-04-01 - Version 0.4.0.0) - Download - General Help & Support - Example Scripts
Excel - Example Scripts - Wiki
Word - Wiki
Tutorials:
ADO - Wiki

 

Share this post


Link to post
Share on other sites

#17 ·  Posted (edited)

I was able to reduce execution time of _AD_GetObjectProperties. I query about 3500 users. The following script runs 161 seconds with the current function and 36 seconds with the new one:

#include <AD.au3>
_AD_Open()
Global $iTimer = TimerInit()
$aArray = _AD_GetObjectsInOU("", "(&(objectcategory=person)(objectclass=user)(name=*))", 2, "samaccountname,name", "")
For $i=1 to $aArray[0][0]
    $aExpires = _AD_GetObjectPropertiesEX($aArray[$i][0], "accountexpires")
Next
ConsoleWrite(TimerDiff($iTimer) & @CRLF)
_AD_Close()

New function (named: _AD_GetobjectPropertiesEX):

; #FUNCTION# ====================================================================================================================
; Name...........: _AD_GetObjectProperties
; Description ...: Returns a two-dimensional array of all or selected properties and their values of an object in readable form.
; Syntax.........: _AD_GetObjectProperties([$vObject = @UserName[, $sProperties = ""[, $bSort = True]]])
; Parameters ....: $vObject     - Optional: SamAccountName, FQDN or ADSPath of the object to retrieve properties from (e.g. computer, user, group ...) (default = @Username)
;                  |Can be of type object as well. Useful to get properties for a schema or configuration object (see _AD_ListRootDSEAttributes)
;                  $sProperties - Optional: Comma separated list of properties to return (default = "" = return all properties)
;                  $bSort       - Optional: True specifies that the array will be sorted on property name (default = True)
; Return values .: Success - Returns a one based two-dimensional array with all properties and their values of an object in readable form
;                  Failure - "" or property name, sets @error to:
;                  |1 - $vObject could not be found
;                  |2 - No values for the specified property. The property in error is returned as the function result
;                  |3 - Error retrieving $vObject. @Extended is set to the error returned by LDAP
; Author ........: Sundance
; Modified.......: water
; Remarks .......: Dates are returned in format: YYYY/MM/DD HH:MM:SS local time of the calling user (AD stores all dates in UTC - Universal Time Coordinated)
;                  Exception: AD internal dates like "whenCreated", "whenChanged" and "dSCorePropagationData". They are returned as UTC
;                  NT Security Descriptors are returned as: Control:nn, Group:Domain\Group, Owner:Domain\Group, Revision:nn
;                  No error is returned if there are properties in $sProperties that are not available for the selected object
;+
;                  Properties are returned in alphabetical order. If $sProperties is set to "samaccountname,displayname" the returned array will contain
;                  displayname as the first and samaccountname as the second row.
; Related .......:
; Link ..........: http://www.autoitscript.com/forum/index.php?showtopic=49627&view=findpost&p=422402, http://msdn.microsoft.com/en-us/library/ms675090(VS.85).aspx
; Example .......: Yes
; ===============================================================================================================================
Func _AD_GetObjectPropertiesEx($vObject = @UserName, $sProperties = "", $bSort = True)

    Local $aObjectProperties[1000][2], $oObject
    Local $oProperty, $oPropertyEntry, $oValue, $iPropertyRecord = 0, $xAD_Dummy
    ; Data Type Mapping between Active Directory and LDAP
    ; http://msdn.microsoft.com/en-us/library/aa772375(VS.85).aspx
    Local Const $ADSTYPE_DN_STRING = 1
    Local Const $ADSTYPE_CASE_IGNORE_STRING = 3
    Local Const $ADSTYPE_BOOLEAN = 6
    Local Const $ADSTYPE_INTEGER = 7
    Local Const $ADSTYPE_OCTET_STRING = 8
    Local Const $ADSTYPE_UTC_TIME = 9
    Local Const $ADSTYPE_LARGE_INTEGER = 10
    Local Const $ADSTYPE_NT_SECURITY_DESCRIPTOR = 25
    Local Const $ADSTYPE_UNKNOWN = 26
    Local $aSAMAccountType[12][2] = [["DOMAIN_OBJECT", 0x0], ["GROUP_OBJECT", 0x10000000], ["NON_SECURITY_GROUP_OBJECT", 0x10000001], _
            ["ALIAS_OBJECT", 0x20000000], ["NON_SECURITY_ALIAS_OBJECT", 0x20000001], ["USER_OBJECT", 0x30000000], ["NORMAL_USER_ACCOUNT", 0x30000000], _
            ["MACHINE_ACCOUNT", 0x30000001], ["TRUST_ACCOUNT", 0x30000002], ["APP_BASIC_GROUP", 0x40000000], ["APP_QUERY_GROUP", 0x40000001], _
            ["ACCOUNT_TYPE_MAX", 0x7fffffff]]
    Local $aUAC[21][2] = [[0x00000001, "SCRIPT"], [0x00000002, "ACCOUNTDISABLE"], [0x00000008, "HOMEDIR_REQUIRED"], [0x00000010, "LOCKOUT"], [0x00000020, "PASSWD_NOTREQD"], _
            [0x00000040, "PASSWD_CANT_CHANGE"], [0x00000080, "ENCRYPTED_TEXT_PASSWORD_ALLOWED"], [0x00000100, "TEMP_DUPLICATE_ACCOUNT"], [0x00000200, "NORMAL_ACCOUNT"], _
            [0x00000800, "INTERDOMAIN_TRUST_ACCOUNT"], [0x00001000, "WORKSTATION_TRUST_ACCOUNT"], [0x00002000, "SERVER_TRUST_ACCOUNT"], [0x00010000, "DONT_EXPIRE_PASSWD"], _
            [0x00020000, "MNS_LOGON_ACCOUNT"], [0x00040000, "SMARTCARD_REQUIRED"], [0x00080000, "TRUSTED_FOR_DELEGATION"], [0x00100000, "NOT_DELEGATED"], _
            [0x00200000, "USE_DES_KEY_ONLY"], [0x00400000, "DONT_REQUIRE_PREAUTH"], [0x00800000, "PASSWORD_EXPIRED"], [0x01000000, "TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION"]]

    If Not IsObj($vObject) Then
        If StringLeft($vObject, 7) <> "LDAP://" Then ; No ADsPath
            If _AD_ObjectExists($vObject) = 0 Then Return SetError(1, 0, "")
            Local $sProperty = "sAMAccountName"
            If StringMid($vObject, 3, 1) = "=" Then $sProperty = "distinguishedName"; FQDN provided
            $__oAD_Command.CommandText = "<LDAP://" & $sAD_HostServer & "/" & $sAD_DNSDomain & ">;(" & $sProperty & "=" & $vObject & ");ADsPath;subtree"
            Local $oRecordSet = $__oAD_Command.Execute ; Retrieve the ADsPath for the object
            If @error Or Not IsObj($oRecordSet) Then Return SetError(3, @error, "")
            $vObject = $oRecordSet.fields(0).Value
        EndIf
        $oObject = __AD_ObjGet($vObject) ; Retrieve the COM Object
    Else
        $oObject = $vObject
    EndIf
    If $sProperties = "" Then
        $oObject.GetInfo() ; Refresh values of all properties in the property cache of the ADSI object
    Else
        Local $aProperties = StringSplit($sProperties, ",", $STR_NOCOUNT)
        $oObject.GetInfoEX($aProperties, 0) ; Refresh values of the selected properties in the property cache of the ADSI object
    EndIf
    Local $iPropertyCount = $oObject.PropertyCount()
    For $iCurrentProperty = 0 To $iPropertyCount - 1
        $oProperty = $oObject.Item($iCurrentProperty)
        $oPropertyEntry = $oObject.GetPropertyItem($oProperty.Name, $ADSTYPE_UNKNOWN)
        $sPropertyName = $oProperty.Name
        If Not IsObj($oPropertyEntry) Then Return SetError(2, 0, $sPropertyName)
        For $vPropertyValue In $oPropertyEntry.Values
            $iPropertyRecord = $iPropertyRecord + 1
            $aObjectProperties[$iPropertyRecord][0] = $sPropertyName
            Switch $oProperty.ADsType
                Case $ADSTYPE_CASE_IGNORE_STRING
                    $aObjectProperties[$iPropertyRecord][1] = $vPropertyValue.CaseIgnoreString
                Case $ADSTYPE_INTEGER
                    If $sPropertyName = "sAMAccountType" Then
                        For $iCount4 = 0 To UBound($aSAMAccountType) - 1
                            If $vPropertyValue.Integer = $aSAMAccountType[$iCount4][1] Then
                                $aObjectProperties[$iPropertyRecord][1] = $aSAMAccountType[$iCount4][0]
                                ExitLoop
                            EndIf
                        Next
                    ElseIf $sPropertyName = "userAccountControl" Then
                        $aObjectProperties[$iPropertyRecord][1] = $vPropertyValue.Integer & " = "
                        For $iCount4 = 0 To UBound($aUAC) - 1
                            If BitAND($vPropertyValue.Integer, $aUAC[$iCount4][0]) = $aUAC[$iCount4][0] Then
                                $aObjectProperties[$iPropertyRecord][1] &= $aUAC[$iCount4][1] & " - "
                            EndIf
                        Next
                        If StringRight($aObjectProperties[$iPropertyRecord][1], 3) = " - " Then $aObjectProperties[$iPropertyRecord][1] = StringTrimRight($aObjectProperties[$iPropertyRecord][1], 3)
                    Else
                        $aObjectProperties[$iPropertyRecord][1] = $vPropertyValue.Integer
                    EndIf
                Case $ADSTYPE_LARGE_INTEGER
                    If $sPropertyName = "pwdLastSet" Or $sPropertyName = "accountExpires" Or $sPropertyName = "lastLogonTimestamp" Or $sPropertyName = "badPasswordTime" Or $sPropertyName = "lastLogon" Or $sPropertyName = "lockoutTime" Then
                        If $vPropertyValue.LargeInteger.LowPart = 0 And $vPropertyValue.LargeInteger.HighPart = 0 Then
                            $aObjectProperties[$iPropertyRecord][1] = "1601/01/01 00:00:00"
                        Else
                            Local $sTemp = DllStructCreate("dword low;dword high")
                            DllStructSetData($sTemp, "Low", $vPropertyValue.LargeInteger.LowPart)
                            DllStructSetData($sTemp, "High", $vPropertyValue.LargeInteger.HighPart)
                            Local $sTemp2 = _Date_Time_FileTimeToSystemTime(DllStructGetPtr($sTemp))
                            Local $sTemp3 = _Date_Time_SystemTimeToTzSpecificLocalTime(DllStructGetPtr($sTemp2))
                            $aObjectProperties[$iPropertyRecord][1] = _Date_Time_SystemTimeToDateTimeStr($sTemp3, 1)
                        EndIf
                    Else
                        $aObjectProperties[$iPropertyRecord][1] = __AD_LargeInt2Double($vPropertyValue.LargeInteger.LowPart, $vPropertyValue.LargeInteger.HighPart)
                    EndIf
                Case $ADSTYPE_OCTET_STRING
                    $xAD_Dummy = DllStructCreate("byte[56]")
                    DllStructSetData($xAD_Dummy, 1, $vPropertyValue.OctetString)
                    ; objectSID etc. See: http://msdn.microsoft.com/en-us/library/aa379597(VS.85).aspx
                    ; objectGUID etc. See: http://www.autoitscript.com/forum/index.php?showtopic=106163&view=findpost&p=767558
                    If _Security__IsValidSid(DllStructGetPtr($xAD_Dummy)) Then
                        $aObjectProperties[$iPropertyRecord][1] = _Security__SidToStringSid(DllStructGetPtr($xAD_Dummy)) ; SID
                    Else
                        $aObjectProperties[$iPropertyRecord][1] = _WinAPI_StringFromGUID(DllStructGetPtr($xAD_Dummy)) ; GUID
                    EndIf
                Case $ADSTYPE_DN_STRING
                    $aObjectProperties[$iPropertyRecord][1] = $vPropertyValue.DNString
                Case $ADSTYPE_UTC_TIME
                    $aObjectProperties[$iPropertyRecord][1] = StringRegExpReplace($vPropertyValue.UTCTime, "(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})", "$1/$2/$3 $4:$5:$6") ; YYYY/MM/DD HH:MM:SS
                Case $ADSTYPE_BOOLEAN
                    If $vPropertyValue.Boolean = 0 Then
                        $aObjectProperties[$iPropertyRecord][1] = "False"
                    Else
                        $aObjectProperties[$iPropertyRecord][1] = "True"
                    EndIf
                Case $ADSTYPE_NT_SECURITY_DESCRIPTOR
                    $oValue = $vPropertyValue.SecurityDescriptor
                    $aObjectProperties[$iPropertyRecord][1] = "Control:" & $oValue.Control & ", " & _
                            "Group:" & $oValue.Group & ", " & _
                            "Owner:" & $oValue.Owner & ", " & _
                            "Revision:" & $oValue.Revision
                Case Else
                    $aObjectProperties[$iPropertyRecord][1] = "Has the unknown ADsType: " & $oProperty.ADsType
            EndSwitch
        Next
    Next
    ReDim $aObjectProperties[$iPropertyRecord + 1][2]
    $aObjectProperties[0][0] = $iPropertyRecord
    $aObjectProperties[0][1] = 2
    If $bSort And $iPropertyRecord > 1 Then _ArraySort($aObjectProperties, 0, 1) ; Only sort if flag is set and array contains > 1 records
    Return $aObjectProperties

EndFunc   ;==>_AD_GetObjectPropertiesEx

 

Edit: The new function is included in the new version 1.4.4.0 of the UDF.

Edited by water
1 person likes this

My UDFs and Tutorials:

Spoiler

UDFs:
Active Directory (NEW 2017-02-03 - Version 1.4.7.0) - Download - General Help & Support - Example Scripts - Wiki
OutlookEX (NEW 2017-02-03 - Version 1.2.4.0) - Download - General Help & Support - Example Scripts - Wiki
ExcelChart (2015-04-01 - Version 0.4.0.0) - Download - General Help & Support - Example Scripts
Excel - Example Scripts - Wiki
Word - Wiki
Tutorials:
ADO - Wiki

 

Share this post


Link to post
Share on other sites

#18 ·  Posted

Hey, 

I am trying to get the information from "LastLogOff" and was reminded of this topic :).

I tired

_AD_GetObjectAttribute(@UserName, "lastlogoff")

Returns Blank

I used 

_AD_GetObjectProperties(@Username)

and see LastLogOff is 0 but this seams to be for every user i select.

I wondered if it is related to this topic. LastLogOff being an object and to get the values you need to use the high & lows. So i tired

_AD_GetObjectPropertiesEX(@username, "lastLogoff")

This returns an array with LastLogOff being 0. 

Where have i gone wrong ^^

Share this post


Link to post
Share on other sites

#19 ·  Posted

Add "lastLogoff" to this line in function _AD_GetObjectProperties:

If $sPropertyName = "pwdLastSet" Or $sPropertyName = "accountExpires" Or $sPropertyName = "lastLogonTimestamp" Or $sPropertyName = "badPasswordTime" Or $sPropertyName = "lastLogon" Or $sPropertyName = "lockoutTime" Or $sPropertyName = "lastLogoff" Then ; "lastLogoff" already added at the end of the line

 

1 person likes this

My UDFs and Tutorials:

Spoiler

UDFs:
Active Directory (NEW 2017-02-03 - Version 1.4.7.0) - Download - General Help & Support - Example Scripts - Wiki
OutlookEX (NEW 2017-02-03 - Version 1.2.4.0) - Download - General Help & Support - Example Scripts - Wiki
ExcelChart (2015-04-01 - Version 0.4.0.0) - Download - General Help & Support - Example Scripts
Excel - Example Scripts - Wiki
Word - Wiki
Tutorials:
ADO - Wiki

 

Share this post


Link to post
Share on other sites

#20 ·  Posted (edited)

Seems this attribute still istn't used by MS.
How to record the last logoff date/time is described here: https://www.ldapsoft.com/adlogoffreport.html

Edit: And it does not get replicated. This means you need to query all DCs to get the "real" lastlogoff date/time.

Edited by water
1 person likes this

My UDFs and Tutorials:

Spoiler

UDFs:
Active Directory (NEW 2017-02-03 - Version 1.4.7.0) - Download - General Help & Support - Example Scripts - Wiki
OutlookEX (NEW 2017-02-03 - Version 1.2.4.0) - Download - General Help & Support - Example Scripts - Wiki
ExcelChart (2015-04-01 - Version 0.4.0.0) - Download - General Help & Support - Example Scripts
Excel - Example Scripts - Wiki
Word - Wiki
Tutorials:
ADO - Wiki

 

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now