The below code works on my local machine by returning the user's full name from Active Directory:
string principal = System.Web.HttpContext.Current.Request.LogonUserIdentity.Name.Remove(0, 12);
string filter = string.Format("(&(ObjectClass={0})(sAMAccountName={1}))", "person", principal);
string[] properties = new string[] { "fullname" };
DirectoryEntry adRoot = new DirectoryEntry("LDAP://myserver.com");
adRoot.AuthenticationType = AuthenticationTypes.Secure;
DirectorySearcher searcher = new DirectorySearcher(adRoot);
searcher.SearchScope = SearchScope.Subtree;
searcher.ReferralChasing = ReferralChasingOption.All;
searcher.PropertiesToLoad.AddRange(properties);
searcher.Filter = filter;
SearchResult result = searcher.FindOne();
DirectoryEntry directoryEntry = result.GetDirectoryEntry();
string displayName = directoryEntry.Properties["displayName"][0].ToString();
if (string.IsNullOrEmpty(displayName) == false)
{
return displayName;
}
When I publish it to the development server I get the following error:
System.NullReferenceException: Object reference not set to an instance
of an object.
The error is thrown on the following line:
DirectoryEntry directoryEntry = result.GetDirectoryEntry();
I have tried
DirectoryEntry adRoot = new DirectoryEntry("LDAP://" + domain, AdAdminUsername, AdAdminPassword, AuthenticationTypes.Secure);
but still no joy.
Any ideas?
Thanks!
Just from outside : your string called principal is built by the following :
string principal = System.Web.HttpContext.Current.Request.LogonUserIdentity.Name.Remove(0, 12);
Have you log 'System.Web.HttpContext.Current.Request.LogonUserIdentity.Name' on your dev server ? This static construction may be the begining of you troubles because if principal is'nt what you think it is, the result of FindOne may be NULL.
In your current code, you must check for NULL after the call to FindOne() - it could return a NULL value if no matching directory entry was found.
See the MSDN docs:
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.
Plus, you should also always check for the presence of a property before accessing it - it could be absent.....
Therefore, your code should be something like this:
SearchResult result = searcher.FindOne();
if(result != null)
{
DirectoryEntry directoryEntry = result.GetDirectoryEntry();
if(directoryEntry.Properties["displayName"] != null &&
directoryEntry.Properties["displayName"].Length > 0)
{
string displayName = directoryEntry.Properties["displayName"][0].ToString();
if (!string.IsNullOrEmpty(displayName))
{
return displayName;
}
}
}
But: if you're on .NET 3.5 or newer, you should check out the System.DirectoryServices.AccountManagement namespace which makes a lot of things a lot easier when dealing with Active Directory.
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 first name (GivenName) of "Bruce"
UserPrincipal qbeUser = new UserPrincipal(ctx);
qbeUser.SamAccountName = "whatever you're looking for.....";
// 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
Of course, depending on your need, you might want to specify other properties on that "query-by-example" user principal you create:
Surname (or last name)
DisplayName (typically: first name + space + last name)
SAM Account Name - your Windows/AD account name
User Principal Name - your "username#yourcompany.com" style name
You can specify any of the properties on the UserPrincipal and use those as "query-by-example" for your PrincipalSearcher.
Related
I'm trying to search using the System.DirectoryServices.AccountManagement library in c#. The goal is to find an AD user with the pager field containing a string.
For example, if I have .pager = "F1234b!#" I need to find a user who's pager field contains "1234".
I can't figure out how to search the contents of the pager field in s.ds.am to contain a string.
If you want to experiment with S.DS.AM, try using this method. Put a breakpoint at the return listPrincipal line and inspect each of the principal variables for what they contain.
private static List<Principal> GetPrincipalList (string strPropertyValue, string strDomainController)
{
List<Principal> listPrincipal = null;
Principal principal = null;
GroupPrincipal groupPrincipal = null;
UserPrincipal userPrincipal = null;
ComputerPrincipal computerPrincipal = null;
PrincipalSearchResult<Principal> listPrincipalSearchResult = null; // Groups
PrincipalContext principalContext = null;
ContextType contextType;
IdentityType identityType;
try
{
// Setup a UserPrincipal list.
listPrincipal = new List<Principal>();
// Set the contextType to Domain because we are going through the AD directory store.
contextType = ContextType.Domain;
// Setup a domain context.
principalContext = new PrincipalContext(contextType, strDomainController);
// Setup the IdentityType. This is required, otherwise you will get a MultipleMatchesException error that says "Multiple principals contain a matching Identity."
// This happens when you have two objects that AD thinks match whatever you're passing to UserPrincipal.FindByIdentity(principalContextDomain, strPropertyValue)
// Use IdentityType.Guid because GUID is unique and never changes for a given object.
identityType = IdentityType.Guid;
// Find user.
principal = Principal.FindByIdentity(principalContext, identityType, strPropertyValue);
groupPrincipal = GroupPrincipal.FindByIdentity(principalContext, identityType, strPropertyValue);
userPrincipal = UserPrincipal.FindByIdentity(principalContext, identityType, strPropertyValue);
computerPrincipal = ComputerPrincipal.FindByIdentity(principalContext, identityType, strPropertyValue);
// Return the listPrincipal list.
return listPrincipal;
}
finally
{
// Cleanup objects.
listPrincipal = null;
listPrincipalSearchResult = null;
principalContext = null;
groupPrincipal = null;
userPrincipal = null;
computerPrincipal = null;
}
}
Use the * character as a wildcard. For example, in the filter criteria for DirectoryEntry, you can use the following:
(&(objectCategory=person)(objectClass=user)(pager=*1234*))
https://social.technet.microsoft.com/wiki/contents/articles/5392.active-directory-ldap-syntax-filters.aspx
https://msdn.microsoft.com/en-us/library/ms679102(v=vs.85).aspx
Also, be careful using S.DS.AM. I know it provides a lot of useful functionality, but it is much slower than S.DS.AD.
Active Directory: The Principal Class - S.DS.AM vs S.DS.AD
Update:
Keep in mind that Microsoft introduced the following classes in the S.DS.AM namespace wrapper:
UserPrincipal
ComputerPrincipal
GroupPrincipal
https://msdn.microsoft.com/en-us/library/system.directoryservices.accountmanagement.principal.aspx
Study the inheritance hierarchy and inspect the properties/attributes that are available -
WYSWIG. If the attribute that you want to search for is not included then you will not be able to use S.DS.AM - you will need to use S.DS.AD.
The * wildcard still stands when searching for properties that are available within the Principal class that contain specific character strings.
A useful post when searching on available properties in S.DS.AM: search by samaccountname with wildcards
Update 2:
I ran across the following post on SO that might be useful for what you are trying to do: How to get Active Directory Attributes not represented by the UserPrincipal class
I am trying to fetch all the users of particular group from Active Directory of LDAP server. Authentication becomes success but i am getting null in result.
Following is my code.
Domain-172.11.12.123
Email-sample#email.com
password-123456
using (var context = new DirectoryEntry(user.Domain, user.Email, user.Password, AuthenticationTypes.Secure))
{
try
{
string FirstName;
string LastName;
string ADUserName;
string Email;
using (var searcher = new DirectorySearcher(context))
{
searcher.Filter = "(&((&(objectCategory=Person)(objectClass=User)))(samaccountname='user3'))";
List<string> Adusers = new List<string>();
System.DirectoryServices.SearchResult result = searcher.FindOne();
}
}
catch (Exception ex)
{
TempData["message"] = "error";
return RedirectToAction("Index", "ADuserList");
}
}
What wrong is going on.
Thanks in advance
If you're on .NET 3.5 and up, you should check out the System.DirectoryServices.AccountManagement (S.DS.AM) namespace.
Basically, you can define a domain context and easily find users and/or groups in AD:
// set up domain context for the currently connected AD domain
using (PrincipalContext ctx = new PrincipalContext(ContextType.Domain))
{
// 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!
Read more about it here:
MSDN docs on System.DirectoryServices.AccountManagement
Update: in order to get all the users of a given OU, the approach is quite different.
You need to create a separate PrincipalContext that defines what OU you're interested in - then you need to use a PrincipalSearcher to get all the users from that OU:
// create your domain context and define what OU to use:
using (PrincipalContext ctx = new PrincipalContext(ContextType.Domain, null, "OU=YourOU,OU=SubOU,dc=YourCompany,dc=com"))
{
// 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())
{
// do whatever here - "found" is of type "Principal" - it could be user, group, computer.....
}
}
I have read several posts, but I haven't been able to get anything to work for me. I would like to create an arraylist of all display names within the "Standard Users" OU. I will then use that arraylist to populate a dropdown list. I found the following in another thread, but it provides groups and not users within the specified OU:
public ArrayList Groups()
{
ArrayList groups = new ArrayList();
foreach (System.Security.Principal.IdentityReference group in
System.Web.HttpContext.Current.Request.LogonUserIdentity.Groups)
{
groups.Add(group.Translate(typeof
(System.Security.Principal.NTAccount)).ToString());
}
return groups;
}
Can this be modified to provide the list of users in the Standard Users OU? Or should I use a different approach?
I also found this, but I get an error (red lines under 'std_users') stating 'not all code paths return a value'.
public ArrayList std_users()
{
// List of strings for your names
List<string> allUsers = new List<string>();
// create your domain context and define the OU container to search in
PrincipalContext ctx = new PrincipalContext(ContextType.Domain, "myco.org", "OU=Standard Users, dc=myco, dc=org");
// define a "query-by-example" principal - here, we search for a UserPrincipal (user)
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.....
allUsers.Add(found.DisplayName);
}
}
Any help would be greatly appreciated.
I am using c#, Visual Studio 2013 and the framework is 4.5.1.
First off: STOP USING ArrayList - that type is dead since .NET 2.0 and should not be used - use List<string> (or more generally: List<T>) instead - much better for performance and usability!
You can use a PrincipalSearcher and a "query-by-example" principal to do your searching:
public List<string> GetAllEmailsFromUsersContainer()
{
List<string> users = new List<string>();
// create your domain context and bind to the standard CN=Users
// container to get all "standard" users
using (PrincipalContext ctx = new PrincipalContext(ContextType.Domain, null, "CN=Users,dc=YourCompany,dc=com"))
{
// define a "query-by-example" principal - here, we search for a UserPrincipal
// which is not locked out, and has an e-mail address
UserPrincipal qbeUser = new UserPrincipal(ctx);
qbeUser.IsAccountLockedOut = false;
qbeUser.EmailAddress = "*";
// create your principal searcher passing in the QBE principal
PrincipalSearcher srch = new PrincipalSearcher(qbeUser);
// find all matches
foreach(var found in srch.FindAll())
{
users.Add(found.EmailAddress);
}
}
return users;
}
Add return allUsers; to std_users() and let us know if that works for you.
I am trying to get the user information for a specific domain which will be the input of the program. On the basis of the domain name it should return the list of the users name/ or NT Id and SID of the user. I am new for the ldap programming can any one help me for get this list.
If you're on .NET 3.5 and up and talking about Active Directory, then 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....
var usersSid = user.Sid;
// not sure what you mean by "username" - the "DisplayName" ? The "SAMAccountName"??
var username = user.DisplayName;
var userSamAccountName = user.SamAccountName;
}
The new S.DS.AM makes it really easy to play around with users and groups in AD!
Update: if you need to loop through all the users of a domain - try this:
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
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())
{
UserPrincipal user = found as UserPrincipal;
if(user != null)
{
// do whatever here
var usersSid = user.Sid;
// not sure what you mean by "username" - the "DisplayName" ?
var username = user.DisplayName;
var userSamAccountName = user.SamAccountName;
}
}
Update #2: if you can't (or don't want to) use the S.DS.AM approach - which is the easiest, for Active Directory, by far - then you need to fall back to the System.DirectoryServices classes and methods:
// define the root of your search
DirectoryEntry root = new DirectoryEntry("LDAP://dc=YourCompany,dc=com");
// set up DirectorySearcher
DirectorySearcher srch = new DirectorySearcher(root);
srch.Filter = "(objectCategory=Person)";
srch.SearchScope = SearchScope.Subtree;
// define properties to load
srch.PropertiesToLoad.Add("objectSid");
srch.PropertiesToLoad.Add("displayName");
// search the directory
foreach(SearchResult result in srch.FindAll())
{
// grab the data - if present
if(result.Properties["objectSid"] != null && result.Properties["objectSid"].Count > 1)
{
var sid = result.Properties["objectSid"][0];
}
if(result.Properties["displayName"] != null && result.Properties["displayName"].Count > 0)
{
var userName = result.Properties["displayName"][0].ToString();
}
}
I am searching LDAP using the following code in C# to poll active directory for users:
DirectoryEntry entry = new DirectoryEntry(ldapPath, userName, password);
DirectorySearcher Searcher = new DirectorySearcher(entry);
Searcher.CacheResults = true;
Searcher.SearchScope = SearchScope.Subtree;
Searcher.Filter = "(&(&(objectCategory=person)(objectClass=user))
(|(samaccountname=" + userSearch.SamAccountName + "*)
(&(GivenName=" + userSearch.FirstName + "*)(SN=" + userSearch.Surname +
"*))))";
Searcher.PropertiesToLoad.AddRange(new string[] {"DisplayName", "GivenName",
"DistinguishedName","Title","manager",
"mail", "physicalDeliveryOfficeName", "DirectReports", "Company",
"Description", "SAMAccountName"});
SearchResultCollection results = Searcher.FindAll();
List<ActiveUser> activeUsers = new List<ActiveUser>();
I ran it with the input parameters userSearch.FirstName = "jo" and userSearch.LastName = "bl" and was expecting one user "Joe Bloggs", but this didn't appear in the result list. If I try this using the name textbox in Active Directory Users and Computers tool in Windows, Joe Bloggs appears as the only user in the list. I am using the correct LDAP path. Am I using the wrong filter to replicate the functionality in the windows tool? Is there a 'like' search on display name?
Any help would be appreciated.
If you're on .NET 3.5 or up, 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 first name (GivenName) of "Bruce"
UserPrincipal qbeUser = new UserPrincipal(ctx);
qbeUser.GivenName = "Jo*";
qbeUser.Surname = "Bl*";
// 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