I'm trying to read all members of ever AD Group. I get the groups with following code
PrincipalContext yourOU = new PrincipalContext(ContextType.Domain, "test.domain.CH", "OU=Verteiler,OU=Gruppen,OU=SGV,OU=Gruppe_04,OU=Kunden,DC=test,DC=domain,DC=CH");
GroupPrincipal findAllGroups = new GroupPrincipal(yourOU, "*");
PrincipalSearcher ps = new PrincipalSearcher(findAllGroups);
foreach (var group in ps.FindAll())
{
Console.WriteLine(group.DisplayName);
}
Now I'm trying to show every user from every group.
How can I handle this?
I tried it by myself, please call the following Code in your foreach and send your Groupname with
static async void populateGroups(string ADGroupName)
{
// set up domain context
PrincipalContext ctx = new PrincipalContext(ContextType.Domain);
// find the group in question
GroupPrincipal group = GroupPrincipal.FindByIdentity(ctx, ADGroupName);
// if found....
if (group != null)
{
// iterate over members
foreach (Principal p in group.GetMembers())
{
// Console.WriteLine("{0}: {1}", p.StructuralObjectClass, p.DisplayName);
// do whatever you need to do to those members
UserPrincipal theUser = p as UserPrincipal;
if (theUser != null)
{
if (theUser.IsAccountLockedOut())
{
Console.WriteLine("The user: {0} is member of following Group {1}", theUser, ADGroupName);
}
else
{
Console.WriteLine("The user: {0} is member of following Group {1}", theUser, ADGroupName);
}
}
}
}
}
Related
I am currently writing some code that searches the Active Directory via some LDAP queries. I have come to a situation where I have an object of type Principal, this is either GroupPrincipal or UserPrincipal. However, if it is a GroupPrincipal it might contain objects of type UserPrincipal. I would like extract all items of type UserPrincipal to a list so that I can perform some other procedures on them.
I imagine that can be done using trees but am not sure how.
Here is a code I wrote that is ineffective, only goes two nodes deep and prints the names rather than adding them to a list:
foreach (var principal in group.GetMembers())
{
if (principal is UserPrincipal)
{
var uPrincipal = principal as UserPrincipal;
Console.WriteLine("User: " + uPrincipal.Name);
}
else if (principal is GroupPrincipal)
{
var gPrincipal = principal as GroupPrincipal;
Console.WriteLine("Group: " + gPrincipal.Name);
foreach(var principalito in gPrincipal.GetMembers())
{
if (principalito is UserPrincipal)
{
var uPrincipalito = principalito as UserPrincipal;
Console.WriteLine(">>User: " + uPrincipalito.Name);
}
else if(principalito is GroupPrincipal)
{
var gPrincipalito = principalito as GroupPrincipal;
Console.WriteLine(">>Group: " + gPrincipalito.Name);
}
}
}
}
Try this:
public void getAllUserPrinicpals(ref List<UserPrincipal> principals, GroupPrincipal principal)
{
if (principal != null)
{
foreach (Principal princ in principal.GetMembers(true))
{
if (princ is UserPrincipal)
principals.Add((UserPrincipal)princ);
else if (princ is GroupPrincipal)
getAllUserPrinicpals(ref principals, (GroupPrincipal)princ);
}
}
}
I have this little problem.
I want to get all the users that has the same manager.
Currently, I have code that can do this, but the problem is that it gets ALL the users. I then loop through all the users, and match the manager.
The problem with this is that this will take a bit too long when there is, let's say, 100 000 users.
My current code:
UserPrincipal managerP = UserPrincipal.FindByIdentity(GetPrincipalContext(), IdentityType.SamAccountName, sAMManager);
if (managerP != null)
{
using (UserPrincipal user = new UserPrincipal(GetPrincipalContext()))
{
using (PrincipalSearcher search = new PrincipalSearcher(user))
{
search.QueryFilter = user;
foreach (UserPrincipal userP in search.FindAll())
{
if (managerP.SamAccountName.ToLower() == sAMManager.ToLower())
{
//Add 'userP' to list.
}
}
}
}
}
How can I change this, so that I can get all the users belonging to a manager, instead of getting them all first?
You can do this with a simple LDAP query:
using (DirectorySearcher searcher = new DirectorySearcher(new DirectoryEntry("LDAP://contoso.com")))
{
searcher.Filter = "(&(objectCategory=person)(objectClass=user)(manager=CN=John Doe,CN=Users,DC=contoso,DC=com))";
searcher.PropertiesToLoad.AddRange(new string[] { "givenName", "sn", "sAMAccountName" });
foreach (SearchResult item in searcher.FindAll())
{
Console.WriteLine(String.Format("User {0} {1} ({2}) works for John Doe", item.Properties["givenName"].ToString(), item.Properties["sn"].ToString(), item.Properties["sAMAccountName"].ToString()));
}
}
I am pretty new to using C# and this is my second time using it with active directory. I keep getting the error: Object reference not set to an instance of an object. Below is my code. I know that my null reference is in the line var result = searcher.FindOne(); I am unsure of what I need to do to fix this.
static void Main(string[] args)
{
List<string> userList = new List<string>();
try
{
string[] newUsers = { List of users is here ex: jsmith#xyz.com, bsmith#xyz.com, ... };
PrincipalContext AD = new PrincipalContext(ContextType.Domain, "xyz.com");
UserPrincipal u = new UserPrincipal(AD);
PrincipalSearcher search = new PrincipalSearcher(u);
DirectorySearcher searcher = new DirectorySearcher();
foreach (string x in newUsers)
{
searcher.Filter = string.Format("(&(objectCategory=person)(anr={0}))", x);
var result = searcher.FindOne();
userList.Add(string.Format("{0} {1}", result.Properties["DisplayName"][0].ToString(), result.Properties["Company"][0].ToString()));
search.Dispose();
}
foreach(string y in userList)
{
Console.WriteLine(y);
}
Console.ReadLine();
}
catch (Exception e)
{
Console.WriteLine("Error: " + e.Message);
}
File.WriteAllLines(file location, userList);
}
Your problem is that you're declaring PrincipalSearcher and DirectorySearcher, yet you're only populating the PrincipalSearcher with UserPrincipal object.
...
UserPrincipal u = new UserPrincipal(AD);
PrincipalSearcher search = new PrincipalSearcher(u);
...
However, your DirectorySearcher object searcher is empty.
DirectorySearcher searcher = new DirectorySearcher();
In foreach loop you're searching for one user using DirectorySearcher object not PrincipalSearcher:
var result = searcher.FindOne();
The above line will always return null. You need to populate DirectorySearcher.
DirectorySearcher searcher = new DirectorySearcher(/*need a DirectoryEntry*/);
I would suggest you take full advantage of UserPrincipal class. It seems that you want to search for users in Active Directory and you know their UserPrincipal names.
using (PrincipalContext ctx = new PrincipalContext(ContextType.Domain, "yourdomain.com"))
{
string [] newUsers; //need to declare list of new users
foreach (string user in newUsers)
{
using (UserPrincipal newUser = UserPrincipal.FindByIdentity(ctx, IdentityType.UserPrincipalName, user))
{
if (newUser != null)
{
//do what you need to do
//newUser will contain all info on a particular user
}
}
}
}
As several commenters have noted, your code is not handling the situation where no user is found by DirectorySearcher.FindOne - and, as noted in the MSDN documentation, FindOne returns null if no user is found:
If more than one entry is found during the search, only the first entry is returned. If no entries are found to match the search criteria, a null reference (Nothing in Visual Basic) is returned.
So you'll need to handle the case where the user you're looking for isn't there:
foreach (string x in newUsers)
{
Console.WriteLine("looking for user {0}", x);
searcher.Filter = string.Format("(&(objectCategory=person)(anr={0}))", x);
var result = searcher.FindOne();
if (result == null)
{
userList.Add(String.Format("user {0} not found!", x));
}
else
{
userList.Add(string.Format("{0} {1}", result.Properties["DisplayName"][0].ToString(), result.Properties["Company"][0].ToString()));
}
search.Dispose();
}
My C# application communicates with the active directory and is able to provide me when i select a user i can see the groups he is a member of and if i select the group i am able to see the users in the group. Now the new requirement i want to see the computers each user is associated with.
private void FillComputers()
{
computers.Items.Clear();
PrincipalContext PrincipalContext1 = new PrincipalContext(ContextType.Domain);
ComputerPrincipal cp = new ComputerPrincipal(PrincipalContext1);
PrincipalSearcher search = new PrincipalSearcher(cp);
foreach (var cpn in search.FindAll())
{
computers.Items.Add(cpn.SamAccountName);
}
}
Gives me all the computers how do i pass the selected user as a parameter to the FillComputers above??? Thanks in Advance for all your suggestions.
For example when i have users and i had to find out the groups they were memebers of i did this
The below fills the listbox with all users:
private void filluser()
{
// create your domain context
PrincipalContext ctx = new PrincipalContext(ContextType.Domain);
// define a "query-by-example" principal - here, we search for any UserPrincipal
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())
{
try
{
// do whatever here
UserPrincipal foundUser = found as UserPrincipal;
if (foundUser != null)
{
foundUser.IsAccountLockedOut();
user.Items.Add(foundUser.GivenName + " " + foundUser.Surname + " " + "[" + foundUser.SamAccountName + "]");
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
}
To Fill another list box with the groups the users were members of I did this
private void fillmembersof()
{
Groups.Items.Clear();
PrincipalContext ctx = new PrincipalContext(ContextType.Domain);
String input = user.Text;
string username = input.Split(new char[] { '[', ']' })[1];
// define a "query-by-example" principal - here, we search for any UserPrincipal
UserPrincipal usr = UserPrincipal.FindByIdentity(ctx, IdentityType.SamAccountName, username);
if (usr != null)
{
foreach (var group in usr.GetGroups())
{
Groups.Items.Add(group.Name);
}
usr.Dispose();
}
ctx.Dispose();
}
Than to fill the above text box based on users selected i did this:
private void user_SelectedIndexChanged(Object sender, EventArgs e)
{
fillmembersof();
**FillComputers();** -> i want to be able to do the same for computers the user has access to?????
Thanks you in advance for all your valuable suggestions!!!!
I'm trying to get all users of a particular group in AD, then return a list of Employees as mapped to properties in my Employee class. I have:
My Filter is producing no results - what should it be?
Also, I tried the first solution here:
List of users in specific Active Directory Distribution Group, but I need details such as mobile, extension, etc. which I couldn't get with that method.
public static List<Employee> CreateEmployeeList(string department)
{
List<Employee> employees = new List<Employee>();
string filter = string.Format("(&(ObjectClass=person)(memberOf=CN={0},OU=Users & Groups,OU=Blah,DC=Blah,DC=Blah,DC=Blah))", department);
DirectoryEntry adRoot = new DirectoryEntry("LDAP://" + domain, null, null, AuthenticationTypes.Secure);
DirectorySearcher searcher = new DirectorySearcher(adRoot);
searcher.SearchScope = SearchScope.Subtree;
searcher.ReferralChasing = ReferralChasingOption.All;
searcher.Filter = filter;
SearchResultCollection results = searcher.FindAll();
foreach (SearchResult user in results)
{
// do whatever you need to do with the entry
if (user != null)
{
UserDirectoryEntry = user.GetDirectoryEntry();
string displayName = GetUserProperty("displayName");
string firstName = GetUserProperty("givenName");
string lastName = GetUserProperty("sn");
string email = GetUserProperty("mail");
string tel = GetUserProperty("telephonenumber");
string extension = GetUserProperty("ipphone");
string mobile = GetUserProperty("mobile");
string title = GetUserProperty("description");
employees.Add(new Employee{ FullName = displayName, FirstName = firstName, Surname = lastName, Email = email.ToLower(), Telephone = tel, Extension = extension, Mobile = mobile, JobTitle = title });
}
}
return employees;
}
using (var context = new PrincipalContext(ContextType.Domain, "domainName"))
{
using (var group = GroupPrincipal.FindByIdentity(context, "groupName"))
{
if (group == null)
{
MessageBox.Show("Group does not exist");
}
else
{
var users = group.GetMembers(true);
foreach (UserPrincipal user in users)
{
//user variable has the details about the user
}
}
}
}
This should return all Active Directory Users in a group.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.DirectoryServices;
namespace ADQuery
{
class Program
{
static void Main(string[] args)
{
GetListOfAdUsersByGroup("domain", "group");
Console.ReadLine();
}
public static void GetListOfAdUsersByGroup(string domainName, string groupName)
{
DirectoryEntry entry = new DirectoryEntry("LDAP://DC=" + domainName + ",DC=com");
DirectorySearcher search = new DirectorySearcher(entry);
string query = "(&(objectCategory=person)(objectClass=user)(memberOf=*))";
search.Filter = query;
search.PropertiesToLoad.Add("memberOf");
search.PropertiesToLoad.Add("name");
System.DirectoryServices.SearchResultCollection mySearchResultColl = search.FindAll();
Console.WriteLine("Members of the {0} Group in the {1} Domain", groupName, domainName);
foreach (SearchResult result in mySearchResultColl)
{
foreach (string prop in result.Properties["memberOf"])
{
if (prop.Contains(groupName))
{
Console.WriteLine(" " + result.Properties["name"][0].ToString());
}
}
}
}
}
}
Good Luck!
The following code will search through nested domain local groups and/or global groups recursively to find users. You can modify this to look through any order of groups to suit what you need or to return any kind of group that you want.
// Set the list to return and get the group we are looking through.
List<UserPrincipal> list = new List<UserPrincipal>();
GroupPrincipal group = GroupPrincipal.FindByIdentity(new PrincipalContext(/* connection info here */), ((groupName.Length > 0) ? groupName : this.Properties.Name));
// For each member of the group add all Users.
foreach (Principal princ in group.Members)
{
/*
To change what you are looking for or how you are looking for it,
simply change some of the following conditions to match what you want.
*/
// If this member is a User then add them.
if (princ.StructuralObjectClass == "user")
{
list.Add(UserPrincipal.FindByIdentity(new PrincipalContext(/* connection info here */), princ.Name);
}
// If we are looking recursively and this member is a GL_Group then get the Users in it and add them.
if (recursive && (princ.StructuralObjectClass == "group") && (((GroupPrincipal)princ).GroupScope == GroupScope.Global))
{
list.AddRange(this.GetUsers(true, princ.Name));
}
}
return list;
Building on the example by Dalton, here's concise code to get group's usernames:
static SortedSet<string> GetUsernames(string domainName, string groupName) {
using (var pc = new PrincipalContext(ContextType.Domain, domainName))
using (var gp = GroupPrincipal.FindByIdentity(pc, groupName))
return gp == null ? null : new SortedSet<string>(
gp.GetMembers(true).Select(u => u.SamAccountName));
}
In this post I wrote something working in an ActiveDirectory 2003 ans 2008 R2. I use Microsoft LDAP_MATCHING_RULE_IN_CHAIN. This service use DirectoryServices. Be careful in this code as there is a double search.
But you can also do it using Managing Directory Security Principals in the .NET Framework 3.5. You can read this other post. You have to get a GroupPrincipal and you are looking for Members property. It also exists other entries in StackOverflow.