;; 
;;=====================================================================================----- 
;; 
;;FUNCTION       ListNestedGroups()     
; 
;;ACTION         Returns a list of all groups that the specified account is a member of. 
;;               Retrieves a list of all the groups an account is a member of including  
;;               nested groups which normally are not seen.  This can be useful for 
;;               locating security holes where users have rights they shouldn't have 
;;               due to nested groups.  
;; 
;;AUTHOR         Ron Lewis (NTDOC) and Glenn Barnas   
;;               (Glenn came up with new method to Golf down the original code)  
;; 
;;VERSION        1.0  - 2006/03/23 
;; 
;;HISTORY        1.0  - 2006/03/23 - Initial Release 
;; 
;;SYNTAX         ListNestedGroups(Account [, Nested])    
;; 
;;PARAMETERS     Account - Required - String 
;;               The full LDAP path to the account you want to check 
;; 
;;               Nested - Optional - Integer 
;;               - This is a two part flag to determine what nested groups to show   
;;               0 or blank = Show all groups including nested  
;;               1 = Show all groups but flag the nested groups with <Nested> tag  
;;               2 = Show only Nested groups  
;; 
;;REMARKS        Based on The Scripting Guys code from MS Scripting Guys  
;;  
;;               Due to the way the Groups method and Active Directory work, normal 
;;               scripts can t return all of Ken Myer s group memberships unless it 
;;               checks to see whether Groups A and B belong to any other groups. 
;;               This script can now do that. 
;; 
;;               The Scripting Guys code shows the nested groups but also allowed 
;;               duplicates to be returned. This KiX UDF does not because the guys 
;;               at Korg cared the most to bring you the best In the example you'll 
;;               see Administrators twice, but strictly speaking they're not duplicates. 
;;               Running the Scripting Guys code returns 3 entries for Administrators 
;; 
;;               The Source looks large only because we commented it and showed a 
;;               good example of running it 
;; 
;;RETURNS        Array of the groups, or Error level on error  
;; 
;;DEPENDENCIES   None, this is a two part UDF that uses a sub-function to operate  
;; 
;  
Function ListNestedGroups($_Account,Optional $_Nested)
  Dim $_objUser, $_colGroups, $_objGroup, $_Grps, $_NFlag
  Dim $_W, $_Element, $_TempString, $_OD, $_CN, $_ERR
 
  ; init the vars  
  $ListNestedGroups = 0                          ; default return value if errors occur  
  $_Nested = Val($_Nested)                       ; force to numeric value  
  $_NFlag = IIf($_Nested = 1, ' <Nested>', '')   ; set the output message for nested groups  
 
  $_objUser = GetObject($_Account)               ; instantiate the object  
  $_ERR = Val('&' + Right(DecToHex(@ERROR), 4))  ; get last 4 nybbles (2 bytes) of the error code  
  If $_ERR Exit $_ERR EndIf
 
  $_colGroups = $_objUser.Groups                 ; get the collection  
 
  For Each $_objGroup in $_colGroups
 
    $_OD = GetNested($_objGroup)                 ; nested group name  
    $_CN = $_objGroup.CN                         ; parent group name  
 
    ; Write the nested group name (and optional NESTED tag) to the index file  
    If $_OD <> ''
      If InStr($_TempString, $_OD) = 0
         $_TempString = $_TempString + $_OD + $_NFlag + Chr(10)
      EndIf
    EndIf
 
    ; write the parent group name to the index file, unless in nested-only mode  
    If $_Nested < 2
      If InStr($_TempString, $_CN) = 0
         $_TempString = $_TempString + $_CN + Chr(10)
      EndIf
    EndIf
 
  Next
 
  ; enumerate the index and put the value(s) into an array  
  $_Grps = Split(Left($_TempString,Len($_TempString)-1), Chr(10))
 
  ; Return the array of groups, and exit with success  
  $ListNestedGroups = $_Grps
  Exit 0
EndFunction
 
; Sub-Function for returning nested groups  
Function GetNested($objGroup)
  Dim $_colMembers, $_strMember, $_strPath, $_objNestedGroup, $_ERR
  ; init the return value to a null string  
  $GetNested = ''
  ; get the collection  
  $_colMembers = $objGroup.GetEx("memberOf")
  ; enumerate the collection  
  For Each $_strMember in $_colMembers
    $_strPath = "LDAP://" + $_strMember
    $_objNestedGroup = GetObject($_strPath)
    $GetNested = $_objNestedGroup.CN
  Next
  Exit 0
EndFunction