Get Active Directory users in Group - c#

I'm trying to get all users in "Programmers" group from AD.
If I use directory entry as LDAP://DC=Domain and filter as memberOf=CN=Programmers,CN=Users,DC=Domain, I can get user list.
But if I directly use entry as LDAP://CN=Programmers,CN=Users,DC=Domain, I can't get any result.
using (DirectoryEntry de = new DirectoryEntry(string.Format("LDAP://CN=Programmers,CN=Users,DC=Domain")))
using (DirectorySearcher ds = new DirectorySearcher(de))
{
int pageIndex = PAGESIZE * nPage + 1;
ds.SearchScope = SearchScope.Subtree;
ds.Sort = new SortOption("samaccountname", SortDirection.Ascending);
ds.VirtualListView = new DirectoryVirtualListView(0, PAGESIZE - 1, pageIndex);
var results = ds.FindAll();
}
Can anybody tell why?
The reason why I want to use this instead of "memberOf" filter, is for the performance consideration. But I'm not sure if this will actually improve the performance. So the second question is: is there any performance difference between these two methods?

It finally worked out...
The code should be:
ds.SearchScope = SearchScope.Base;
ds.AttributeScopeQuery = "member";
Then it will work.

Related

How to search a user that has a letter (or a few) in his display name

I'll try to explain myself better.
I'm using C# to build a mini-program to myself. I want to search a user within my active directory, but I want to search a user without a full display name. Let me explain myself.
For example, my display name can be: "David Holonka\Jeramy".
Is there a way to search the letters "lonka" and it'll find me all the users that has these combinations of letters within their display name?
My current code:
using (var pc = new PrinicpalContext(ContextType.Domain, "MyDomain"))
{
UserPrincipal user = new UserPrinicpal(pc);
User.DisplayName = "Holonka";
PrinicpalSearcher scrh = new PrinicpalSearcher(user);
Prinicpal found = scrh.FindOne();
}
}
Right now it doesn't find anything becasue there isn't a user that its display name is only "Holonka", but I want it to find the user that i've mentioned before
Thank you very much!
You can use query string in the PrinicpalSearcher:
UserPrincipal user = new UserPrinicpal(pc);
User.DisplayName = "*Holonka*";
PrinicpalSearcher searcher = new PrinicpalSearcher(user);
var results = searcher.FindAll();
You can also using PrincipalSearcher to find users with “or” parameters like in the example below:
List<UserPrincipal> searchPrinciples = new List<UserPrincipal>();
searchPrinciples.Add(new UserPrincipal(context) { DisplayName="*Holonka*"});
searchPrinciples.Add(new UserPrincipal(context) { SamAccountName = "*Holonka*" });
searchPrinciples.Add(new UserPrincipal(context) { MiddleName = "*Holonka*" });
searchPrinciples.Add(new UserPrincipal(context) { GivenName = "*Holonka*" });
List<Principal> results = new List<Principal>();
foreach (var item in searchPrinciples)
{
var searcher = new PrincipalSearcher(item);
// Results may contains duplicate values because of separate searchers can handle the same user
results.AddRange(searcher.FindAll());
}
You can also try using Ambiguous Name Resolution, which is a special AD query that looks for partial matches in several attributes (the list of those attributes is in that article).
You can't use PrincipalSearcher do use ANR though. You have to use DirectorySearcher (which is what PrincipalSearcher uses in the background anyway).
Here's an example:
var searchRoot = new DirectoryEntry("LDAP://domain.com");
var searcher = new DirectorySearcher(searchRoot) {
Filter = "(anr=Holonka)"
};
searcher.PropertiesToLoad.Add("displayName");
using (var results in = searcher.FindAll()) {
foreach (SearchResult result in results) {
if (result.Properties.Contains("displayName")) {
var displayName = (string) result.Properties["displayName"][0];
//do something else
}
}
}
When using DirectorySearcher, it's wise to use PropertiesToLoad. If you don't, it will return every attribute that has a value, which is likely way more data than you need. It's a waste of network traffic and time.
The using statement is also wise, since SearchResultCollection can't be completely cleaned up by the garbage collector.
I wrote some more about that in an article I wrote: Active Directory: Better Performance

C# Active Directory calls very slow

I have an application that needs to have a list of names and email addresses of users in a specific security group. I am currently doing this with the code below. When I run on VPN it comes back right away within a second or two usually but when I run on either on ethernet or wireless (both on the domain), it takes about 40 seconds for this to come back. Is there any way I can improve the time of this method on ethernet or wireless?
...
DirectoryEntry entry = new DirectoryEntry(ldap);
DirectorySearcher mySearcher = new DirectorySearcher(entry);
mySearcher.Filter = "(&(objectCategory=group)(objectClass=group)(groupType:1.2.840.113556.1.4.803:=2147483648))";
mySearcher.PropertiesToLoad.Add("member");
SearchResultCollection results = mySearcher.FindAll();
foreach (SearchResult result in results)
{
foreach (string distinguishedMember in result.Properties["member"])
{
string memberPath = "LDAP://" + distinguishedMember;
DirectoryEntry member = new DirectoryEntry(memberPath);
DirectorySearcher Searcher = new DirectorySearcher(member);
Searcher.Filter = "(&(objectCategory=user))";
Searcher.PropertiesToLoad.Add("mail");
Searcher.PropertiesToLoad.Add("name");
SearchResult memberFound = Searcher.FindOne();
if (memberFound != null)
{
String memberEmail = memberFound.Properties["mail"][0].ToString();
String memberName = memberFound.Properties["name"][0].ToString();
users.Add(new KeyValuePair<String, String>(memberName, memberEmail));
}
}
}
Maybe it would help to get all of the users in one go, instead of fetching them one by one*:
Searcher.Filter = "(&(objectCategory=user)(memberOf=" + myGroupsDistinguishedName + "))"
Searcher.PropertiesToLoad.Add("mail");
Searcher.PropertiesToLoad.Add("name");
var allMembers = Searcher.FindAll();
var users = allMembers.Cast<SearchResult>().ToDictionary(sr=>sr.Properties["name"].ToString(), sr=>sr.Properties["mail"].ToString());
*This doesn't handle scenarios with over 1000 users.
Do not fetch all members at one time. Instead, I recommend using the pagesize property of the DirectorySearcher class:
mySearcher.PageSize = 10;

Fast way to get all users + specify attribute + use paging from LDAP

I would like to get all users with their attributes from active directory
I checked many topics includes Linq to LDAP + enter link description here
But all seems to be complicated.
I started with this:
public SearchResultCollection GetAllUsrs()
{
var dirEntry = new DirectoryEntry(string.Format("LDAP://{0}/{1}", "x.y.com", "DC=x,DC=y,DC=com"));
var searcher = new DirectorySearcher(dirEntry)
searcher.Filter = "(&(&(objectClass=user)(objectClass=person)))";
searcher.PageSize = 999;
return searcher.FindAll();
}
How can i use pagging since the active directory will only return 1000 record at the time
+ how can i specify the attribute?
Problem:
I want to query a domain that contain up to 60 K users with console application
I want to specify the attribute
Performance is very important.
Can you please guide me to the best way to achieve this?
Paging is not required. AD will return more than 1000 objects. Leave PageSize at 0 and set SizeLimit as required. Use int.MaxValue ;) if you're unsure.
Here's how you can do it with LINQ to LDAP:
using (var connection = new LdapConnection("x.y.com"))
{
using (var context = new DirectoryContext(connection))
{
List<IDirectoryAttributes> users = context
.Query("DC=x,DC=y,DC=com")
.Where("(&(objectClass=user)(objectClass=person))")
.InPagesOf(1000);
}
}

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