Adding and Removing Users from Active Directory Groups in .Net

Adding and removing users from Active Directory groups in .NET

Ugh. LDAP. If you're using the .Net Framework 3.5 or above, I highly recommend using the System.DirectoryServices.AccountManagement namespace. That makes things so much easier.

public void AddUserToGroup(string userId, string groupName) 
{
try
{
using (PrincipalContext pc = new PrincipalContext(ContextType.Domain, "COMPANY"))
{
GroupPrincipal group = GroupPrincipal.FindByIdentity(pc, groupName);
group.Members.Add(pc, IdentityType.UserPrincipalName, userId);
group.Save();
}
}
catch (System.DirectoryServices.DirectoryServicesCOMException E)
{
//doSomething with E.Message.ToString();

}
}

public void RemoveUserFromGroup(string userId, string groupName)
{
try
{
using (PrincipalContext pc = new PrincipalContext(ContextType.Domain, "COMPANY"))
{
GroupPrincipal group = GroupPrincipal.FindByIdentity(pc, groupName);
group.Members.Remove(pc, IdentityType.UserPrincipalName, userId);
group.Save();
}
}
catch (System.DirectoryServices.DirectoryServicesCOMException E)
{
//doSomething with E.Message.ToString();

}
}

Removing a User From an Active Directory Group

Use:

public void RemoveUserFromGroup(string userId, string groupName)
{
try
{
using (PrincipalContext pc = new PrincipalContext(ContextType.Domain, "COMPANY"))
{
GroupPrincipal group = GroupPrincipal.FindByIdentity(pc, groupName);
group.Members.Remove(pc, IdentityType.UserPrincipalName, userId);
group.Save();
}
}
catch (System.DirectoryServices.DirectoryServicesCOMException E)
{
//doSomething with E.Message.ToString();

}
}

Performance Issue - Adding / Removing users from large Active Directory groups in .net

I opened an "Advisory Call" at Microsoft for this issue, here is their answer (in German, English below):

S.DS.AM (System.DirectoryServices.Accountmanagement) ist nun nicht der
Renner unter den Programmierschnittstellen, Bequemlichkeit ist Trumpf,
perf-issues mit großen Gruppen sind also by Design. Wenn er auf
Performance aus ist, sollte er S.DS.P
(System.DirectoryServices.Protocols) oder plain LDAP verwenden.“

The meaningful translation in English would be:

Comparing the APIs, S.DS.AM (System.DirectoryServices.Accountmanagement) is not a "racer", but comfort is trump. Performance issues for larger groups is by design. When performance matters, use S.DS.P (System.DirectoryServices.Protocols) or plain LDAP.

I created a Console application in order to measure the differences of adding and removing a user from a group in milliseconds.

AccountManagement

public static void InsertGroupAccountManagement(UserPrincipal userPrincipal)
{
using (GroupPrincipal adGroup = GroupPrincipal.FindByIdentity(_principalGroupContext, IdentityType.Guid, PRODUCT_USER_GROUP_ID))
{
adGroup.Members.Add(userPrincipal);
adGroup.Save();
adGroup.Members.Remove(userPrincipal);
adGroup.Save();
}
}

DirectoryServices

public static void InsertGroupDirectoryServices(string samAccountName)
{
DirectoryEntry groupEntry = new DirectoryEntry("LDAP://server.address/CN=PSO_PRODUCT_USER,OU=PSO_,OU=Groups,OU=_PRODUCT,DC=address,DC=server", "USERNAME", "PASSWORD");
string userDn = String.Concat("LDAP://server.address/CN=", samAccountName, ",OU=Users,OU=_PRODUCT,DC=address,DC=server");
DirectoryEntry userEntry = new DirectoryEntry(userDn, "USERNAME", "PASSWORD");
groupEntry.Invoke("Add", new object[] { userDn });
groupEntry.CommitChanges();
groupEntry.Invoke("Remove", new object[] { userDn });
groupEntry.CommitChanges();
groupEntry.Close();
}

Protocols

public static void InsertGroupProtocols(string samAccountName)
{
LdapDirectoryIdentifier ldapDirectoryIdentifier = new LdapDirectoryIdentifier("server.address");
NetworkCredential credentials = new NetworkCredential("USERNAME", "PASSWORD");
LdapConnection ldapConnection = new LdapConnection(ldapDirectoryIdentifier, credentials);
ldapConnection.SessionOptions.ProtocolVersion = 3;
ldapConnection.SessionOptions.Signing = true;
ldapConnection.SessionOptions.Sealing = true;
ldapConnection.AuthType = AuthType.Negotiate;
ldapConnection.Bind();

// Add
DirectoryAttributeModification addDirectoryModification = new DirectoryAttributeModification();
addDirectoryModification.Name = "member";
addDirectoryModification.Add(String.Concat("CN=", samAccountName, ",OU=Users,OU=_PRODUCT,DC=address,DC=server"));
addDirectoryModification.Operation = DirectoryAttributeOperation.Add;

ModifyRequest addRequest = new ModifyRequest("CN=PSO_PRODUCT_USER,OU=PSO_,OU=Groups,OU=_PRODUCT,DC=address,DC=server", addDirectoryModification);
ModifyResponse addResponse = ldapConnection.SendRequest(addRequest) as ModifyResponse;

// Remoove
DirectoryAttributeModification deleteDirectoryModification = new DirectoryAttributeModification();
deleteDirectoryModification.Name = "member";
deleteDirectoryModification.Add(String.Concat("CN=", samAccountName, ",OU=Users,OU=_PRODUCT,DC=address,DC=server"));
deleteDirectoryModification.Operation = DirectoryAttributeOperation.Delete;

ModifyRequest deleteRequest = new ModifyRequest("CN=PSO_PRODUCT_USER,OU=PSO_,OU=Groups,OU=_PRODUCT,DC=address,DC=server", deleteDirectoryModification);
ModifyResponse deleteResponse = ldapConnection.SendRequest(deleteRequest) as ModifyResponse;
}

Result table in milliseconds

Running 10 tests in a row

Result table of time taken

So in my particular case the solution via DirectoryServices / DirectoryEntry is the fastest.

Delete User from AD Group

You seem to be doing it extremely complicated - unnecessarily so.

Check out the Howto do almost everything in Active Directory CodeProject article - excellent stuff.

Here's the snippet needed to remove a user (given by his DN) from a group (also defined by the DN):

public void RemoveUserFromGroup(string userDn, string groupDn)
{
try
{
DirectoryEntry dirEntry = new DirectoryEntry("LDAP://" + groupDn);
dirEntry.Properties["member"].Remove(userDn);
dirEntry.CommitChanges();
dirEntry.Close();
}
catch (System.DirectoryServices.DirectoryServicesCOMException E)
{
//doSomething with E.Message.ToString();

}
}

Does that work for you??

Add users to a Security Group in active directory

Sigh, i fixed my problem.

I was working on this on my prod workstation connecting to the 1 of our dev AD servers. I than decided to run the project from my dev workstation and everything worked fine.

Error adding/removing Outlook Distribution List users through .NET

I finally figured this out. I was confused by this permissions problem since I could edit the DL in Outlook, but not thru .NET.

I started looking for differences between the DL's that I could edit thru .NET and those that I could not, and found the difference was represented in the AD property shown in this GUI as "Manager can update membership list":

dl

Even though I was the "manager" (list owner), if the DL didn't have that property set, I could ONLY edit in Outlook.

I didn't want to have to visually check all the DL's, so I wrote the following code to detect the "real" owners/editors of a DL:

    static List<string> GetGroupOwners(GroupPrincipal group)
{
List<string> owners = new List<string>();
DirectoryEntry deGroup = group.GetUnderlyingObject() as DirectoryEntry;
ActiveDirectorySecurity ads = deGroup.ObjectSecurity;
AuthorizationRuleCollection rules = ads.GetAccessRules(true, true, typeof(SecurityIdentifier));
Guid exRight_Member = new Guid("{bf9679c0-0de6-11d0-a285-00aa003049e2}");

foreach (ActiveDirectoryAccessRule ar in rules)
{
if (ar.ActiveDirectoryRights.HasFlag(ActiveDirectoryRights.GenericWrite) || (ar.ObjectType.Equals(exRight_Member) && ar.ActiveDirectoryRights.HasFlag(ActiveDirectoryRights.WriteProperty)))
{
string friendlyName = "";
try
{
friendlyName = ar.IdentityReference.Translate(typeof(NTAccount)).Value;
}
catch
{
}
owners.Add(friendlyName);
}
}
return owners;
}

If you want to know who has Outlook-based edit access, that's different:

    static List<string> GetGroupOwnersOutlook(GroupPrincipal group)
{
List<string> owners = new List<string>();
DirectoryEntry deGroup = group.GetUnderlyingObject() as DirectoryEntry;
System.DirectoryServices.PropertyCollection r = deGroup.Properties;
foreach (string a in r["managedBy"])
{
owners.Add(a);
}
foreach (string a in r["msExchCoManagedByLink"])
{
owners.Add(a);
}

return owners;
}


Related Topics



Leave a reply



Submit