S2K
S2K

Reputation: 1285

.net : How to add a user to a Active Directory Security Group using C#?

I am finding a reference to a security group to which I need to add user by using the following code:

string strActiveDirectoryPath = @"GC://domain.com";

DirectoryEntry directoryEntryRoot = new DirectoryEntry(strActiveDirectoryPath);

using (DirectorySearcher searcher = new DirectorySearcher(directoryEntryRoot))
{  
    searcher.PageSize = 1000;
    searcher.Filter = "(&(objectClass=group)(cn=*SGNAME*))";
    //searcher.SearchScope = SearchScope.Subtree;
    SearchResult securityGroup = searcher.FindOne();  
}

The above code sometimes throws an exception saying

Search resulted in too many records

Is my logic of fetching the security group correct?

Then I get reference to the user and try to add it to the security group:

searcher.Filter = "(SAMAccountName=" + UserAlias + ")";
searcher.PropertiesToLoad.Add("givenname");
searcher.PropertiesToLoad.Add("displayName");               

SearchResult userALias = searcher.FindOne();

DirectoryEntry ent = new DirectoryEntry(securityGroup.Path);              
string domainString = "GC://domain.com/";
int Start =  domainString.Length;
string member = userALias.Path.Substring(domainString.Length);

ent.Properties["member"].Add(member);
// ent.Invoke("Add", new object[] { s });

ent.CommitChanges();
ent.Close();

I have created an instance of DirectoryEntry and provided a path of the security group that I have found.

What should be provided to DirectoryEntry?

CommitChanges fails with exception:

The server is unwilling to process the request.

enter image description here

Upvotes: 0

Views: 2224

Answers (1)

Gabriel Luci
Gabriel Luci

Reputation: 41008

I see a couple issue. First:

searcher.Filter = "(&(objectClass=group)(cn=*SGNAME*))";
SearchResult securityGroup = searcher.FindOne();

Because you're using wildcards, you're searching for any group with SGNAME anywhere in the name. This has two problems:

  1. Even though the cn attribute is indexed, the index can't be used because you're using a wildcard at the beginning. It has to look at every group to try and find matches. This will slow down your search.
  2. Because you're doing a wildcard search, it could match to more than one account. The documentation for DirectorySearcher.FindOne() says:

If more than one entry is found during the search, only the first entry is returned.

So you can't guarantee that the group returned is actually the one you want.

Why are you getting an exception then? I don't know. I would be curious to see the full exception details. There will probably be a hex number in there.

But I don't think that really matters. All of this would be solved by just matching the name exactly:

searcher.Filter = "(&(objectClass=group)(cn=SGNAME))";

Adding a member to the group

My guess is that your member variable isn't a proper distinguishedName. Instead of trying to parse the DN out of the Path, just ask for the distinguishedName in the search results. For example:

searcher.Filter = "(SAMAccountName=" + UserAlias + ")";
searcher.PropertiesToLoad.Add("distinguishedName");

SearchResult userALias = searcher.FindOne();

DirectoryEntry ent = securityGroup.GetDirectoryEntry();              

string member = (string) userALias.Properties["distinguishedName"][0];

ent.Properties["member"].Add(member);

ent.CommitChanges();
ent.Close();

Update: You also cannot update via the Global Catalog. You must use LDAP://:

string strActiveDirectoryPath = "LDAP://domain.com";

Or, if you really do need to search the GC (if you have multiple domains in your forest) then you'll have to switch to LDAP when you create your DirectoryEntry for the group.

DirectoryEntry ent = new DirectoryEntry(securityGroup.Path.Replace("GC://", "LDAP://"));

Upvotes: 2

Related Questions