Jump to content

Active Directory UDF - Help & Support


water
 Share

Recommended Posts

Looks quite good so far. There must be a discrepancy between the number of records returned and $oAD_RecordSet.RecordCount.

Could you please run this modified version? It writes a line for every record (in your case 960) and will show us the record number and the record content where it fails:

#include <AD.au3>

_AD_Open()
Global $aDisabled[1]
$aDisabled = _AD_GetObjectsDisabledEX()
If @error > 0 Then
    MsgBox(64, "Active Directory Functions - Example 1", "No disabled user accounts could be found")
Else
    _ArrayDisplay($aDisabled, "Active Directory Functions - Example 1 - Disabled User Accounts")
EndIf
_AD_Close()

Func _AD_GetObjectsDisabledEX($sAD_Class = "user")

    If $sAD_Class <> "user" And $sAD_Class <> "computer" Then Return SetError(1, 0, "")
    Local $sAD_Query = "<LDAP://" & $sAD_HostServer & "/" & $sAD_DNSDomain & ">;(&(objectcategory=" & $sAD_Class & ")(!userAccountControl:1.2.840.113556.1.4.803:=" & _
            $ADS_UF_ACCOUNTDISABLE & "));distinguishedName;subtree"
    Local $oAD_RecordSet = $oAD_Connection.Execute($sAD_Query)
    ConsoleWrite("Execute: " & @error & "-" & IsObj($oAD_RecordSet) & @CRLF)
    ConsoleWrite("RecordCount: " & $oAD_RecordSet.RecordCount & @CRLF)
    Local $aAD_FQDN[$oAD_RecordSet.RecordCount + 1]
    $aAD_FQDN[0] = $oAD_RecordSet.RecordCount
    Local $iCount1 = 1
    While Not $oAD_RecordSet.EOF
        ConsoleWrite($iCount1 & ":" & $oAD_RecordSet.Fields(0).Value & @CRLF)
        $aAD_FQDN[$iCount1] = $oAD_RecordSet.Fields(0).Value
        $iCount1 += 1
        $oAD_RecordSet.MoveNext
    WEnd
    Return $aAD_FQDN

EndFunc   ;==>_AD_GetObjectsDisabledEX

I've noticed a problem with the way the query is executed. It only returns a max of 1000 records.

I might have to change the way the function works :graduated:

i get 961 lines.

.

.

959:CN=[id1],OU=[ou],OU=[ou2],DC=[DC],DC=[DC2],DC=[DC3]

960:CN=[id2],OU=[ou],OU=[ou2],DC=[DC],DC=[DC2],DC=[DC3]

961:CN=[id3],OU=[ou],OU=[ou2],DC=[DC],DC=[DC2],DC=[DC3]

Sorry, had to redact the actual content. looking more closely at these last 3 ids only one is a user, the other two are just contact objects which is weird since they should be user objects. they are not disabled either. alphabetically the results get to 'fs***' before punking out.

unles im misnterperting this the recordset should only contain disabled user objects. in this case it does not. the results of that query are something else.

Link to comment
Share on other sites

I've noticed a problem with the way the query is executed. It only returns a max of 1000 records.

I might have to change the way the function works :graduated:

Unless you change the settings in AD you will only get 1000 records per search, it's the default that Microsoft has set for AD. You can do it remotely using ntdsutil.exe, or directly on the server itself. It's the MaxPageSize setting you need to change.

If I posted any code, assume that code was written using the latest release version unless stated otherwise. Also, if it doesn't work on XP I can't help with that because I don't have access to XP, and I'm not going to.
Give a programmer the correct code and he can do his work for a day. Teach a programmer to debug and he can do his work for a lifetime - by Chirag Gude
How to ask questions the smart way!

I hereby grant any person the right to use any code I post, that I am the original author of, on the autoitscript.com forums, unless I've specifically stated otherwise in the code or the thread post. If you do use my code all I ask, as a courtesy, is to make note of where you got it from.

Back up and restore Windows user files _Array.au3 - Modified array functions that include support for 2D arrays.  -  ColorChooser - An add-on for SciTE that pops up a color dialog so you can select and paste a color code into a script.  -  Customizable Splashscreen GUI w/Progress Bar - Create a custom "splash screen" GUI with a progress bar and custom label.  -  _FileGetProperty - Retrieve the properties of a file  -  SciTE Toolbar - A toolbar demo for use with the SciTE editor  -  GUIRegisterMsg demo - Demo script to show how to use the Windows messages to interact with controls and your GUI.  -   Latin Square password generator

Link to comment
Share on other sites

I've slightly modified the test script. The array now has a predefined size of 2000 elements. So we will know if we just get Recordcount+1 records or even more.

In addition the objectcategory is written to the console so we can check the type of records returned.

Could you please post the (anonymized) output?

Thanks

BTW: My previous test script had a bug. For testing purposes it returned all users that are NOT disabled. Todays version should work as needed.

#include <AD.au3>

_AD_Open()
Global $aDisabled[1]
$iAD_Debug = 2
$aDisabled = _AD_GetObjectsDisabledEX()
If @error > 0 Then
    MsgBox(64, "Active Directory Functions - Example 1", "No disabled user accounts could be found")
Else
    _ArrayDisplay($aDisabled, "Active Directory Functions - Example 1 - Disabled User Accounts")
EndIf
_AD_Close()

Func _AD_GetObjectsDisabledEX($sAD_Class = "user")

    If $sAD_Class <> "user" And $sAD_Class <> "computer" Then Return SetError(1, 0, "")
    Local $sAD_Query = "<LDAP://" & $sAD_HostServer & "/" & $sAD_DNSDomain & ">;(&(objectcategory=" & $sAD_Class & ")(userAccountControl:1.2.840.113556.1.4.803:=" & _
            $ADS_UF_ACCOUNTDISABLE & "));distinguishedName,objectcategory;subtree"
    Local $oAD_RecordSet = $oAD_Connection.Execute($sAD_Query)
    ConsoleWrite("Execute: " & @error & "-" & IsObj($oAD_RecordSet) & @CRLF)
    ConsoleWrite("RecordCount: " & $oAD_RecordSet.RecordCount & @CRLF)
    Local $aAD_FQDN[2000]
    $aAD_FQDN[0] = $oAD_RecordSet.RecordCount
    Local $iCount1 = 1
    While Not $oAD_RecordSet.EOF
        ConsoleWrite($iCount1 & " : " & $oAD_RecordSet.Fields(0).Value & " : " & $oAD_RecordSet.Fields(1).Value & @CRLF)
        $aAD_FQDN[$iCount1] = $oAD_RecordSet.Fields(0).Value
        $iCount1 += 1
        $oAD_RecordSet.MoveNext
    WEnd
    Return $aAD_FQDN

EndFunc   ;==>_AD_GetObjectsDisabledEX

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've slightly modified the test script. The array now has a predefined size of 2000 elements. So we will know if we just get Recordcount+1 records or even more.

In addition the objectcategory is written to the console so we can check the type of records returned.

Could you please post the (anonymized) output?

Thanks

BTW: My previous test script had a bug. For testing purposes it returned all users that are NOT disabled. Todays version should work as needed.

#include <AD.au3>

_AD_Open()
Global $aDisabled[1]
$iAD_Debug = 2
$aDisabled = _AD_GetObjectsDisabledEX()
If @error > 0 Then
    MsgBox(64, "Active Directory Functions - Example 1", "No disabled user accounts could be found")
Else
    _ArrayDisplay($aDisabled, "Active Directory Functions - Example 1 - Disabled User Accounts")
EndIf
_AD_Close()

Func _AD_GetObjectsDisabledEX($sAD_Class = "user")

    If $sAD_Class <> "user" And $sAD_Class <> "computer" Then Return SetError(1, 0, "")
    Local $sAD_Query = "<LDAP://" & $sAD_HostServer & "/" & $sAD_DNSDomain & ">;(&(objectcategory=" & $sAD_Class & ")(userAccountControl:1.2.840.113556.1.4.803:=" & _
            $ADS_UF_ACCOUNTDISABLE & "));distinguishedName,objectcategory;subtree"
    Local $oAD_RecordSet = $oAD_Connection.Execute($sAD_Query)
    ConsoleWrite("Execute: " & @error & "-" & IsObj($oAD_RecordSet) & @CRLF)
    ConsoleWrite("RecordCount: " & $oAD_RecordSet.RecordCount & @CRLF)
    Local $aAD_FQDN[2000]
    $aAD_FQDN[0] = $oAD_RecordSet.RecordCount
    Local $iCount1 = 1
    While Not $oAD_RecordSet.EOF
        ConsoleWrite($iCount1 & " : " & $oAD_RecordSet.Fields(0).Value & " : " & $oAD_RecordSet.Fields(1).Value & @CRLF)
        $aAD_FQDN[$iCount1] = $oAD_RecordSet.Fields(0).Value
        $iCount1 += 1
        $oAD_RecordSet.MoveNext
    WEnd
    Return $aAD_FQDN

EndFunc   ;==>_AD_GetObjectsDisabledEX

Execute: 0-1

RecordCount: 960

1 : CN=[id1],CN=Users,DC=[DC1],DC=[DC2],DC=[DC3] : CN=Person,CN=Schema,CN=Configuration,[DC1],DC=[DC2],DC=[DC3]

.

.

.

999 : CN=[id999],OU=[OU],OU=[ou2],DC=[DC1],DC=[DC2],DC=[DC3]: CN=Person,CN=Schema,CN=Configuration,DC=[DC1],DC=[DC2],DC=[DC3]

COM Error Encountered in AD tests.au3

scriptline 29

NumberHex = 80020009

Number = -2147352567

WinDescription = The size limit for this request was exceeded

Description = the size limit for this request was exceeded.

source = provider

HelpContext = 1240640

lastdllerror = 0

i get the above pop up for every line after 999,

looks like i can only return 1000 as well. though the code you posted earlier:

$array = _AD_GetObjectsInOU("", "(&(objectcategory=user)(userAccountControl:1.2.840.113556.1.4.803:=" & $ADS_UF_ACCOUNTDISABLE & "))", 2, "CN,description")
_ArrayDisplay($array)

is quite useful since it returns all disabled users (bout 2200) very quickly.

Link to comment
Share on other sites

Thanks for your reply!

I've modified the script to remove the 1000 records limit.

Could you please test and report if you now get the 2200 users?

#include <AD.au3>

_AD_Open()
Global $aDisabled[1]
$iAD_Debug = 2
$aDisabled = _AD_GetObjectsDisabledEX()
If @error > 0 Then
    MsgBox(64, "Active Directory Functions - Example 1", "No disabled user accounts could be found")
Else
    _ArrayDisplay($aDisabled, "Active Directory Functions - Example 1 - Disabled User Accounts")
EndIf
_AD_Close()

Func _AD_GetObjectsDisabledEX($sAD_Class = "user")

    If $sAD_Class <> "user" And $sAD_Class <> "computer" Then Return SetError(1, 0, "")
    Local $oAD_Command = ObjCreate("ADODB.Command")
    $oAD_Command.ActiveConnection = $oAD_Connection
    $oAD_Command.Properties("Page Size") = 1000
    $oAD_Command.CommandText = "<LDAP://" & $sAD_HostServer & "/" & $sAD_DNSDomain & ">;(&(objectcategory=" & $sAD_Class & ")(userAccountControl:1.2.840.113556.1.4.803:=" & _
            $ADS_UF_ACCOUNTDISABLE & "));distinguishedName,objectcategory;subtree"
    Local $oAD_RecordSet = $oAD_Command.Execute
    ConsoleWrite("Execute: " & @error & "-" & IsObj($oAD_RecordSet) & @CRLF)
    ConsoleWrite("RecordCount: " & $oAD_RecordSet.RecordCount & @CRLF)
    Local $aAD_FQDN[$oAD_RecordSet.RecordCount + 1]
    $aAD_FQDN[0] = $oAD_RecordSet.RecordCount
    Local $iCount1 = 1
    While Not $oAD_RecordSet.EOF
        ConsoleWrite($iCount1 & " : " & $oAD_RecordSet.Fields(0).Value & " : " & $oAD_RecordSet.Fields(1).Value & @CRLF)
        $aAD_FQDN[$iCount1] = $oAD_RecordSet.Fields(0).Value
        $iCount1 += 1
        $oAD_RecordSet.MoveNext
    WEnd
    Return $aAD_FQDN

EndFunc   ;==>_AD_GetObjectsDisabledEX

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

Thanks for your reply!

I've modified the script to remove the 1000 records limit.

Could you please test and report if you now get the 2200 users?

#include <AD.au3>

_AD_Open()
Global $aDisabled[1]
$iAD_Debug = 2
$aDisabled = _AD_GetObjectsDisabledEX()
If @error > 0 Then
    MsgBox(64, "Active Directory Functions - Example 1", "No disabled user accounts could be found")
Else
    _ArrayDisplay($aDisabled, "Active Directory Functions - Example 1 - Disabled User Accounts")
EndIf
_AD_Close()

Func _AD_GetObjectsDisabledEX($sAD_Class = "user")

    If $sAD_Class <> "user" And $sAD_Class <> "computer" Then Return SetError(1, 0, "")
    Local $oAD_Command = ObjCreate("ADODB.Command")
    $oAD_Command.ActiveConnection = $oAD_Connection
    $oAD_Command.Properties("Page Size") = 1000
    $oAD_Command.CommandText = "<LDAP://" & $sAD_HostServer & "/" & $sAD_DNSDomain & ">;(&(objectcategory=" & $sAD_Class & ")(userAccountControl:1.2.840.113556.1.4.803:=" & _
            $ADS_UF_ACCOUNTDISABLE & "));distinguishedName,objectcategory;subtree"
    Local $oAD_RecordSet = $oAD_Command.Execute
    ConsoleWrite("Execute: " & @error & "-" & IsObj($oAD_RecordSet) & @CRLF)
    ConsoleWrite("RecordCount: " & $oAD_RecordSet.RecordCount & @CRLF)
    Local $aAD_FQDN[$oAD_RecordSet.RecordCount + 1]
    $aAD_FQDN[0] = $oAD_RecordSet.RecordCount
    Local $iCount1 = 1
    While Not $oAD_RecordSet.EOF
        ConsoleWrite($iCount1 & " : " & $oAD_RecordSet.Fields(0).Value & " : " & $oAD_RecordSet.Fields(1).Value & @CRLF)
        $aAD_FQDN[$iCount1] = $oAD_RecordSet.Fields(0).Value
        $iCount1 += 1
        $oAD_RecordSet.MoveNext
    WEnd
    Return $aAD_FQDN

EndFunc   ;==>_AD_GetObjectsDisabledEX

no problem, glad i could help

yep that works nicely. i get 2283, same number reported by the other code. it completes without error.

Link to comment
Share on other sites

Hi SpinningCone,

thanks a lot for your patience to track down this error!

The builtin records limit of 1000 was the culprit!

I have already enumerated all affected functions and will change them as soon as possible and release a new version.

Greetings from Austria

water

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

Hi SpinningCone,

thanks a lot for your patience to track down this error!

The builtin records limit of 1000 was the culprit!

I have already enumerated all affected functions and will change them as soon as possible and release a new version.

Greetings from Austria

water

NP, thanks for your help awith my messy scripts and for releasing this great UDF. guess it's a hard bug to catch if you test against a record set smaller than 1000 ;-)

on a different topic can this UDF delete contact objects? i noticed get objects in OU is capable of returning description and CN from contacts but getobjectProperties cant find them and delete can't find them. possibly because sAMAccountName is blank for contacts.

Link to comment
Share on other sites

on a different topic can this UDF delete contact objects? i noticed get objects in OU is capable of returning description and CN from contacts but getobjectProperties cant find them and delete can't find them. possibly because sAMAccountName is blank for contacts.

If you specify "distinguishedname" as the 4th parameter for _AD_GetObjectsInOU replacing the default of "samaccountname" then you can use the returned FQDN to delete the object using _AD_DeleteObject.

Edit: If this doesn't work, could you please post a distinguished name of such a contact (if you like you can anonymize company data)? The displayname is derived from the FQDN but might be wrong in certain situations.

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

If you specify "distinguishedname" as the 4th parameter for _AD_GetObjectsInOU replacing the default of "samaccountname" then you can use the returned FQDN to delete the object using _AD_DeleteObject.

Edit: If this doesn't work, could you please post a distinguished name of such a contact (if you like you can anonymize company data)? The displayname is derived from the FQDN but might be wrong in certain situations.

this actually works fine though you have to also put "contact" in the delete command which is technically undocumented. Even though delete works I'm still having the problems i had before with the network hanging. made the following script to delete contacts from our AD who don't have proper attributes (stored in a different database)

$log = FileOpen("ContactLog "&@MON&"-"&@MDAY&"-"&@YEAR&".txt",10)


    _AD_Open()

    $contactArray = _AD_GetObjectsInOU("", "(&(objectclass=contact)(!cn=_*))", 2, "CN,distinguishedname")

    For $i = 1 To UBound($contactArray) - 1

    $currentPID = StringLower($contactArray[$i][0])
    $adoRsReg = $adoCnRegistry.Execute("select * blah blach blah where $currentPID;")
                ;if the results are empty then they dont have proper attributes
                if $adoRsReg.eof Then
                    _AD_DeleteObject($contactArray[$i][1], "contact")
                    if @error Then
                        ConsoleWrite("error: " & @error)
                        Exit
                    EndIf
                    FileWriteLine($log,$currentPID & @tab & " Deleted")
                EndIf

            if mod($i, 10) = 0 then ConsoleWrite(".")
    next


    _AD_Close()
endfunc

i run this and i can process the first 192-193 lines of the array (very consistent its always 192 or 193). then it hangs

so i went into the UDF and commented out the 'ifexists' check and i can process 387 lines (almost exactly double the lines.)further debugging shows that its the _AD_ObjGet line that causes the Hang. putting a sleep(300) before the delete command in my code has no effect :-/

Link to comment
Share on other sites

Could you please put a

$iAD_Debug = x
at the start of your script?

x = 1 will display every COM error on the console

x = 2 will display every COM error using MSGBOX

x = 3 will write every COM error to file AD_Debug.txt in the @Scriptdir

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

Could you please put a

$iAD_Debug = x
at the start of your script?

x = 1 will display every COM error on the console

x = 2 will display every COM error using MSGBOX

x = 3 will write every COM error to file AD_Debug.txt in the @Scriptdir

this is the same error i got before. network resource not available. after some further snooping i found out that somewhere in _AD_ObjGet its doing a sasl bind with ldap. when they look at the servers they see hundreds of TCP connections. and since the connections don't close immediately it overloads the servers. looking in wireshark the server sends back TCP zerowindow messages which indicate that it cant receive data anymore.

each delete shows a bind success, search requests, a delete request, then it unbinds and sends a fin,ack. so for my script every contact it deletes opens a full TCP connection/session.

i'm not sure if there is away around this. i dont fully understand what the ldap object being returned by _AD_ObjGet is and how $oAD_OU.Delete() works. i'm not sure if there is a way to create batch functions which can more efficiently use TCP connection/sessions.

Link to comment
Share on other sites

Hi SpinningCone,

thank you very much for this very useful information and for taking the time to track down the problem.

As I'm not the original author of this UDF I just took what was already there and made a "real" UDF out of it adding examples, help file ...

It seems to be a design flaw that some functions use _AD_ObjGet which opens a new connection to AD every time it is called. I will check if there is a way to eliminte this function and to use the connection created by _AD_Open.

I hope to be back in a few days with a solution.

May I then ask you to test this new version and check if the number of connections has dropped?

This would be a great enhancement to the UDF.

Thanks

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

Hi SpinningCone,

thank you very much for this very useful information and for taking the time to track down the problem.

As I'm not the original author of this UDF I just took what was already there and made a "real" UDF out of it adding examples, help file ...

It seems to be a design flaw that some functions use _AD_ObjGet which opens a new connection to AD every time it is called. I will check if there is a way to eliminate this function and to use the connection created by _AD_Open.

I hope to be back in a few days with a solution.

May I then ask you to test this new version and check if the number of connections has dropped?

This would be a great enhancement to the UDF.

Thanks

water

NP thanks for picking up this UDF, it's still very useful especially for gathering information from AD. but the *doing* part needs some tweaking. I'll poke around inside the UDF myself and see if i can't figure out how to re-use an ldap session or otherwise avoid the network congestion caused by acting on large numbers of objects in sequence.

Link to comment
Share on other sites

i started digging around into COM objects and found this http://msdn.microsoft.com/en-us/library/ms806997.aspx

looking at the way the UDF works it has a rather expensive binding method. causing new binds with each get object. looks like if adOpen() is modified to do an initial bind to the root DSE and maintains that connection then _AD_ObjGet can be trimmed down to something like this GetObject("LDAP://cn=myUser,dc=myCompany,dc=com")

and since the root DSE is persistent it shouldn't do a full bind each time. I'll see if i can figure out how to do this and post some snippets.

Link to comment
Share on other sites

D'accord. The connection opened with _AD_Open should be used for every access to the AD.

I will try to understand how it works. Maybe we can improve the UDF in this part!

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

OK it looks like AD_Open does do what that link says. it does try to open a persistent rootDSE connection.

if i use _ad_Open() i still get individial binds.

if i use _ad_Open and include a username and password as part of it _AD_ObjGet uses the more complex bind $oAD_OpenDS.OpenDSObject() which causes individual binds. *however*

if i do this : _AD_Open("","",$sAD_DNSDomainParam,$sAD_HostServerParam,$sAD_ConfigurationParam) it works like a champ!

it looks like for some reason without putting in a $sAD_HostServerParam it dosent work. looking at the connect code all the variables seem the same. the only thing i can think of is that for some reason

$oAD_RootDSE = ObjGet("LDAP://" & $sAD_HostServerParam & "/RootDSE") works but $oAD_RootDSE = ObjGet("LDAP://RootDSE") doesen't. i have no idea why :-/

Link to comment
Share on other sites

As the $sAD_HostServerparam seems to be the key to our problem do you think this code change in _AD_Open will solve the problem (inserted line marked with <==)?

; Connect to another Domain if the Domain parameter is provided
    If $sAD_DNSDomainParam <> "" Then
        If $sAD_HostServerParam = "" Or $sAD_ConfigurationParam = "" Then Return SetError(6, 0, 0)
        $oAD_RootDSE = ObjGet("LDAP://" & $sAD_HostServerParam & "/RootDSE")
        If Not IsObj($oAD_RootDSE) Or @error <> 0 Then Return SetError(4, @error, 0)
        $sAD_DNSDomain = $sAD_DNSDomainParam
        $sAD_HostServer = $sAD_HostServerParam
        $sAD_Configuration = $sAD_ConfigurationParam
    Else
        $oAD_RootDSE = ObjGet("LDAP://RootDSE")
        If Not IsObj($oAD_RootDSE) Or @error <> 0 Then Return SetError(4, @error, 0)
        $sAD_DNSDomain = $oAD_RootDSE.Get("defaultNamingContext") ; Retrieve the current AD domain name
        $sAD_HostServer = $oAD_RootDSE.Get("dnsHostName") ; Retrieve the name of the connected DC
        $sAD_Configuration = $oAD_RootDSE.Get("ConfigurationNamingContext") ; Retrieve the Configuration naming context
        $oAD_RootDSE = ObjGet("LDAP://" & $sAD_HostServer & "/RootDSE")     ; <== Inserted
    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 tried to monitor the number of connections on my computer using Sysinternals Process Explorer.

I ran the following script but I only get 1 LDAP connection when _AD_Open() has finished. The calls to _AD_ObjGet do not create additional connections.

#include <AD.au3>
MsgBox(0,"Start","")
_AD_Open()
MsgBox(0,"0","")
$n = _AD_SamAccountNameToFQDN(@username)
$n1 = _AD_ObjGet("LDAP://" & $n)
MsgBox(0,"1","")
$n2 = _AD_ObjGet("LDAP://" & $n)
MsgBox(0,"2","")
_AD_Close()

How do you check the number of connections?

Do you check them on the client and/or the AD server?

What OS are you running?

What version of the AD UDF do you use?

I run Windows XP SP 3 and use the latest AD UDF version 0.41.

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

As the $sAD_HostServerparam seems to be the key to our problem do you think this code change in _AD_Open will solve the problem (inserted line marked with <==)?

; Connect to another Domain if the Domain parameter is provided
    If $sAD_DNSDomainParam <> "" Then
        If $sAD_HostServerParam = "" Or $sAD_ConfigurationParam = "" Then Return SetError(6, 0, 0)
        $oAD_RootDSE = ObjGet("LDAP://" & $sAD_HostServerParam & "/RootDSE")
        If Not IsObj($oAD_RootDSE) Or @error <> 0 Then Return SetError(4, @error, 0)
        $sAD_DNSDomain = $sAD_DNSDomainParam
        $sAD_HostServer = $sAD_HostServerParam
        $sAD_Configuration = $sAD_ConfigurationParam
    Else
        $oAD_RootDSE = ObjGet("LDAP://RootDSE")
        If Not IsObj($oAD_RootDSE) Or @error <> 0 Then Return SetError(4, @error, 0)
        $sAD_DNSDomain = $oAD_RootDSE.Get("defaultNamingContext") ; Retrieve the current AD domain name
        $sAD_HostServer = $oAD_RootDSE.Get("dnsHostName") ; Retrieve the name of the connected DC
        $sAD_Configuration = $oAD_RootDSE.Get("ConfigurationNamingContext") ; Retrieve the Configuration naming context
        $oAD_RootDSE = ObjGet("LDAP://" & $sAD_HostServer & "/RootDSE")     ; <== Inserted
    EndIf

i was thinking the same thing. building one root dse then doing a re-assign just havent had time to test it.

i'm runing windows 7 64 and i'm checking my connections by monitoring my packets with Wireshark. with a live trace i can see the differenece between the two types of qureis/binds . this may be something that acts differently from environment to environment. i can defenitely say that adding in the host server fixed the multiple bind problem for me.

Link to comment
Share on other sites

Guest
This topic is now closed to further replies.
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...