LDAP DirectorySearcher with MemberOf property - c#

I want to find all the users that are a member of a group in a certain OU, so my filter would look something like this:
(&(objectClass=user)(memberOf=*OU=something,OU=yep,DC=dev,DC=local))
Is there a way to run a directorysearcher on the memberof property with a wildcard?

You need to set the OU you want to search as the root of your DirectorySearcher:
DirectoryEntry myOU = new DirectoryEntry("OU=something,OU=yep,DC=dev,DC=local");
DirectorySearcher srch = new DirectorySearcher(myOU);
srch.SearchScope = SearchScope.Subtree;
and then use just the objectCategory=person for your filter - I would use objectCategory which is single-valued and indexed and thus fast rather than objectClass (which is multi-valued and not indexed):
srch.Filter = "(objectCategory=person)";
If you still want to check for membership in a group in addition to being part of the OU, you can add this as a member-of part to the filter:
srch.Filter = "(&(objectCategory=person)(memberOf=cn=Group,ou=yep,dc=dev,dc=local))";
Not totally sure about the wildcards - in general, LDAP search filters do support wildcards, but I'm a bit hesitant about using a wildcard in a RDN like this group DN here.
Marc

According to this thread, wildcard search for DNs are not supported in Active Directory.

Don't specify a memberOf clause.

Don't specify the memberOf clause. Just use "(objectClass=user)"

Here is how i did this
is the LDAP name
is the group for which you need members
DirectoryEntry entry = new DirectoryEntry("LDAP://<COMPANYLDAP>/CN=<Group Name>,OU=something,OU=yep,DC=dev,DC=local");
DirectorySearcher Dsearch = new DirectorySearcher(entry);
SearchResult sResultSet = Dsearch.FindOne();
GetProperty(sResultSet, "member");
public static void GetProperty(SearchResult searchResult, string PropertyName)
{
StringBuilder strb = new StringBuilder();
if (searchResult.Properties.Contains(PropertyName))
{
ResultPropertyValueCollection rc = searchResult.Properties[PropertyName];
foreach (string name in rc)
{
DirectoryEntry entry = new DirectoryEntry("LDAP://<COMPANYLDAP>/" + name);
DirectorySearcher Dsearch = new DirectorySearcher(entry);
//Dsearch.Filter = name;
SearchResult sResultSet = Dsearch.FindOne();
strb.AppendLine(GetPropertyvalue(sResultSet, "displayname") + "," + GetPropertyvalue(sResultSet, "mail"));
}
}
File.WriteAllText(strb.ToString(), "c:\\Users.txt");
}

Related

Trying to pull 'ManagedBy' property from Computer object in AD

I've found some examples here and there, but I can't seem to find one that addresses retrieving the managedby property from a computer record. (I don't know the username, but it's stored in the managedby)
DirectoryEntry searchRoot = new DirectoryEntry("LDAP://"+lblDomain.Text);
DirectorySearcher search = new DirectorySearcher(searchRoot);
search.Filter = ("(objectClass=computer)");
search.PropertiesToLoad.Add("managedBy");
search.PropertiesToLoad.Add("distinguishedName");
search.PropertiesToLoad.Add("cn");
SearchResultCollection groups = search.FindAll();
foreach (SearchResult sr in groups)
{
if (sr.Properties.Contains("managedby"))
{
lblManagedBy.Text=(sr.Properties["managedBy"][0].ToString());
}
else
{
lblManagedBy.Text = "No owner specified in ManagedBy";
}
}
Your example works fine for me, so a few things to check.
1) Is the domain name correct in lblDomain.Text? Could you provide an example of what you are using for it? Fake names are fine.
2) Do you actually have computer accounts with the Managed By set? It is empty by default.
Other than that, I used you exact code and got back the DN of the user I assigned to a computer account, so it's probably in how you are connecting.
search.Filter = "(&(objectClass=computer)(cn=pcname))";
DirectoryEntry searchRoot = new DirectoryEntry("LDAP://"+lblDomain.Text);
DirectorySearcher search = new DirectorySearcher(searchRoot);
search.Filter = "(&(objectClass=computer)(name=" + host + "))";
search.PropertiesToLoad.Add("managedBy");
search.PropertiesToLoad.Add("distinguishedName");
search.PropertiesToLoad.Add("cn");
SearchResultCollection groups = search.FindAll();
foreach (SearchResult sr in groups)
{
if (sr.Properties["managedBy"].Count > 0)
{
lblManagedBy.Text=(sr.Properties["managedBy"][0].ToString());
}
else
{
lblManagedBy.Text = "No owner specified in ManagedBy";
}
}

How to get SID of a group once i get groups of a user in Active Directory?

I am using DirectorySearcher to get groups of a User in ActiveDirectory.
My Question is how to get SID associated with each group once i get user groups using "memberOf"?
I am working in .NETFramework 2.0 Environment.
DirectoryEntry entry = new DirectoryEntry(string.Format("LDAP://{0}", sUserDomain));
DirectorySearcher mySearcher = new DirectorySearcher(entry);
mySearcher.Filter = string.Format("(&(objectClass=user) (cn= {0}))", ui.DisplayName.ToString());
mySearcher.PropertiesToLoad.Add("memberOf");
SearchResult searchresult = mySearcher.FindOne();
There is no way to do it in one single LDAP search because memberOf returns a distinguish name. You have to do another bind to get the objectSid attribute from the group object. Here is the code.
DirectoryEntry entry = new DirectoryEntry(string.Format("LDAP://{0}", sUserDomain));
DirectorySearcher mySearcher = new DirectorySearcher(entry);
mySearcher.Filter = string.Format("(&(objectClass=user) (cn= {0}))", ui.DisplayName.ToString());
mySearcher.PropertiesToLoad.Add("memberOf");
SearchResult searchresult = mySearcher.FindOne();
foreach (string dn in searchresult.Properties["memberOf"])
{
DirectoryEntry group = new DirectoryEntry(string.Format("LDAP://{0}/{1}", sUserDomain, dn));
SecurityIdentifier sid = new SecurityIdentifier(group.Properties["objectSid"][0] as byte[], 0);
Console.Out.WriteLine(sid.Value);
}
If you're on .NET 3.5 and up, you should check out the System.DirectoryServices.AccountManagement (S.DS.AM) namespace. Read all about it here:
Managing Directory Security Principals in the .NET Framework 3.5
MSDN docs on System.DirectoryServices.AccountManagement
Basically, you can define a domain context and easily find users and/or groups in AD:
// define context for current domain
using(PrincipalContext ctx = new PrincipalContext(ContextType.Domain))
{
// find user
UserPrincipal user = UserPrincipal.FindByIdentity(ctx, "YourNameHere");
if (user != null)
{
// get groups the user is a member of
var groups = current.GetGroups();
// iterate over all those groups
foreach(var group in groups)
{
// fetch the SID for each group
var sid = group.Sid;
}
}
}
The new S.DS.AM makes it really easy to play around with users and groups in AD!
Have a look at his article:
Retrieving user SID using DirectoryEntry and DirectorySearcher
This gives you a full working example for retrieving the SID.

DirectorySearcher Filter

When I run this query
// Next row is used to login to AD
DirectoryEntry entry = GetEntry(domain, adminUser, adminPassword);
// Here starts the query
DirectorySearcher search = new DirectorySearcher(entry)
{
SearchScope = SearchScope.Subtree,
Filter = "(&" +
"(objectClass=user)" +
// "(distinguishedname=*OU=Ingegneria*)" +
"(givenname=s*)" +
"(samaccountname=*100)" +
")"
};
search.PropertiesToLoad.Add("distinguishedname");
SearchResultCollection result = search.FindAll();
I get six entries and that's correct.
All records, if I use record.GetDirectoryEntry() have
distinguishedname: CN=xxx,OU=Utenti,OU=Ingegneria,DC=xxx,DC=xxx
Anyway if I remove comment on distinguishedname part of the filter, I get zero entries!!
I also tried to use search.PropertiesToLoad.Add("distinguishedname"); without luck.
How can I search distinguishedname in filter?
UPDATE:
If I try to use "(distinguishedname=*)" + in filter , I still get six records, so I think I can search on distinguishedname...
UPDATE2:
I also tried to use code in Search Active Directory for an OU using a partial path to the OU:
Filter = "(&(objectClass=user)(ou=Ingegneria))";
but I have zero entries (I got two if I remove (objectClass=user) part)
If you want to query just that, then you should bind to that container in your initial connect:
// Next row is used to login to AD
string ldapPath = "LDAP://OU=Ingegneria,DC=xxx,DC=xxx";
DirectoryEntry searchRoot = GetEntry(ldapPath, adminUser, adminPassword);
// Here starts the query
DirectorySearcher search = new DirectorySearcher(searchRoot)
{
SearchScope = SearchScope.Subtree,
Filter = "(&" +
"(objectClass=user)" +
"(givenname=s*)" +
"(samaccountname=*100)" +
")"
};
search.PropertiesToLoad.Add("distinguishedname");
SearchResultCollection result = search.FindAll();
That way, you also massively reduce the space in AD that needs to be searched, thus speeding up your search.
And if you're using .NET 3.5 or newer, you can use a PrincipalSearcher and a "query-by-example" principal to do your searching:
// create your domain context
PrincipalContext ctx = new PrincipalContext(ContextType.Domain, "YOURDOMAIN", "OU=Ingegneria,DC=xxx,DC=xxx");
// define a "query-by-example" principal - here, we search for a UserPrincipal
UserPrincipal qbeUser = new UserPrincipal(ctx);
qbeUser.GivenName = "s*";
qbeUser.SamAccountName = "*100";
// create your principal searcher passing in the QBE principal
PrincipalSearcher srch = new PrincipalSearcher(qbeUser);
// find all matches
foreach(var found in srch.FindAll())
{
// do whatever here - "found" is of type "Principal"
UserPrincipal userFound = found as UserPrincipal;
if(userFound != null)
{
// do something with your user principal here....
}
}
If you haven't already - absolutely read the MSDN article Managing Directory Security Principals in the .NET Framework 3.5 which shows nicely how to make the best use of the new features in System.DirectoryServices.AccountManagement

How to get a collection of strings of what Groups a user belongs to?

if (DomainHelpers.DomainExists(ConnectionString))
{
using(var baseDirectory = new DirectoryEntry(ConnectionString))
{
baseDirectory.Username = Username;
baseDirectory.Password = Password;
using (DirectorySearcher searcher = new DirectorySearcher())
{
searcher.SearchRoot = baseDirectory;
searcher.Filter = "(objectCategory=user)";
searcher.SearchScope = SearchScope.Subtree;
var userResults = searcher.FindAll();
foreach (SearchResult user in userResults)
{
var newUser = new User();
newUser.Name = user.Properties["name"][0].ToString();
newUser.Path = user.Path;
//.Groups is just a List<string>.
newUser.Groups = user.Properties?????
_users.Add(newUser);
}
}
}
}
How do I retrieve a collection of groups the user belongs to?
Thank you! :)
user.Properties["memberOf"]
don't forget to add searcher.PropertiesToLoad.Add("memberOf"); before ...searcher.FindAll()
To populate your property:
//.Groups is just a List<string>.
foreach(object group in user.Properties["memberOf"])
newUser.Groups.Add((string)group);
You should use System.DirectoryServices.AccountManagement. It's much easier. Here is a nice code project article giving you an overview on all the classes in this DLL.
It's really hard to get it right using DirectoryEntry. First of all, getting memberOf attribute doesn't give you primary group. Also, if the user has a domain local group from another domain, it won't show up in memberOf attribute. You can check here for details. Here is how the code looks like if you switch to use System.DirectoryServices.AccountManagement. The following code can find the immediate groups this user assigned to, which includes the primary group.
UserPrincipal user = UserPrincipal.FindByIdentity(new PrincipalContext (ContextType.Domain, "mydomain.com"), IdentityType.SamAccountName, "username");
foreach (GroupPrincipal group in user.GetGroups())
{
Console.Out.WriteLine(group);
}

Active Directory List OU's

I have this code currently,
string defaultNamingContext;
DirectoryEntry rootDSE = new DirectoryEntry("LDAP://RootDSE");
defaultNamingContext = rootDSE.Properties["defaultNamingContext"].Value.ToString();
rootDSE = new DirectoryEntry("LDAP://" + defaultNamingContext);
//DirectoryEntry domain = new DirectoryEntry((string)"LDAP://" + defaultNamingContext);
DirectorySearcher ouSearch = new DirectorySearcher(rootDSE,"(objectCategory=Organizational-Unit)",
null, SearchScope.Subtree);
MessageBox.Show(rootDSE.Path.ToString());
try
{
SearchResultCollection collectedResult = ouSearch.FindAll();
foreach (SearchResult temp in collectedResult)
{
comboBox1.Items.Add(temp.Properties["name"][0]);
DirectoryEntry ou = temp.GetDirectoryEntry();
}
}
When i use the debugger i can see that rootDSE.Path is infact pointing to the right place, in this case DC=g-t-p,DC=Local but the directory searcher doesn't find any results. Can anyone help?
Stephen - my bad - for some reason, the search using objectCategory doesn't work.
Even though the objectCategory is displayed as CN=Organizational-Unit, for searching, you still need to use the same value as for the objectClass:
So try to use the filter (objectCategory=organizationalUnit) - that definitely works for me!
UPDATE: in order to get some properties in your search result (in order to display them in the combo box), you need to include those when you create the DirectorySearcher:
DirectorySearcher ouSearch = new DirectorySearcher(rootDSE);
ouSearch.Filter = "(objectCategory=Organizational-Unit)";
ouSearch.SearchScope = SearchScope.Subtree;
ouSearch.PropertiesToLoad.Add("name");
// add more properties if you want to ...
With this, you should definitely be able to grab the temp.Properties["name"][0] and stick it into the combobox's list of items.
I don't really see what you need the line
DirectoryEntry ou = temp.GetDirectoryEntry();
after grabbing the name property .....

Categories

Resources