Announcement

Collapse
No announcement yet.

Count the number of groups a user belongs to?

Collapse
X
  • Filter
  • Time
  • Show
Clear All
new posts

  • Count the number of groups a user belongs to?

    Hi Everybody,

    I work for a very large company that is updating the AD struture. A part of it includes duplicating the amount of an specific security group with another name.

    Example:

    John was member of ONE-A, TWO-A, and THREE-A. Now he will be also member of ONE-B, TWO-B, THREE-B.

    Unfortunately, we have -too late- found that some users reached the 1024 access token limit.

    What I need: I need to list the users that are currently member of more than 500 groups.

    Limitations: 1) AD structure won't be changed, this is a design error I know but It's not up to me to change it. 2) Can't use Powershell / Quest tool. 3) If this can be done with the "DSTools" would be GREAT!.

    I tried with something like:

    dsquery * OU=Users,DC=domain,DC=2008,DC=com -filter "&(objectCategory=user)(!memberOf=>500)" -limit 0

    But it didn't work. =(
    Any kind of help or advice would be greatly appreciated.

  • #2
    Re: Count the number of groups a user belongs to?

    Don't know if this will help you any.

    http://www.petri.co.il/list_all_users_and_groups_in_domain.htm

    Or this

    If not, Scripting Jesus..I mean Rems, will most likely be able to help you.
    "To err is human but to really **** things up requires a computer user..."

    "The path to enlightenment is /user/bin/enlightenment"

    A+ CE

    Comment


    • #3
      Re: Count the number of groups a user belongs to?

      Originally posted by Managor View Post
      Don't know if this will help you any.

      -URLs deleted since I haven't made 5 posts yet-

      If not, Scripting Jesus..I mean Rems, will most likely be able to help you.
      Thank you! But the first one is too basic and the second one lists groups. I need something that can find those users that are members of more than N number of security groups. Thank you anyway!

      Comment


      • #4
        Re: Count the number of groups a user belongs to?

        I shall go keep ransacking then.

        Edit: Found these two:

        Tryyyyyy

        This

        ooor

        This
        Last edited by Managor; 9th November 2010, 19:04.
        "To err is human but to really **** things up requires a computer user..."

        "The path to enlightenment is /user/bin/enlightenment"

        A+ CE

        Comment


        • #5
          Re: Count the number of groups a user belongs to?

          I've got some Powershell stuff at work, but how come you can't use 'em?

          Dsquery user -samid %username% -memberof | find /i "cn=" /c would return the number of matches. If the user belongs to more than 1000 groups, dsquery doesn't return value. So take the complement, that is, find all the users that belong to 1-1000 users.

          Some VBScript solutions might work too.

          -vP

          Comment


          • #6
            Re: Count the number of groups a user belongs to?

            Originally posted by vonPryz View Post
            I've got some Powershell stuff at work, but how come you can't use 'em?

            Dsquery user -samid %username% -memberof | find /i "cn=" /c would return the number of matches. If the user belongs to more than 1000 groups, dsquery doesn't return value. So take the complement, that is, find all the users that belong to 1-1000 users.

            Some VBScript solutions might work too.

            -vP
            That would not be sufficient, you also need to include the groups where the user is indirect a member of! And you should exclude Distribution Group types.


            Save the script below as *.vbs file.
            - Then create a shortcut to the vbs-file.
            - Next, edit the "Target" of the properties of the shortcut -> leading the path to the vbs file you add:
            Code:
            CMD /c >"SearchResultsADO.txt" CScript.exe //NoLogo "<path to vbs-file>"
            - save the shortcut.
            - Use the shortcut to run the script and saving the output to the txt file "SearchResultsADO.txt".

            script sample (script modified November 15, 2010):
            Code:
            '# A problem occurs when a user who is a member of more than 1,015
            '# security groups tries to log on.
            '# When a user logs on to a computer, the Local Security Authority
            '# generates an access token for the user to represent the security
            '# context of the user. The access token contains the userís unique
            '# security identifier (SID) and the SIDs of every group that the
            '# user is a member of, INCLUDING transitive groups.
            '# (http://support.microsoft.com/kb/328889)
            
            Option Explicit
            
            Const Minimum_Group_Count = 500
            
            Dim objRootDSE, objRecordSet, strObjDN
            Dim strDNSDomain, objCommand, objConnection
            
            With WScript.CreateObject("WScript.Network")
               Set objRootDSE = GetObject _
                 ("GC://" & .UserDomain & "/RootDSE")
               strDNSDomain = objRootDSE.Get("DefaultNamingContext")
            End With
            
            'Find all user objects in Active Directory
            Set objCommand = CreateObject("ADODB.Command")
            Set objConnection = CreateObject("ADODB.Connection")
            
            objConnection.Provider = "ADsDSOObject"
            objConnection.Open "Active Directory Provider"
            
            objCommand.ActiveConnection = objConnection
            objCommand.Properties("Searchscope") = 2 ' SUBTREE
            objCommand.Properties("Page Size") = 300
            objCommand.Properties("Timeout") = 30
            objCommand.Properties("Cache Results") = False
            objCommand.CommandText = _
                "SELECT distinguishedName FROM 'GC://" & strDNSDomain _
                & "' WHERE sAMAccountType=805306368"
            
            Set objRecordSet = objCommand.Execute
            If not objRecordSet.eof then 
               objRecordSet.MoveFirst
            
               Do Until objRecordSet.EOF
                 strObjDN = objRecordSet.Fields("distinguishedName").Value
            
                 TokenGroupsInfo strObjDN
            
                 objRecordSet.MoveNext
               Loop
            End If
            objRecordset.Close : objConnection.Close
            
            Wscript.quit 0
            
            Sub TokenGroupsInfo(strDN)
               Dim objADObject, arrbytGroups, cntGroups
            
               ' objADObject is a user or computer object.
               Set objADObject = GetObject("GC://" & strDN)
            
               ' Retrieve tokenGroups array, a calculated attribute.
               objADObject.GetInfoEx Array("tokenGroups"), 0
               arrbytGroups = objADObject.Get("tokenGroups")
               cntGroups = 1+Ubound(arrbytGroups)
               If cntGroups >= Minimum_Group_Count Then
                 wscript.echo objADObject.cn & vbTab _
                   & "=>  member of  " _
                   & cntGroups & "  Security_Groups."
               End If
            End Sub
            \Rems
            Last edited by Rems; 15th November 2010, 21:55.

            This posting is provided "AS IS" with no warranties, and confers no rights.

            __________________

            ** Remember to give credit where credit's due **
            and leave Reputation Points for meaningful posts

            Comment


            • #7
              Re: Count the number of groups a user belongs to?

              Originally posted by Rems View Post
              That would not be sufficient, you also need to include the groups where the user is indirect a member of!


              Save the script below as *.vbs file.
              - Then create a shortcut to the vbs-file.
              - Next, edit the "Target" of the properties of the shortcut -> leading the path to the vbs file you add:
              Code:
              CMD /c >"SearchResultsADO.txt" CScript.exe //NoLogo "<path to vbs-file>"
              - save the shortcut.
              - Use the shortcut to run the script and saving the output to the txt file "SearchResultsADO.txt".


              \Rems
              I get this:

              V:\SearchResultsADO.vbs(149, 13) Microsoft VBScript compilation error: Expected end of statement

              Comment


              • #8
                Re: Count the number of groups a user belongs to?

                Originally posted by jaunis View Post
                I get this:

                V:\SearchResultsADO.vbs(149, 13) Microsoft VBScript compilation error: Expected end of statement
                On line number 149 I have in my script: End Function There on position 12 is the letter n (the last letter of Function) there is no 13th character or sign.
                What is on position 13 on line 149 in your script?


                \Rems

                This posting is provided "AS IS" with no warranties, and confers no rights.

                __________________

                ** Remember to give credit where credit's due **
                and leave Reputation Points for meaningful posts

                Comment


                • #9
                  Re: Count the number of groups a user belongs to?

                  Originally posted by Rems View Post
                  On line number 149 I have in my script: End Function There on position 12 is the letter n (the last letter of Function) there is no 13th character or sign.
                  What is on position 13 on line 149 in your script?


                  \Rems
                  I'm sorry, I'm just plain stupid. This is what I had: "\Rems"

                  Sorry, again, I should have checked that before asking.

                  Ok, here's the deal: I know that I have users with more than 500 groups but the vbs is not taking them. If I use 100 instead of 500 I get a result with only 8 users.

                  I just ran a dsquery user -name NAME | dsget user -memberof on a random user and I got 807 results. I ran the script on a domain controller.

                  Do you have any idea on why the script might not be working?

                  Comment


                  • #10
                    Re: Count the number of groups a user belongs to?

                    Originally posted by jaunis View Post
                    I know that I have users with more than 500 groups but the vbs is not taking them. If I use 100 instead of 500 I get a result with only 8 users.
                    I just ran a dsquery user -name NAME | dsget user -memberof on a random user and I got 807 results. I ran the script on a domain controller.

                    Do you have any idea on why the script might not be working?
                    That was unexpected because -
                    The results of dsquery user -name CN | dsget user -memberof should show equal or less security groups than the 'tokensgroups' dynamic property of the user will show.

                    Originally posted by [URL=http://support.microsoft.com/kb/301916]support.microsoft.com[/URL]
                    _

                    The tokenGroups property of an Active Directory (AD) user object contains the binary security identifiers (SIDs) of all of the security groups that a user is a member of. This property is a constructed attribute, which means that the property is created on the client by the provider and not stored as data in the AD.
                    An alternate approach is to read the MemberOf attribute, which is an enumeration of the immediate groups, including both security and distribution groups. The MemberOf attribute does not enumerate the nested groups.
                    _

                    Idea's why the script might not be working,

                    -*1*- The "Distribution Groups" are not counted by the script! only security groups.

                    -*2*- The script does not reveal cross-domain group membership! Do you have a single or multiple domain environment?

                    -*3*- SOLVED, script changed There probably is a limitation for the search (constructed searchstring) for ADO as used in the in the previous subroutine.

                    \Rems
                    Last edited by Rems; 15th November 2010, 21:50.

                    This posting is provided "AS IS" with no warranties, and confers no rights.

                    __________________

                    ** Remember to give credit where credit's due **
                    and leave Reputation Points for meaningful posts

                    Comment


                    • #11
                      Re: Count the number of groups a user belongs to?

                      This other script; - Reveals membership also in "Nested Groups" and the "Primary Group"; - finds"Distribution groups" and "Security groups"; - Will reveal cross-domain group membership.

                      This script runs slower than the other one. It uses a recursive subroutine to enumerate group memberships.

                      Save the script below as *.vbs file.
                      - Then create a shortcut to the vbs-file.
                      - Next, edit the "Target" of the properties of the shortcut -> leading the path to the vbs file you add:
                      Code:
                      CMD /c >"SearchResultsADO.txt" CScript.exe //NoLogo "<path to vbs-file>"
                      - save the shortcut.
                      - Use the shortcut to run the script and saving the output to the txt file "SearchResultsADO.txt".

                      script sample:
                      Code:
                      Option Explicit
                      
                      Const Minimum_Group_Count = 500
                      
                      Const ADS_GROUP_TYPE_GLOBAL_GROUP = &h2
                      Const ADS_GROUP_TYPE_LOCAL_GROUP = &h4
                      Const ADS_GROUP_TYPE_UNIVERSAL_GROUP = &h8
                      Const ADS_GROUP_TYPE_SECURITY_ENABLED = &h80000000
                      
                      Dim objRootDSE, objRecordSet, strADsPath, xstCnt, strAccountName, objUser
                      Dim strDNSDomain, objGroupList, objCommand, objConnection, colKeys, strKey
                      
                      With WScript.CreateObject("WScript.Network")
                         Set objRootDSE = GetObject _
                           ("LDAP://" & .UserDomain & "/RootDSE")
                         strDNSDomain = objRootDSE.Get("DefaultNamingContext")
                      End With
                      
                      ' Setup the dictionary object
                      Set objGroupList = CreateObject("Scripting.Dictionary")
                      objGroupList.CompareMode = vbTextCompare
                      
                      'Find all user objects in Active Directory
                      Set objCommand = CreateObject("ADODB.Command")
                      Set objConnection = CreateObject("ADODB.Connection")
                      
                      objConnection.Provider = "ADsDSOObject"
                      objConnection.Open "Active Directory Provider"
                      
                      objCommand.ActiveConnection = objConnection
                      objCommand.Properties("Searchscope") = 2 ' SUBTREE
                      objCommand.Properties("Page Size") = 100
                      objCommand.Properties("Timeout") = 30
                      objCommand.Properties("Cache Results") = False
                      objCommand.CommandText = _
                          "SELECT ADsPath FROM 'LDAP://" & strDNSDomain _
                          & "' WHERE sAMAccountType=805306368"
                      
                      Set objRecordSet = objCommand.Execute
                      If not objRecordSet.eof then 
                         objRecordSet.MoveFirst
                      
                         Do Until objRecordSet.EOF
                           strADsPath = objRecordSet.Fields("ADsPath").Value
                           Set objUser = GetObject(strADsPath)
                           GroupsInfo objUser
                           xstCnt = objGroupList.count
                      
                           If xstCnt >= Minimum_Group_Count Then
                             strAccountName = objUser.sAMAccountname
                      
                             Wscript.echo strAccountName, "(" & objUser.cn _
                               & ") is member of", xstCnt, "groups."
                      
                             colKeys = objGroupList.Keys
                             For Each strKey in colKeys
                               Wscript.Echo vbTab & strKey & "     " & objGroupList(strKey) 
                             Next
                      
                           End If
                      
                           objRecordSet.MoveNext
                         Loop
                      End If
                      objRecordset.Close : objConnection.Close
                      
                      Wscript.quit 0
                      
                      
                      Sub GroupsInfo(ByVal objADObject)
                         ' ** This originally used to be a Function to test
                         '    for group membership. by Richard Mueller:
                         '    http://www.rlmueller.net/Programs/IsMember6.txt
                      
                         Dim strAttributes, strFilter, strQuery, adoRecordset
                         Dim intPrimaryGroupID, intPrimaryGroupToken, strPrimaryGroup
                         Dim intgroupType, objPrimaryGroup, strGroupType
                      
                         'clear the Group List
                         objGroupList.RemoveAll
                      
                         ' Use ADO to retrieve all group "primaryGroupToken" values.
                         strAttributes = "sAMAccountName,primaryGroupToken,groupType"
                         strFilter = "(objectCategory=group)"
                         strQuery = "<LDAP://" & strDNSDomain & ">;" & strFilter & ";" _
                           & strAttributes & ";subtree"
                         objCommand.CommandText = strQuery
                         Set adoRecordset = objCommand.Execute
                      
                         ' Call LoadGroups for each different objADObject.
                         ' Add object name to dictionary object so groups need only be
                         ' enumerated once.
                         Call LoadGroups(objADObject, objADObject)
                      
                         ' Determine which group is the primary group for this object.
                         intPrimaryGroupID = objADObject.primaryGroupID
                         If not adoRecordset.eof then
                           adoRecordset.MoveFirst
                           Do Until adoRecordset.EOF
                             intPrimaryGroupToken = adoRecordset.Fields("primaryGroupToken").Value
                             If (intPrimaryGroupToken = intPrimaryGroupID) Then
                               strPrimaryGroup = adoRecordset.Fields("sAMAccountName").Value
                               intgroupType = adoRecordset.Fields("groupType").Value 
                      
                               If intGroupType AND ADS_GROUP_TYPE_SECURITY_ENABLED Then
                                 strGroupType = "Security"
                               Else
                                 strGroupType = "Distribution"
                               End If
                      
                               If intGroupType AND ADS_GROUP_TYPE_LOCAL_GROUP Then
                                 strGroupType = strGroupType & ", Domain local"
                               ElseIf intGroupType AND ADS_GROUP_TYPE_GLOBAL_GROUP Then
                                 strGroupType = strGroupType & ", Global"
                               ElseIf intGroupType AND ADS_GROUP_TYPE_UNIVERSAL_GROUP Then
                                 strGroupType = strGroupType & ", Universal"
                               Else
                                 strGroupType = strGroupType & ", -"
                               End If
                      
                               strGroupType = "(" & strGroupType & ", Primary Group)"
                               objGroupList.Add strPrimaryGroup, strGroupType
                               Exit Do
                             End If
                             adoRecordset.MoveNext
                           Loop
                         End If
                         adoRecordset.Close
                      End Sub
                      
                      Sub LoadGroups(ByVal objPriADObject, ByVal objSubADObject)
                         Dim colstrGroups, objGroup, j, intgroupType, strGroupType
                      
                         colstrGroups = objSubADObject.memberOf
                         If (IsEmpty(colstrGroups) = True) Then
                              Exit Sub
                         End If
                         If (TypeName(colstrGroups) = "String") Then
                              ' Escape any forward slash characters, "/", with the backslash
                              ' escape character. All other characters that should be escaped are.
                              colstrGroups = Replace(colstrGroups, "/", "\/")
                              Set objGroup = GetObject("LDAP://" & colstrGroups)
                      
                              If (objGroupList.Exists(objGroup.sAMAccountName) = False) Then
                                intgroupType = objGroup.Get("groupType")
                      
                                If intGroupType AND ADS_GROUP_TYPE_SECURITY_ENABLED Then
                                  strGroupType = "Security"
                                Else
                                  strGroupType = "Distribution"
                                End If
                      
                                If intGroupType AND ADS_GROUP_TYPE_LOCAL_GROUP Then
                                  strGroupType = strGroupType & ", Domain local"
                                ElseIf intGroupType AND ADS_GROUP_TYPE_GLOBAL_GROUP Then
                                  strGroupType = strGroupType & ", Global"
                                ElseIf intGroupType AND ADS_GROUP_TYPE_UNIVERSAL_GROUP Then
                                  strGroupType = strGroupType & ", Universal"
                                Else
                                  strGroupType = strGroupType & ", -"
                                End If
                                strGroupType = "(" & strGroupType & " Group)"
                                objGroupList.Add objGroup.sAMAccountName, strGroupType
                                Call LoadGroups(objPriADObject, objGroup)
                              End If
                              Exit Sub
                         End If
                         For j = 0 To UBound(colstrGroups)
                              ' Escape any forward slash characters, "/", with the backslash
                              ' escape character. All other characters that should be escaped are.
                              colstrGroups(j) = Replace(colstrGroups(j), "/", "\/")
                              Set objGroup = GetObject("LDAP://" & colstrGroups(j))
                              If (objGroupList.Exists(objGroup.sAMAccountName) = False) Then
                      
                                intgroupType = objGroup.Get("groupType")
                      
                                If intGroupType AND ADS_GROUP_TYPE_SECURITY_ENABLED Then
                                  strGroupType = "Security"
                                Else
                                  strGroupType = "Distribution"
                                End If
                      
                                If intGroupType AND ADS_GROUP_TYPE_LOCAL_GROUP Then
                                  strGroupType = strGroupType & ", Domain local"
                                ElseIf intGroupType AND ADS_GROUP_TYPE_GLOBAL_GROUP Then
                                  strGroupType = strGroupType & ", Global"
                                ElseIf intGroupType AND ADS_GROUP_TYPE_UNIVERSAL_GROUP Then
                                  strGroupType = strGroupType & ", Universal"
                                Else
                                  strGroupType = strGroupType & ", -"
                                End If
                                strGroupType = "(" & strGroupType & " Group)"
                      
                                objGroupList.Add objGroup.sAMAccountName, strGroupType
                                Call LoadGroups(objPriADObject, objGroup)
                              End If
                         Next
                      End Sub
                      \Rems
                      Last edited by Rems; 15th November 2010, 22:09.

                      This posting is provided "AS IS" with no warranties, and confers no rights.

                      __________________

                      ** Remember to give credit where credit's due **
                      and leave Reputation Points for meaningful posts

                      Comment


                      • #12
                        Re: Count the number of groups a user belongs to?

                        This is a single domain working with another one trough a trust. But they're administered separately and have completely different structure. This is the result of a recent merge that our company had.

                        I only need security groups.

                        I ran the script that counts tokengroups and it worked fine. ("NNN tokengroups contains 880 items")

                        The new version of the script, on the other hand, has been working for 30 minutes and still haven't got any result,.

                        Comment


                        • #13
                          Re: Count the number of groups a user belongs to?

                          Originally posted by jaunis View Post
                          This is a single domain working with another one trough a trust. But they're administered separately and have completely different structure. This is the result of a recent merge that our company had.

                          I only need security groups.

                          I ran the script that counts tokengroups and it worked fine. ("NNN tokengroups contains 880 items")
                          Modified the first script:
                          http://forums.petri.com/showpost.php...90&postcount=6
                          it hopefully works fine now.


                          \Rems

                          This posting is provided "AS IS" with no warranties, and confers no rights.

                          __________________

                          ** Remember to give credit where credit's due **
                          and leave Reputation Points for meaningful posts

                          Comment


                          • #14
                            Re: Count the number of groups a user belongs to?

                            Hi,
                            Your modified version was not working, I got "(18, 4) (null): The server is not operational."

                            BUT, then I replaced

                            ("GC://" & .UserDomain & "/RootDSE")

                            for

                            ("GC://domain.com/RootDSE")

                            And it worked!!

                            I'm so happy right now, thank you thank you thank you!

                            One last question, why do you think it worked putting explicitly the domain and not with "& .UserDomain & if my user is in the same domain?

                            THANK YOU again, where do I give you credits? How do I buy you a coffee?

                            THANK YOU!

                            Comment

                            Working...
                            X