Trying to get all the groups a user belongs to, INCLUDING the primary group:
Doing something like this:
DirectoryEntry entry = new DirectoryEntry(LDAP:/domainXYZ, userx, passwordx);
DirectorySearcher searcher = new DirectorySearcher(entry);
searcher.Filter = String.Format("(&(objectClass=user)(userPrincipalName={0}{1}))", userY, LDAP://domainXYZ);
SearchResultCollection resultColln= searcher.FindOne();
string actualGroupName =string.empty;
string grp ="";
foreach (SearchResult singleRes in resultColln)
{
foreach (object value in singleRes.Properties["memberof"])
{
grp = value.ToString();
Console.WriteLine("group:{0} ", grp);
}
}
This gives me all the groups except the primary group. Is there a way to get the primary group name, using the primaryGroupID in addition to the other groups?
You should run another search using the following search filter
string.Format("(&(objectCategory=group)(objectClass=group)(primaryGroupToken={0}))", singleRes.Properties["primaryGroupID"]);
primaryGroupToken is a calculated attribute that automatically generated by Active Directory when the group is created. The primaryGroupID assigned to the user is storing this value.
Actually, if you want a really easy way, I would suggest UserPrincipal.GetGroups is really easy. The only thing is that you can find it only in .NET 3.5 or later.
using (PrincipalContext context = new PrincipalContext(ContextType.Domain, "yourdomain.com"))
{
using (UserPrincipal user = UserPrincipal.FindByIdentity(context, IdentityType.SamAccountName, "YourUser"))
{
foreach (Principal p in user.GetGroups())
{
Console.WriteLine(p.Name);
}
}
}
GetGroups returns you only the group that immediately contains your user, including its primary group. If you want to get all the nested groups, you can use GetAuthorizationGroups.
Related
I can't get a part of my windows form functioning. I don't know where I have gone wrong because many other sources have said to add users to groups this way. I get this error everytime:
System.Runtime.InteropServices.COMException: 'Unspecified error'
It fails on this line here: de.Properties["member"].Add(up);
But I can't figure out why it is failing. I have also tried with string group = chklbADGroups.CheckedItems to no avail, which is why I tried specifying the group name instead.
foreach (string item in chklbADGroups.Items)
{
string group = "CN=mygroup";
bool isChecked = chklbADGroups.GetItemChecked(chklbADGroups.FindStringExact(item));
string LDAP = System.Net.NetworkInformation.IPGlobalProperties.GetIPGlobalProperties().DomainName;
PrincipalContext ouContext = new PrincipalContext(ContextType.Domain, LDAP);
WindowsIdentity.GetCurrent();
SearchResult results;
DirectorySearcher ds = null;
DirectoryEntry de = new
DirectoryEntry(ouContext + group);
UserPrincipal up = new UserPrincipal(ouContext);
if (de != null && isChecked == true)
{
de.Properties["member"].Add(up);
de.CommitChanges();
de.Close();
}
}
So I actually figured it out. I worked around it using a different method. Instead of using a foreach loop that looped through every item that was checked in the checklist. (I kept getting an error that the list had changed and couldn't be looped through a second time.) I used a foreach loop that loops through all checked items and then puts those into strings and puts them in a list.
Then I used a foreach that loops through that list (Which doesn't change) and gets the strings from the list and passes them to the group principal via the GroupName variable.
var checkedItems = new List<string>();
foreach (var chk in chklbADGroups.CheckedItems)
{
checkedItems.Add(chk.ToString());
}
foreach (string GroupName in checkedItems)
{
WindowsIdentity.GetCurrent();
string username = up.SamAccountName;
MessageBox.Show(GroupName);
PrincipalContext context = new PrincipalContext(ContextType.Domain, DomainName);
GroupPrincipal grp = GroupPrincipal.FindByIdentity(context, IdentityType.Name, GroupName);
if (GroupName != null)
{
grp.Members.Add(context, IdentityType.SamAccountName, username);
grp.Save();
grp.Dispose();
context.Dispose();
}
}
I currently have the following code which successfully gets all Security Groups from AD and adds them into a Check List box:
try
{
Logging.LogMessageToFile("Reading Security Groups from AD.");
PrincipalContext ctx = new PrincipalContext(ContextType.Domain);
GroupPrincipal qbeGroup = new GroupPrincipal(ctx);
PrincipalSearcher srch = new PrincipalSearcher(qbeGroup);
foreach (var found in srch.FindAll())
{
lstAdGroups.Items.Clear();
lstAdGroups.Items.Add(found);
}
}
catch (Exception ex)
{
Logging.LogMessageToFile("Unexpected error reading Security Groups from AD: " + ex.Message);
}
My issue is that it currently pulls every Security Group (where ideally I'd only like to only list custom created security groups (eg, exclude any from the Users or Builtin OU's). I can't see if there are any properties against groups to filter 'custom' from out the box. Is this even possible?
PrincipalSearcher can only filter based on attributes that are exposed in properties of the various Principal classes. If you're looking for groups, you're limited to filtering based on the properties of the GroupPrincipal class.
That issues aside, filtering out objects in certain OUs isn't something you can do in a query at all simply because there is no AD attribute that contains the OU that you're allowed to filter on. So there is two ways you can do this:
Do what you're already doing, but in your loop, look at the DistinguishedName property of the result. If it's in an OU you don't like, then just continue;.
You can use DirectorySearcher directly (which is what PrincipalSearcher uses in the background anyway), and filter by the isCriticalSystemObject attribute. That will filter out built-in objects like the Domain Admins and Users groups, etc.
Here is a simple example using DirectorySearcher that just outputs the name of each group:
var searcher = new DirectorySearcher("(&(objectClass=group)(!isCriticalSystemObject=TRUE))");
using (var results = searcher.FindAll()) {
foreach (SearchResult result in results) {
Console.WriteLine(result.Properties["cn"][0]);
}
}
I have the following code. It is supposed to check with the ldap server what roles does a user has and display all of them and delete any role that doesnt exist on the ldap server. Right now it doesnt display "domain users" group as it is the primary group. But i need it to display domain users role as well. I tried including the (primaryGroupID=513) in the filter but that doesnt work as 'directorySearcher.FindOne();' returns null after i add the primaryGroupID to the filter.
I am sure you have done your research as well. I dont believe there is an easy way to access the groups that are set up as primary, or part of the groups that are members of the same group as Domain Users. My account in my AD have 125 groups but only 70 shows up if i query via powershell or DirectoryEntry.
I know that the following code works and pulls all the groups regardless of what type of group it is.
PrincipalContext ctx = new PrincipalContext(ContextType.Domain);
UserPrincipal user = (UserPrincipal)Principal.FindByIdentity(ctx, userID);
PrincipalSearchResult<Principal> userGroups = user.GetAuthorizationGroups();
You can access the default group if you get the PrimaryGroupID first.
We document the LDAP Filter that can be used.
And there is also Get-ADPrincipalGroupMembership
This worked flawlessly
`if (results!=null)
{
//find primary group (by default Domain Users)
var User = results.GetDirectoryEntry();
User.RefreshCache(new string[] { "tokenGroups" });
foreach (byte[] resultBytes in User.Properties["tokenGroups"])
{
var SID = new SecurityIdentifier(resultBytes, 0);
var sidSearcher = new DirectorySearcher();
sidSearcher.SearchRoot = directoryEntry;
sidSearcher.Filter = "(objectSid=" + SID.Value + ")";
sidSearcher.PropertiesToLoad.Add("name");
var sidResult = sidSearcher.FindOne();
if (sidResult != null)
{
MemberGroups.Add((string)sidResult.Properties["name"][0]);
}
}`
I have an ActiveDirectory Group called "AuditUsers" and it has some members.
This is my code:
` DirectoryEntry de = new DirectoryEntry(ADSPath);
DirectorySearcher deSearch = new DirectorySearcher(LDAP://CN=AuditUsers,OU=WEB Groups,OU=Groups,DC=doamin,DC=com);
deSearch.Filter = "(&(objectCategory=person)(objectClass=user)(!userAccountControl:1.2.840.113556.1.4.803:=2))";
object members = de.Invoke("Members", null);`
So this object member doesn't pull all the users who are actually their members. Only some members are showing up. Does anyone have any idea why some people are missing here even if they are part of this group? IS any key field is missing in AD for those who are missed?
I checked the missing member's AD and found their objectCategory has person, objectClass has user. userAccountControl is same for those members who are pulled and not pulled.
Thanks
Invoking IADsGroup.Members is just the harder way of enumerating de.Properties["member"]. Both just read the member attribute of the group.
But that is not the only way a user can be a member. I go into it in more detail in an article I wrote, but what I suspect is going on here is that the group is used as the primary group for many of your users. And that membership is done differently.
If that is the case, then the primaryGroupId attribute of the users will be set to the Relative Identifier (RID) of the group. The RID is the last set of numbers in the SID (which can also be retrieved from the primaryGroupToken attribute of the group). In the article I wrote about finding all the members of a group, I included an example of how to find all the users that have the group as their primary group. On my site it was returning the DOMAIN\username, but I modified it here so it returns the distinguishedName, so you can add what you get from this to what you get from the member attribute.
public static IEnumerable<string> GetPrimaryGroupMemberList(DirectoryEntry group) {
group.RefreshCache(new[] { "distinguishedName", "primaryGroupToken" });
var groupDn = (string) group.Properties["distinguishedName"].Value;
var ds = new DirectorySearcher(
new DirectoryEntry($"LDAP://{groupDn.Substring(groupDn.IndexOf("DC=", StringComparison.Ordinal))}"),
$"(&(objectClass=user)(primaryGroupId={group.Properties["primaryGroupToken"].Value}))",
new [] { "distinguishedName" })
{
PageSize = 1000
};
using (var primaryMembers = ds.FindAll()) {
foreach (SearchResult primaryMember in primaryMembers) {
yield return (string) primaryMember.Properties["distinguishedName"][0];
}
}
}
We got a special multivalue attribute. Let's call it ourOwnManagedBy which can contain users or groups (their DN) that manages the current group.
How can I retrieve a list of all groups that a specific user manages (with the help of managedBy and ourOwnManagedBy)?
For instance. Let's say that the user is member of the group GlobalAdministrators and that the group ApplicationAdministrators has GlobalAdministrations as a member. And finally the group MyApplication which has ApplicationAdministrators in the ourOwnManagedBy attribute.
User is member of GlobalAdministrators
GlobalAdministrators is member of ApplicationAdministrators
MyApplication got ApplicationAdministrators in ourOwnManagedBy
How do I use that information to find all groups that a specific user manages? Is it possible to do some kind of recursive check in custom attributes (that contains DNs of users and groups)?
Update
I've tried to use a directory search filter like this:
string.Format("(ourOwnManagedBy:1.2.840.113556.1.4.1941:={0})", dn);
but I might have missunderstood what 1.2.840.113556.1.4.1941 does? (MSDN page)
This is, I'm afraid, not possible to accomplish with only one LDAP query. You will have to split it into subqueries and run the each separately, which in turn will choke the domain controller if there's a lot to iterate over.
I tried to do it the way I described, and the performance was horrible, at least doing it using the available modules for .NET.
The following page says 3.1.1.3.4.4 LDAP Matching Rules (extensibleMatch) says that the LDAP_MATCHING_RULE_TRANSITIVE_EVAL that you are using does work in Windows 2008 and higher editions. If you are using 2003, it may not work.
No recursion, no idea on how it will do performance wise, may have bugs.
string user = "username";
//get domain
DirectoryEntry de = System.DirectoryServices.ActiveDirectory.Domain.GetCurrentDomain().GetDirectoryEntry();
//get users dn first
string userDN;
using (var searcher = new DirectorySearcher(de))
{
searcher.Filter = String.Format("(&(objectCategory=person)(objectClass=user)(sAMAccountName={0}))", user);
searcher.PropertiesToLoad.Add("distinguishedName");
userDN = searcher.FindOne().Properties["distinguishedName"][0].ToString();
}
//get list of all users groups
List<string> groups;
//see http://stackoverflow.com/questions/6252819/find-recursive-group-membership-active-directory-using-c-sharp
using (var searcher2 = new DirectorySearcher(de))
{
searcher2.Filter = String.Format("(member:1.2.840.113556.1.4.1941:={0})", userDN);
searcher2.SearchScope = SearchScope.Subtree;
searcher2.PropertiesToLoad.Add("distinguishedName");
SearchResultCollection src = searcher2.FindAll();
groups = (from SearchResult c in src
select c.Properties["distinguishedName"][0].ToString()).ToList();
}
//build giant search query
SearchResultCollection srcGroups;
using (var searcher = new DirectorySearcher(de))
{
string baseString = "(|{0})";
string managedbybase = "(managedBy={0})";
//I've read that you can search multivalued lists using a standard ='s.
string ourOwnManagedByBase = "(ourOwnManagedBy={0})";
StringBuilder sb = new StringBuilder();
//add user DN to list of group dn's
groups.Add(userDN);
foreach (string g in groups)
{
sb.AppendFormat(managedbybase, g);
sb.AppendFormat(ourOwnManagedByBase, g);
}
searcher.Filter = string.Format(baseString, sb.ToString());
srcGroups = searcher.FindAll();
}
I'll be honest and say that this doesn't actually work for me :) But I think it's because of the way our domain is configured. If nothing else maybe it will push you in the right direciton.