How to retrieve all users of Active Directory? - c#

I use following code to retrieve all users of active directory but not all users retrieved. Should I include something else in Filter?
this is simplified code.
DirectoryEntry entry = new DirectoryEntry("LDAP://" + Bous.DomainName, Bous.UserName, Bous.Password);
DirectorySearcher mySearcher = new DirectorySearcher(entry);
mySearcher.Filter = ("(&(objectCategory=person)(objectClass=user))");
foreach (SearchResult result in mySearcher.FindAll())
{
dr = dt.NewRow();
ResultPropertyCollection myResultPropColl = result.Properties;
dr[0] = myResultPropColl["samaccountname"][0].ToString() + "#" + Bous.DomainName;
dt.Rows.Add(dr);
}

Try this one:
DirectoryEntry entry = new DirectoryEntry("LDAP://" + Bous.DomainName, Bous.UserName, Bous.Password);
DirectorySearcher mySearcher = new DirectorySearcher(entry);
mySearcher.PageSize = 1000; // <--- Important!
mySearcher.Filter = ("(&(objectCategory=person)(objectClass=user))");
foreach (SearchResult result in mySearcher.FindAll())
{
dr = dt.NewRow();
ResultPropertyCollection myResultPropColl = result.Properties;
dr[0] = myResultPropColl["samaccountname"][0].ToString() + "#" + Bous.DomainName;
dt.Rows.Add(dr);
}

If you're on .NET 3.5 or newer, you can use a PrincipalSearcher and a "query-by-example" principal to do your searching:
// create your domain context
using (PrincipalContext ctx = new PrincipalContext(ContextType.Domain))
{
// define a "query-by-example" principal - here, we search for UserPrincipal (users)
UserPrincipal qbeUser = new UserPrincipal(ctx);
// 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" - it could be user, group, computer.....
}
}
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. Or see the MSDN documentation on the System.DirectoryServices.AccountManagement namespace.

using System.DirectoryServices;
using System.DirectoryServices.AccountManagement;
...
protected static UserPrincipal QueryFilterUsers(string FilterFullName, string FilterDescription, string FilterLogin, string FilterPhone, string FilterEmail)
{
PrincipalContext ctx = new PrincipalContext(ContextType.Domain, _Domain);
UserPrincipal _UserPrincipal = new UserPrincipal(ctx);
_UserPrincipal.SamAccountName = "*" + ((!string.IsNullOrEmpty(FilterLogin)) ? FilterLogin.Trim() + "*" : "");
if (!string.IsNullOrEmpty(FilterFullName)) _UserPrincipal.DisplayName = "*" + FilterFullName.Trim() + "*";
if (!string.IsNullOrEmpty(FilterDescription)) _UserPrincipal.Description = "*" + FilterDescription.Trim() + "*";
if (!string.IsNullOrEmpty(FilterPhone)) _UserPrincipal.VoiceTelephoneNumber = "*" + FilterPhone.Trim() + "*" ;
if (!string.IsNullOrEmpty(FilterEmail)) _UserPrincipal.EmailAddress = "*" + FilterEmail.Trim() + "*";
return _UserPrincipal;
}
//Получение списков
public static List<Principal> GetUsersPrincipalList(string FilterFullName, string FilterDescription, string FilterLogin, string FilterPhone, string FilterEmail)
{
PrincipalSearcher _PrincipalSearcher = new PrincipalSearcher();
_PrincipalSearcher.QueryFilter = QueryFilterUsers(FilterFullName, FilterDescription, FilterLogin, FilterPhone, FilterEmail);
(_PrincipalSearcher.GetUnderlyingSearcher() as DirectorySearcher).PageSize = _PageSize;
(_PrincipalSearcher.GetUnderlyingSearcher() as DirectorySearcher).SizeLimit = _SizeLimit;
return _PrincipalSearcher.FindAll().ToList();
}

Related

Unable to get complete usergroups from active directory c#

I am trying to convert some old code to use new namespaces to get the users, groups, subgroups from active directory and insert them into DB. The new code is not returning the complete list of groups a user is associated to. Some of the groups the user is associated to is not returned by the new code.
Old Code :
DirectorySearcher searcher = new DirectorySearcher(new DirectoryEntry(directoryPath));
searcher.PageSize = 1000;
searcher.Filter = "(&(objectCategory=user))";
//adding these properties assist in assuring they are returned by Active Directory
searcher.PropertiesToLoad.Add("memberOf");
searcher.PropertiesToLoad.Add("member");
searcher.PropertiesToLoad.Add("samaccountname");
searcher.PropertiesToLoad.Add("cn");
searcher.PropertiesToLoad.Add("description");
searcher.PropertiesToLoad.Add("whencreated");
searcher.PropertiesToLoad.Add("mail");
SearchResultCollection resultUsers = searcher.FindAll();
Dictionary<string, Group> groups = new Group().GetAllGroups(); //get the list of groups that were inserted into DB
foreach (SearchResult resultUser in resultUsers)
{
DirectoryEntry userEntry = resultUser.GetDirectoryEntry();
string userName = GetProperty(userEntry, "samaccountname"); //Custom method to get samaccountname
//make sure the username exists
if (userName.Length != 0)
{
User user = new User();
//set user properties
user.FullName = user.Email = GetProperty(userEntry, "cn");
user.Email = GetProperty(userEntry, "mail");
string createdDateString = GetProperty(userEntry, "whencreated");
user.CreatedDate = (createdDateString.Length > 0) ? DateTime.Parse(createdDateString) : DateTime.MinValue;
user.UserName = userName;
user.DomainName = _dataSource.UserDomainName;
//check to see if the account is disabled
ActiveDs.IADsUser objIADsUser = (ActiveDs.IADsUser)userEntry.NativeObject;
user.Inactive = objIADsUser.AccountDisabled;
//save the user
user.SaveNew();
userEntry.RefreshCache(new string[] { "tokenGroups" });
//now the attribute will be available
int count = userEntry.Properties["tokenGroups"].Count;
IdentityReferenceCollection irc = ExpandTokenGroups(userEntry).Translate(typeof(NTAccount));
foreach (IdentityReference ir in irc)
{
NTAccount testAccount;
bool isNTAccount = false;
try
{
testAccount = (NTAccount)ir;
isNTAccount = true;
}
catch
{
}
if (isNTAccount)
{
NTAccount account = (NTAccount)ir;
string groupName = account.Value.Split('\\')[1];
if (groups.ContainsKey(groupName.ToLower()))
{
Group group = groups[groupName.ToLower()];
//add user to group
UserGroupLink userGroupLink = new UserGroupLink();
userGroupLink.GroupId = group.GroupId;
userGroupLink.UserId = user.UserID;
userGroupLink.SaveNew();
}
}
}
}
}
//close connection to active directory
searcher.Dispose();
New code:
var section = (NameValueCollection)ConfigurationManager.GetSection("DataSource_ActiveDirectory1");
string domainName = section["userDomainName"];
string domainFilter = section["domainFilter"];
PrincipalContext MyPrincipalContext = new PrincipalContext(ContextType.Domain, domainName, domainFilter); //Create your domain context
GroupPrincipal FindAllGroups = new GroupPrincipal(MyPrincipalContext); //group principal to search for all group.
UserPrincipal FindAllUsers = new UserPrincipal(MyPrincipalContext); //user principal to search for all users.
PrincipalSearcher UserSearcher = new PrincipalSearcher(FindAllUsers); //search results for user
PrincipalSearchResult<Principal> UserReults = UserSearcher.FindAll(); //find all users
PrincipalSearcher MySearcher = new PrincipalSearcher(FindAllGroups); //search results for groups
PrincipalSearchResult<Principal> GroupResults = MySearcher.FindAll(); //search all groups
ArrayList AllUsers = new ArrayList();
foreach (Principal UserReult in UserReults)
{
UserPrincipal UserName = UserPrincipal.FindByIdentity(MyPrincipalContext, IdentityType.SamAccountName, UserReult.SamAccountName);
//logic to save users to DB
}
foreach (Principal UserName in AllUsers)
{
foreach (Principal FindParentGroup in UserName.GetGroups())
{
string ParentGroupEntry = FindParentGroup.SamAccountName;
if (ParentGroupEntry != null || ParentGroupEntry.Length > 0)
{
//Insert into DB
}
}
}

AD User list from certain OU's

I am trying to print users of only certain OUs in my company AD.
So far I've come up with this:
string groupName = "Domain Users";
string domainName = "domain";
PrincipalContext ctx = new PrincipalContext(ContextType.Domain, domainName);
GroupPrincipal grp = GroupPrincipal.FindByIdentity(ctx, IdentityType.SamAccountName, groupName);
if (grp != null)
{
foreach (Principal p in grp.GetMembers(false))
{
Console.WriteLine(p.SamAccountName + " - " + p.DisplayName);
}
grp.Dispose();
ctx.Dispose();
Console.ReadLine();
}
else
{
Console.WriteLine("\nWe did not find that group in that domain, perhaps the group resides in a different domain?");
Console.ReadLine();
}
The problem is that it prints every user and not a specific OU like "Employees" or "Students".
How do I add a parameter to specify 1 or 2 OU's that it should cycle through instead of a group?
If you want to limit your search to a single OU / container, you can just bind to that using another PrincipalContext constructor:
string groupName = "Domain Users";
string domainName = "domain";
string ouName = "CN=Users,DC=yourcompany,DC=com";
// bind to the specified container you want
PrincipalContext ctx = new PrincipalContext(ContextType.Domain, domainName, ouName);
Then, of course, you're only searching in that CN=Users container - no where else.
I don't know your code exactly so this is pseudocode.
When you have some property e.g. a string to specify the type then use Where:
var groupName = "Student";
foreach (Principal p in grp.GetMembers(false).Where(princ => princ.OUName.Equals(groupName))
{
Console.WriteLine(p.SamAccountName + " - " + p.DisplayName);
}
Or is it some kind of inheritance then OfType can be used:
foreach (Principal p in grp.GetMembers(false).OfType<Student>())
{
Console.WriteLine(p.SamAccountName + " - " + p.DisplayName);
}
You are searching the entire Domain, and "Domain Users" is probably not the OU you would wan´t, change the name of the variable and add:
string domainName = "Domain Users";
string groupName = "Students";
Then add the OU to your PrincipalContext:
var ctx = new PrincipalContext(ContextType.Domain, domainName, groupName);
I use the following code in my Application.
This might be a bit overkill for you, but i think it mostly fits your needs.
public static void DoStuff(UserPrincipal princ) {
var allDomains = Forest.GetCurrentForest().Domains.Cast<Domain>();
var allSearcher = allDomains.Select(domain => {
var searcher = new DirectorySearcher(new DirectoryEntry("LDAP://" + domain.Name));
searcher.Filter = $"(&(&(objectCategory=person)(objectClass=user)(userPrincipalName=*{princ.SamAccountName}*)))";
return searcher;
});
var directoryEntriesFound =
allSearcher.SelectMany(searcher =>
searcher.FindAll()
.Cast<SearchResult>()
.Select(result => result.GetDirectoryEntry()));
var memberOf = directoryEntriesFound.Select(entry => {
using (entry) {
return new {
Name = entry.Name,
GroupName = ((object[])entry.Properties["MemberOf"].Value)
.Select(obj => obj.ToString())
};
}
}
);
var result1 = new List<string>();
foreach (var member in memberOf) {
if(member.GroupName.Contains("Student") )
Console.WriteLine(princ.SamAccountName + " is Student");
if (member.GroupName.Contains("Employee"))
Console.WriteLine(princ.SamAccountName + " is Employee");
}
}
Just call this in your foreach (Principal p in grp.GetMembers(false))

AD PrincipalSearcher: Search where property does not contain some value

Principal Searcher seems to do a great job when building a filter to find an object with a particular value. What about without? For example How do I build a filter to exclude everyone with "Joe" in their name. The code below would not work.
PrincipalContext ctx = new PrincipalContext(ContextType.Domain);
UserPrincipal qbeUser = new UserPrincipal(ctx);
PrincipalSearcher srch = new PrincipalSearcher(qbeUser);
//this is the problem line. How to format to exclude values with Joe?
qbeUser.Name != "*Joe*";
srch.QueryFilter = qbeUser;
foreach (var found in srch.FindAll())
{ do something to non Joe users... }
....
Seems it's not possible with PrincipalSearcher.
Two possible workaround:
Use PrincipalSearcher to get all users and filter at client side
PrincipalContext ctx = new PrincipalContext(ContextType.Domain);
UserPrincipal qbeUser = new UserPrincipal(ctx);
PrincipalSearcher srch = new PrincipalSearcher(qbeUser);
srch.QueryFilter = qbeUser;
foreach (var found in srch.FindAll())
{ //filter out users with "Joe" in its name }
Use DirectorySearcher
DirectoryEntry de = new DirectoryEntry("LDAP://domain.com/dc=domain,dc=com", "user", "pwd");
DirectorySearcher srch = new DirectorySearcher(de);
srch.Filter = "(&(objectCategory=person)(objectClass=user)(!(name=*Joe*)))";
srch.SearchScope = SearchScope.Subtree;
// add the attributes
srch.PropertiesToLoad.Add("distinguishedName");
using (SearchResultCollection results = srch.FindAll())
{
foreach (SearchResult result in results)
{
string dn = result.Properties["distinguishedName"][0] as string;
Console.WriteLine("- {0}", dn);
}
}

How to retrieve SAMAccountName from Active Directory

I implemented a method that returns a list of Active Directory users, I would like to retrieve SAMAccountName like this Domain\Administrator.
This is the method I use:
public Collection<software_user> GetUsersFromAD(String adConnectionString)
{
var users = new Collection<software_user>();
using (var directoryEntry = new DirectoryEntry(adConnectionString))
{
var directorySearcher = new DirectorySearcher(directoryEntry);
directorySearcher.Filter = "(&(objectClass=user))";
var propertiesToLoad = new[]
{
"SAMAccountName",
"displayName",
"givenName",
"sn",
"mail",
"userAccountControl",
"objectSid"
};
directorySearcher.PropertiesToLoad.AddRange(propertiesToLoad);
foreach (SearchResult searchEntry in directorySearcher.FindAll())
{
var userEntry = searchEntry.GetDirectoryEntry();
var ldapUser = new software_user();
ldapUser.User_name = NullHandler.GetString(userEntry.Properties["displayName"].Value);
if (string.IsNullOrEmpty(ldapUser.User_name))
continue;
ldapUser.User_name = NullHandler.GetString(userEntry.Properties["SAMAccountName"].Value);
ldapUser.email = NullHandler.GetString(userEntry.Properties["mail"].Value);
ldapUser.user_shortname = NullHandler.GetString(userEntry.Properties["givenName"].Value);
var userAccountControl = (int)userEntry.Properties["userAccountControl"].Value;
//ldapUser.IsActive = (userAccountControl & UF_ACCOUNTDISABLE) != UF_ACCOUNTDISABLE;
var sid = new SecurityIdentifier((byte[])userEntry.Properties["objectSid"][0], 0).Value;
//ldapUser.SId = sid;
users.Add(ldapUser);
}
}
return users;
}
First off: Domain\Administrator is NOT a SAM account name! The SAM account name is a unique (over the whole domain) name of up to 20 characters in length - typically it's your "Windows user name" (e.g. Administrator) - but it does NOT include the domain name. That value made up of domain\username is NOT stored in Active Directory anywhere!
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:
// set up domain context
PrincipalContext ctx = new PrincipalContext(ContextType.Domain);
// find a user
UserPrincipal user = UserPrincipal.FindByIdentity(ctx, "SomeUserName");
if(user != null)
{
// do something here....
string samAccountName = user.SamAccountName;
}
The new S.DS.AM makes it really easy to play around with users and groups in AD!
If you want to search for a whole group of users (or groups or computers), 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);
// define a "query-by-example" principal - here, we search for a UserPrincipal
// and with the last name (Surname) of "Miller"
UserPrincipal qbeUser = new UserPrincipal(ctx);
qbeUser.Surname = "Miller";
// 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" - it could be user, group, computer.....
}
You can translate a user as a Distinguished name to DOMAIN\SAMaccount form using the Object's SID, and the System.Security.Principal.SecurityIdentifier.Translate command.
public Collection<software_user> GetUsersFromAD(String adConnectionString)
{
var users = new Collection<software_user>();
using (var directoryEntry = new DirectoryEntry(adConnectionString))
{
var directorySearcher = new DirectorySearcher(directoryEntry);
directorySearcher.Filter = "(&(objectClass=user))";
var propertiesToLoad = new[]
{
"SAMAccountName",
"displayName",
"givenName",
"sn",
"mail",
"userAccountControl",
"objectSid"
};
directorySearcher.PropertiesToLoad.AddRange(propertiesToLoad);
foreach (SearchResult searchEntry in directorySearcher.FindAll())
{
var userEntry = searchEntry.GetDirectoryEntry();
var ldapUser = new software_user();
ldapUser.User_name = NullHandler.GetString(userEntry.Properties["displayName"].Value);
if (string.IsNullOrEmpty(ldapUser.User_name))
continue;
ldapUser.User_name = NullHandler.GetString(userEntry.Properties["SAMAccountName"].Value);
ldapUser.email = NullHandler.GetString(userEntry.Properties["mail"].Value);
ldapUser.user_shortname = NullHandler.GetString(userEntry.Properties["givenName"].Value);
var userAccountControl = (int)userEntry.Properties["userAccountControl"].Value;
//ldapUser.IsActive = (userAccountControl & UF_ACCOUNTDISABLE) != UF_ACCOUNTDISABLE;
SecurityIdentifier sid = new SecurityIdentifier((byte[])userEntry.Properties["objectSid"][0], 0).Value;
--> NTAccount account = (NTAccount) sid.Translate(typeof(NTAccount));
--> ldapUser.User_name = account.ToString();
//ldapUser.SId = sid;
users.Add(ldapUser);
}
}
return users;
}

Listing All Active Directory Groups

The following code lists some, but not all, Active Directory Groups. Why?
I am trying to list all security groups, distribution groups, computer groups etc. Have I specified the wrong objectClass?
private static void ListGroups()
{
DirectoryEntry objADAM = default(DirectoryEntry);
DirectoryEntry objGroupEntry = default(DirectoryEntry);
DirectorySearcher objSearchADAM = default(DirectorySearcher);
SearchResultCollection objSearchResults = default(SearchResultCollection);
SearchResult myResult=null;
objADAM = new DirectoryEntry(LDAP);
objADAM.RefreshCache();
objSearchADAM = new DirectorySearcher(objADAM);
objSearchADAM.Filter = "(&(objectClass=group))";
objSearchADAM.SearchScope = SearchScope.Subtree;
objSearchResults = objSearchADAM.FindAll();
// Enumerate groups
try
{
fileGroups.AutoFlush = true;
if (objSearchResults.Count != 0)
{
foreach (SearchResult objResult in objSearchResults)
{
myResult = objResult;
objGroupEntry = objResult.GetDirectoryEntry();
Console.WriteLine(objGroupEntry.Name);
fileGroups.WriteLine(objGroupEntry.Name.Substring(3));
}
}
else
{
throw new Exception("No groups found");
}
}
catch (PrincipalException e)
{
fileErrorLog.AutoFlush = true;
fileErrorLog.WriteLine(e.Message + " " + myResult.Path);
}
catch (Exception e)
{
throw new Exception(e.Message);
}
}
If you're on .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);
// define a "query-by-example" principal - here, we search for a GroupPrincipal
GroupPrincipal qbeGroup = new GroupPrincipal(ctx);
// create your principal searcher passing in the QBE principal
PrincipalSearcher srch = new PrincipalSearcher(qbeGroup);
// find all matches
foreach(var found in srch.FindAll())
{
// do whatever here - "found" is of type "Principal" - it could be user, group, computer.....
}
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
Try filter "(objectcategory=group)"
Found solution here
DirectoryEntry entry = new DirectoryEntry("ldap://ldap.gaurangjadia.com", "scott", "tiger");
DirectorySearcher dSearch = new DirectorySearcher(entry);
dSearch.Filter = "(&(objectClass=group))";
dSearch.SearchScope = SearchScope.Subtree;
SearchResultCollection results = dSearch.FindAll();
for (int i = 0; i < results.Count; i++) {
DirectoryEntry de = results[i].GetDirectoryEntry();
//TODO with "de"
}
I tried this and it worked
public ArrayList GetAllGroupNames(string ipAddress, string ouPath)
{
DirectorySearcher deSearch = new DirectorySearcher();
deSearch.SearchRoot = GetRootDirectoryEntry(ipAddress, ouPath);
deSearch.Filter = "(&(objectClass=group))";
SearchResultCollection results = deSearch.FindAll();
if (results.Count > 0)
{
ArrayList groupNames = new ArrayList();
foreach (SearchResult group in results)
{
var entry = new DirectoryEntry(group.Path, UserName, Password);
string shortName = entry.Name.Substring(3, entry.Name.Length - 3);
groupNames.Add(shortName);
}
return groupNames;
}
else
{
return new ArrayList();
}
}
private DirectoryEntry GetRootDirectoryEntry(string ipAddress, string domainPath, string username, string password)
{
var ldapPath = "LDAP://" + ipAddress + "/" + domainPath;
return new DirectoryEntry(ldapPath, username, password, AuthenticationTypes.Secure);
}
To retrieve a set of results that is larger than 1000 items, you must set SizeLimit to its default value (zero) and set PageSize to a value that is less than or equal to 1000.
objSearchADAM.PageSize = 1000;
you can get the all ad group details by the below powershell and if you want particular Name against of AD Group then write filter instead of *
Get-ADGroup -Filter * -properties * | Export-csv c:\csv\new.csv

Categories