0

I need to retrieve group members for several hundred AD groups. While the code below gives the right answer, it is very slow. Is there a more efficient approach to decompose these groups to its members?

My current approach is using System.DirectoryServices.AccountManagement. I have a List<T> of group names to search. Iterate through each one and call GroupPrincipal.GetMembers() for each (Currently this code takes 2+ minutes to decompose about 100 groups; my target would be under 15 seconds)

[EnvironmentPermissionAttribute(SecurityAction.LinkDemand, Unrestricted = true)]
        private static void GetGroupMembership(List<ActiveDirectoryPrincipalProperties> userGroupProperties)
        {
            List<ActiveDirectoryPrincipalProperties> groupProperties = new List<ActiveDirectoryPrincipalProperties>();

            foreach (ActiveDirectoryPrincipalProperties gProperties in userGroupProperties)
            {
                if (gProperties.groupYesNo)
                {
                    PrincipalContext ctx = new PrincipalContext(ContextType.Domain, gProperties.groupDomain);
                    try
                    {
                        GroupPrincipal group = GroupPrincipal.FindByIdentity(ctx, IdentityType.Name, gProperties.groupName);

                        foreach (Principal member in group.GetMembers(true))
                        {
                            ActiveDirectoryPrincipalProperties memberProperties = new ActiveDirectoryPrincipalProperties();
                            memberProperties.fullGroupName = gProperties.fullGroupName;
                            memberProperties.groupDomain = gProperties.groupDomain;
                            memberProperties.groupName = gProperties.groupName;
                            memberProperties.groupType = gProperties.groupType;
                            memberProperties.groupYesNo = false;
                            memberProperties.memberDomain = member.Context.Name.ToString();
                            memberProperties.memberName = member.SamAccountName.ToString();
                            memberProperties.memberType = member.StructuralObjectClass.ToString();
                            memberProperties.sqlUserOnlyYesNo = false;

                            groupProperties.Add(memberProperties);
                        }
                        group.Dispose();
                    }
                    finally
                    {
                        ctx.Dispose();
                    }
                }

            }

            userGroupProperties.AddRange(groupProperties);
        }

        public class ActiveDirectoryPrincipalProperties
        {
            public string fullGroupName { get; set; }
            public string groupDomain { get; set; }
            public string groupName { get; set; }
            public string groupType { get; set; }
            public string memberDomain { get; set; }
            public string memberName { get; set; }
            public string memberType { get; set; }
            public bool groupYesNo { get; set; }
            public bool sqlUserOnlyYesNo { get; set; }
        }
MauMen
  • 1,369
  • 1
  • 9
  • 7

2 Answers2

0

Well

I am really far from being an expert but, since a user can belong to more than one group... Have you tried requesting all users with his group and then constructs the group from this. I suggest also to make some profiling to see which method is the bottleneck and have a better idea about how to proceed.

Hope it helps.

k-dev
  • 1,657
  • 19
  • 30
  • k-dev Thank you for the response. In this method I only have group Principals not users. I need to return the members for each group. Having profiled my project, the method I posted is the one that was taking the longest (2+ min.) to execute. – MauMen Jun 20 '11 at 14:57
0

I shaved off about a half a minute from my procedure using a LAMDA filter on my list before iterating it's elements and removed one conditional statement in the method. Here is my updated code.

[SecurityCritical]
        [SecurityPermissionAttribute(SecurityAction.Demand)] 
        private static void GetGroupMembership(List<ActiveDirectoryPrincipalProperties> userGroupProperties)
        {
            List<ActiveDirectoryPrincipalProperties> groupProperties = new List<ActiveDirectoryPrincipalProperties>();

            foreach (ActiveDirectoryPrincipalProperties gProperties in userGroupProperties.FindAll(token => token.groupYesNo.Equals(true)))
            {

                PrincipalContext ctx = new PrincipalContext(ContextType.Domain, gProperties.groupDomain);
                try
                {

                    GroupPrincipal group = GroupPrincipal.FindByIdentity(ctx, IdentityType.Name, gProperties.groupName);

                    foreach (Principal member in group.GetMembers(true))
                    {
                        ActiveDirectoryPrincipalProperties memberProperties = new ActiveDirectoryPrincipalProperties();
                        memberProperties.fullGroupName = gProperties.fullGroupName;
                        memberProperties.groupDomain = gProperties.groupDomain;
                        memberProperties.groupName = gProperties.groupName;
                        memberProperties.groupType = gProperties.groupType;
                        memberProperties.groupYesNo = false;
                        memberProperties.memberDomain = member.Context.Name.ToString();
                        memberProperties.memberName = member.SamAccountName.ToString();
                        memberProperties.memberType = member.StructuralObjectClass.ToString();
                        memberProperties.sqlUserOnlyYesNo = false;

                        groupProperties.Add(memberProperties);
                    }
                    group.Dispose();
                }
                finally
                {
                    ctx.Dispose();
                }


            }

            userGroupProperties.AddRange(groupProperties);
        }
MauMen
  • 1,369
  • 1
  • 9
  • 7