I just want to Add a new method on an existing code below.
Method is a simply check a given User_ID if it is exists on the AD.
It's my 1st time dealing with AD.
public class AD
{
// Fields
private static string ADPassword = ConfigurationManager.AppSettings["ADPassword"].ToString();
private static string ADPath = ConfigurationManager.AppSettings["ADConnection"].ToString();
private static string ADServerName = ConfigurationManager.AppSettings["ADServerName"].ToString();
private static string ADUserName = ConfigurationManager.AppSettings["ADUserName"].ToString();
// Methods
public static string GetLogin(string sUserName, string sPassword)
{
try
{
DirectoryEntry entry = new DirectoryEntry(ADPath, ADServerName + sUserName, sPassword);
object nativeObject = entry.NativeObject;
return string.Empty;
}
catch
{
return "Invalid Username or Password";
}
}
public static string Update(string sUserName, string sOldPassword, string sNewPassword)
{
string message;
try
{
DirectoryEntry searchRoot = new DirectoryEntry();
searchRoot.Path = ADPath;
searchRoot.Username = ADServerName + ADUserName;
searchRoot.Password = ADPassword;
DirectorySearcher searcher = new DirectorySearcher(searchRoot);
searcher.Filter = "(SAMAccountName=" + sUserName + ")";
DirectoryEntry directoryEntry = searcher.FindOne().GetDirectoryEntry();
directoryEntry.Invoke("ChangePassword", new object[] { sOldPassword, sNewPassword });
directoryEntry.CommitChanges();
directoryEntry.Close();
message = string.Empty;
}
catch (Exception exception)
{
try
{
message = exception.InnerException.Message;
}
catch
{
message = exception.Message;
}
}
return message;
}
}
Which version of the .NET Framework are you on??
In .NET before 3.5, you could probably do a DirectorySearch on the whole server (or alternatively a more constrained subtree):
public bool UserExists(string userName)
{
DirectoryEntry searchRoot = new DirectoryEntry("LDAP://dc=yourcompany,dc=com", userName, password);
DirectorySearcher searchForUser = new DirectorySearcher(searchRoot);
searchForUser.SearchScope = SearchScope.SubTree;
searchForUser.Filter = string.Format("(&(objectCategory=Person)(anr={0}))", userName);
if(searchForUser.FindOne() != null)
{
return true;
}
else
{
return false;
}
}
This is just off the top of my head, can't test it right now. This will search in your entire domain - check the LDAP path for the searchRoot - it would have to be something like
LDAP://dc=yourcompany,dc=com
or if you want to search just inside the "Users" container:
LDAP://cn=Users,dc=yourcompany,dc=com
With .NET 3.5 things got a lot easier - see this MSDN Article for a lot of useful info on how to search and find users and groups in .NET 3.5 using the new System.DirectoryServices.AccountManagement namespace. You can basically now do a FindByIdentity call:
PrincipalContext ctx = new PrincipalContext(ContextType.Domain, "YOURDOMAIN");
UserPrincipal foundUser = UserPrincipal.FindByIdentity(ctx, "your user name");
and that's all there is.
Marc
If it's your first AD experience, it might be worth taking a look at this codeproject article: Howto: (Almost) Everything In Active Directory via C#. It contains lots of examples that might help you.
What do you mean exactly by User_ID? Account name? LDAP distinguished name?
Related
Update:
For me, LDAP way only worked for finding email addresses inside AD groups, for eg: named ITSolutionDeliveryDevelopers group. NOT inside Exchange Distribution Lists, for eg: named abc#domainname.com.
// I was able to figure out entry as suggested by #Gabriel Luci and
// all of the following possible formats worked for me:
// ngroupnet.com is my company domain name.
var entry = new DirectoryEntry();
var entry = new DirectoryEntry("LDAP://ngroupnet.com");
var entry = new DirectoryEntry("LDAP://ngroupnet.com", "MyAccountUsername", "MyAccountPassword");
var entry = new DirectoryEntry("LDAP://ngroupnet.com", "MyName#mycompany.com", "MyEmailAccountPassword");
For my complete answer, take a look below: https://stackoverflow.com/a/71518937/8644294
Original Question:
What is the best way to get all the individual email addresses comprising an exchange distribution list?
For eg: I have this distribution list called abc#domainname.com that has email addresses:
a#domainname.com
b#domainname.com
c#domainname.com
Now I need to get these addresses using C# code.
I found solution using LDAP but I felt it'd be a hassle to figure out LDAP path to my Active Directory.
// How do I get this LDAP Path, username and password?
// Is the username and password service account credentials of the app?
// And do they need to be registered in AD?
var entry = new DirectoryEntry("LDAP Path");//, username, password);
LDAP Way:
public static List<string> GetDistributionListMembers(string dlName = "abc#domainname.com")
{
var result = new List<string>();
try
{
// How do I get this LDAP Path?
var entry = new DirectoryEntry("LDAP Path");//, username, password);
var search = new DirectorySearcher(entry);
search.Filter = $"CN={dlName}";
int i = search.Filter.Length;
string str = "", str1 = "";
foreach (SearchResult AdObj in search.FindAll())
{
foreach (String objName in AdObj.GetDirectoryEntry().Properties["member"])
{
str += Convert.ToString(objName) + "<Br>";
int selIndex = objName.IndexOf("CN=") + 3;
int selEnd = objName.IndexOf(",OU") - 3;
str1 += objName.Substring(selIndex, selEnd).Replace("\\", "");
DirectorySearcher dsSearch = new DirectorySearcher(entry);
dsSearch.Filter = "CN=" + objName.Substring(selIndex, selEnd).Replace("\\", "");
foreach (SearchResult rs in dsSearch.FindAll())
{
//str1 += "<p align='right'><font face='calibri' color='#2266aa' size=2>" + Convert.ToString(rs.GetDirectoryEntry().Properties["mail"].Value) + "|" + Convert.ToString(rs.GetDirectoryEntry().Properties["displayName"].Value) + "|" + Convert.ToString(rs.GetDirectoryEntry().Properties["sAMAccountName"].Value) + "|" + Convert.ToString(rs.GetDirectoryEntry().Properties["department"].Value) + "|" + Convert.ToString(rs.GetDirectoryEntry().Properties["memberOf"].Value) + "</font></p>";
str1 = Convert.ToString(rs.GetDirectoryEntry().Properties["mail"].Value);
result.Add(str1);
}
}
}
return result;
}
catch (Exception ex)
{
//Do some logging or what have you.
throw;
}
}
So I just went with the EWS route.
EWS Way:
public static static List<string> GetDistributionListMembers(string dlName = "abc#domainname.com")
{
try
{
var service = new ExchangeService();
var cred = new WebCredentials("sharedmailbox#domain.com", "some_password");
service.Credentials = cred;
service.Url = new Uri("https://outlook.office365.com/ews/exchange.asmx");
service.TraceEnabled = true;
service.TraceFlags = TraceFlags.All;
var expandedEmailAddresses = new List<string>();
ExpandGroupResults myGroupMembers = service.ExpandGroup(dlName);
foreach (EmailAddress address in myGroupMembers.Members)
{
expandedEmailAddresses.Add(address.Address);
}
return expandedEmailAddresses;
}
catch (Exception ex)
{
// The DL doesn't have any members. Handle it how you want.
// Handle/ Log other errors.
}
}
Is EWS approach a good way?
If Yes, then I'm good. If not, I'll have to figure out that LDAP path.
Or if there's even a better way, please let me know.
If the computer you run this from is joined to the same domain as the group you're looking for, then you don't need to figure out the LDAP path. You can just do:
var search = new DirectorySearcher();
If your computer is not joined to the same domain, then you just use the domain name:
var entry = new DirectoryEntry("LDAP://domainname.com");
This requires that there is no firewall blocking port 389 between your computer and the domain controller(s). If you need to pass credentials, then do that:
var entry = new DirectoryEntry("LDAP://domainname.com", username, password);
The credentials can be any user on the domain.
That said, there are a lot of inefficiencies in your code that will make it run much slower than needed. I wrote an article about this that can help you update your code: Active Directory: Better Performance
Is EWS approach a good way?
If it works, it works. I'm not an expert on EWS (although I have used it), but I'm fairly certain that's using Basic Authentication, which is going to be disabled in October.
If all the Mailboxes are on Office365 then i would suggest you use the Graph API instead eg https://learn.microsoft.com/en-us/graph/api/group-list-members?view=graph-rest-1.0&tabs=http . There are several advantage in terms of security eg you could use Application permissions and all you need is access to the directory while if you did the same thing in EWS it would require full access to at least one mailbox.
LDAP will be best performing of the 3 if ultimate speed in the only thing that is important.
My complete solution for future reference. :)
EWS Way - For expanding Exchange Distribution Lists
public class SomeHelper
{
private static ExchangeService _exchangeService = null;
public static async Task<HashSet<string>> GetExchangeDistributionListMembersAsync(IEnumerable<string> dlNames)
{
var allEmailAddresses = new HashSet<string>();
foreach (var dlName in dlNames)
{
if (!SomeCache.TryGetCachedItem(dlName, out var dlMembers))
{
var groupEmailAddresses = new List<string>();
var exchangeService = await GetExchangeServiceAsync();
try
{
var myGroupMembers = exchangeService.ExpandGroup(dlName);
// Add the group members.
foreach (var address in myGroupMembers.Members)
{
groupEmailAddresses.Add(address.Address);
}
}
catch (Exception ex)
{
//If it can't expand the dlName, just return it.
groupEmailAddresses.Add(dlName);
//groupEmailAddresses.Add($"Attempting to expand '{dlName}' resulted in error message: '{ex.Message}'.");
}
// Cache the groupEmailAddresses for 7 days.
// Because Distribution Lists rarely change and expanding DL is an expensive operation.- AshishK Notes
SomeCache.AddItemToCache(dlName, groupEmailAddresses, 10080);
allEmailAddresses.UnionWith(groupEmailAddresses);
}
else
{
allEmailAddresses.UnionWith((List<string>)dlMembers);
}
}
return allEmailAddresses;
}
private static async Task<ExchangeService> GetExchangeServiceAsync()
{
if (_exchangeService == null)
{
_exchangeService = new ExchangeService();
var exchangeUrl = "https://outlook.office365.com/ews/exchange.asmx";
var cred = new WebCredentials("sharedmailbox#domain.com", "some_password");
_exchangeService.Credentials = cred;
//_exchangeService.AutodiscoverUrl("sharedmailbox#domain.com");
_exchangeService.Url = new Uri(exchangeUrl);
_exchangeService.TraceEnabled = true;
_exchangeService.TraceFlags = TraceFlags.All;
return _exchangeService;
}
else
{
return _exchangeService;
}
}
}
public class SomeCache
{
private static readonly ObjectCache _cache = MemoryCache.Default;
public static void AddItemToCache(string key, object itemToAdd, int cacheDurationMinutes)
{
var _policy = new CacheItemPolicy
{
Priority = CacheItemPriority.Default,
AbsoluteExpiration = DateTimeOffset.Now.AddMinutes(cacheDurationMinutes)
};
_cache.Set(key, itemToAdd, _policy);
}
public static bool TryGetCachedItem(string key, out object cachedObject)
{
try
{
cachedObject = _cache[key] as object;
}
catch (Exception ex)
{
cachedObject = null;
}
return !(cachedObject == null);
}
}
LDAP Way - For expanding Active Directory Groups
public static List<string> GetADGroupDistributionListMembers(string adGroupName)
{
var returnResult = new List<string>();
var entry = GetDirectoryEntry();
DirectorySearcher groupSearch = new DirectorySearcher(entry)
{
Filter = "(SAMAccountName=" + adGroupName + ")"
};
groupSearch.PropertiesToLoad.Add("member");
SearchResult groupResult = groupSearch.FindOne(); // getting members who belong to the adGroupName
if (groupResult != null)
{
for (int iSearchLoop = 0; iSearchLoop < groupResult.Properties["member"].Count; iSearchLoop++)
{
string userName = groupResult.Properties["member"][iSearchLoop].ToString();
int index = userName.IndexOf(',');
userName = userName.Substring(0, index).Replace("CN=", "").ToString(); // the name of the user will be fetched.
DirectorySearcher search = new DirectorySearcher(entry)
{
Filter = "(name=" + userName + ")"
};
search.PropertiesToLoad.Add("mail");
SearchResult result = search.FindOne(); //finding the mail id
if (result != null)
{
returnResult.Add(result.Properties["mail"][0].ToString());
}
}
}
return returnResult;
}
public static DirectoryEntry GetDirectoryEntry()
{
DirectoryEntry entryRoot = new DirectoryEntry("LDAP://RootDSE");
string Domain = (string)entryRoot.Properties["defaultNamingContext"][0];
DirectoryEntry de = new DirectoryEntry
{
Path = "LDAP://" + Domain,
AuthenticationType = AuthenticationTypes.Secure
};
return de;
}
I am trying to create a new AD-User with this code:
PrincipalContext ctx = new PrincipalContext(ContextType.Domain, "Domain", "ou=some_ou, dc=Mydomain");
UserPrincipal user = new UserPrincipal(ctx, account, passwd, true);
user.GivenName = Givenname;
user.Surname = Surname;
user.DisplayName = Displayname;
user.UserPrincipalName = account + "#Domain";
user.Save();
The User is created without error. But I also have to set properties like Address etc, so the code continues with:
string distname = user.DistinguishedName;
DirectoryEntry duser = new DirectoryEntry(distname);
try
{
duser.Properties["company"].Value = "Company";
}
catch (Exception e)
{
}
Now I am getting
Error: System.Exception._COMPlusExceptionCode -532459699
The string distname shows the correct distinguished name.
I am not 100% sure what is causing your problem but one thing that may make things easier on you and may clear up some errors due to you improperly using both DirectoryServices and DirectoryServices.AccountManagement at the same time is creating a new class that includes the company attribute.
Its actually not that hard to do.
[DirectoryObjectClass("user")]
[DirectoryRdnPrefix("CN")]
public class UserPrincipalEx : UserPrincipal
{
public UserPrincipalEx(PrincipalContext context) : base(context) { }
public UserPrincipalEx(PrincipalContext context, string samAccountName, string password, bool enabled)
: base(context, samAccountName, password, enabled)
{
}
[DirectoryProperty("company")]
public string Company
{
get
{
if (ExtensionGet("company").Length != 1)
return null;
return (string)ExtensionGet("company")[0];
}
set { this.ExtensionSet("company", value); }
}
}
You can then just modify your code to
PrincipalContext ctx = new PrincipalContext(ContextType.Domain, "Domain", "ou=some_ou, dc=Mydomain");
UserPrincipalEx user = new UserPrincipalEx(ctx, account, passwd, true);
user.GivenName = Givenname;
user.Surname = Surname;
user.DisplayName = Displayname;
user.UserPrincipalName = account + "#Domain";
user.Company = "Company";
user.Save();
My hunch is you are having some kind of interaction with the two methods of interfacing with active directory, if you switch to a single interface your problem may just go away.
For DirectoryEntry, you have to specify the protocol (LDAP, GC, WinNT, ...). So you would have to do:
DirectoryEntry duser = new DirectoryEntry("LDAP://" + distname);
Note that the protocol is case sensitive, LDAP has to be all caps.
I see you are using credentials in the UserPrincipal,
Did you forgot to use them when creating your DirectoryEntry?
Also, you need to add "LDAP://" before you server name
Try something like :
DirectoryEntry duser = new DirectoryEntry("LDAP://" + distname);
duser.Username = account;
duser.Password = passwd;
duser.AuthenticationType = AuthenticationTypes.Secure;
I am a new web developer and in my company all the ASP.NET applications rely on a system that pulls down the user information from the SAP system and retrieve them as a XML document. This system has only one textbox for inserting the username to retrieve his information. An example of it:
If you insert the username: johnA
the system will provide you with the following information:
John
Arneson
Elli
and so on.
Then, in the ASP.NET web-based applications, we used to use three C# classes that does the connections with this system and helpes in getting the specific user information from that system.
Anyway, Now we want to replace that system with a new system that gets the user information from the Active Directory.
I put the following code in the server and it works well, so when the employee goes to this code in our server, he will see a page that shows all of his information. What I want to do right now is utilizing this in all our developed and the next new-developed web-based applications by putting a TextBox to put the username of the user and retrieve of all of his information from this system. So how to do that?
I am a beginner and I could not be able to find a way for doing this in Google or anywhere else.
My code of the class for accessing the Active Directory is:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.DirectoryServices;
/// <summary>
/// Summary description for ActiveDirectory
/// </summary>
public class ActiveDirectory
{
public static string GetPersonData(string id, string datatype)
{
//return "x xx xxxx xxx xxx"; //comment this line.
//Faster performance through Active Directory
string property = datatype;
switch (property) //backwards compatibility
{
/* case "tel":
return FindProperty(id, Property.Tel);*/
case "name":
return FindProperty(id, Property.Name);
case "dept":
return FindProperty(id, Property.Dept);
case "line":
return FindProperty(id, Property.Line);
case "email":
return FindProperty(id, Property.Email);
case "id":
return FindProperty(id, Property.Name);
default:
return "";
}
}
//ACTIVE DIRECTORY OPTION.. FOR A BETTER PERFORMANCE
const string ID = "cn";
const string NAME = "displayName";
const string TEL = "telephoneNumber";
const string DEPT = "department";
const string LINE = "extensionAttribute3";
const string UNIT = "extensionAttribute10";
const string TITLE = "title";
const string FNAME = "givenName";
const string MNAME = "initials";
const string LNAME = "sn";
const string EMAIL = "mail";
const string AREA = "extensionAttribute3";
const string MANAGER = "manager";
const string ORGCODE = "extensionAttribute10";
const string DN = "distinguishedName";
public enum Property
{
Name, Tel, Dept, Line, Unit, Title, Fname, Mname, Lname, Email, Manager, OrgCode, DistinguishedName
}
public static DirectoryEntry GetDirectoryEntry()
{
using (((System.Security.Principal.WindowsIdentity)HttpContext.Current.User.Identity).Impersonate())
{
DirectoryEntry de = new DirectoryEntry(); //DirectoryEntry class encapsulates a node or object in the AD hierarchy
de.Path = "LDAP://CompanyName.COM";
de.AuthenticationType = AuthenticationTypes.Delegation;
return de;
}
}
public static bool UserExists(string username)
{
DirectoryEntry de = GetDirectoryEntry();
DirectorySearcher deSearch = new DirectorySearcher(); //Directory Searcher: It will perform queries against the active directory hierarchy
deSearch.SearchRoot = de; //SearchRoot is used to specify where the search starts
deSearch.Filter = "(&(objectClass=user) (cn=" + username + "))"; //the search retrieves all objects.
// Create a SearchResultCollection object to hold a collection of SearchResults
// returned by the FindAll method.
SearchResultCollection results = deSearch.FindAll();
return results.Count > 0;
}
public static String FindName(String userAccount)
{
DirectoryEntry entry = GetDirectoryEntry();
String account = userAccount.Replace(#"Domain\", "");
try
{
DirectorySearcher search = new DirectorySearcher(entry);
search.Filter = "(SAMAccountName=" + account + ")";
search.PropertiesToLoad.Add("displayName");
SearchResult result = search.FindOne();
if (result != null)
{
return result.Properties["displayname"][0].ToString();
}
else
{
return "Unknown User";
}
}
catch (Exception ex)
{
string debug = ex.Message;
return debug;
}
}
public static String FindProperty(String userAccount, Property p)
{
string property = "";
//proceed with LDAP search.
switch (p)
{
case Property.Dept:
property = DEPT;
break;
case Property.Email:
property = EMAIL;
break;
case Property.Fname:
property = FNAME;
break;
case Property.Line:
property = LINE;
break;
case Property.Lname:
property = LNAME;
break;
case Property.Mname:
property = MNAME;
break;
case Property.Name:
property = NAME;
break;
case Property.Tel:
property = TEL;
break;
case Property.Title:
property = TITLE;
break;
case Property.Unit:
property = UNIT;
break;
case Property.Manager:
property = MANAGER;
break;
case Property.OrgCode:
property = ORGCODE;
break;
case Property.DistinguishedName:
property = DN;
break;
default:
return "";
}
DirectoryEntry entry = GetDirectoryEntry();
String account = userAccount.Replace(#"Domain\", "");
try
{
System.Text.Encoding enc = System.Text.Encoding.ASCII;
DirectorySearcher search = new DirectorySearcher(entry);
search.Filter = "(&(objectCategory=user)(SAMAccountName=" + account + "))";
search.PropertiesToLoad.Add(property);
SearchResult result = search.FindOne();
search.Dispose();
entry.Close();
entry.Dispose();
if (result != null)
{
object value = result.Properties[property][0];
if (value is System.Byte[])
return enc.GetString((byte[])value);
else
return value.ToString();
}
else
{
return "-";
}
}
catch (Exception ex)
{
string debug = ex.Message;
return "debug";
}
}
public static List<string> FindChildren(string userAccount)
{
DirectoryEntry entry = GetDirectoryEntry();
String account = userAccount.Replace(#"Domain\", "");
string dn = FindProperty(userAccount, Property.DistinguishedName);
dn.Replace("*","\\2a");
dn.Replace("(", "\\28");
dn.Replace(")", "\\29");
dn.Replace("\\", "\\5c");
dn.Replace("NUL", "\\00");
dn.Replace("/", "\\2f");
string property = ID;
List<string> output = new List<string>();
try
{
System.Text.Encoding enc = System.Text.Encoding.ASCII;
DirectorySearcher search = new DirectorySearcher(entry);
search.Filter = "(&(objectCategory=user)(manager=" + dn + "))";
search.PropertiesToLoad.Add(property);
SearchResultCollection results = search.FindAll();
search.Dispose();
entry.Close();
entry.Dispose();
if (results != null)
{
foreach (SearchResult result in results)
{
object value = result.Properties[property][0];
if (value is System.Byte[])
output.Add(enc.GetString((byte[])value));
else
output.Add(value.ToString());
}
}
}
catch (Exception ex)
{
throw ex;
}
return output;
}
public static string FindOrg(string orgcode, string property)
{
DirectoryEntry entry = GetDirectoryEntry();
try
{
System.Text.Encoding enc = System.Text.Encoding.ASCII;
DirectorySearcher search = new DirectorySearcher(entry);
search.Filter = "(&(objectCategory=user)(" + ORGCODE + "=" + orgcode + "*))";
search.PropertiesToLoad.Add(property);
SearchResult result = search.FindOne();
search.Dispose();
entry.Close();
entry.Dispose();
if (result != null)
{
object value = result.Properties[property][0];
if (value is System.Byte[])
return enc.GetString((byte[])value);
else
return value.ToString();
}
else
{
return "-";
}
}
catch (Exception ex)
{
string debug = ex.Message;
return "debug";
}
}
}
UPDATE:
For your information, the above classes are on the server. Now, I am developing a new web-based application. And in this web-based application, I have a textbox that I will use to enter the username. So how I will be able to send this username to that system and retrieve the user information for it to this application? Could you please provide me with an example?
Ok understand now what you really need. The best way for this to be accomplish is by using asp.net webservices. What this means is that you must make some edits to your code that is currently running on your server.
Please look up Asp.net Web Services and check out these links: Microsoft Web Services weblink and Create and Use ASP.NET Web Service
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....
}
// find the group in question
GroupPrincipal group = GroupPrincipal.FindByIdentity(ctx, "YourGroupNameHere");
// 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
}
}
The new S.DS.AM makes it really easy to play around with users and groups in AD!
And as "Nation" mentioned in his response, if you "hide" this behind a web service interface, then all sorts of applications can call into your code and get the information they need out of Active Directory!
I am working with LDAP and I am new to this.
Is there a way to get the domain when you only know the username, password, servername
I am trying to do this:
string ldapPath = "LDAP://serverName";
string uid = username;
string password = pwd;
string qry = String.Format("(uid={0})", uid);
string adsPath = String.Empty;
try
{
DirectoryEntry nRoot = new DirectoryEntry(ldapPath, null, null, AuthenticationTypes.Anonymous);
DirectorySearcher ds = new DirectorySearcher(nRoot, qry);
SearchResult sr = ds.FindOne();
if (sr != null)
{
// we want to retrieve the DN like this: "uid=myuser,ou=People,dc=findlay,dc=edu
ldapPath = sr.Path; //update where we will bind next
}
This does not work unless I change
string ldapPath = "LDAP://serverName";
to
string ldapPath = "LDAP://serverName/DC=mydomain,DC=com";
Any help..??
Thanks
Edit rootDSE
string defaultNamingContext;
using (DirectoryEntry rootDSE = new DirectoryEntry("LDAP://serverName/rootDSE", null, null, AuthenticationTypes.Anonymous))
{
defaultNamingContext = rootDSE.Properties["rootDomainNamingContext"].Value.ToString();
}
I too feel this is the solution but it is currently not working for me.. please help!
RootDSE is not server-bound - try this:
string defaultNamingContext;
using (DirectoryEntry rootDSE = new DirectoryEntry("LDAP://rootDSE", null, null, AuthenticationTypes.Anonymous))
{
defaultNamingContext = rootDSE.Properties["defaultNamingContext"].Value.ToString();
}
Or if you're on .NET 3.5 and newer, you could use PrincipalContext instead, which can be constructed without any path - it will just pick up the default domain you're connected to:
PrincipalContext context = new PrincipalContext(ContextType.Domain);
You should check out the System.DirectoryServices.AccountManagement (S.DS.AM) namespace. Read all about it here (that's .NET 3.5 and newer):
Managing Directory Security Principals in the .NET Framework 3.5
MSDN docs on System.DirectoryServices.AccountManagement
If :
using (DirectoryEntry rootDSE = new DirectoryEntry("LDAP://serverName/DC=mydomain,DC=com")
{
...
}
works, have you try (without being anonymous):
string defaultNamingContext;
using (DirectoryEntry rootDSE = new DirectoryEntry("LDAP://serverName/rootDSE")
{
defaultNamingContext = rootDSE.Properties["rootDomainNamingContext"].Value.ToString();
}
or
using (DirectoryEntry rootDSE = new DirectoryEntry("LDAP://serverName/rootDSE", user, password)
{
defaultNamingContext = rootDSE.Properties["rootDomainNamingContext"].Value.ToString();
}
It works for me, from a computer not in the domain.
you can try like this
// Method call
string netBiosName = GetNetBiosName(LDAP://CN=Partitions,CN=Configuration,DC=<DomainName>,DC=<local|com>, "<userName"", "<password>");
// Method call
// Method Definition
private string GetNetBiosName(string ldapUrl, string userName, string password)
{
string netbiosName = string.Empty;
DirectoryEntry dirEntry = new DirectoryEntry(ldapUrl,userName, password);
DirectorySearcher searcher = new DirectorySearcher(dirEntry);
searcher.Filter = "netbiosname=*";
searcher.PropertiesToLoad.Add("cn");
SearchResultCollection results = searcher.FindAll();
if (results.Count > 0)
{
ResultPropertyValueCollection rpvc = results[0].Properties["CN"];
netbiosName = rpvc[0].ToString();
}
return netbiosName;
}
pls take a look at this link for more info
You should be able to get the domain by just calling RootDse.
I'm writing a web application which uses windows authentication and I can happily get the user's login name using something like:
string login = User.Identity.Name.ToString();
But I don't need their login name I want their DisplayName. I've been banging my head for a couple hours now...
Can I access my organisation's AD via a web application?
How about this:
private static string GetFullName()
{
try
{
DirectoryEntry de = new DirectoryEntry("WinNT://" + Environment.UserDomainName + "/" + Environment.UserName);
return de.Properties["displayName"].Value.ToString();
}
catch { return null; }
}
See related question: Active Directory: Retrieve User information
See also: Howto: (Almost) Everything In Active Directory via C# and more specifically section "Enumerate an object's properties".
If you have a path to connect to a group in a domain, the following snippet may be helpful:
GetUserProperty("<myaccount>", "DisplayName");
public static string GetUserProperty(string accountName, string propertyName)
{
DirectoryEntry entry = new DirectoryEntry();
// "LDAP://CN=<group name>, CN =<Users>, DC=<domain component>, DC=<domain component>,..."
entry.Path = "LDAP://...";
entry.AuthenticationType = AuthenticationTypes.Secure;
DirectorySearcher search = new DirectorySearcher(entry);
search.Filter = "(SAMAccountName=" + accountName + ")";
search.PropertiesToLoad.Add(propertyName);
SearchResultCollection results = search.FindAll();
if (results != null && results.Count > 0)
{
return results[0].Properties[propertyName][0].ToString();
}
else
{
return "Unknown User";
}
}
Use this:
string displayName = UserPrincipal.Current.DisplayName;
In case anyone cares I managed to crack this one:
/// This is some imaginary code to show you how to use it
Session["USER"] = User.Identity.Name.ToString();
Session["LOGIN"] = RemoveDomainPrefix(User.Identity.Name.ToString()); // not a real function :D
string ldappath = "LDAP://your_ldap_path";
// "LDAP://CN=<group name>, CN =<Users>, DC=<domain component>, DC=<domain component>,..."
Session["cn"] = GetAttribute(ldappath, (string)Session["LOGIN"], "cn");
Session["displayName"] = GetAttribute(ldappath, (string)Session["LOGIN"], "displayName");
Session["mail"] = GetAttribute(ldappath, (string)Session["LOGIN"], "mail");
Session["givenName"] = GetAttribute(ldappath, (string)Session["LOGIN"], "givenName");
Session["sn"] = GetAttribute(ldappath, (string)Session["LOGIN"], "sn");
/// working code
public static string GetAttribute(string ldappath, string sAMAccountName, string attribute)
{
string OUT = string.Empty;
try
{
DirectoryEntry de = new DirectoryEntry(ldappath);
DirectorySearcher ds = new DirectorySearcher(de);
ds.Filter = "(&(objectClass=user)(objectCategory=person)(sAMAccountName=" + sAMAccountName + "))";
SearchResultCollection results = ds.FindAll();
foreach (SearchResult result in results)
{
OUT = GetProperty(result, attribute);
}
}
catch (Exception t)
{
// System.Diagnostics.Debug.WriteLine(t.Message);
}
return (OUT != null) ? OUT : string.Empty;
}
public static string GetProperty(SearchResult searchResult, string PropertyName)
{
if (searchResult.Properties.Contains(PropertyName))
{
return searchResult.Properties[PropertyName][0].ToString();
}
else
{
return string.Empty;
}
}
There is a CodePlex project for Linq to AD, if you're interested.
It's also covered in the book LINQ Unleashed for C# by Paul Kimmel - he uses the above project as his starting point.
not affiliated with either source - I just read the book recently