1

I have a very large number of users that I need to add to an AD group. I have all the users SAMAccountNames stored in a datagridview.

The code below works but slowly. It's as if it's querying each user directly when I call g.members.add. Is there a more efficient way to add them?

For Each r As DataGridViewRow In dgvFinalUsers.Rows
   Dim userName As String = r.Cells(0).Value
   If Not g.Members.Contains(ctx, IdentityType.SamAccountName, userName) Then
      g.Members.Add(ctx, IdentityType.SamAccountName, userName)
      i += 1
      Debug.Print(i)
   End If
Next
g.save
marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
Force
  • 3,288
  • 1
  • 13
  • 19

1 Answers1

1

What if you loaded all users that exist into a List object before the For Each and then see if the user exists in the List? That way you are only querying AD once?

Like this:

var domainMembers = new List<Principal>();
using (var context = new PrincipalContext( ContextType.Domain ))
{
     GroupPrincipal grp = GroupPrincipal.FindByIdentity(context, IdentityType.SamAccountName, "Domain Users"); 
     foreach(var user in grp.GetMembers(false))
     {
          if(user)
          {
              domainMembers.add(user);
          }
     }
}
Dakotah Hicock
  • 380
  • 2
  • 15
  • He sounds to want to add users to an AD group, not to an inmemory collection. – Wiktor Zychla Sep 04 '14 at 16:55
  • 1
    @WiktorZychla [I ran in to a similar problem](http://stackoverflow.com/questions/2409432/improving-performance-of-system-directoryservices-accountmanagement) in my coding too. A lot of methods in DirectyServices don't cache the result of things like 'Members` so it re-queries every time. Copying the list of members currently in the group to a in memory collection really speeds up the `g.Members.Contains` call. – Scott Chamberlain Sep 04 '14 at 16:55
  • @WiktorZychla, by adding it this way, he won't have to query AD each time it iterates. Thus, speeding up the process. – Dakotah Hicock Sep 04 '14 at 16:56
  • @ScottChamberlain: the AccountManagement API will have a terrible performance anyway. We have domain controllers with > 50k users and doing users to groups that way lasts like 3 seconds where working at `DirectoryEntry` level lets you do things in miliseconds (http://www.codeproject.com/Articles/18102/Howto-Almost-Everything-In-Active-Directory-via-C#36) – Wiktor Zychla Sep 04 '14 at 17:01
  • I work at a pretty large organization so querying all users wouldn't be viable. I'm curious though if I built a userprincipal for each user and then tried adding them to the group. I'll do a test and see if it has an impact on performance. – Force Sep 04 '14 at 17:02
  • I just saw the comments that Wiktor and Scott posted and I think I'm seeing the same thing they have. I modified the code to build a list of userprincipals first and then add them and it's going much faster. Though not as fast as the old school queries like Wiktor mentioned. – Force Sep 04 '14 at 17:05
  • 1
    Can you post your code as an answer so other users that have this question can see how you did it, or if this answer answered your question, mark it as an answer? – Dakotah Hicock Sep 04 '14 at 17:08