water Posted February 6, 2013 Author Share Posted February 6, 2013 chaoticyeshua, can you please post your latest version of function _AD_HasRequiredRights__GivenMembers? I would like to replace the permission checking functions in the UDF with your version. In addition I want to modify the example script (permission checking, progress bar) so it can be used by other memberrs too. 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 February 6, 2013 Author Share Posted February 6, 2013 Can you please post how you call _AD_GetOUTreeView? There might be a way to improve performance. 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...
chaoticyeshua Posted February 6, 2013 Share Posted February 6, 2013 (edited) Hi Water! Sorry for the delay. Here's _AD_HasRequiredRights__GivenMembers. The only thing I really changed from the original is that you provide the groups the user is in to the function instead of it pulling those groups every time the function is called. It actually saved a lot of time. Func _AD_HasRequiredRights__GivenMembers($sAD_Object, $iAD_Right = 983551, $sAD_User = @UserName, $aAD_MemberOf = "") If StringMid($sAD_Object, 3, 1) <> "=" Then $sAD_Object = _AD_SamAccountNameToFQDN($sAD_Object) ; sAMAccountName provided Local $aAD_TrusteeArray, $sAD_TrusteeGroup, $sAD_TrusteeArrayFQDN Local $oAD_Object = __AD_ObjGet("LDAP://" & $sAD_HostServer & "/" & $sAD_Object) If IsObj($oAD_Object) Then Local $oAD_Security = $oAD_Object.Get("ntSecurityDescriptor") Local $oAD_DACL = $oAD_Security.DiscretionaryAcl For $oAD_ACE In $oAD_DACL $aAD_TrusteeArray = StringSplit($oAD_ACE.Trustee, "\") $sAD_TrusteeGroup = $aAD_TrusteeArray[$aAD_TrusteeArray[0]] If (UBound($aAD_TrusteeArray) - 1 ) = 2 And $aAD_TrusteeArray[2] = $sAD_User And BitAND($oAD_ACE.AccessMask, $iAD_Right) = $iAD_Right Then Return 1 If (UBound($aAD_TrusteeArray) - 1 ) = 2 Then $sAD_TrusteeArrayFQDN = _AD_SamAccountNameToFQDN($aAD_TrusteeArray[2]) EndIf For $iCount1 = 0 To UBound($aAD_MemberOf) - 1 If StringInStr($aAD_MemberOf[$iCount1], $sAD_TrusteeArrayFQDN) And _ BitAND($oAD_ACE.AccessMask, $iAD_Right) = $iAD_Right Then Return 1 If StringInStr($aAD_MemberOf[$iCount1], "CN=" & $sAD_TrusteeGroup & ",") And _ BitAND($oAD_ACE.AccessMask, $iAD_Right) = $iAD_Right Then Return 1 Next Next EndIf Return 0 EndFunc As for how I call _AD_GetOUTreeView, I've hardly changed the code you gave me at all and I am just running the script directly essentially as you gave it to me. Later on, I will call it only if it detects that a given computer object doesn't exist in AD already. The problem is that I work for a university, and we have close to 150 top level OUs (basically one for each department). In other words, unless the _AD_HasRequiredRights can somehow be further optimized, I don't think much else can be done about it. Edited February 6, 2013 by chaoticyeshua Link to comment Share on other sites More sharing options...
water Posted February 6, 2013 Author Share Posted February 6, 2013 Could you please set the following variables like this: Global $iScope = 1 ; Scope for the LDAP search to calculate the count. 1 = Only the OU, 2 = OU + sub-OUs Global $bCount = False ; True = Display the object count right to the OU Global $bDisplay = False ; True = Display objects in the OU as well (selection = $sCategory)It removes calculating the number of objects in the OUs and should enhance performance a lot. 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...
chaoticyeshua Posted February 6, 2013 Share Posted February 6, 2013 Water, Thanks for the suggestion! Unfortunately those changes had already been made. While it did help a lot with the speed, the three minute wait I was referring to is even after those changes. Link to comment Share on other sites More sharing options...
water Posted February 6, 2013 Author Share Posted February 6, 2013 This means we will need to do some time measurement to see where we need to improve the code. I'm going to implement your permission checking function and do some tests. 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 February 7, 2013 Author Share Posted February 7, 2013 Just built everything together and did some "performance" tests: 91 OUs including 20 top level OUs Total run time without permission check: 2.97 seconds Total run time with permission check: 5.8 seconds (only the 20 top OUs were checked because I have no permissions at all) 4.9 seconds to do the permission checks I will check if performance of the permission checking routine can be improved. 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 February 7, 2013 Author Share Posted February 7, 2013 (edited) Most time is spent doing the pre-windows-2000 check. If I remove this check the processing time drops from 5000 milliseconds to 500. Edited February 7, 2013 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 February 7, 2013 Author Share Posted February 7, 2013 How about this: Every SamAccountName is translated once to the FQDN and then stored in a Dictionary. The second time it can be found there and reduces the processing time. expandcollapse popup#region ;**** Directives created by AutoIt3Wrapper_GUI **** #AutoIt3Wrapper_UseX64=n #endregion ;**** Directives created by AutoIt3Wrapper_GUI **** #include <AD.au3> #include <TreeviewConstants.au3> #include <WindowsConstants.au3> #include <GUIConstants.au3> #include <GuiTreeView.au3> Global $sTitle = "Active Direcory OU Treeview" #region ### START Koda GUI section ### Form= Global $hMain = GUICreate($sTitle, 743, 683, -1, -1) Global $hTree = GUICtrlCreateTreeView(6, 6, 600, 666, -1, $WS_EX_CLIENTEDGE) Global $bExit = GUICtrlCreateButton("Exit", 624, 8, 97, 33) Global $bExpand = GUICtrlCreateButton("Expand all", 624, 56, 97, 33) Global $bCollapse = GUICtrlCreateButton("Collapse all", 624, 104, 97, 33) Global $bSelect = GUICtrlCreateButton("Select OU", 624, 152, 97, 33) Global $hProgress = GUICtrlCreateProgress(624, 200, 97, 20) GUISetState(@SW_SHOW) #endregion ### END Koda GUI section ### ;------------------------------ ; Make your changes below ;------------------------------ Global $sOU = "" ; FQDN of the OU where to start Global $sCategory = "computer" ; Category to select when counts should be displayed or full LDAP query Global $sText = " (Computer: %)" ; Text to use for the counts to display. % is replaced with the count Global $iScope = 1 ; Scope for the LDAP search to calculate the count. 1 = Only the OU, 2 = OU + sub-OUs Global $bCount = False ; True = Display the object count right to the OU Global $bDisplay = False ; True = Display objects in the OU as well (selection = $sCategory) Global $iTestTimerTotal Global $oDict = ObjCreate("Scripting.Dictionary") ;------------------------------ ; Make your changes above ;------------------------------ $iTestTimerTotal = TimerInit() Global $aTreeView = _AD_GetOUTreeView($sOU, $hTree, False, $bCount, $bDisplay, $sCategory, $sText, $iScope, $hProgress) If @error <> 0 Then MsgBox(16, "Active Direcory OU Treeview", "Error creating list of OUs starting with '" & $sOU & "'." & @CRLF & _ "Error returned by function _AD_GetALLOUs: @error = " & @error & ", @extended = " & @extended) MsgBox(0, "", "Total: " & TimerDiff($iTestTimerTotal)) Sleep(1000) GUICtrlDelete($hProgress) While 1 $Msg = GUIGetMsg() Switch $Msg Case $GUI_EVENT_CLOSE, $bExit Exit Case $bExpand _GUICtrlTreeView_Expand($hTree) Case $bCollapse _GUICtrlTreeView_Expand($hTree, 0, False) Case $bSelect $hSelection = _GUICtrlTreeView_GetSelection($hTree) $sSelection = _GUICtrlTreeView_GetText($hTree, $hSelection) For $i = 1 To $aTreeView[0][0] If $hSelection = $aTreeView[$i][2] Then ExitLoop Next $sOU = $aTreeView[$i][1] MsgBox(64, $sTitle & " - Selected OU", "Name: " & $sSelection & @CRLF & "FQDN: " & $sOU) EndSwitch WEnd ; #FUNCTION# ==================================================================================================================== ; Name...........: _AD_GetOUTreeView ; Description ...: Fills a given TreeView control with all OUs starting with a given OU. ; Syntax.........: _AD_GetOUTreeView($sOU, $hTreeView[, $bIsADOpen = False[, $bCount = False[, $bDisplay = False[, $sCategory = ""[, $sText = " (%)"[, $iSearchScope = 1[, $hProgress = Default]]]]]]]) ; Parameters ....: $sOU - FQDN of the OU where to start. "" displays all OUs ; $hTreeView - Handle of the TreeView where the OUs will be displayed. Has to be created in advance ; $bIsADOpen - Optional: Pass as True if the connection to the AD has already been made by the calling script (default = False) ; $bCount - Optional: True will display the count of objects in the OU right to the OU name (default = False) ; The LDAP query to determine the count is built from $sCategory ; $bDisplay - Optional: True will display the objects in the OU below the OU itself (default = False) ; $sCategory - Optional: Category to search for or the complete LDAP search string e.g. "computer" and "(objectcategory=computer)" are equivalent ; The number of found objects is added to the OUs name (default = "" = don't count objects) ; $sText - Optional: Text to display the count. Must contain a % which will be replaced by the actual number (default = " (%)") ; $iSearchScope - Optional: Search scope for function _AD_GetObjectsInOU: 0 = base, 1 = one-level, 2 = sub-tree (default = 1) ; $hProgress - Optional: ControlID of a progress bar to show during creation of the TreeView (default = Default) ; Return values .: Success - 1 ; Failure - Returns 0 and sets @error: ; |x - Function _AD_Open or _AD_GetAllOUs failed. @error and @extended are set by _AD_Open or _AD_GetAllOUs ; Author ........: water based on code by ReFran - http://www.autoitscript.com/forum/topic/84119-treeview-read-to-from-file ; Modified.......: water including ideas by HaeMHuK ; Remarks .......: Use $iSearchScope = 1 to get the number of objects of a single OU. ; Use $iSearchScope = 2 to get the number of objects in the OU plus all sub-OUs. ; Related .......: ; Link ..........: ; Example .......: ; =============================================================================================================================== Func _AD_GetOUTreeView($sOU, $hTreeView, $bIsADOpen = False, $bCount = False, $bDisplay = False, $sCategory = "", $sText = " (%)", $iSearchScope = 1, $hProgress = Default) Local $iCount, $aObjects If $bIsADOpen = False Then _AD_Open() If @error Then Return SetError(@error, @extended, 0) EndIf $sSeparator = "\" Local $aOUs = _AD_GetAllOUs($sOU, $sSeparator) If @error <> 0 Then Return SetError(@error, @extended, 0) Local $aTreeView[$aOUs[0][0] + 1][3] = [[$aOUs[0][0], 3]] Local $aResult = $aTreeView Local $iIndexTV = 0, $sIgnoreOU = "" Local $aMemberOf = _AD_GetUserGroups(@UserName) ; Dummy can be removed For $i = 1 To $aOUs[0][0] If $sIgnoreOU = "" Or ($sIgnoreOU <> "" And StringInStr($aOUs[$i][1], $sIgnoreOU, -1) = 0) Then ; OU to ignore if not set or OU to ignore is set and entry to check isn't a sub-OU of the ignored OU then check permissions If _AD_HasRequiredRights__GivenMembers($aOUs[$i][1], 0, @UserName, $aMemberOf) = 0 Then ; User doesn't have needed permissions. Ignore this OU and all sub-OUs ==> $sIgnoreOU = $aOUs[$i][1] Else $sIgnoreOU = "" EndIf EndIf If $sIgnoreOU = "" Then $iIndexTV = $iIndexTV + 1 $aTemp = StringSplit($aOUs[$i][0], $sSeparator) $aTreeView[$iIndexTV][0] = StringFormat("%" & $aTemp[0] - 1 & "s", "") & "#" & $aTemp[$aTemp[0]] $aTreeView[$iIndexTV][1] = $aOUs[$i][1] EndIf Next ReDim $aTreeView[$iIndexTV + 1][3] $aTreeView[0][0] = $iIndexTV _GUICtrlTreeView_BeginUpdate($hTreeView) Local $ah[50], $sLDAPString If $sCategory <> "" And StringIsAlNum($sCategory) Then $sLDAPString = "(objectcategory=" & $sCategory & ")" Else $sLDAPString = $sCategory EndIf $iOutIndex = 0 For $iIndex = 1 To $aTreeView[0][0] If $hProgress <> Default Then GUICtrlSetData($hProgress, $iIndex * 100 / $aTreeView[0][0]) $iOutIndex += 1 $aObjects = "" $sLine = StringSplit(StringStripCR($aTreeView[$iIndex][0]), @TAB) $iLevel = StringInStr($sLine[1], "#") If $iLevel = 0 Then ExitLoop If ($bCount Or $bDisplay) And $sLDAPString <> "" Then If $bDisplay Then $aObjects = _AD_GetObjectsInOU($aTreeView[$iIndex][1], $sLDAPString, 1, "samaccountname,distinguishedname", "", False) If @error Then $iCount = 0 Else $iCount = $aObjects[0][0] EndIf Else $iCount = _AD_GetObjectsInOU($aTreeView[$iIndex][1], $sLDAPString, $iSearchScope, "samaccountname,distinguishedname", "", True) EndIf EndIf $sTemp = "" If $bCount And $sLDAPString <> "" Then $sTemp = StringReplace($sText, "%", $iCount) If $iLevel = 1 Then $ah[$iLevel] = _GUICtrlTreeView_Add($hTreeView, 0, StringMid($sLine[1], $iLevel + 1) & $sTemp) Else $ah[$iLevel] = _GUICtrlTreeView_AddChild($hTreeView, $ah[$iLevel - 1], StringMid($sLine[1], $iLevel + 1) & $sTemp) EndIf $aResult[$iOutIndex][0] = $aTreeView[$iIndex][0] $aResult[$iOutIndex][1] = $aTreeView[$iIndex][1] $aResult[$iOutIndex][2] = $ah[$iLevel] ; Add the objects of the OU to the TreeView If IsArray($aObjects) Then ReDim $aResult[UBound($aResult, 1) + $aObjects[0][0]][UBound($aResult, 2)] For $iIndex2 = 1 To $aObjects[0][0] $iOutIndex += 1 If StringRight($aObjects[$iIndex2][0], 1) = "$" Then $aObjects[$iIndex2][0] = StringLeft($aObjects[$iIndex2][0], StringLen($aObjects[$iIndex2][0]) - 1) $aResult[$iOutIndex][0] = $aObjects[$iIndex2][0] $aResult[$iOutIndex][1] = $aObjects[$iIndex2][1] $aResult[$iOutIndex][2] = _GUICtrlTreeView_AddChild($hTreeView, $ah[$iLevel], $aObjects[$iIndex2][0]) Next EndIf Next If $bIsADOpen = False Then _AD_Close() _GUICtrlTreeView_EndUpdate($hTreeView) $aResult[0][0] = UBound($aResult, 1) - 1 $aResult[0][1] = UBound($aResult, 2) Return $aResult EndFunc ;==>_AD_GetOUTreeView Func _AD_HasRequiredRights__GivenMembers($sAD_Object, $iAD_Right = 983551, $sAD_User = @UserName, $aAD_MemberOf = "") If StringMid($sAD_Object, 3, 1) <> "=" Then $sAD_Object = _AD_SamAccountNameToFQDN($sAD_Object) ; sAMAccountName provided Local $aAD_TrusteeArray, $sAD_TrusteeGroup, $sAD_TrusteeArrayFQDN Local $oAD_Object = __AD_ObjGet("LDAP://" & $sAD_HostServer & "/" & $sAD_Object) If IsObj($oAD_Object) Then Local $oAD_Security = $oAD_Object.Get("ntSecurityDescriptor") Local $oAD_DACL = $oAD_Security.DiscretionaryAcl For $oAD_ACE In $oAD_DACL $aAD_TrusteeArray = StringSplit($oAD_ACE.Trustee, "\") $sAD_TrusteeGroup = $aAD_TrusteeArray[$aAD_TrusteeArray[0]] If (UBound($aAD_TrusteeArray) - 1) = 2 And $aAD_TrusteeArray[2] = $sAD_User And BitAND($oAD_ACE.AccessMask, $iAD_Right) = $iAD_Right Then Return 1 If (UBound($aAD_TrusteeArray) - 1) = 2 Then ; Check if the entry exists in the Dictionary If $oDict.Exists($aAD_TrusteeArray[2]) Then $sAD_TrusteeArrayFQDN = $oDict.Item($aAD_TrusteeArray[2]) Else $sAD_TrusteeArrayFQDN = _AD_SamAccountNameToFQDN($aAD_TrusteeArray[2]) $oDict.Add($aAD_TrusteeArray[2], $sAD_TrusteeArrayFQDN) Endif EndIf For $iCount1 = 0 To UBound($aAD_MemberOf) - 1 If StringInStr($aAD_MemberOf[$iCount1], $sAD_TrusteeArrayFQDN) And _ BitAND($oAD_ACE.AccessMask, $iAD_Right) = $iAD_Right Then Return 1 If StringInStr($aAD_MemberOf[$iCount1], "CN=" & $sAD_TrusteeGroup & ",") And _ BitAND($oAD_ACE.AccessMask, $iAD_Right) = $iAD_Right Then Return 1 Next Next EndIf Return 0 EndFunc ;==>_AD_HasRequiredRights__GivenMembers 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...
chaoticyeshua Posted February 7, 2013 Share Posted February 7, 2013 I'll try that when I have a chance at work today. Thanks! Link to comment Share on other sites More sharing options...
chaoticyeshua Posted February 7, 2013 Share Posted February 7, 2013 After completing: 1st Attempt: Total: 72615.1899575378 2nd Attempt: Total: 78105.8512278546 3rd Attempt: Total: 72126.7845051606 Overall, MUCH better than before. Link to comment Share on other sites More sharing options...
water Posted February 7, 2013 Author Share Posted February 7, 2013 (edited) But still rather slow! Could you insertReturn 1afterFunc _AD_HasRequiredRights__GivenMembers($sAD_Object, $iAD_Right = 983551, $sAD_User = @UserName, $aAD_MemberOf = "") If you first run the unmodified version of the script with a user who has full permissions on every OU and then run the changed version we know how much time we "lose" with permission checking. Then we can decide if it makes sense to make permission checking even faster. Edited February 7, 2013 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...
chaoticyeshua Posted February 7, 2013 Share Posted February 7, 2013 (edited) If I put "Return 1" immediately under the Func as you suggested: Total: 10407.0055566789 Total: 10384.6118935539 Total: 10496.474043506 So it's taking about a minute total on top of that for permission checking. Which about resembles what a co-worker of mine attempted with a Powershell script. Edited February 7, 2013 by chaoticyeshua Link to comment Share on other sites More sharing options...
water Posted February 7, 2013 Author Share Posted February 7, 2013 If you like I can add some counters so we can see where we spend the time. Then we can check if we can improve performance of certain parts of the code. 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...
chaoticyeshua Posted February 7, 2013 Share Posted February 7, 2013 Sure, if you have time and don't mind, that would be great. Link to comment Share on other sites More sharing options...
water Posted February 7, 2013 Author Share Posted February 7, 2013 (edited) This checks the permissions but always returns "success" even if the user doesn't have proper permissions. The counters displayed at the end show that most time is spend in the loop checking the trustees. It loops 894000 times and spends 6.85 seconds of 9.2 seconds in permission checking and 9.83 seconds of overall processing time. If we could reduce the loop processing time we could gain a lot. Which numbers do you get? expandcollapse popup#region ;**** Directives created by AutoIt3Wrapper_GUI **** #AutoIt3Wrapper_UseX64=n #endregion ;**** Directives created by AutoIt3Wrapper_GUI **** #include <AD.au3> #include <TreeviewConstants.au3> #include <WindowsConstants.au3> #include <GUIConstants.au3> #include <GuiTreeView.au3> Global $sTitle = "Active Direcory OU Treeview" #region ### START Koda GUI section ### Form= Global $hMain = GUICreate($sTitle, 743, 683, -1, -1) Global $hTree = GUICtrlCreateTreeView(6, 6, 600, 666, -1, $WS_EX_CLIENTEDGE) Global $bExit = GUICtrlCreateButton("Exit", 624, 8, 97, 33) Global $bExpand = GUICtrlCreateButton("Expand all", 624, 56, 97, 33) Global $bCollapse = GUICtrlCreateButton("Collapse all", 624, 104, 97, 33) Global $bSelect = GUICtrlCreateButton("Select OU", 624, 152, 97, 33) Global $hProgress = GUICtrlCreateProgress(624, 200, 97, 20) GUISetState(@SW_SHOW) #endregion ### END Koda GUI section ### ;------------------------------ ; Make your changes below ;------------------------------ Global $sOU = "" ; FQDN of the OU where to start Global $sCategory = "computer" ; Category to select when counts should be displayed or full LDAP query Global $sText = " (Computer: %)" ; Text to use for the counts to display. % is replaced with the count Global $iScope = 1 ; Scope for the LDAP search to calculate the count. 1 = Only the OU, 2 = OU + sub-OUs Global $bCount = False ; True = Display the object count right to the OU Global $bDisplay = False ; True = Display objects in the OU as well (selection = $sCategory) Global $iTimerTotal, $iTimerOU, $iTimerGroups, $iTimerTV, $iTimerPerm = 0, $iTimerLoop = 0 Global $iCountSamFQDN = 0, $iCountLoop = 0 Global $oDict = ObjCreate("Scripting.Dictionary") ;------------------------------ ; Make your changes above ;------------------------------ $iTimerTotal = TimerInit() Global $aTreeView = _AD_GetOUTreeView($sOU, $hTree, False, $bCount, $bDisplay, $sCategory, $sText, $iScope, $hProgress) If @error <> 0 Then MsgBox(16, "Active Direcory OU Treeview", "Error creating list of OUs starting with '" & $sOU & "'." & @CRLF & _ "Error returned by function _AD_GetALLOUs: @error = " & @error & ", @extended = " & @extended) MsgBox(0, "", "Total: " & TimerDiff($iTimerTotal) & @CRLF & _ "Get OUs: " & $iTimerOU & @CRLF & _ "Get Groups: " & $iTimerGroups & @CRLF & _ "Check Permissions: " & $iTimerPerm & @CRLF & _ " SamToFQDN called: " & $iCountSamFQDN & @CRLF & _ " Time in Loop: " & $iTimerLoop & @CRLF & _ " Count Loop: " & $iCountLoop & @CRLF & _ "Display TreeView: " & $iTimerTV) Sleep(1000) GUICtrlDelete($hProgress) While 1 $Msg = GUIGetMsg() Switch $Msg Case $GUI_EVENT_CLOSE, $bExit Exit Case $bExpand _GUICtrlTreeView_Expand($hTree) Case $bCollapse _GUICtrlTreeView_Expand($hTree, 0, False) Case $bSelect $hSelection = _GUICtrlTreeView_GetSelection($hTree) $sSelection = _GUICtrlTreeView_GetText($hTree, $hSelection) For $i = 1 To $aTreeView[0][0] If $hSelection = $aTreeView[$i][2] Then ExitLoop Next $sOU = $aTreeView[$i][1] MsgBox(64, $sTitle & " - Selected OU", "Name: " & $sSelection & @CRLF & "FQDN: " & $sOU) EndSwitch WEnd ; #FUNCTION# ==================================================================================================================== ; Name...........: _AD_GetOUTreeView ; Description ...: Fills a given TreeView control with all OUs starting with a given OU. ; Syntax.........: _AD_GetOUTreeView($sOU, $hTreeView[, $bIsADOpen = False[, $bCount = False[, $bDisplay = False[, $sCategory = ""[, $sText = " (%)"[, $iSearchScope = 1[, $hProgress = Default]]]]]]]) ; Parameters ....: $sOU - FQDN of the OU where to start. "" displays all OUs ; $hTreeView - Handle of the TreeView where the OUs will be displayed. Has to be created in advance ; $bIsADOpen - Optional: Pass as True if the connection to the AD has already been made by the calling script (default = False) ; $bCount - Optional: True will display the count of objects in the OU right to the OU name (default = False) ; The LDAP query to determine the count is built from $sCategory ; $bDisplay - Optional: True will display the objects in the OU below the OU itself (default = False) ; $sCategory - Optional: Category to search for or the complete LDAP search string e.g. "computer" and "(objectcategory=computer)" are equivalent ; The number of found objects is added to the OUs name (default = "" = don't count objects) ; $sText - Optional: Text to display the count. Must contain a % which will be replaced by the actual number (default = " (%)") ; $iSearchScope - Optional: Search scope for function _AD_GetObjectsInOU: 0 = base, 1 = one-level, 2 = sub-tree (default = 1) ; $hProgress - Optional: ControlID of a progress bar to show during creation of the TreeView (default = Default) ; Return values .: Success - 1 ; Failure - Returns 0 and sets @error: ; |x - Function _AD_Open or _AD_GetAllOUs failed. @error and @extended are set by _AD_Open or _AD_GetAllOUs ; Author ........: water based on code by ReFran - [url="http://www.autoitscript.com/forum/topic/84119-treeview-read-to-from-file"]http://www.autoitscript.com/forum/topic/84119-treeview-read-to-from-file[/url] ; Modified.......: water including ideas by HaeMHuK ; Remarks .......: Use $iSearchScope = 1 to get the number of objects of a single OU. ; Use $iSearchScope = 2 to get the number of objects in the OU plus all sub-OUs. ; Related .......: ; Link ..........: ; Example .......: ; =============================================================================================================================== Func _AD_GetOUTreeView($sOU, $hTreeView, $bIsADOpen = False, $bCount = False, $bDisplay = False, $sCategory = "", $sText = " (%)", $iSearchScope = 1, $hProgress = Default) Local $iCount, $aObjects If $bIsADOpen = False Then _AD_Open() If @error Then Return SetError(@error, @extended, 0) EndIf $sSeparator = "\" $iTimerOU = TimerInit() Local $aOUs = _AD_GetAllOUs($sOU, $sSeparator) If @error <> 0 Then Return SetError(@error, @extended, 0) $iTimerOU = TimerDiff($iTimerOU) Local $aTreeView[$aOUs[0][0] + 1][3] = [[$aOUs[0][0], 3]] Local $aResult = $aTreeView Local $iIndexTV = 0, $sIgnoreOU = "" $iTimerGroups = TimerInit() Local $aMemberOf = _AD_GetUserGroups(@UserName) ; Dummy can be removed $iTimerGroups = TimerDiff($iTimerGroups) For $i = 1 To $aOUs[0][0] If $hProgress <> Default Then GUICtrlSetData($hProgress, $i * 100 / $aOUs[0][0] / 2) ; 50 of the progress by processing the OUs If $sIgnoreOU = "" Or ($sIgnoreOU <> "" And StringInStr($aOUs[$i][1], $sIgnoreOU, -1) = 0) Then ; OU to ignore if not set or OU to ignore is set and entry to check isn't a sub-OU of the ignored OU then check permissions If _AD_HasRequiredRights__GivenMembers($aOUs[$i][1], 0, @UserName, $aMemberOf) = 0 Then ; User doesn't have needed permissions. Ignore this OU and all sub-OUs $sIgnoreOU = $aOUs[$i][1] Else $sIgnoreOU = "" EndIf EndIf If $sIgnoreOU = "" Then $iIndexTV = $iIndexTV + 1 $aTemp = StringSplit($aOUs[$i][0], $sSeparator) $aTreeView[$iIndexTV][0] = StringFormat("%" & $aTemp[0] - 1 & "s", "") & "#" & $aTemp[$aTemp[0]] $aTreeView[$iIndexTV][1] = $aOUs[$i][1] EndIf Next ReDim $aTreeView[$iIndexTV + 1][3] $aTreeView[0][0] = $iIndexTV $iTimerTV = TimerInit() _GUICtrlTreeView_BeginUpdate($hTreeView) Local $ah[50], $sLDAPString If $sCategory <> "" And StringIsAlNum($sCategory) Then $sLDAPString = "(objectcategory=" & $sCategory & ")" Else $sLDAPString = $sCategory EndIf $iOutIndex = 0 For $iIndex = 1 To $aTreeView[0][0] If $hProgress <> Default Then GUICtrlSetData($hProgress, 50 + $iIndex * 100 / $aTreeView[0][0] / 2) ; 50 of the progress by processing the result $iOutIndex += 1 $aObjects = "" $sLine = StringSplit(StringStripCR($aTreeView[$iIndex][0]), @TAB) $iLevel = StringInStr($sLine[1], "#") If $iLevel = 0 Then ExitLoop If ($bCount Or $bDisplay) And $sLDAPString <> "" Then If $bDisplay Then $aObjects = _AD_GetObjectsInOU($aTreeView[$iIndex][1], $sLDAPString, 1, "samaccountname,distinguishedname", "", False) If @error Then $iCount = 0 Else $iCount = $aObjects[0][0] EndIf Else $iCount = _AD_GetObjectsInOU($aTreeView[$iIndex][1], $sLDAPString, $iSearchScope, "samaccountname,distinguishedname", "", True) EndIf EndIf $sTemp = "" If $bCount And $sLDAPString <> "" Then $sTemp = StringReplace($sText, "%", $iCount) If $iLevel = 1 Then $ah[$iLevel] = _GUICtrlTreeView_Add($hTreeView, 0, StringMid($sLine[1], $iLevel + 1) & $sTemp) Else $ah[$iLevel] = _GUICtrlTreeView_AddChild($hTreeView, $ah[$iLevel - 1], StringMid($sLine[1], $iLevel + 1) & $sTemp) EndIf $aResult[$iOutIndex][0] = $aTreeView[$iIndex][0] $aResult[$iOutIndex][1] = $aTreeView[$iIndex][1] $aResult[$iOutIndex][2] = $ah[$iLevel] ; Add the objects of the OU to the TreeView If IsArray($aObjects) Then ReDim $aResult[UBound($aResult, 1) + $aObjects[0][0]][UBound($aResult, 2)] For $iIndex2 = 1 To $aObjects[0][0] $iOutIndex += 1 If StringRight($aObjects[$iIndex2][0], 1) = "$" Then $aObjects[$iIndex2][0] = StringLeft($aObjects[$iIndex2][0], StringLen($aObjects[$iIndex2][0]) - 1) $aResult[$iOutIndex][0] = $aObjects[$iIndex2][0] $aResult[$iOutIndex][1] = $aObjects[$iIndex2][1] $aResult[$iOutIndex][2] = _GUICtrlTreeView_AddChild($hTreeView, $ah[$iLevel], $aObjects[$iIndex2][0]) Next EndIf Next If $bIsADOpen = False Then _AD_Close() _GUICtrlTreeView_EndUpdate($hTreeView) $aResult[0][0] = UBound($aResult, 1) - 1 $aResult[0][1] = UBound($aResult, 2) $iTimerTV = TimerDiff($iTimerTV) Return $aResult EndFunc ;==>_AD_GetOUTreeView Func _AD_HasRequiredRights__GivenMembers($sAD_Object, $iAD_Right = 983551, $sAD_User = @UserName, $aAD_MemberOf = "") Local $iPerm = TimerInit() Local $iLoop = TimerInit() If StringMid($sAD_Object, 3, 1) <> "=" Then $sAD_Object = _AD_SamAccountNameToFQDN($sAD_Object) ; sAMAccountName provided Local $aAD_TrusteeArray, $sAD_TrusteeGroup, $sAD_TrusteeArrayFQDN Local $oAD_Object = __AD_ObjGet("LDAP://" & $sAD_HostServer & "/" & $sAD_Object) If IsObj($oAD_Object) Then Local $oAD_Security = $oAD_Object.Get("ntSecurityDescriptor") Local $oAD_DACL = $oAD_Security.DiscretionaryAcl For $oAD_ACE In $oAD_DACL $aAD_TrusteeArray = StringSplit($oAD_ACE.Trustee, "\") $sAD_TrusteeGroup = $aAD_TrusteeArray[$aAD_TrusteeArray[0]] If (UBound($aAD_TrusteeArray) - 1) = 2 And $aAD_TrusteeArray[2] = $sAD_User And BitAND($oAD_ACE.AccessMask, $iAD_Right) = $iAD_Right Then Return 1 If (UBound($aAD_TrusteeArray) - 1) = 2 Then ; Check if the entry exists in the Dictionary If $oDict.Exists($aAD_TrusteeArray[2]) Then $sAD_TrusteeArrayFQDN = $oDict.Item($aAD_TrusteeArray[2]) Else $iCountSamFQDN = $iCountSamFQDN + 1 $sAD_TrusteeArrayFQDN = _AD_SamAccountNameToFQDN($aAD_TrusteeArray[2]) $oDict.Add($aAD_TrusteeArray[2], $sAD_TrusteeArrayFQDN) EndIf EndIf $iLoop = TimerInit() For $iCount1 = 0 To UBound($aAD_MemberOf) - 1 $iCountLoop = $iCountLoop + 1 If StringInStr($aAD_MemberOf[$iCount1], $sAD_TrusteeArrayFQDN) And _ BitAND($oAD_ACE.AccessMask, $iAD_Right) = $iAD_Right Then $iTimerPerm = $iTimerPerm + TimerDiff($iPerm) Return 1 ElseIf StringInStr($aAD_MemberOf[$iCount1], "CN=" & $sAD_TrusteeGroup & ",") And _ BitAND($oAD_ACE.AccessMask, $iAD_Right) = $iAD_Right Then $iTimerPerm = $iTimerPerm + TimerDiff($iPerm) Return 1 EndIf Next $iTimerLoop = $iTimerLoop + TimerDiff($iLoop) Next EndIf $iTimerPerm = $iTimerPerm + TimerDiff($iPerm) Return 1 ; 1: Test. Change to 0 for production EndFunc ;==>_AD_HasRequiredRights__GivenMembers Edited February 7, 2013 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...
chaoticyeshua Posted February 7, 2013 Share Posted February 7, 2013 Running the script you provided above as you gave it to me, here are the numbers returned: Total: 258437.521704194 Get OUs: 4004.1720678115 Get Groups: 297.634247911434 Check Permissions: 245035.587381845 SamToFQDN called: 330 Time in Loop: 85837.8615153769 Count Loop: 5208609 Display TreeView: 1259.03492161772 Link to comment Share on other sites More sharing options...
water Posted February 7, 2013 Author Share Posted February 7, 2013 How about this one? I moved some code out of the loop: expandcollapse popup#region ;**** Directives created by AutoIt3Wrapper_GUI **** #AutoIt3Wrapper_UseX64=n #endregion ;**** Directives created by AutoIt3Wrapper_GUI **** #include <AD.au3> #include <TreeviewConstants.au3> #include <WindowsConstants.au3> #include <GUIConstants.au3> #include <GuiTreeView.au3> Global $sTitle = "Active Direcory OU Treeview" #region ### START Koda GUI section ### Form= Global $hMain = GUICreate($sTitle, 743, 683, -1, -1) Global $hTree = GUICtrlCreateTreeView(6, 6, 600, 666, -1, $WS_EX_CLIENTEDGE) Global $bExit = GUICtrlCreateButton("Exit", 624, 8, 97, 33) Global $bExpand = GUICtrlCreateButton("Expand all", 624, 56, 97, 33) Global $bCollapse = GUICtrlCreateButton("Collapse all", 624, 104, 97, 33) Global $bSelect = GUICtrlCreateButton("Select OU", 624, 152, 97, 33) Global $hProgress = GUICtrlCreateProgress(624, 200, 97, 20) GUISetState(@SW_SHOW) #endregion ### END Koda GUI section ### ;------------------------------ ; Make your changes below ;------------------------------ Global $sOU = "" ; FQDN of the OU where to start Global $sCategory = "computer" ; Category to select when counts should be displayed or full LDAP query Global $sText = " (Computer: %)" ; Text to use for the counts to display. % is replaced with the count Global $iScope = 1 ; Scope for the LDAP search to calculate the count. 1 = Only the OU, 2 = OU + sub-OUs Global $bCount = False ; True = Display the object count right to the OU Global $bDisplay = False ; True = Display objects in the OU as well (selection = $sCategory) Global $iTimerTotal, $iTimerOU, $iTimerGroups, $iTimerTV, $iTimerPerm = 0, $iTimerLoop = 0 Global $iCountSamFQDN = 0, $iCountLoop = 0 Global $oDict = ObjCreate("Scripting.Dictionary") ;------------------------------ ; Make your changes above ;------------------------------ $iTimerTotal = TimerInit() Global $aTreeView = _AD_GetOUTreeView($sOU, $hTree, False, $bCount, $bDisplay, $sCategory, $sText, $iScope, $hProgress) If @error <> 0 Then MsgBox(16, "Active Direcory OU Treeview", "Error creating list of OUs starting with '" & $sOU & "'." & @CRLF & _ "Error returned by function _AD_GetALLOUs: @error = " & @error & ", @extended = " & @extended) MsgBox(0, "", "Total: " & TimerDiff($iTimerTotal) & @CRLF & _ "Get OUs: " & $iTimerOU & @CRLF & _ "Get Groups: " & $iTimerGroups & @CRLF & _ "Check Permissions: " & $iTimerPerm & @CRLF & _ " SamToFQDN called: " & $iCountSamFQDN & @CRLF & _ " Time in Loop: " & $iTimerLoop & @CRLF & _ " Count Loop: " & $iCountLoop & @CRLF & _ "Display TreeView: " & $iTimerTV) Sleep(1000) GUICtrlDelete($hProgress) While 1 $Msg = GUIGetMsg() Switch $Msg Case $GUI_EVENT_CLOSE, $bExit Exit Case $bExpand _GUICtrlTreeView_Expand($hTree) Case $bCollapse _GUICtrlTreeView_Expand($hTree, 0, False) Case $bSelect $hSelection = _GUICtrlTreeView_GetSelection($hTree) $sSelection = _GUICtrlTreeView_GetText($hTree, $hSelection) For $i = 1 To $aTreeView[0][0] If $hSelection = $aTreeView[$i][2] Then ExitLoop Next $sOU = $aTreeView[$i][1] MsgBox(64, $sTitle & " - Selected OU", "Name: " & $sSelection & @CRLF & "FQDN: " & $sOU) EndSwitch WEnd ; #FUNCTION# ==================================================================================================================== ; Name...........: _AD_GetOUTreeView ; Description ...: Fills a given TreeView control with all OUs starting with a given OU. ; Syntax.........: _AD_GetOUTreeView($sOU, $hTreeView[, $bIsADOpen = False[, $bCount = False[, $bDisplay = False[, $sCategory = ""[, $sText = " (%)"[, $iSearchScope = 1[, $hProgress = Default]]]]]]]) ; Parameters ....: $sOU - FQDN of the OU where to start. "" displays all OUs ; $hTreeView - Handle of the TreeView where the OUs will be displayed. Has to be created in advance ; $bIsADOpen - Optional: Pass as True if the connection to the AD has already been made by the calling script (default = False) ; $bCount - Optional: True will display the count of objects in the OU right to the OU name (default = False) ; The LDAP query to determine the count is built from $sCategory ; $bDisplay - Optional: True will display the objects in the OU below the OU itself (default = False) ; $sCategory - Optional: Category to search for or the complete LDAP search string e.g. "computer" and "(objectcategory=computer)" are equivalent ; The number of found objects is added to the OUs name (default = "" = don't count objects) ; $sText - Optional: Text to display the count. Must contain a % which will be replaced by the actual number (default = " (%)") ; $iSearchScope - Optional: Search scope for function _AD_GetObjectsInOU: 0 = base, 1 = one-level, 2 = sub-tree (default = 1) ; $hProgress - Optional: ControlID of a progress bar to show during creation of the TreeView (default = Default) ; Return values .: Success - 1 ; Failure - Returns 0 and sets @error: ; |x - Function _AD_Open or _AD_GetAllOUs failed. @error and @extended are set by _AD_Open or _AD_GetAllOUs ; Author ........: water based on code by ReFran - http://www.autoitscript.com/forum/topic/84119-treeview-read-to-from-file ; Modified.......: water including ideas by HaeMHuK ; Remarks .......: Use $iSearchScope = 1 to get the number of objects of a single OU. ; Use $iSearchScope = 2 to get the number of objects in the OU plus all sub-OUs. ; Related .......: ; Link ..........: ; Example .......: ; =============================================================================================================================== Func _AD_GetOUTreeView($sOU, $hTreeView, $bIsADOpen = False, $bCount = False, $bDisplay = False, $sCategory = "", $sText = " (%)", $iSearchScope = 1, $hProgress = Default) Local $iCount, $aObjects If $bIsADOpen = False Then _AD_Open() If @error Then Return SetError(@error, @extended, 0) EndIf $sSeparator = "\" $iTimerOU = TimerInit() Local $aOUs = _AD_GetAllOUs($sOU, $sSeparator) If @error <> 0 Then Return SetError(@error, @extended, 0) $iTimerOU = TimerDiff($iTimerOU) Local $aTreeView[$aOUs[0][0] + 1][3] = [[$aOUs[0][0], 3]] Local $aResult = $aTreeView Local $iIndexTV = 0, $sIgnoreOU = "" $iTimerGroups = TimerInit() Local $aMemberOf = _AD_GetUserGroups(@UserName) ; Dummy can be removed $iTimerGroups = TimerDiff($iTimerGroups) For $i = 1 To $aOUs[0][0] If $hProgress <> Default Then GUICtrlSetData($hProgress, $i * 100 / $aOUs[0][0] / 2) ; 50 of the progress by processing the OUs If $sIgnoreOU = "" Or ($sIgnoreOU <> "" And StringInStr($aOUs[$i][1], $sIgnoreOU, -1) = 0) Then ; OU to ignore if not set or OU to ignore is set and entry to check isn't a sub-OU of the ignored OU then check permissions If _AD_HasRequiredRights__GivenMembers($aOUs[$i][1], 0, @UserName, $aMemberOf) = 0 Then ; User doesn't have needed permissions. Ignore this OU and all sub-OUs $sIgnoreOU = $aOUs[$i][1] Else $sIgnoreOU = "" EndIf EndIf If $sIgnoreOU = "" Then $iIndexTV = $iIndexTV + 1 $aTemp = StringSplit($aOUs[$i][0], $sSeparator) $aTreeView[$iIndexTV][0] = StringFormat("%" & $aTemp[0] - 1 & "s", "") & "#" & $aTemp[$aTemp[0]] $aTreeView[$iIndexTV][1] = $aOUs[$i][1] EndIf Next ReDim $aTreeView[$iIndexTV + 1][3] $aTreeView[0][0] = $iIndexTV $iTimerTV = TimerInit() _GUICtrlTreeView_BeginUpdate($hTreeView) Local $ah[50], $sLDAPString If $sCategory <> "" And StringIsAlNum($sCategory) Then $sLDAPString = "(objectcategory=" & $sCategory & ")" Else $sLDAPString = $sCategory EndIf $iOutIndex = 0 For $iIndex = 1 To $aTreeView[0][0] If $hProgress <> Default Then GUICtrlSetData($hProgress, 50 + $iIndex * 100 / $aTreeView[0][0] / 2) ; 50 of the progress by processing the result $iOutIndex += 1 $aObjects = "" $sLine = StringSplit(StringStripCR($aTreeView[$iIndex][0]), @TAB) $iLevel = StringInStr($sLine[1], "#") If $iLevel = 0 Then ExitLoop If ($bCount Or $bDisplay) And $sLDAPString <> "" Then If $bDisplay Then $aObjects = _AD_GetObjectsInOU($aTreeView[$iIndex][1], $sLDAPString, 1, "samaccountname,distinguishedname", "", False) If @error Then $iCount = 0 Else $iCount = $aObjects[0][0] EndIf Else $iCount = _AD_GetObjectsInOU($aTreeView[$iIndex][1], $sLDAPString, $iSearchScope, "samaccountname,distinguishedname", "", True) EndIf EndIf $sTemp = "" If $bCount And $sLDAPString <> "" Then $sTemp = StringReplace($sText, "%", $iCount) If $iLevel = 1 Then $ah[$iLevel] = _GUICtrlTreeView_Add($hTreeView, 0, StringMid($sLine[1], $iLevel + 1) & $sTemp) Else $ah[$iLevel] = _GUICtrlTreeView_AddChild($hTreeView, $ah[$iLevel - 1], StringMid($sLine[1], $iLevel + 1) & $sTemp) EndIf $aResult[$iOutIndex][0] = $aTreeView[$iIndex][0] $aResult[$iOutIndex][1] = $aTreeView[$iIndex][1] $aResult[$iOutIndex][2] = $ah[$iLevel] ; Add the objects of the OU to the TreeView If IsArray($aObjects) Then ReDim $aResult[UBound($aResult, 1) + $aObjects[0][0]][UBound($aResult, 2)] For $iIndex2 = 1 To $aObjects[0][0] $iOutIndex += 1 If StringRight($aObjects[$iIndex2][0], 1) = "$" Then $aObjects[$iIndex2][0] = StringLeft($aObjects[$iIndex2][0], StringLen($aObjects[$iIndex2][0]) - 1) $aResult[$iOutIndex][0] = $aObjects[$iIndex2][0] $aResult[$iOutIndex][1] = $aObjects[$iIndex2][1] $aResult[$iOutIndex][2] = _GUICtrlTreeView_AddChild($hTreeView, $ah[$iLevel], $aObjects[$iIndex2][0]) Next EndIf Next If $bIsADOpen = False Then _AD_Close() _GUICtrlTreeView_EndUpdate($hTreeView) $aResult[0][0] = UBound($aResult, 1) - 1 $aResult[0][1] = UBound($aResult, 2) $iTimerTV = TimerDiff($iTimerTV) Return $aResult EndFunc ;==>_AD_GetOUTreeView Func _AD_HasRequiredRights__GivenMembers($sAD_Object, $iAD_Right = 983551, $sAD_User = @UserName, $aAD_MemberOf = "") Local $iPerm = TimerInit() Local $iLoop = TimerInit() If StringMid($sAD_Object, 3, 1) <> "=" Then $sAD_Object = _AD_SamAccountNameToFQDN($sAD_Object) ; sAMAccountName provided Local $aAD_TrusteeArray, $sAD_TrusteeGroup, $sAD_TrusteeArrayFQDN Local $oAD_Object = __AD_ObjGet("LDAP://" & $sAD_HostServer & "/" & $sAD_Object) If IsObj($oAD_Object) Then Local $oAD_Security = $oAD_Object.Get("ntSecurityDescriptor") Local $oAD_DACL = $oAD_Security.DiscretionaryAcl For $oAD_ACE In $oAD_DACL If BitAND($oAD_ACE.AccessMask, $iAD_Right) <> $iAD_Right Then ConsoleWrite("**" & @LF) ContinueLoop EndIf $aAD_TrusteeArray = StringSplit($oAD_ACE.Trustee, "\") $sAD_TrusteeGroup = "CN=" & $aAD_TrusteeArray[$aAD_TrusteeArray[0]] & "," If $aAD_TrusteeArray[0] = 2 Then If $aAD_TrusteeArray[2] = $sAD_User And BitAND($oAD_ACE.AccessMask, $iAD_Right) = $iAD_Right Then Return 1 ; Check if the entry exists in the Dictionary If $oDict.Exists($aAD_TrusteeArray[2]) Then $sAD_TrusteeArrayFQDN = $oDict.Item($aAD_TrusteeArray[2]) Else $iCountSamFQDN = $iCountSamFQDN + 1 $sAD_TrusteeArrayFQDN = _AD_SamAccountNameToFQDN($aAD_TrusteeArray[2]) $oDict.Add($aAD_TrusteeArray[2], $sAD_TrusteeArrayFQDN) EndIf EndIf $iLoop = TimerInit() For $iCount1 = 0 To UBound($aAD_MemberOf) - 1 $iCountLoop = $iCountLoop + 1 If StringInStr($aAD_MemberOf[$iCount1], $sAD_TrusteeArrayFQDN) Then $iTimerPerm = $iTimerPerm + TimerDiff($iPerm) Return 1 ElseIf StringInStr($aAD_MemberOf[$iCount1], $sAD_TrusteeGroup) Then $iTimerPerm = $iTimerPerm + TimerDiff($iPerm) Return 1 EndIf Next $iTimerLoop = $iTimerLoop + TimerDiff($iLoop) Next EndIf $iTimerPerm = $iTimerPerm + TimerDiff($iPerm) Return 1 ; 1: Test. Change to 0 for production EndFunc ;==>_AD_HasRequiredRights__GivenMembers 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...
chaoticyeshua Posted February 7, 2013 Share Posted February 7, 2013 Sorry having to do this through my phone's remote desktop for a while.... Total: 251937.709114971 Get OUs: 3888.85102403275 Get Groups: 236.36206708617 Check Permissions: 239218.078879474 SamToFQDN called: 330 Time in Loop: 77195.5899914161 Count Loop: 5211244 Display TreeView: 1009.50628504835 Link to comment Share on other sites More sharing options...
water Posted February 7, 2013 Author Share Posted February 7, 2013 Didn't get much faster Was my last post for today. Will think about this problem again tomorrow. 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...
Recommended Posts