I am admittedly very new to AD. I have a dropdown list that I have bound with a list of members within our organization. My end goal is to find their manager name, but I'm starting with baby steps.
I've done enough searching to get the right result. I'm having a problem getting the right data (verified by using breakpoints etc) out of the result
private void cmbUserList_SelectedIndexChanged(object sender, EventArgs e)
{
var userName = cmbUserList.SelectedValue.ToString();
DirectorySearcher search = new DirectorySearcher();
search.Filter = String.Format("(cn={0})", userName);
search.PropertiesToLoad.Add("givenName");
SearchResult result = search.FindOne();
if (result != null)
{
// For now I'm trying to just retrieve their name
lblManagerName.Text = result.GetDirectoryEntry().Name;
}
}
EDIT: I'm using .net version 4.0
Could someone point me towards retrieving the correct name, and then maybe even a link or resources to pull the manager name?
I think the problem with your code is you are using "(cn={0})", userName. You need to pass fully qualified name like
CN=Doe,John,OU=Users,OU=Headquarters,DC=company,DC=net
If you only have login ID, then the code below should work
DirectorySearcher directorySearcher = new DirectorySearcher("LDAP://RootDSE");
directorySearcher.Filter = "sAMAccountName=" + acctName;
directorySearcher.PropertiesToLoad.Add("manager");
SearchResult searchResult = directorySearcher.FindOne();
if (searchResult != null)
DirectoryEntry user = searchResult.GetDirectoryEntry();
Note that acctName is Windows login ID. If you want to play with AD and check out vearious properties and how they are stored, try dsquery and dsget command line tools. The command below will return a user record based on login id and will display contents of the manager field:
dsquery user domainroot -samid "loginid" | dsget user -samid -mgr
helper class and enum
public enum ActiveDirectoryObjectClass
{
Computer,
User,
Domain,
Group,
}
public static class ActiveDirectorySearcher
{
public static string GetCurrentDomainName()
{
string result;
using (Domain domain = Domain.GetCurrentDomain())
{
result = domain.Name;
}
return result;
}
public static IEnumerable<T> Select<T>(
ActiveDirectoryObjectClass activeDirectoryObjectClass,
Func<DirectoryEntry, ActiveDirectoryObjectClass, bool> condition,
Func<DirectoryEntry, T> selector
)
{
List<T> list = new List<T>();
using (Domain domain = Domain.GetCurrentDomain())
using (DirectoryEntry root = domain.GetDirectoryEntry())
{
string filter = string.Format("(objectClass={0})", activeDirectoryObjectClass);
using (DirectorySearcher searcher = new DirectorySearcher(filter))
{
searcher.SearchRoot = root;
searcher.SearchScope = SearchScope.Subtree;
using (SearchResultCollection result = searcher.FindAll())
{
foreach (SearchResult item in result)
{
using (DirectoryEntry entry = item.GetDirectoryEntry())
{
if (condition(entry, activeDirectoryObjectClass))
{
list.Add(selector(entry));
}
}
}
}
}
}
return list;
}
}
how to use
public IEnumerable<User> GetUsers()
{
return ActiveDirectorySearcher.Select(
ActiveDirectoryObjectClass.User,
(entry, adObjectClass) => string.Compare(entry.SchemaClassName, adObjectClass.ToString(), StringComparison.InvariantCultureIgnoreCase) == 0,
_ => new User
{
Name = _.Name.Substring(3),
Domain = ActiveDirectorySearcher.GetCurrentDomainName(),
});
}
Note: User in sample - custom class with properties Name, Domain, etc.
to find name and/or manager name:
if (sResult != null)
{
string userName = sResult.Properties["name"][0].ToString();
string managerDN = sResult.Properties["manager"][0].ToString();
DirectoryEntry man = new DirectoryEntry("LDAP://server_name/"+managerDN);
string managerName = man.Properties["name"][0].ToString();
}
server_name can be just domain component of FQDN i.e yourcompany.com, that way it will find catalog server on its own via DNS.
Edit:
I also recomend Active Directory Explorer from Sysinternals. It is great tool for exploring and understanding structure of AD
Related
I have a problem in my SearchResult querying Active Directory. Here is what I try to do: I can search users from Active Directory and then show their name in a link form. This works. Then when you click on link it has to show all the information on the user. I uses lists to pass the query results, and when I search a name in Active Directory I have a full list of results, but when try to show the information of a specific user, my list is always null and I can't figure out why.
Here is my search result page with the links:
#{
var incLoop = 0;
var incArr = 0;
var list = (List<string>)ViewData["Names"];
var size = list.Count();
string[] objSID = new string[size];
foreach (var link in list)
{
if (incLoop % 2 == 0)
{
objSID[incArr] = link;
incArr++;
<p>#incArr</p>
}
else
{
#link
}
incLoop++;
}
}
When you click the link, it then does a research of AD using sAMAccountName parameter, here is the controller :
public ActionResult ShowUserInfo(string name)
{
ADManager adManager = new ADManager();
List<string> info = adManager.UserInformation(name);
if (info != null)
{
ViewData["UserInfo"] = info;
return View();
}
else
return View("SearchUser");
}
And finally here is my function that searches in AD from the ADManager class
public List<string> UserInformation(string SAMAccountName)
{
try
{
DirectoryEntry ldapConnection = createDirectoryEntry();
DirectorySearcher search = new DirectorySearcher(ldapConnection);
search.Filter = "(sAMAccountName="+ SAMAccountName + ")";
search.PropertiesToLoad.Add("displayName");
search.PropertiesToLoad.Add("userPrincipalName");
search.PropertiesToLoad.Add("description");
search.PropertiesToLoad.Add("accountExpires");
search.PropertiesToLoad.Add("memberOf");
search.PropertiesToLoad.Add("profilePath");
search.PropertiesToLoad.Add("objectSID");
search.PropertiesToLoad.Add("anr");
resultCollection = search.FindAll();
//result = search.FindOne();
foreach (SearchResult sr in resultCollection)
{
lastName.Add(sr.Properties["anr"][0].ToString());
lastName.Add(sr.Properties["displayName"][0].ToString());
lastName.Add(sr.Properties["userPrincipalName"][0].ToString());
lastName.Add(sr.Properties["description"][0].ToString());
lastName.Add(sr.Properties["accountExpires"][0].ToString());
lastName.Add(sr.Properties["memberOf"][0].ToString());
lastName.Add(sr.Properties["profilePath"][0].ToString());
lastName.Add(sr.Properties["objectSID"][0].ToString());
}
return lastName;
}
catch(Exception e)
{
Console.WriteLine("Exception caught:\n\n" + e.ToString());
}
return null;
}
}
createDirectoryEntry() allows to create the connection to AD, and ADManager class contains all the access functions to AD. Normally I should be able to use a simple SearchResult.FindOne() for this query since sAMAccountName is unique but it didn't work so I tried with collections (since this works for searching all users using anr parameter from AD).
EDIT: I forgot to say that I have an exception: System.ArgumentException in System.DirectoryServices.dll when I click on user links. So probably the problem comes from ADManager search query.
Thanks for your help, if unclear I can add precision.
I am trying to get detailed information about a user's group membership using directory services queries to the global catalog. I don't want to use GetAuthorizationGroups() because it's flaky.
There are 2 domains: DomainA and DomainB. The global catalog server is a domain controller for DomainB. Finally, there is a user (UserA) which is part of DomainA.
I find UserA in the global catalog and look at the tokenGroups property to get the SIDs of all groups to which UserA belongs.
To my great surprise, I find that DomainB\Domain Users is included in the list. Why is this being included, given that UserA is not part of DomainB?
Here is the code I'm running:
using (DirectoryEntry gc = new DirectoryEntry("GC:"))
{
string userPrincipalName = "UserA#DomainA.local";
DirectoryEntry searchRoot = null;
gc.AuthenticationType = System.DirectoryServices.AuthenticationTypes.Secure;
// There is only 1 child under "GC:".
foreach (DirectoryEntry de in gc.Children)
{
searchRoot = de;
break;
}
using (searchRoot)
{
SearchResult samResult;
using (var samSearcher = new DirectorySearcher())
{
// Find the user.
samSearcher.SearchRoot = searchRoot;
samSearcher.Filter = "(userPrincipalName=" + userPrincipalName + ")";
samSearcher.PropertiesToLoad.Add("distinguishedName");
samResult = samSearcher.FindOne();
}
List<byte[]> tokenGroups;
using (DirectoryEntry theUser = samResult.GetDirectoryEntry())
{
theUser.RefreshCache(new string[] { "tokenGroups" });
tokenGroups = theUser.Properties["tokenGroups"].Cast<byte[]>().ToList();
IdentityReferenceCollection irc = new IdentityReferenceCollection(tokenGroups.Count);
foreach (byte[] groupSidBytes in tokenGroups)
{
irc.Add(new SecurityIdentifier(groupSidBytes, 0));
}
List<string> groupNames =
irc.Translate(typeof(NTAccount), true)
.Cast<NTAccount>()
.Select(a => a.Value.ToString())
.ToList();
return groupNames;
}
}
}
I want to login in a only specific OU, but not in previous OU.
My parent function is:
if (Autentificado("LDAP://localhost/DC=ic,DC=enterprise,DC=us", user, pass, "cn=SpecificPeople,ou=Users,ou=Aplications,dc=ic,dc=enterprise,dc=us") != "")
{
return "OK";
}
It contains server direction with path, user, pass and a string for the "memberof" filter:
public static string Autentificado(string ldap, string usr, string pwd,string member)
{
try
{
DirectoryEntry entry = new DirectoryEntry(ldap, usr, pwd);
DirectorySearcher search = new DirectorySearcher(entry)
{
Filter = "(&(objectCategory=person)(memberof=" + member + "))"
};
search.PropertiesToLoad.Add("sn");
SearchResult result = search.FindOne();
return result.Properties["sn"][0].ToString();
}
catch (DirectoryServicesCOMException cex)
{
Console.WriteLine(cex);
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
return "";
}
It return the correct user of "OU=Users", but it return users of others OU or DC. I want that people only can login in the "OU=Users".
Thanks in advance.
UPDATE 1:
I think that the problem is with the structure of my LDAP and the filter of the DirectorySearcher:
DC=US
-DC=enterprise
-DC=ic
-OU=Apps
-OU=1
-OU=2
-OU=USERS
If i use: SearchScope.Subtree, it search in all directories.SearchScope.OneLevel, it search in the DC=enterprise or in all OU=Apps (if i'm not mistaken).SearchScope.Base, it search in the DC=US.
I want that the search will be only in the OU=USERS, and not in the others Directories (OU=1, OU=2).
UPDATE 2
My GETUSER funtion is:
DirectoryEntry usercheck = GetUser(user, pass,"LDAP://someIP:389/CN=qualifiers,OU=USERS,OU=Aplications,DC=ic,DC=enterprise,DC=us");
And in the "DirectoryEntry searchRoot", i need to set an user and password for enter in the LDAP. If not, it take me error:
using (DirectoryEntry searchRoot = new DirectoryEntry(rootWeAreLooking,"ic\\"+userName,pass, AuthenticationTypes.None))
I see that this could be work, but it search in all directories of OU=Aplications yet.
I think that i need to filter by CN=qualifiers, but i don't know how.
Update 3
I need to try properly, but i think that i do the correct filter:
searcher.Filter = String.Format("(&(objectCategory=person)(memberof=CN=qualifiers,OU=USERS,OU=Aplications,DC=ic,DC=enterprise,DC=us)(sAMAccountName={0}))", userName);
So I just created this code which does the thing you want. I splitted the code into multiple methods, so you can use some singe functions like ValidateUser else where.
Find the user in the AD and the ou (root) you are searching in and make shure he exits
Now that we know that he is allowed to "LOGIN" we are validating his password against AD.
If all went fine, the user is in the OU=USER (in your case) and also the password is correct
private void TestTheMethods()
{
//Search for the user, in the ou "user"
DirectoryEntry user = GetUser("FirstName LastName","FullOrganisationUnitPath");
//Found user?
if (user == null) { return; }
//ValidateUser
if (!ValidateUser(user, "userPassword")) { return; }
}
public DirectoryEntry GetUser(string userName, string rootWeAreLooking = "")
{
DirectoryEntry user = null;
using(DirectoryEntry searchRoot = new DirectoryEntry(rootWeAreLooking))
using(DirectorySearcher searcher = new DirectorySearcher(searchRoot))
{
searcher.Filter = String.Format("(&(objectCategory=person)(cn={0}))",userName);
//searcher.SearchScope = SearchScope.Subtree;
//SearchScope.Subtree --> Search in all nested OUs
//SearchScope.OneLevel --> Search in the Ou underneath
//SearchScope.Base --> Search in the current OU
search.SearchScope = SearchScope.OneLevel;
SearchResult result = searcher.FindOne();
if (result == null) { return null; }
//Found user
return result.GetDirectoryEntry();
}
}
public Boolean ValidateUser(DirectoryEntry entry, string pwd)
{
Boolean isValid = false;
try
{
DirectoryEntry validatedUser = new DirectoryEntry(entry.Path, entry.Name.Remove(0,3), pwd);
//Check if we can access the Schema
var Name = validatedEntry.SchemaEntry;
//User exits, username is correct and password is accepted
isValid = true;
}
catch(DirectoryServicesCOMException ex)
{
isValid = false;
///User wrong? wrong password?
}
return isValid;
}
Finally, I do this filter and works for me:
searcher.Filter = String.Format("(&(objectCategory=person)(memberof=CN=qualifiers,OU=USERS,OU=Aplications,DC=ic,DC=enterprise,DC=us)(sAMAccountName={0}))", userName);
And in my LDAP path, i put the root path directory
DC=ic,DC=enterprise,DC=us
I want to check, if a a user is in a specific parent OU.
How can I do that?
Check below code for a clear desciption of what I am looking for.
using System.DirectoryServices.AccountManagement;
public bool IsUserInOU(string samAccountName, string OUName){
using (var context = new PrincipalContext(ContextType.Domain))
{
using (var user = UserPrincipal.FindByIdentity(context, IdentityType.SamAccountName, samAccountName))
{
//Check if the user is in the OU specified in OUName
//Something like:
//return user.IsInOU(OUName);
}
}
}
public void TestIt_1(){
//The parent OU of this user is "AwesomeOU"
string samAccountName = "Joe";
string OUName = "AwesomeOU";
bool expected = true;
bool actual = IsUserInOU(samAccountName, OUName);
Assert.AreEqual(expected, actual);
}
public void TestIt_2(){
//The parent OU of this user is "WhateverOU"
string samAccountName = "Mike";
string OUName = "AwesomeOU";
bool expected = false;
bool actual = IsUserInOU(samAccountName, OUName);
Assert.AreEqual(expected, actual);
}
The Domain:
National OU
Awesome OU
Joe
Whatever OU
Mike
Solution 1 after empi's answer
With the information given by empi, I wrote the below method to extract the first OU in the DistinguishedName. Having done that, the rest is a breeze.
public static string GetOUForUser(string samAccountName)
{
using (var context = new PrincipalContext(ContextType.Domain))
{
using (var user = UserPrincipal.FindByIdentity(context, IdentityType.SamAccountName, samAccountName))
{
//System.Console.WriteLine(user.DistinguishedName);
int startIndex = user.DistinguishedName.IndexOf("OU=", 1) + 3; //+3 for length of "OU="
int endIndex = user.DistinguishedName.IndexOf(",", startIndex);
var group = user.DistinguishedName.Substring((startIndex), (endIndex - startIndex));
return group;
}
}
}
Solution 2 after JPBlanc's answer
public static string GetOUForUser(string samAccountName)
{
using (var context = new PrincipalContext(ContextType.Domain))
{
using (var user = UserPrincipal.FindByIdentity(context, IdentityType.SamAccountName, samAccountName))
{
using (DirectoryEntry deUser = user.GetUnderlyingObject() as DirectoryEntry)
{
using (DirectoryEntry deUserContainer = deUser.Parent)
{
return deUserContainer.Properties["Name"].Value.ToString();
}
}
}
}
}
Ok #Empi solution is working, but UserPrincipal is built on DirectoryEntry objects that provides a parent or container properties that just give you the object you are looking for, without using string way.
/* Retreiving a principal context
*/
PrincipalContext domainContext = new PrincipalContext(ContextType.Domain, "WM2008R2ENT:389", "dc=dom,dc=fr", "dom\\jpb", "MyPwd");
/* Retreive a user
*/
UserPrincipal user = UserPrincipal.FindByIdentity(domainContext, "user1");
/* Retreive the container
*/
DirectoryEntry deUser = user.GetUnderlyingObject() as DirectoryEntry;
DirectoryEntry deUserContainer = deUser.Parent;
Console.WriteLine (deUserContainer.Properties["distinguishedName"].Value);
This information is in UserPrincipal.DistinguishedName. You should check if DistinguishedName ends with "," + ou distinguished name (case insensitive). However, you must know the distingushed name of ou you're checking.
For example, if dn is: CN=Jeff Smith,OU=Sales,DC=Fabrikam,DC=COM, then it says that user is in OU=Sales,DC=Fabrikam,DC=COM ou.
This is how I would get the Distinguished Name for a specific AD user, hope it helps :-)
private static string GetDNOfUser(string user)
{
var ctx = new PrincipalContext(ContextType.Domain, Environmentals.Domain, Environmentals.OUPath);
//Creating object for search filter
UserPrincipal userPrin = new UserPrincipal(ctx)
{
//Only getting users with the same name as the input
Name = user
};
var searcher = new PrincipalSearcher
{
//Applying filter to query
QueryFilter = userPrin
};
//Finding the user
var results = searcher.FindOne();
searcher.Dispose();
//Return the distinguishedname
return results.DistinguishedName;
}
I know that this type of question has been asked before, but other methods are failing me right now.
As it stands our windows service polls AD, given an LDAP (i.e. LDAP://10.32.16.80) and a list of usergroups within that AD server to search for.
It retrieves all users within those given groups, recursively searching those groups for more groups as well.
Each user is then added to another applications authenticated users list.
This part of the application is running successfully. However, we're in need of each user's friendly domain name (i.e. the part of their login DOMAIN/username)
So if there is a user that is part of TEST domain, named Steve: TEST/steve is his login.
I'm able to find steve in the AD, however I also need "TEST" to be stored along with his AD information.
Again, I can find 'steve' fine by using a directory searcher and the LDAP IP I'm given, but given the LDAP IP, how can I find the friendly domain name?
When I try the following code I'm given an error when attempting to access the 'defaultNamingContext':
System.Runtime.InteropServices.COMException (0x8007202A): The authentication mechanism is unknown.
Here is the code:
private string SetCurrentDomain(string server)
{
string result = string.Empty;
try
{
logger.Debug("'SetCurrentDomain'; Instantiating rootDSE LDAP");
DirectoryEntry ldapRoot = new DirectoryEntry(server + "/rootDSE", username, password);
logger.Debug("'SetCurrentDomain'; Successfully instantiated rootDSE LDAP");
logger.Debug("Attempting to retrieve 'defaultNamingContext'...");
string domain = (string)ldapRoot.Properties["defaultNamingContext"][0]; //THIS IS WHERE I HIT THE COMEXCEPTION
logger.Debug("Retrieved 'defaultNamingContext': " + domain);
if (!domain.IsEmpty())
{
logger.Debug("'SetCurrentDomain'; Instantiating partitions/configuration LDAP entry");
DirectoryEntry parts = new DirectoryEntry(server + "/CN=Partitions,CN=Configuration," + domain, username, password);
logger.Debug("'SetCurrentDomain'; Successfully instantiated partitions/configuration LDAP entry");
foreach (DirectoryEntry part in parts.Children)
{
if (part.Properties["nCName"] != null && (string)part.Properties["nCName"][0] != null)
{
logger.Debug("'SetCurrentDomain'; Found property nCName");
if ((string)part.Properties["nCName"][0] == domain)
{
logger.Debug("'SetCurrentDomain'; nCName matched defaultnamingcontext");
result = (string)part.Properties["NetBIOSName"][0];
logger.Debug("'SetCurrentDomain'; Found NetBIOSName (friendly domain name): " + result);
break;
}
}
}
}
logger.Debug("finished setting current domain...");
}
catch (Exception ex)
{
logger.Error("error attempting to set domain:" + ex.ToString());
}
return result;
}
edit
I added this sample method in order to attempt a suggestion but am getting an exception: "Unspecified error" when I hit the "FindAll()" call on the searcher.
The string being passed in is: "CN=TEST USER,CN=Users,DC=tempe,DC=ktregression,DC=com"
private string GetUserDomain(string dn)
{
string domain = string.Empty;
string firstPart = dn.Substring(dn.IndexOf("DC="));
string secondPart = "CN=Partitions,CN=Configuration," + firstPart;
DirectoryEntry root = new DirectoryEntry(secondPart, textBox2.Text, textBox3.Text);
DirectorySearcher searcher = new DirectorySearcher(root);
searcher.SearchScope = SearchScope.Subtree;
searcher.ReferralChasing = ReferralChasingOption.All;
searcher.Filter = "(&(nCName=" + firstPart + ")(nETBIOSName=*))";
try
{
SearchResultCollection rs = searcher.FindAll();
if (rs != null)
{
domain = GetProperty(rs[0], "nETBIOSName");
}
}
catch (Exception ex)
{
}
return domain;
This article helped me much to understand how to work with the Active Directory.
Howto: (Almost) Everything In Active Directory via C#
From this point forward, if you require further assitance, please let me know with proper questions in comment, and I shall answer them for you to the best of my knowledge.
EDIT #1
You had better go with this example's filter instead. I have written some sample code to briefly show how to work with the System.DirectoryServices and System.DirectoryServices.ActiveDirectory namespaces. The System.DirectoryServices.ActiveDirectory namespace is used to retrieve information about the domains within your Forest.
private IEnumerable<DirectoryEntry> GetDomains() {
ICollection<string> domains = new List<string>();
// Querying the current Forest for the domains within.
foreach(Domain d in Forest.GetCurrentForest().Domains)
domains.Add(d.Name);
return domains;
}
private string GetDomainFullName(string friendlyName) {
DirectoryContext context = new DirectoryContext(DirectoryContextType.Domain, friendlyName);
Domain domain = Domain.GetDomain(context);
return domain.Name;
}
private IEnumerable<string> GetUserDomain(string userName) {
foreach(string d in GetDomains())
// From the domains obtained from the Forest, we search the domain subtree for the given userName.
using (DirectoryEntry domain = new DirectoryEntry(GetDomainFullName(d))) {
using (DirectorySearcher searcher = new DirectorySearcher()){
searcher.SearchRoot = domain;
searcher.SearchScope = SearchScope.Subtree;
searcher.PropertiesToLoad.Add("sAMAccountName");
// The Filter is very important, so is its query string. The 'objectClass' parameter is mandatory.
// Once we specified the 'objectClass', we want to look for the user whose login
// login is userName.
searcher.Filter = string.Format("(&(objectClass=user)(sAMAccountName={0}))", userName);
try {
SearchResultCollection results = searcher.FindAll();
// If the user cannot be found, then let's check next domain.
if (results == null || results.Count = 0)
continue;
// Here, we yield return for we want all of the domain which this userName is authenticated.
yield return domain.Path;
} finally {
searcher.Dispose();
domain.Dispose();
}
}
}
Here, I didn't test this code and might have some minor issue to fix. This sample is provided as-is for the sake of helping you. I hope this will help.
EDIT #2
I found out another way out:
You have first to look whether you can find the user account within your domain;
If found, then get the domain NetBIOS Name; and
concatenate it to a backslash (****) and the found login.
The example below uses a NUnit TestCase which you can test for yourself and see if it does what you are required to.
[TestCase("LDAP://fully.qualified.domain.name", "TestUser1")]
public void GetNetBiosName(string ldapUrl, string login)
string netBiosName = null;
string foundLogin = null;
using (DirectoryEntry root = new DirectoryEntry(ldapUrl))
Using (DirectorySearcher searcher = new DirectorySearcher(root) {
searcher.SearchScope = SearchScope.Subtree;
searcher.PropertiesToLoad.Add("sAMAccountName");
searcher.Filter = string.Format("(&(objectClass=user)(sAMAccountName={0}))", login);
SearchResult result = null;
try {
result = searcher.FindOne();
if (result == null)
if (string.Equals(login, result.GetDirectoryEntry().Properties("sAMAccountName").Value))
foundLogin = result.GetDirectoryEntry().Properties("sAMAccountName").Value
} finally {
searcher.Dispose();
root.Dispose();
if (result != null) result = null;
}
}
if (!string.IsNullOrEmpty(foundLogin))
using (DirectoryEntry root = new DirectoryEntry(ldapUrl.Insert(7, "CN=Partitions,CN=Configuration,DC=").Replace(".", ",DC="))
Using DirectorySearcher searcher = new DirectorySearcher(root)
searcher.Filter = "nETBIOSName=*";
searcher.PropertiesToLoad.Add("cn");
SearchResultCollection results = null;
try {
results = searcher.FindAll();
if (results != null && results.Count > 0 && results[0] != null) {
ResultPropertyValueCollection values = results[0].Properties("cn");
netBiosName = rpvc[0].ToString();
} finally {
searcher.Dispose();
root.Dispose();
if (results != null) {
results.Dispose();
results = null;
}
}
}
Assert.AreEqual("FULLY\TESTUSER1", string.Concat(netBiosName, "\", foundLogin).ToUpperInvariant())
}
The source from which I inspired myself is:
Find the NetBios Name of a domain in AD
Since I could not find any example code I would like to share my own solution. This will search the parents of the DirectoryEntry object until it hits the domainDNS class.
using System.DirectoryServices;
public static class Methods
{
public static T ldap_get_value<T>(PropertyValueCollection property)
{
object value = null;
foreach (object tmpValue in property) value = tmpValue;
return (T)value;
}
public static string ldap_get_domainname(DirectoryEntry entry)
{
if (entry == null || entry.Parent == null) return null;
using (DirectoryEntry parent = entry.Parent)
{
if (ldap_get_value<string>(parent.Properties["objectClass"]) == "domainDNS")
return ldap_get_value<string>(parent.Properties["dc"]);
else
return ldap_get_domainname(parent);
}
}
}
Use it like this:
string[] _properties = new string[] { "objectClass", "distinguishedName", "samAccountName", "userPrincipalName", "displayName", "mail", "title", "company", "thumbnailPhoto", "useraccountcontrol" };
string account = "my-user-name";
// OR even better:
// string account = "my-user-name#DOMAIN.local";
using (DirectoryEntry ldap = new DirectoryEntry())
{
using (DirectorySearcher searcher = new DirectorySearcher(ldap))
{
searcher.PropertiesToLoad.AddRange(_properties);
if (account.Contains('#')) searcher.Filter = "(userPrincipalName=" + account + ")";
else searcher.Filter = "(samAccountName=" + account + ")";
var user = searcher.FindOne().GetDirectoryEntry();
Console.WriteLine("Name: " + Methods.ldap_get_value<string>(user.Properties["displayName"]));
Console.WriteLine("Domain: " + Methods.ldap_get_domainname(user));
Console.WriteLine("Login: " + Methods.ldap_get_domainname(user) + "\\" + Methods.ldap_get_value<string>(user.Properties["samAccountName"]));
}
}
I haven't got a forest to test it on but in theory this should cut it.
You can retrieve the name of the domain that the current user is on using the Environment.UserDomainName Property.
string domainName;
domainName = System.Environment.UserDomainName;
Maybe not entirely correct but...
DirectoryEntry dirEntry = new DirectoryEntry();
DirectorySearcher dirSearcher = new DirectorySearcher(dirEntry);
dirSearcher.SearchScope = SearchScope.Subtree;
dirSearcher.Filter = string.Format("(&(objectClass=user)(|(cn={0})(sn={0}*)(givenName={0})(sAMAccountName={0}*)))", userName);
var searchResults = dirSearcher.FindAll();
foreach (SearchResult sr in searchResults)
{
var de = sr.GetDirectoryEntry();
string user = de.Properties["SAMAccountName"][0].ToString();
string domain = de.Path.ToString().Split(new [] { ",DC=" },StringSplitOptions.None)[1];
MessageBox.Show(domain + "/" + user);
}
Because the value of de.Path is
LDAP://CN=FullName,DC=domain,DC=local