Active Directory - Get Manager account (from Distinguished Name) - c#

I am trying to get the manager's account for a user account in active directory.
Here's the code I have..
using System.DirectoryServices;
using System.DirectoryServices.ActiveDirectory;
DirectoryContext directoryContext = new DirectoryContext(DirectoryContextType.Domain, "MyDomain");
Domain domain = Domain.GetDomain(directoryContext);
// Find MY directory Entry
DirectorySearcher search = new DirectorySearcher(domain.GetDirectoryEntry())
{
Filter = String.Format("(SAMAccountName={0})", "<my user id>")
};
search.PropertiesToLoad.Add("displayName");
search.PropertiesToLoad.Add("mail");
search.PropertiesToLoad.Add("manager");
DirectoryEntry userAccount = search.FindOne()?.GetDirectoryEntry();
As you can see, there's a property called manager that is requested and comes back as
CN=Manager Name,OU=Employee,OU=United Kingdom, OU=CompantUsers, DC=MyDomain, DC=xxx,DC=zzzzz
The CN=Manager Name is the full name, not the LoginID/SAMAccountName (as used when I searched for MY AD entry ... so how can I now find the AD entry for my manager

Ahhh ... When you know the right question to ask then Google knows the answer ... I did not know that the CN..... string was known as a distinguishedName
if (userAccount.Properties["manager"].Value != null)
{
DirectorySearcher search2 = new DirectorySearcher(domain.GetDirectoryEntry())
{
Filter = string.Format("(distinguishedName={0})", userAccount.Properties["manager"].Value)
};
search2.PropertiesToLoad.Add("displayName");
search2.PropertiesToLoad.Add("mail");
search2.PropertiesToLoad.Add("manager");
DirectoryEntry mgrAcc = search2.FindOne()?.GetDirectoryEntry();
}

Related

How to get users from Active Directory in C# and display them in a ComboBox

I'm trying to show, in a ComboBox control, the users from an Active Directory on the network. To do this, I've the next function:
public static List<Usuario> MostrarUsuariosDominio()
{
List<Usuario> rst = new List<Usuario>();
try
{
DirectoryContext dc = new DirectoryContext(DirectoryContextType.Domain, Environment.UserDomainName);
Domain domain = Domain.GetDomain(dc);
DirectoryEntry de = domain.GetDirectoryEntry();
DirectorySearcher adSearcher = new DirectorySearcher(de);
adSearcher.Filter = "(&(objectClass=user)(objectCategory=person))";
adSearcher.PropertiesToLoad.Add("samaccountname");
SearchResult result;
SearchResultCollection iResult = adSearcher.FindAll();
Usuario item;
if (iResult != null)
{
for (int counter = 0; counter < iResult.Count; counter++)
{
result = iResult[counter];
if (result.Properties.Contains("samaccountname"))
{
item = new Usuario();
item.Nombre = (String)result.Properties["samaccountname"][0];
rst.Add(item);
}
}
}
adSearcher.Dispose();
}
catch (Exception ex)
{
Usuario item = new Usuario();
item.Nombre = "No se pudo recuperar la lista de usuarios";
rst.Add(item);
}
return rst;
}
If I run the application in the PC who's domain controller it works fine: the function returns to me all users. But if I run it on another PC, I get the exception:
Specified domain does not exist or couldn't contact with it
Is there any way to recover the users list from another PC?
This line:
DirectoryContext dc = new DirectoryContext(DirectoryContextType.Domain, Environment.UserDomainName);
Tells it to connect to the domain that the current user is logged into. Are you logged in as a domain user?
Maybe check what Environment.UserDomainName is equal to and see if it is right.
If it's right, then it may be a network issue - it can't talk to the domain. Do you need to be connected to VPN?
To get all the users in a Active Directory domain you can use an DirectorySearcher class object to querie to a domain about all the users availables in that domain.
The class DirectorySearcher is contained in System.DirectoryServices namespace and is a class to perform queries against Active Directory Domain Services.
In this page is an example about how to do it:
...
string DomainPath = "LDAP://DC=xxxx,DC=com"
DirectoryEntry searchRoot = new DirectoryEntry(DomainPath);
DirectorySearcher search = new DirectorySearcher(searchRoot);
search.Filter = "(&(objectClass=user)(objectCategory=person))";
search.PropertiesToLoad.Add("samaccountname");
search.PropertiesToLoad.Add("mail");
search.PropertiesToLoad.Add("usergroup");
search.PropertiesToLoad.Add("displayname");//first name
SearchResultCollection resultCol = search.FindAll();
...
In DirectorySearcher, create a DirectorySearcher object which searches
for all users in a domain. search.Filter = "(&(objectClass=user)(objectCategory=person))" filters the search.
The search filter syntax looks a bit complicated, but basically it
filters the search results to only include users -> "objectCategory=person" and "objectClass=user" - and excludes disabled
user accounts by performing a bitwise AND of the userAccountControl
flags and the "account disabled" flag.
To point to the local Active Directory domain you can use this:
DirectoryEntry searchRoot = new DirectoryEntry("WinNT://" + Environment.MachineName);
You can combine that example with this code that uses foreach instead of use the for loop in the page example:
foreach (SearchResult result in resultCol)
{
yourComboBox.Items.Add(result.Properties["displayname"]);
}
I left here some pages from the Microsoft MSDN and codeproject.com sites:
DirectorySearcher Class
Get List of Active Directory Users in C#
SearchResultCollection Class
SearchResult Class
SearchResult.Properties Property

Different results for Active Directory "memberof" on different computers

I have some code that retrieves the Active Directory groups that a user is a member of. On localhost it returns the correct results, but when deployed to a another computer (web server on same network) it returns much less results.
I am specifying AD server and a special user name and password I was given by administrators to access.
DirectoryEntry de = new DirectoryEntry("LDAP://***:389", "***", "***");
DirectorySearcher ds = new DirectorySearcher(de);
ds.Filter = "(&((&(objectCategory=Person)(objectClass=User)))(samaccountname=" + search + "))";
ds.SearchScope = SearchScope.Subtree;
ds.PropertiesToLoad.Add("*");
SearchResult rs = ds.FindOne();
if (rs != null)
{
if (rs.GetDirectoryEntry().Properties["memberof"].Value != null)
//rest of code removed
I also tried a different method and the results were also different...
using (PrincipalContext pc = new PrincipalContext(ContextType.Domain, "***, "***", "***"))
{
UserPrincipal user = UserPrincipal.FindByIdentity(pc, name);
if (user != null)
{
List<string> groups = new List<string>();
PrincipalSearchResult<Principal> groups2 = user.GetAuthorizationGroups();
//rest of code removed
I would have thought that by specifying a user name and password that the result should be the same. Any idea why this is happening?
These are different because they're retrieving different datasets. The memberOf attribute is constructed on the fly and it will give you the groups the user is a /direct/ member of. The GetAuthorizationGroups() call, on the other hand, will give you all the security groups that the user is transitively a member of. It does this by looking at the tokenGroups attribute in AD.

Connect to Active Directory via LDAP

I want to connect to our local Active Directory with C#.
I've found this good documentation.
But I really don't get how to connect via LDAP.
Can somebody of you explain how to use the asked parameters?
Sample Code:
static DirectoryEntry createDirectoryEntry()
{
// create and return new LDAP connection with desired settings
DirectoryEntry ldapConnection = new DirectoryEntry("rizzo.leeds-art.ac.uk");
ldapConnection.Path = "LDAP://OU=staffusers,DC=leeds-art,DC=ac,DC=uk";
ldapConnection.AuthenticationType = AuthenticationTypes.Secure;
return ldapConnection;
}
I just have the Hostname and the IP Address of our Active Directory Server. What does DC=xxx,DC=xx and so on mean?
DC is your domain. If you want to connect to the domain example.com than your dc's are: DC=example,DC=com
You actually don't need any hostname or ip address of your domain controller (There could be plenty of them).
Just imagine that you're connecting to the domain itself. So for connecting to the domain example.com you can simply write
DirectoryEntry directoryEntry = new DirectoryEntry("LDAP://example.com");
And you're done.
You can also specify a user and a password used to connect:
DirectoryEntry directoryEntry = new DirectoryEntry("LDAP://example.com", "username", "password");
Also be sure to always write LDAP in upper case. I had some trouble and strange exceptions until I read somewhere that I should try to write it in upper case and that solved my problems.
The directoryEntry.Path Property allows you to dive deeper into your domain. So if you want to search a user in a specific OU (Organizational Unit) you can set it there.
DirectoryEntry directoryEntry = new DirectoryEntry("LDAP://example.com");
directoryEntry.Path = "LDAP://OU=Specific Users,OU=All Users,OU=Users,DC=example,DC=com";
This would match the following AD hierarchy:
com
example
Users
All Users
Specific Users
Simply write the hierarchy from deepest to highest.
Now you can do plenty of things
For example search a user by account name and get the user's surname:
DirectoryEntry directoryEntry = new DirectoryEntry("LDAP://example.com");
DirectorySearcher searcher = new DirectorySearcher(directoryEntry) {
PageSize = int.MaxValue,
Filter = "(&(objectCategory=person)(objectClass=user)(sAMAccountName=AnAccountName))"
};
searcher.PropertiesToLoad.Add("sn");
var result = searcher.FindOne();
if (result == null) {
return; // Or whatever you need to do in this case
}
string surname;
if (result.Properties.Contains("sn")) {
surname = result.Properties["sn"][0].ToString();
}
ldapConnection is the server adres: ldap.example.com
Ldap.Connection.Path is the path inside the ADS that you like to use insert in LDAP format.
OU=Your_OU,OU=other_ou,dc=example,dc=com
You start at the deepest OU working back to the root of the AD, then add dc=X for every domain section until you have everything including the top level domain
Now i miss a parameter to authenticate, this works the same as the path for the username
CN=username,OU=users,DC=example,DC=com
Introduction to LDAP
If your email address is 'myname#mydomain.com', try changing the createDirectoryEntry() as below.
XYZ is an optional parameter if it exists in mydomain directory
static DirectoryEntry createDirectoryEntry()
{
// create and return new LDAP connection with desired settings
DirectoryEntry ldapConnection = new DirectoryEntry("myname.mydomain.com");
ldapConnection.Path = "LDAP://OU=Users, OU=XYZ,DC=mydomain,DC=com";
ldapConnection.AuthenticationType = AuthenticationTypes.Secure;
return ldapConnection;
}
This will basically check for com -> mydomain -> XYZ -> Users -> abcd
The main function looks as below:
try
{
username = "Firstname LastName"
DirectoryEntry myLdapConnection = createDirectoryEntry();
DirectorySearcher search = new DirectorySearcher(myLdapConnection);
search.Filter = "(cn=" + username + ")";
....

Find local groups that a domain user belongs to?

I'm using the System.DirectoryServices.AccountManagement namespace to find domain users and their corresponding AD security groups. This works well.
I'm also using that namespace to query the local security groups on a remote server. I am able to find a security group and then list the users of that group no problem.
What I'm having issues with is displaying which LOCAL groups a DOMAIN user belongs to:
PrincipalContext localmachine = new PrincipalContext(ContextType.Machine, "ServerName");
PrincipalContext domain = new PrincipalContext(ContextType.Domain);
// find the user using the domain context (Works fine)
UserPrincipal user = UserPrincipal.FindByIdentity(domain, userName);
// if found - grab its groups
if (user != null)
{
// The get groups method is the only method that would accept a new context
PrincipalSearchResult<Principal> groups = user.GetGroups(localMachine);
// no groups are returned .... removed rest of code
}
I'm attempting to use the GetGroups method passing in the localMachine PrincipalContext but no groups are returned.
The users exists only in the Domain AD. There is not an entry for this user in the local users on the localMachine. The domain users are added to local security groups.
Any ideas? I'd like to be able to pull a list of all local groups this domain user belongs to and then see if a certain groups exists in that list. The only option that is working now is for me to search certain groups on the system and see if the domain user belongs to that group.
The following code will return the local groups that a domain user is member of:
PrincipalContext domain = new PrincipalContext(ContextType.Domain);
UserPrincipal user = UserPrincipal.FindByIdentity(domain, userName);
foreach (GroupPrincipal group in user.GetAuthorizationGroups())
{
if (group.Context.ConnectedServer == serverName)
Console.Out.WriteLine("{0}\\{1}", group.Context.Name, group.SamAccountName);
}
I know my answer is late, but this worked for me (after I tried all sorts of permutations):
private static IList<string> GetUserLocalGroups(string userAccountName, string computerName, string domainName)
{
List<string> groups = new List<string>();
// We have to deal with a local computer
DirectoryEntry root = new DirectoryEntry(String.Format("WinNT://{0},Computer", computerName), null, null, AuthenticationTypes.Secure);
foreach (DirectoryEntry groupDirectoryEntry in root.Children)
{
if (groupDirectoryEntry.SchemaClassName != "Group")
continue;
string groupName = groupDirectoryEntry.Name;
Console.WriteLine("Checking: {0}", groupName);
if (IsUserMemberOfGroup(groupDirectoryEntry, String.Format("WinNT://{0}/{1}", domainName, userAccountName)))
{
groups.Add(groupName);
}
}
return groups;
}
private static bool IsUserMemberOfGroup(DirectoryEntry group, string userPath)
{
return (bool)group.Invoke(
"IsMember",
new object[] { userPath }
);
}
The call is something like this:
GetUserLocalGroups("samaccountname", "computerName.yourdomain", "yourdomain");

How to retrieve DirectoryEntry from a DirectoryEntry and a DN

I have a DirectoryEntry object representing a user. From the DirectoryEntry.Properties collection, I am retrieving the "manager" property, which will give me a Distinguished Name ("DN") value for the user's manager.
Can I retrieve a DirectoryEntry object for the manager from just these two objects? If so, how?
I'm envisioning something like DirectoryEntry.GetEntryFromDN(dnManager);, but I cannot find a similar call.
Just to clarify, the DirectoryEntry and DN are the only pieces of information I have. I cannot instantiate a new DirectoryEntry because then I would have have to either use the default Directory and credentials or have the Directory name/port and username/password.
DirectoryEntry User = YourPreExistingUser();
string managerDN = User.Properties["manager"][0].ToString();
// Browse up the object hierarchy using DirectoryEntry.Parent looking for the
// domain root (domainDNS) object starting from the existing user.
DirectoryEntry DomainRoot = User;
do
{
DomainRoot = DomainRoot.Parent;
}
while (DomainRoot.SchemaClassName != "domainDNS");
// Use the domain root object we found as the search root for a DirectorySearcher
// and search for the manager's distinguished name.
using (DirectorySearcher Search = new DirectorySearcher())
{
Search.SearchRoot = DomainRoot;
Search.Filter = "(&(distinguishedName=" + managerDN + "))";
SearchResult Result = Search.FindOne();
if (Result != null)
{
DirectoryEntry Manager = Result.GetDirectoryEntry();
}
}
You can create a new DirectoryEntry instance providing the the DN as argument and then
attempt to bind (by refreshing properties for example).
DirectoryEntry e = new DirectoryEntry(dn, "u", "p");
e.RefreshCache();

Categories