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
Related
I want to find all users which belongs to one department. But there are no options in the user principal for filtering the department. How can I realize that? It is already working great to find users.
When I use DisplayName where the department is written as well I get an time-out error.
private void FindFromGroupName()
{
string departement = _departement;
// Create the context for the principal object.
PrincipalContext ctx;
ctx = new PrincipalContext(ContextType.Domain);
// Create an in-memory user object to use as the query example.
UserPrincipal u = new UserPrincipal(ctx);
// Set properties on the user principal object.
u.Surname = "Doe";
//u.DisplayName = "*" + departement + "*";
// Create a PrincipalSearcher object to perform the search.
PrincipalSearcher ps = new PrincipalSearcher();
// Tell the PrincipalSearcher what to search for.
ps.QueryFilter = u;
var _results = ps.FindAll();
foreach (UserPrincipal whatever in _results)
{
Console.WriteLine(whatever.Name.ToUpper() + ": \t\t" + whatever.DisplayName + Environment.NewLine);
}
}
EDIT:
If I just filter like this:
u.DisplayName = "*" + departement + "*";
Then I get the following error:
System.Runtime.InteropServices.COMException: {"The time limit for this request was exceeded.\r\n"}
The Display Name looks Like this: John Doe (Departement/GroupName)
It probably takes to long to search through. But the I don't know how to analyse my company network. And I couldn't find an entry which holds the departement in the userPrincipal. Is there away to understand accounts better. How can I create a self created filter?
Note the DistinguishedName looks like this: CN=(1),OU=(2),OU=Useraccounts,OU=(3),DC=(4),DC=(5),DC=com
Explanation
(1):accountname
(2):First Letter of Surname
(3):City
(4):Country
(5):Company name
i want to get list of OU from Active Directory.
i have only domain name.
how can i achieve this using c#?
Try something like this:
// connect to "RootDSE" to find default naming context
DirectoryEntry rootDSE = new DirectoryEntry("LDAP://RootDSE");
string defaultContext = rootDSE.Properties["defaultNamingContext"][0].ToString();
// bind to default naming context - if you *know* where you want to bind to -
// you can just use that information right away
DirectoryEntry domainRoot = new DirectoryEntry("LDAP://" + defaultContext);
// set up directory searcher based on default naming context entry
DirectorySearcher ouSearcher = new DirectorySearcher(domainRoot);
// SearchScope: OneLevel = only immediate subordinates (top-level OUs);
// subtree = all OU's in the whole domain (can take **LONG** time!)
ouSearcher.SearchScope = SearchScope.OneLevel;
// ouSearcher.SearchScope = SearchScope.Subtree;
// define properties to load - here I just get the "OU" attribute, the name of the OU
ouSearcher.PropertiesToLoad.Add("ou");
// define filter - only select organizational units
ouSearcher.Filter = "(objectCategory=organizationalUnit)";
// do search and iterate over results
foreach (SearchResult deResult in ouSearcher.FindAll())
{
string ouName = deResult.Properties["ou"][0].ToString();
}
If you have a domain name (e.g. mycompany.com), then the LDAP root domain typically will be called dc=mycompany,dc=com - that's a convention, it doesn't have to be that way though. That's why I'm connecting to the LDAP://RootDSE virtual LDAP root and I read out the property Default Naming Context which gives me the default LDAP path.
If you know where you want to connect to - feel free to skip that first step and just provide the valid LDAP path (e.g. LDAP://dc=YourCompany,dc=co,dc=jp or whatever) to create the domainRoot directory entry.
Add a reference to System.DirectoryServices in the project
public static List<string> ListOu()
{
List<string> ous = new List<string>();
using (DirectoryEntry root = new DirectoryEntry("LDAP://dc=DOMAIN,dc=COM"))
{
DirectorySearcher searcher = new DirectorySearcher(root);
searcher.Filter = "(&(objectClass=organizationalUnit))";
searcher.SearchScope = SearchScope.Subtree;
searcher.PropertiesToLoad.Add("distinguishedName");
var result = searcher.FindAll();
foreach (SearchResult entry in result)
{
ous.Add(entry.GetDirectoryEntry().Properties["distinguishedName"].Value.ToString());
}
result.Dispose();
searcher.Dispose();
}
return ous;
}
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.
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 .....
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");
}