1

I have created a function to add one user at a time into particular group (Administrators etc) but it seems to be taking too long to respond on GroupPrinciple(5-10 seconds) and group.members.add(5-10 seconds) call and slowing down my app, it takes almost 15-20 sec to respond, is there a faster way to do this?

private static void Add()
{
 var userContext = new PrincipalContext(ContextType.Domain);
 var user = new UserPrincipal(userContext);
 user.SamAccountName = "c1111111";
 var searcher = new PrincipalSearcher(user);
 user = searcher.FindOne() as UserPrincipal;

var machineContext = new PrincipalContext(ContextType.Machine, "ABCDEFGHI1",
   null, ContextOptions.Negotiate, "c123789", "test123");
var group = GroupPrincipal.FindByIdentity(machineContext,"Administrators"); 

group.Members.Add(user); 

Console.WriteLine("saving group");
group.Save();

}
user2229874
  • 79
  • 1
  • 9

2 Answers2

0

I have run in to this myself, because you are using the same group every single time see if you can refactor out the finding of the group from the adding of the user and add multiple users at once.

private static void Add(IEnumerable<UserPrincipal> users)
{
    var machineContext = new PrincipalContext(ContextType.Machine, "ABCDEFGHI1",
       null, ContextOptions.Negotiate, "c123789", "test123");
    var group = GroupPrincipal.FindByIdentity(machineContext,"Administrators"); 
    foreach(var user in users)
    {
        group.Members.Add(user); 
    }
    Console.WriteLine("saving group");
    group.Save();
}

Or another option is find the group once but then cache it. Using Task.Run makes this very easy, just start the task up in the static constructor then grab the result in your Add function. .Result will block till the task finishes then will be instant after that. Important note, GroupPrincipal is not thread safe so you will need to lock around the modifications to the class.

static YourClassName()
{
    _administratorsGroup = Task.Run(() =>
    {
        var machineContext = new PrincipalContext(ContextType.Machine, "ABCDEFGHI1",
           null, ContextOptions.Negotiate, "c123789", "test123");
        return GroupPrincipal.FindByIdentity(machineContext,"Administrators"); 
    });
}

private static Task<GroupPrincipal> _administratorsGroup;

private static void Add(UserPrincipal user)
{
    group = _administratorsGroup.Result;
    lock(group)
    {
        group.Members.Add(user); 

        Console.WriteLine("saving group");
        group.Save();
    }
}

If this will be on a UI thread replace the _administratorsGroup.Result with await _administratorsGroup, it also has the same waiting behavior but will not lock up your UI.

Community
  • 1
  • 1
Scott Chamberlain
  • 124,994
  • 33
  • 282
  • 431
  • Thank you for your help! I inserted whole Add function functionality. Could you please review the code and provide your feedback. – user2229874 Jun 12 '15 at 21:23
  • Do you really always have those fixed values for `Add`, you don't pass in any parameters? – Scott Chamberlain Jun 12 '15 at 21:31
  • I am passing username as a parameter in the Add function but adding/getting only one username from user at a time. user.SamAccountName = userName ("c1111111"); – user2229874 Jun 14 '15 at 18:20
  • I have improved code performance by using PrincipalSearch instead of GroupPrincipal.FindByIdentity. Is there any way to improve performance of "group.Members.Add(user);"? – user2229874 Jun 15 '15 at 18:03
  • You could try `group.Members.Add(PrincipalContext, IdentityType.Sid, user.Sid.Value);` instead of giving the principal. – tar Mar 04 '22 at 17:55
0

FindAll() is way faster for ContextType.Machine. Then just filter the result by your available input: Name, UserPrincipalName, SAMAccountName or Sid.Value.

Linq variant, untested for ContextType.Domain:

PrincipalContext principalContext = new PrincipalContext(ContextType.Machine);

// user (input: userSID)
PrincipalSearcher userPrincipalSearcher = new PrincipalSearcher(new UserPrincipal(principalContext));
UserPrincipal userPrincipal = userPrincipalSearcher.FindAll().FirstOrDefault(x => (x is UserPrincipal) && x.Sid.Value == userSID) as UserPrincipal;

// group (input: groupSID)
PrincipalSearcher groupPrincipalSearcher = new PrincipalSearcher(new GroupPrincipal(principalContext));
GroupPrincipal groupPrincipal = groupPrincipalSearcher.FindAll().FirstOrDefault(x => (x is GroupPrincipal) && x.Sid.Value == groupSID) as GroupPrincipal;
tar
  • 156
  • 2
  • 13