SpinningCone Posted December 7, 2010 Share Posted December 7, 2010 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 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 More sharing options...
BrewManNH Posted December 7, 2010 Share Posted December 7, 2010 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 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 GudeHow 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 More sharing options...
water Posted December 8, 2010 Author Share Posted December 8, 2010 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 2024-07-28 - Version 1.6.3.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 (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 More sharing options...
SpinningCone Posted December 8, 2010 Share Posted December 8, 2010 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 More sharing options...
water Posted December 8, 2010 Author Share Posted December 8, 2010 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 2024-07-28 - Version 1.6.3.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 (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 More sharing options...
SpinningCone Posted December 8, 2010 Share Posted December 8, 2010 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 More sharing options...
water Posted December 8, 2010 Author Share Posted December 8, 2010 (edited) 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 December 8, 2010 by water My UDFs and Tutorials: Spoiler UDFs: Active Directory (NEW 2024-07-28 - Version 1.6.3.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 (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 More sharing options...
SpinningCone Posted December 8, 2010 Share Posted December 8, 2010 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 AustriawaterNP, 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 More sharing options...
water Posted December 9, 2010 Author Share Posted December 9, 2010 (edited) 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 December 12, 2010 by water My UDFs and Tutorials: Spoiler UDFs: Active Directory (NEW 2024-07-28 - Version 1.6.3.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 (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 More sharing options...
SpinningCone Posted December 13, 2010 Share Posted December 13, 2010 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 More sharing options...
water Posted December 13, 2010 Author Share Posted December 13, 2010 Could you please put a $iAD_Debug = xat 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 2024-07-28 - Version 1.6.3.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 (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 More sharing options...
SpinningCone Posted December 13, 2010 Share Posted December 13, 2010 Could you please put a $iAD_Debug = xat 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 More sharing options...
water Posted December 14, 2010 Author Share Posted December 14, 2010 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 2024-07-28 - Version 1.6.3.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 (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 More sharing options...
SpinningCone Posted December 14, 2010 Share Posted December 14, 2010 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.ThankswaterNP 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 More sharing options...
SpinningCone Posted December 14, 2010 Share Posted December 14, 2010 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 More sharing options...
water Posted December 14, 2010 Author Share Posted December 14, 2010 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 2024-07-28 - Version 1.6.3.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 (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 More sharing options...
SpinningCone Posted December 14, 2010 Share Posted December 14, 2010 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 More sharing options...
water Posted December 15, 2010 Author Share Posted December 15, 2010 (edited) 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 December 15, 2010 by water My UDFs and Tutorials: Spoiler UDFs: Active Directory (NEW 2024-07-28 - Version 1.6.3.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 (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 More sharing options...
water Posted December 16, 2010 Author Share Posted December 16, 2010 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 2024-07-28 - Version 1.6.3.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 (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 More sharing options...
SpinningCone Posted December 16, 2010 Share Posted December 16, 2010 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 More sharing options...
Recommended Posts