Jump to content

Active Directory UDF - Help & Support (III)


water
 Share

Recommended Posts

How can I pull the lastLogonTimestamp AD attribute via _AD_GetObjectsInOU? The script does not error, it simply returns blank fields in the array.

_AD_Open($LS_AD_User & "@" & $LS_AD_Domain, $LS_AD_Password, $LS_AD_DNSDomain, $LS_AD_HostServer, $LS_AD_Configuration)
    _ArrayDisplay(_AD_GetObjectProperties("CN=Username,OU=Users,DC=Domain,DC=com"))
    _ArrayDisplay(_AD_GetObjectsInOU("DC=Domain,DC=com", "(Mail=*)", 2, "GivenName, Mail, sAMAccountName, SN, lastLogon, lastLogonTimestamp", "sAMAccountName"))
_AD_Close()

This is obviously a test script, but _AD_GetObjectProperties returns the attributes with values, _AD_GetObjectsInOU does not.

Thanks again for all your help.

Link to comment
Share on other sites

_AD_GetObjectsInOU returns the attribute "as is".

LastLogonTimeStamp is a 64 bit integer. You need to decode it. Function _AD_GetObjectProperties shows how to decode attribute LastLogonTimeStamp.

Details can be found here.

"Many attributes in Active Directory have a data type (syntax) called Integer8. These 64-bit numbers (8 bytes) often represent time in 100-nanosecond intervals. If the Integer8 attribute is a date, the value represents the number of 100-nanosecond intervals since 12:00 AM January 1, 1601."

My UDFs and Tutorials:

Spoiler

UDFs:
Active Directory (NEW 2022-02-19 - Version 1.6.1.0) - Download - General Help & Support - Example Scripts - Wiki
ExcelChart (2017-07-21 - Version 0.4.0.1) - Download - General Help & Support - Example Scripts
OutlookEX (2021-11-16 - Version 1.7.0.0) - Download - General Help & Support - Example Scripts - Wiki
OutlookEX_GUI (2021-04-13 - Version 1.4.0.0) - Download
Outlook Tools (2019-07-22 - Version 0.6.0.0) - Download - General Help & Support - Wiki
PowerPoint (2021-08-31 - Version 1.5.0.0) - Download - General Help & Support - Example Scripts - Wiki
Task Scheduler (NEW 2022-07-28 - Version 1.6.0.1) - Download - General Help & Support - Wiki

Standard UDFs:
Excel - Example Scripts - Wiki
Word - Wiki

Tutorials:
ADO - Wiki
WebDriver - Wiki

 

Link to comment
Share on other sites

I understand the need to decode LastLogonTimeStamp to be an actual date and wrote a function to do just that, but why is it that the column returns empty, not an integer, nothing at all from _AD_GetObjectsInOU? From _AD_GetObjectProperties I get the formatted date, on the exact same user as is returned in _AD_GetObjectsInOU.

Link to comment
Share on other sites

I think _ArrayDisplay just can't display the value. Can you try VargetType on the returned value and check what you get?

I can't test at the moment.

My UDFs and Tutorials:

Spoiler

UDFs:
Active Directory (NEW 2022-02-19 - Version 1.6.1.0) - Download - General Help & Support - Example Scripts - Wiki
ExcelChart (2017-07-21 - Version 0.4.0.1) - Download - General Help & Support - Example Scripts
OutlookEX (2021-11-16 - Version 1.7.0.0) - Download - General Help & Support - Example Scripts - Wiki
OutlookEX_GUI (2021-04-13 - Version 1.4.0.0) - Download
Outlook Tools (2019-07-22 - Version 0.6.0.0) - Download - General Help & Support - Wiki
PowerPoint (2021-08-31 - Version 1.5.0.0) - Download - General Help & Support - Example Scripts - Wiki
Task Scheduler (NEW 2022-07-28 - Version 1.6.0.1) - Download - General Help & Support - Wiki

Standard UDFs:
Excel - Example Scripts - Wiki
Word - Wiki

Tutorials:
ADO - Wiki
WebDriver - Wiki

 

Link to comment
Share on other sites

I Did:

_AD_Open($LS_AD_User & "@" & $LS_AD_Domain, $LS_AD_Password, $LS_AD_DNSDomain, $LS_AD_HostServer, $LS_AD_Configuration)
    $IS_Users = _AD_GetObjectsInOU("DC=domain,DC=com", "(&(sAMAccountType=805306368)(memberOf=CN=IS_Users,OU=Groups,DC=domain,DC=com)(Mail=*))", 2, "lastLogon, lastLogonTimestamp", "sAMAccountName")
    MsgBox(4096, "Test", 'Last Logon: ' & VarGetType($IS_Users[1][0]) & @CRLF & 'Last Logon Timestamp: ' & VarGetType($IS_Users[1][1]))
_AD_Close()

It returned:

Last Logon: Object

Last Logon Timestamp: Object

Link to comment
Share on other sites

So this is correct. You then can translate this object into a date by using the function I referred to above.

My UDFs and Tutorials:

Spoiler

UDFs:
Active Directory (NEW 2022-02-19 - Version 1.6.1.0) - Download - General Help & Support - Example Scripts - Wiki
ExcelChart (2017-07-21 - Version 0.4.0.1) - Download - General Help & Support - Example Scripts
OutlookEX (2021-11-16 - Version 1.7.0.0) - Download - General Help & Support - Example Scripts - Wiki
OutlookEX_GUI (2021-04-13 - Version 1.4.0.0) - Download
Outlook Tools (2019-07-22 - Version 0.6.0.0) - Download - General Help & Support - Wiki
PowerPoint (2021-08-31 - Version 1.5.0.0) - Download - General Help & Support - Example Scripts - Wiki
Task Scheduler (NEW 2022-07-28 - Version 1.6.0.1) - Download - General Help & Support - Wiki

Standard UDFs:
Excel - Example Scripts - Wiki
Word - Wiki

Tutorials:
ADO - Wiki
WebDriver - Wiki

 

Link to comment
Share on other sites

I hate to seem stupid, but some of your code is fairly foreign to me, as I do not work with objects on a normal basis. Is there a way you can assist me in getting this setup so I can get the right information? I would think it could be useful to persons other than myself and might be helpful to include in the UDF.

Edited by JoshuaBarnette
Link to comment
Share on other sites

When you look for "lastlogontimestamp" you will find this code in function _AD_GetObjectProperties to translate the value:

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
Edited by water

My UDFs and Tutorials:

Spoiler

UDFs:
Active Directory (NEW 2022-02-19 - Version 1.6.1.0) - Download - General Help & Support - Example Scripts - Wiki
ExcelChart (2017-07-21 - Version 0.4.0.1) - Download - General Help & Support - Example Scripts
OutlookEX (2021-11-16 - Version 1.7.0.0) - Download - General Help & Support - Example Scripts - Wiki
OutlookEX_GUI (2021-04-13 - Version 1.4.0.0) - Download
Outlook Tools (2019-07-22 - Version 0.6.0.0) - Download - General Help & Support - Wiki
PowerPoint (2021-08-31 - Version 1.5.0.0) - Download - General Help & Support - Example Scripts - Wiki
Task Scheduler (NEW 2022-07-28 - Version 1.6.0.1) - Download - General Help & Support - Wiki

Standard UDFs:
Excel - Example Scripts - Wiki
Word - Wiki

Tutorials:
ADO - Wiki
WebDriver - Wiki

 

Link to comment
Share on other sites

I know I will be showing my ignorance here, but here goes....Below is what I have been trying to use to adapt the GetObjectPropeties function to the GetObjectInOU function, Line 1330 returns $iCount1 as blank.

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

    ; 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

    If $sOU = "" Then
        $sOU = $sAD_DNSDomain
    Else
        If _AD_ObjectExists($sOU, "distinguishedName") = 0 Then Return SetError(1, 0, "")
    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
        $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
                EndIf
            Next
            $oRecordSet.MoveNext
            $iCount2 += 1
        Until $oRecordSet.EOF
        #Region ; Translate Objects To Values
            For $r = 1 To $aObjects[0][0]
                For $c = 0 To $aObjects[0][1] - 1
                    If IsObj($aObjects[$r][$c]) Then
MsgBox(4096, "Test Is Object", "Array Row: " & $r & " And Column: " & $c & " Is An Object.")
                        $oObject = $aObjects[$r][$c]
                        $oObject.GetInfo()
                        Local $iCount1 = $oObject.PropertyCount()
MsgBox(4096, "Test Is Object", "Array Row: " & $r & " And Column: " & $c & " Has " & $iCount1 & " Properties.")
                        For $iCount2 = 0 To $iCount1 - 1
                            $oItem = $oObject.Item($iCount2)
                            If Not ($sProperties = ",," Or StringInStr($sProperties, "," & $oItem.Name & ",") > 0) Then ContinueLoop
                            $oPropertyEntry = $oObject.GetPropertyItem($oItem.Name, $ADSTYPE_UNKNOWN)
                            If Not IsObj($oPropertyEntry) Then
                                Return SetError(2, 0, $oItem.Name)
                            Else
                                For $vPropertyValue In $oPropertyEntry.Values
                                    If $oItem.ADsType = $ADSTYPE_CASE_IGNORE_STRING Then
                                        $aObjects[$r][$c] = $vPropertyValue.CaseIgnoreString
                                    ElseIf $oItem.ADsType = $ADSTYPE_INTEGER Then
                                        If $oItem.Name = "sAMAccountType" Then
                                            For $iCount4 = 0 To 11
                                                If $vPropertyValue.Integer = $aSAMAccountType[$iCount4][1] Then
                                                    $aObjects[$r][$c] = $aSAMAccountType[$iCount4][0]
                                                    ExitLoop
                                                EndIf
                                            Next
                                        ElseIf $oItem.Name = "userAccountControl" Then
                                            $aObjects[$r][$c] = $vPropertyValue.Integer & " = "
                                            For $iCount4 = 0 To 20
                                                If BitAND($vPropertyValue.Integer, $aUAC[$iCount4][0]) = $aUAC[$iCount4][0] Then
                                                    $aObjects[$r][$c] &= $aUAC[$iCount4][1] & " - "
                                                EndIf
                                            Next
                                            If StringRight($aObjects[$r][$c], 3) = " - " Then $aObjects[$r][$c] = StringTrimRight($aObjects[$r][$c], 3)
                                        Else
                                            $aObjects[$r][$c] = $vPropertyValue.Integer
                                        EndIf
                                    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
                                                $aObjects[$r][$c] = "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))
                                                $aObjects[$r][$c] = _Date_Time_SystemTimeToDateTimeStr($sTemp3, 1)
                                            EndIf
                                        Else
                                            $aObjects[$r][$c] = __AD_LargeInt2Double($vPropertyValue.LargeInteger.LowPart, $vPropertyValue.LargeInteger.HighPart)
                                        EndIf
                                    ElseIf $oItem.ADsType = $ADSTYPE_OCTET_STRING Then
                                        $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
                                            $aObjects[$r][$c] = _Security__SidToStringSid(DllStructGetPtr($xAD_Dummy)) ; SID
                                        Else
                                            $aObjects[$r][$c] = _WinAPI_StringFromGUID(DllStructGetPtr($xAD_Dummy)) ; GUID
                                        EndIf
                                    ElseIf $oItem.ADsType = $ADSTYPE_DN_STRING Then
                                        $aObjects[$r][$c] = $vPropertyValue.DNString
                                    ElseIf $oItem.ADsType = $ADSTYPE_UTC_TIME Then
                                        Local $iDateTime = $vPropertyValue.UTCTime
                                        $aObjects[$r][$c] = StringLeft($iDateTime, 4) & "/" & StringMid($iDateTime, 5, 2) & "/" & StringMid($iDateTime, 7, 2) & _
                                                " " & StringMid($iDateTime, 9, 2) & ":" & StringMid($iDateTime, 11, 2) & ":" & StringMid($iDateTime, 13, 2)
                                    ElseIf $oItem.ADsType = $ADSTYPE_BOOLEAN Then
                                        If $vPropertyValue.Boolean = 0 Then
                                            $aObjects[$r][$c] = "False"
                                        Else
                                            $aObjects[$r][$c] = "True"
                                        EndIf
                                    ElseIf $oItem.ADsType = $ADSTYPE_NT_SECURITY_DESCRIPTOR Then
                                        $oValue = $vPropertyValue.SecurityDescriptor
                                        $aObjects[$r][$c] = "Control:" & $oValue.Control & ", " & _
                                                "Group:" & $oValue.Group & ", " & _
                                                "Owner:" & $oValue.Owner & ", " & _
                                                "Revision:" & $oValue.Revision
                                    Else
                                        $aObjects[$r][$c] = "Has the unknown ADsType: " & $oItem.ADsType
                                    EndIf
                                Next
                            EndIf
                        Next
                    EndIf
                Next
            Next
        #EndRegion
    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
                $aObjects[$iCount2] = $oRecordSet.Fields($sDataToRetrieve).Value
            EndIf
            $oRecordSet.MoveNext
            $iCount2 += 1
        Until $oRecordSet.EOF
        #Region ; Translate Objects To Values
            For $r = 1 To $aObjects[0]
                If IsObj($aObjects[$r]) Then
                    $oObject = $aObjects[$r]
                    $oObject.GetInfo()
                    Local $iCount1 = $oObject.PropertyCount()
                    For $iCount2 = 0 To $iCount1 - 1
                        $oItem = $oObject.Item($iCount2)
                        If Not ($sProperties = ",," Or StringInStr($sProperties, "," & $oItem.Name & ",") > 0) Then ContinueLoop
                        $oPropertyEntry = $oObject.GetPropertyItem($oItem.Name, $ADSTYPE_UNKNOWN)
                        If Not IsObj($oPropertyEntry) Then
                            Return SetError(2, 0, $oItem.Name)
                        Else
                            For $vPropertyValue In $oPropertyEntry.Values
                                If $oItem.ADsType = $ADSTYPE_CASE_IGNORE_STRING Then
                                    $aObjects[$r] = $vPropertyValue.CaseIgnoreString
                                ElseIf $oItem.ADsType = $ADSTYPE_INTEGER Then
                                    If $oItem.Name = "sAMAccountType" Then
                                        For $iCount4 = 0 To 11
                                            If $vPropertyValue.Integer = $aSAMAccountType[$iCount4][1] Then
                                                $aObjects[$r] = $aSAMAccountType[$iCount4][0]
                                                ExitLoop
                                            EndIf
                                        Next
                                    ElseIf $oItem.Name = "userAccountControl" Then
                                        $aObjects[$r] = $vPropertyValue.Integer & " = "
                                        For $iCount4 = 0 To 20
                                            If BitAND($vPropertyValue.Integer, $aUAC[$iCount4][0]) = $aUAC[$iCount4][0] Then
                                                $aObjects[$r] &= $aUAC[$iCount4][1] & " - "
                                            EndIf
                                        Next
                                        If StringRight($aObjects[$r], 3) = " - " Then $aObjects[$r] = StringTrimRight($aObjects[$r], 3)
                                    Else
                                        $aObjects[$r] = $vPropertyValue.Integer
                                    EndIf
                                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
                                            $aObjects[$r] = "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))
                                            $aObjects[$r] = _Date_Time_SystemTimeToDateTimeStr($sTemp3, 1)
                                        EndIf
                                    Else
                                        $aObjects[$r] = __AD_LargeInt2Double($vPropertyValue.LargeInteger.LowPart, $vPropertyValue.LargeInteger.HighPart)
                                    EndIf
                                ElseIf $oItem.ADsType = $ADSTYPE_OCTET_STRING Then
                                    $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
                                        $aObjects[$r] = _Security__SidToStringSid(DllStructGetPtr($xAD_Dummy)) ; SID
                                    Else
                                        $aObjects[$r] = _WinAPI_StringFromGUID(DllStructGetPtr($xAD_Dummy)) ; GUID
                                    EndIf
                                ElseIf $oItem.ADsType = $ADSTYPE_DN_STRING Then
                                    $aObjects[$r] = $vPropertyValue.DNString
                                ElseIf $oItem.ADsType = $ADSTYPE_UTC_TIME Then
                                    Local $iDateTime = $vPropertyValue.UTCTime
                                    $aObjects[$r] = StringLeft($iDateTime, 4) & "/" & StringMid($iDateTime, 5, 2) & "/" & StringMid($iDateTime, 7, 2) & _
                                            " " & StringMid($iDateTime, 9, 2) & ":" & StringMid($iDateTime, 11, 2) & ":" & StringMid($iDateTime, 13, 2)
                                ElseIf $oItem.ADsType = $ADSTYPE_BOOLEAN Then
                                    If $vPropertyValue.Boolean = 0 Then
                                        $aObjects[$r] = "False"
                                    Else
                                        $aObjects[$r] = "True"
                                    EndIf
                                ElseIf $oItem.ADsType = $ADSTYPE_NT_SECURITY_DESCRIPTOR Then
                                    $oValue = $vPropertyValue.SecurityDescriptor
                                    $aObjects[$r] = "Control:" & $oValue.Control & ", " & _
                                            "Group:" & $oValue.Group & ", " & _
                                            "Owner:" & $oValue.Owner & ", " & _
                                            "Revision:" & $oValue.Revision
                                Else
                                    $aObjects[$r] = "Has the unknown ADsType: " & $oItem.ADsType
                                EndIf
                            Next
                        EndIf
                    Next
                EndIf
            Next
        #EndRegion
    EndIf
    $__oAD_Command.Properties("Sort On") = "" ; Reset sort property
    Return $aObjects

EndFunc   ;==>_AD_GetObjectsInOU

I am sure this has something to go with the object only being the LargeInteger and not a property list, but as I said before I have never worked much with Objects.

Link to comment
Share on other sites

I just tried it myself and got an invalid result as well.

I have always used _AD_GetObjectsInOU to return the FQDNs of objects and then called _AD_GetObjectProperties to get their translated properties.

Why do you need to do it in a single function? Performance?

My UDFs and Tutorials:

Spoiler

UDFs:
Active Directory (NEW 2022-02-19 - Version 1.6.1.0) - Download - General Help & Support - Example Scripts - Wiki
ExcelChart (2017-07-21 - Version 0.4.0.1) - Download - General Help & Support - Example Scripts
OutlookEX (2021-11-16 - Version 1.7.0.0) - Download - General Help & Support - Example Scripts - Wiki
OutlookEX_GUI (2021-04-13 - Version 1.4.0.0) - Download
Outlook Tools (2019-07-22 - Version 0.6.0.0) - Download - General Help & Support - Wiki
PowerPoint (2021-08-31 - Version 1.5.0.0) - Download - General Help & Support - Example Scripts - Wiki
Task Scheduler (NEW 2022-07-28 - Version 1.6.0.1) - Download - General Help & Support - Wiki

Standard UDFs:
Excel - Example Scripts - Wiki
Word - Wiki

Tutorials:
ADO - Wiki
WebDriver - Wiki

 

Link to comment
Share on other sites

Remember the Windows 8 slowness we were talking about the other day? This is faster, it runs in under 10 seconds on Windows 7 and Windows 8. Also I can filter based on MemberOf here, etc, thus leaving me to make only one AD call versus 115 for the full membership of the Information Services group. The performance this way is phenomenal, also if I ask for a Property that isn't set for an object, it returns a blank field versus me having to loop through every user's _AD_GetObjectProperties to ensure that all the properties are returned, etc. I really think this call, if it can be fixed to get the TimeStamps could seriously improve performance overall.

Link to comment
Share on other sites

JoshuaBarnette,

I had a situation similar to you a few years ago, and I wrote >_AD_GetLastLogonTimeStamp by editing _AD_GetPasswordExpired.  This function works like _AD_GetLastLoginDate and _AD_GetPasswordExpired.  This may help with what you are trying to do.  

I also like the idea of the time stamps in a readable format in the return from _AD_GetObjectsInOU, but I haven't looked into how much coding that would require.  

 

Adam

Link to comment
Share on other sites

I have been thinking about this issue. The UDF function _AD_GetObjectsInOU has it's main goal to return objects the user searches for plus some of the properties.

So the UDF function will never translate any properties like _AD_GetObjectProperties does.

But feel free to write such a function yourself when performance is a goal.

Unfortunately I don't have much spare time at the moment to make _AD_GetObjectsInOU translate the properties.

But on the other hand I'm interested in any solution you might post here for other users.

My UDFs and Tutorials:

Spoiler

UDFs:
Active Directory (NEW 2022-02-19 - Version 1.6.1.0) - Download - General Help & Support - Example Scripts - Wiki
ExcelChart (2017-07-21 - Version 0.4.0.1) - Download - General Help & Support - Example Scripts
OutlookEX (2021-11-16 - Version 1.7.0.0) - Download - General Help & Support - Example Scripts - Wiki
OutlookEX_GUI (2021-04-13 - Version 1.4.0.0) - Download
Outlook Tools (2019-07-22 - Version 0.6.0.0) - Download - General Help & Support - Wiki
PowerPoint (2021-08-31 - Version 1.5.0.0) - Download - General Help & Support - Example Scripts - Wiki
Task Scheduler (NEW 2022-07-28 - Version 1.6.0.1) - Download - General Help & Support - Wiki

Standard UDFs:
Excel - Example Scripts - Wiki
Word - Wiki

Tutorials:
ADO - Wiki
WebDriver - Wiki

 

Link to comment
Share on other sites

Water,

I have spent a couple of days off and between yesterday and today, I have combined both functions into one and hope you will be pleased with the updated function. This combines the aspects of _AD_GetObjectsInOU and _AD_GetObjectProperties you get the speed of GetObjectInOU and the versatility of GetObjectProperties. I have test and see great results. Please let me know what you think and if you might include these changes in the next UDF revision?

; #FUNCTION# ====================================================================================================================
; Name...........: _AD_GetObjectsInOU
; Description ...: Returns a filtered array of objects and attributes for a given OU or just the number of records if $bCount is True.
; Syntax.........: _AD_GetObjectsInOU($sOU[, $sFilter = "(name=*)"[, $iSearchScope = 2[, $sDataToRetrieve =  "sAMAccountName"[, $sSortBy = "sAMAccountName"[, $bCount = False]]]]])
; Parameters ....: $sOU - The OU to retrieve from (FQDN) (default = "", equals "search the whole AD tree")
;                  $sFilter - Optional: An additional LDAP filter if required (default = "(name=*)")
;                  $iSearchScope - Optional: 0 = base, 1 = one-level, 2 = sub-tree (default)
;                  $sDataToRetrieve - Optional: A comma-seperated list of attributes to retrieve (default = "sAMAccountName").
;                  |More than one attribute will create a 2-dimensional array
;                  $sSortBy - Optional: name of the attribute the resulting array will be sorted upon (default = "sAMAccountName").
;                  |To completely suppress sorting (even the default sort) set this parameter to "". This improves performance when doing large queries
;                  $bCount - Optional: If set to True only returns the number of records returned by the query (default = "False")
; Return values .: Success - Number of records retrieved or a one or two dimensional array of objects and attributes in the given OU. First entry is for the given OU itself
;                  Failure - "", sets @error to:
;                  |1 - Specified OU does not exist
;                  |2 - No records returned from Active Directory. $sDataToRetrieve is invalid (attribute may not exist). @extended is set to the error returned by LDAP
;                  |3 - No records returned from Active Directory. $sFilter didn't return a record
; Author ........: Jonathan Clelland, Sundance
; Modified.......: water, JoshuaBarnette
; Remarks .......: The default filter returns an array including one record for the OU itself. To exclude the OU use a different filter that doesn't include the OU
;                  e.g. "(&(objectcategory=person)(objectclass=user)(name=*))"
;+
;                  To make sure that all properties you specify in $sDataToRetrieve exist in the AD you can use _AD_ObjectExistsInSchema.
;+
;                  The following examples illustrate the use of the escaping mechanism in the LDAP filter:
;                    (o=Parens R Us \28for all your parenthetical needs\29)
;                    (cn=*\2A*)
;                    (filename=C:\5cMyFile)
;                    (bin=\00\00\00\04)
;                    (sn=Lu\c4\8di\c4\87)
;                  The first example shows the use of the escaping mechanism to represent parenthesis characters.
;                  The second shows how to represent a "*" in a value, preventing it from being interpreted as a substring indicator.
;                  The third illustrates the escaping of the backslash character.
;                  The fourth example shows a filter searching for the four-byte value 0x00000004, illustrating the use of the escaping mechanism to
;                  represent arbitrary data, including NUL characters.
;                  The final example illustrates the use of the escaping mechanism to represent various non-ASCII UTF-8 characters.
; Related .......: _AD_GetAllOUs
; Link ..........:
; Example .......: Yes
; ===============================================================================================================================
Func _AD_GetObjectsInOU($sOU = "", $sFilter = "(name=*)", $iSearchScope = 2, $sDataToRetrieve = "sAMAccountName", $sSortBy = "sAMAccountName", $bCount = False)

    Local $oObject
    Local $oItem, $oPropertyEntry, $oValue, $iCount3, $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 $sOU = "" Then
        $sOU = $sAD_DNSDomain
    Else
        If _AD_ObjectExists($sOU, "distinguishedName") = 0 Then Return SetError(1, 0, "")
    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 & ";ADsPath"
    $__oAD_Command.Properties("Sort On") = $sSortBy
    Local $oRecordSet = $__oAD_Command.Execute
    If @error Or Not IsObj($oRecordSet) Then Return SetError(2, @error, "")
    Local $rCount = $oRecordSet.RecordCount
    If $rCount = 0 Then
        If $bCount Then Return SetError(3, 0, 0)
        Return SetError(3, 0, "")
    EndIf
    If $bCount Then Return $rCount

    If StringInStr($sDataToRetrieve, ",") Then
        $aDataToRetrieve = StringSplit($sDataToRetrieve, ",")
        Local $aObjects[$rCount + 1][$aDataToRetrieve[0]]
        $aObjects[0][0] = $rCount
        $aObjects[0][1] = $aDataToRetrieve[0]
        $crCount = 1 ; Current Record
        $oRecordSet.MoveFirst
        Do
            Local $sLDAPEntry = $oRecordSet.fields(0).Value
            $oObject = __AD_ObjGet($sLDAPEntry) ; Retrieve the COM Object
            $oObject.GetInfo()
            Local $iCount1 = $oObject.PropertyCount()
            For $iCount2 = 0 To $iCount1 - 1
                $oItem = $oObject.Item($iCount2)
                $pIndex = _ArraySearch($aDataToRetrieve, $oItem.Name)
                If @Error Then ContinueLoop
                $oPropertyEntry = $oObject.GetPropertyItem($oItem.Name, $ADSTYPE_UNKNOWN)
                If Not IsObj($oPropertyEntry) Then
                    Return SetError(2, 0, $oItem.Name)
                Else
                    For $vPropertyValue In $oPropertyEntry.Values
                        If $oItem.ADsType = $ADSTYPE_CASE_IGNORE_STRING Then
                            $aObjects[$crCount][$pIndex - 1] = $vPropertyValue.CaseIgnoreString
                        ElseIf $oItem.ADsType = $ADSTYPE_INTEGER Then
                            If $oItem.Name = "sAMAccountType" Then
                                For $iCount4 = 0 To 11
                                    If $vPropertyValue.Integer = $aSAMAccountType[$iCount4][1] Then
                                        $aObjects[$crCount][$pIndex - 1] = $aSAMAccountType[$iCount4][0]
                                        ExitLoop
                                    EndIf
                                Next
                            ElseIf $oItem.Name = "userAccountControl" Then
                                $aObjects[$crCount][$pIndex - 1] = $vPropertyValue.Integer & " = "
                                For $iCount4 = 0 To 20
                                    If BitAND($vPropertyValue.Integer, $aUAC[$iCount4][0]) = $aUAC[$iCount4][0] Then
                                        $aObjects[$crCount][$pIndex - 1] &= $aUAC[$iCount4][1] & " - "
                                    EndIf
                                Next
                                If StringRight($aObjects[$crCount][$pIndex - 1], 3) = " - " Then $aObjects[$crCount][$pIndex - 1] = StringTrimRight($aObjects[$crCount][$pIndex - 1], 3)
                            Else
                                $aObjects[$crCount][$pIndex - 1] = $vPropertyValue.Integer
                            EndIf
                        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
                                    $aObjects[$crCount][$pIndex - 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))
                                    $aObjects[$crCount][$pIndex - 1] = _Date_Time_SystemTimeToDateTimeStr($sTemp3, 1)
                                EndIf
                            Else
                                $aObjects[$crCount][$pIndex - 1] = __AD_LargeInt2Double($vPropertyValue.LargeInteger.LowPart, $vPropertyValue.LargeInteger.HighPart)
                            EndIf
                        ElseIf $oItem.ADsType = $ADSTYPE_OCTET_STRING Then
                            $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
                                $aObjects[$crCount][$pIndex - 1] = _Security__SidToStringSid(DllStructGetPtr($xAD_Dummy)) ; SID
                            Else
                                $aObjects[$crCount][$pIndex - 1] = _WinAPI_StringFromGUID(DllStructGetPtr($xAD_Dummy)) ; GUID
                            EndIf
                        ElseIf $oItem.ADsType = $ADSTYPE_DN_STRING Then
                            $aObjects[$crCount][$pIndex - 1] = $vPropertyValue.DNString
                        ElseIf $oItem.ADsType = $ADSTYPE_UTC_TIME Then
                            Local $iDateTime = $vPropertyValue.UTCTime
                            $aObjects[$crCount][$pIndex - 1] = StringLeft($iDateTime, 4) & "/" & StringMid($iDateTime, 5, 2) & "/" & StringMid($iDateTime, 7, 2) & _
                                    " " & StringMid($iDateTime, 9, 2) & ":" & StringMid($iDateTime, 11, 2) & ":" & StringMid($iDateTime, 13, 2)
                        ElseIf $oItem.ADsType = $ADSTYPE_BOOLEAN Then
                            If $vPropertyValue.Boolean = 0 Then
                                $aObjects[$crCount][$pIndex - 1] = "False"
                            Else
                                $aObjects[$crCount][$pIndex - 1] = "True"
                            EndIf
                        ElseIf $oItem.ADsType = $ADSTYPE_NT_SECURITY_DESCRIPTOR Then
                            $oValue = $vPropertyValue.SecurityDescriptor
                            $aObjects[$crCount][$pIndex - 1] = "Control:" & $oValue.Control & ", " & _
                                    "Group:" & $oValue.Group & ", " & _
                                    "Owner:" & $oValue.Owner & ", " & _
                                    "Revision:" & $oValue.Revision
                        Else
                            $aObjects[$crCount][$pIndex - 1] = "Unknown ADsType" & $oItem.ADsType
                        EndIf
                    Next
                EndIf
            Next
            $oRecordSet.MoveNext
            $crCount += 1
        Until $oRecordSet.EOF
    Else
        Local $aObjects[$rCount + 1]
        $aObjects[0] = $rCount
        $crCount = 1 ; Current Record
        $oRecordSet.MoveFirst
        Do
            Local $sLDAPEntry = $oRecordSet.fields(0).Value
            $oObject = __AD_ObjGet($sLDAPEntry) ; Retrieve the COM Object
            $oObject.GetInfo()
            Local $iCount1 = $oObject.PropertyCount()
            For $iCount2 = 0 To $iCount1 - 1
                $oItem = $oObject.Item($iCount2)
                $sDataToRetrieve = "," & $sDataToRetrieve & ","
                If Not StringInStr($sDataToRetrieve, "," & $oItem.Name & ",") Then ContinueLoop
                $oPropertyEntry = $oObject.GetPropertyItem($oItem.Name, $ADSTYPE_UNKNOWN)
                If Not IsObj($oPropertyEntry) Then
                    Return SetError(2, 0, $oItem.Name)
                Else
                    For $vPropertyValue In $oPropertyEntry.Values
                        If $oItem.ADsType = $ADSTYPE_CASE_IGNORE_STRING Then
                            $aObjects[$crCount] = $vPropertyValue.CaseIgnoreString
                        ElseIf $oItem.ADsType = $ADSTYPE_INTEGER Then
                            If $oItem.Name = "sAMAccountType" Then
                                For $iCount4 = 0 To 11
                                    If $vPropertyValue.Integer = $aSAMAccountType[$iCount4][1] Then
                                        $aObjects[$crCount] = $aSAMAccountType[$iCount4][0]
                                        ExitLoop
                                    EndIf
                                Next
                            ElseIf $oItem.Name = "userAccountControl" Then
                                $aObjects[$crCount] = $vPropertyValue.Integer & " = "
                                For $iCount4 = 0 To 20
                                    If BitAND($vPropertyValue.Integer, $aUAC[$iCount4][0]) = $aUAC[$iCount4][0] Then
                                        $aObjects[$crCount] &= $aUAC[$iCount4][1] & " - "
                                    EndIf
                                Next
                                If StringRight($aObjects[$crCount], 3) = " - " Then $aObjects[$crCount] = StringTrimRight($aObjects[$crCount], 3)
                            Else
                                $aObjects[$crCount] = $vPropertyValue.Integer
                            EndIf
                        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
                                    $aObjects[$crCount] = "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))
                                    $aObjects[$crCount] = _Date_Time_SystemTimeToDateTimeStr($sTemp3, 1)
                                EndIf
                            Else
                                $aObjects[$crCount] = __AD_LargeInt2Double($vPropertyValue.LargeInteger.LowPart, $vPropertyValue.LargeInteger.HighPart)
                            EndIf
                        ElseIf $oItem.ADsType = $ADSTYPE_OCTET_STRING Then
                            $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
                                $aObjects[$crCount] = _Security__SidToStringSid(DllStructGetPtr($xAD_Dummy)) ; SID
                            Else
                                $aObjects[$crCount] = _WinAPI_StringFromGUID(DllStructGetPtr($xAD_Dummy)) ; GUID
                            EndIf
                        ElseIf $oItem.ADsType = $ADSTYPE_DN_STRING Then
                            $aObjects[$crCount] = $vPropertyValue.DNString
                        ElseIf $oItem.ADsType = $ADSTYPE_UTC_TIME Then
                            Local $iDateTime = $vPropertyValue.UTCTime
                            $aObjects[$crCount] = StringLeft($iDateTime, 4) & "/" & StringMid($iDateTime, 5, 2) & "/" & StringMid($iDateTime, 7, 2) & _
                                    " " & StringMid($iDateTime, 9, 2) & ":" & StringMid($iDateTime, 11, 2) & ":" & StringMid($iDateTime, 13, 2)
                        ElseIf $oItem.ADsType = $ADSTYPE_BOOLEAN Then
                            If $vPropertyValue.Boolean = 0 Then
                                $aObjects[$crCount] = "False"
                            Else
                                $aObjects[$crCount] = "True"
                            EndIf
                        ElseIf $oItem.ADsType = $ADSTYPE_NT_SECURITY_DESCRIPTOR Then
                            $oValue = $vPropertyValue.SecurityDescriptor
                            $aObjects[$crCount] = "Control:" & $oValue.Control & ", " & _
                                    "Group:" & $oValue.Group & ", " & _
                                    "Owner:" & $oValue.Owner & ", " & _
                                    "Revision:" & $oValue.Revision
                        Else
                            $aObjects[$crCount] = "Unknown ADsType" & $oItem.ADsType
                        EndIf
                    Next
                EndIf
            Next
            $oRecordSet.MoveNext
            $crCount += 1
        Until $oRecordSet.EOF
    EndIf
    $__oAD_Command.Properties("Sort On") = "" ; Reset sort property
    Return $aObjects

EndFunc   ;==>_AD_GetObjectsInOU
Link to comment
Share on other sites

Thanks a lot for this modification!

I will have a look as soon as I find some spare time. Maybe I will make it an optional feature that can be switched on/off by the user.

My UDFs and Tutorials:

Spoiler

UDFs:
Active Directory (NEW 2022-02-19 - Version 1.6.1.0) - Download - General Help & Support - Example Scripts - Wiki
ExcelChart (2017-07-21 - Version 0.4.0.1) - Download - General Help & Support - Example Scripts
OutlookEX (2021-11-16 - Version 1.7.0.0) - Download - General Help & Support - Example Scripts - Wiki
OutlookEX_GUI (2021-04-13 - Version 1.4.0.0) - Download
Outlook Tools (2019-07-22 - Version 0.6.0.0) - Download - General Help & Support - Wiki
PowerPoint (2021-08-31 - Version 1.5.0.0) - Download - General Help & Support - Example Scripts - Wiki
Task Scheduler (NEW 2022-07-28 - Version 1.6.0.1) - Download - General Help & Support - Wiki

Standard UDFs:
Excel - Example Scripts - Wiki
Word - Wiki

Tutorials:
ADO - Wiki
WebDriver - Wiki

 

Link to comment
Share on other sites

  • 2 weeks later...

Hi Water

Is there a way to recurse someone's surname and populate their domain windows username, just like when adding domain users to the local Administrators or Power Users security groups?

Many thanks in advance

Iceman

Edited by Iceman682
Link to comment
Share on other sites

Have you tried _AD_GetObjectsInOU?

My UDFs and Tutorials:

Spoiler

UDFs:
Active Directory (NEW 2022-02-19 - Version 1.6.1.0) - Download - General Help & Support - Example Scripts - Wiki
ExcelChart (2017-07-21 - Version 0.4.0.1) - Download - General Help & Support - Example Scripts
OutlookEX (2021-11-16 - Version 1.7.0.0) - Download - General Help & Support - Example Scripts - Wiki
OutlookEX_GUI (2021-04-13 - Version 1.4.0.0) - Download
Outlook Tools (2019-07-22 - Version 0.6.0.0) - Download - General Help & Support - Wiki
PowerPoint (2021-08-31 - Version 1.5.0.0) - Download - General Help & Support - Example Scripts - Wiki
Task Scheduler (NEW 2022-07-28 - Version 1.6.0.1) - Download - General Help & Support - Wiki

Standard UDFs:
Excel - Example Scripts - Wiki
Word - Wiki

Tutorials:
ADO - Wiki
WebDriver - Wiki

 

Link to comment
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
 Share

×
×
  • Create New...