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
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":
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
How to Get the Correct Ip from Http_X_Forwarded_For If It Contains Multiple Ip Addresses
Providing Input/Subcommands to a Command (Cli) Executed with Ssh.Net Sshclient.Runcommand
How to Check If a Property Exists on a Dynamic Anonymous Type in C#
Find the Next Tcp Port in .Net
C# Iterate Through Class Properties
Automated Property with Getter Only, Can Be Set, Why
Determine Label Size Based Upon Amount of Text and Font Size in Winforms/C#
Print List of Objects to Console
Add Custom Header in Httpwebrequest
Is It There Any Lru Implementation of Idictionary
ASP.NET Core Jwt Mapping Role Claims to Claimsidentity