I have implemented System.DirectoryServices.AccountManagement for authentication into my webapps finding users (UserPrincipal) byidentity given username. However, I have several cases where I need to get AD accounts given only an employeeID. Is there a good way to get a UserPrincipal (or even just the sAMAccountName) given an employeeID in AccountManagement?
I currently have this working to grab users by username:
PrincipalContext adAuth = new PrincipalContext(ContextType.Domain, Environment.UserDomainName);
//get user
UserPrincipal usr = UserPrincipal.FindByIdentity(adAuth, username);
I have been searching and can't seem to find answers to confirm whether this can or cannot be done. If I can't do it with AccountManagement, what's the best way to get sAMAccountName given employeeID?
You don't need to go outside of the System.DirectoryServices.AccountManagement namespace.
UserPrincipal searchTemplate = new UserPrincipal(adAuth);
searchTemplate.EmployeeID = "employeeID";
PrincipalSearcher ps = new PrincipalSearcher(searchTemplate);
UserPrincipal user = (UserPrincipal)ps.FindOne();
In this example, if no user is found the user object will be null. If you want to find a collection of UserPrinicipal object you can use the FindAll method on the PrincipalSearcher (ps) object.
Also note that the FindOne method returns a Principal object, but we know it is really a UserPrincipal and should be handled (casted) as such since UserPrincipal is part of the search filter.
So, I found a way using System.DirectoryServices as below, but it seems rather lengthy:
string username = "";
DirectoryEntry entry = new DirectoryEntry(_path);
//search for a DirectoryEntry based on employeeID
DirectorySearcher search = new DirectorySearcher(entry);
search.Filter = "(employeeID=" + empID + ")";
//username
search.PropertiesToLoad.Add("sAMAccountName");
SearchResult result = search.FindOne();
//get sAMAccountName property
username = result.Properties["sAMAccountName"][0].ToString();
Of course, I could use this for the other attributes, but I really like the strongly-typed attributes with AccountManagement.
Related
I have this code:
public static DataTable ExecutesAMAccountNameQuery(string sAMAccountName)
{
string filter = "(&(objectCategory=person)(objectClass=user)(sAMAccountName=" + sAMAccountName + "))";
return ExecuteADQuery("GC:", filter);
}
It only works with the full username, I dont know the syntax to make it work with wildcards, like a LIKE in sql?
Thanks
If you're using .NET 3.5 or newer, 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);
qbeUser.SamAccountName = "Esteban*";
// 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. Or see the MSDN documentation on the System.DirectoryServices.AccountManagement namespace.
Of course, depending on your need, you might want to specify other properties on that "query-by-example" user principal you create:
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.
I trying to search my organization Active directory for users.
If the FirstName or LastName or DisplayName matches a particular string value, it should return the users.
My Code:
// create your domain context
PrincipalContext ctx = new PrincipalContext(ContextType.Domain);
UserPrincipal qbeUser = new UserPrincipal(ctx);
qbeUser.GivenName = "Ramesh*";
// qbeUser.Surname = "Ramesh*";
// qbeUser.DisplayName= "Ramesh*";
PrincipalSearcher srch = new PrincipalSearcher(qbeUser);
// find all matches
foreach(var found in srch.FindAll())
{
//
}
The problem is that I am able to search by only one filter.
I am able to AND the filters but not OR. Whether any solutions are available?
See a possible solution for this issue in this other SO question.
You will need to use the extensibility of UserPrincipal to create a descendant class, in order to get access to the anr property (anr = ambiguous name resolution) which allows searches in multiple name-related properties at once.
Have a look at the DirectorySearcher.
This article may help.
I have this code:
public static DataTable ExecutesAMAccountNameQuery(string sAMAccountName)
{
string filter = "(&(objectCategory=person)(objectClass=user)(sAMAccountName=" + sAMAccountName + "))";
return ExecuteADQuery("GC:", filter);
}
It only works with the full username, I dont know the syntax to make it work with wildcards, like a LIKE in sql?
Thanks
If you're using .NET 3.5 or newer, 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);
qbeUser.SamAccountName = "Esteban*";
// 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. Or see the MSDN documentation on the System.DirectoryServices.AccountManagement namespace.
Of course, depending on your need, you might want to specify other properties on that "query-by-example" user principal you create:
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.
I use this code:
DirectoryEntry objEntry;
DirectorySearcher objSearchEntry;
SearchResultCollection objSearchResult;
string strFilter = "(&(objectCategory=User))";
objEntry = new DirectoryEntry(conOUPath, conUser, conPwd, AuthenticationTypes.Secure);
objEntry.RefreshCache();
objSearchEntry = new DirectorySearcher(objEntry);
objSearchEntry.Filter=strFilter;
objSearchEntry.SearchScope=SearchScope.Subtree;
objSearchEntry.CacheResults=false;
objSearchResult=objSearchEntry.FindAll();
Each time, it only return 1000 users, but there are 3000 users in that OU.
How can i find all of them ?
If you're on .NET 3.5 or newer, you should check out the PrincipalSearcher and a "query-by-example" principal to do your searching:
// create your domain context
PrincipalContext ctx = new PrincipalContext(ContextType.Domain, "YOURDOMAIN", "OU=SomeOU,DC=YourCompany,DC=com");
// 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 = "Bruce";
// create your principal searcher passing in the QBE principal
PrincipalSearcher srch = new PrincipalSearcher(qbeUser);
// set the PageSize on the underlying DirectorySearcher to get all 3000 entries
((DirectorySearcher)srch.GetUnderlyingSearcher()).PageSize = 500;
// 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
Update:
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.
Update #2: If you want to search just inside a given OU, you can define that OU in the constructor of the PrincipalContext.
You need to set the DirectorySearcher.PageSize property to be able to return all the results. For example:
objSearchEntry.PageSize = 500;
Otherwise the number of items returned will be limited by the limit on the server side, which is 1000 by default. There is also something called SizeLimit, which you can set if you want to explicitly limit the number of returned items. If both SizeLimit and PageSize are 0 (default values) then it will use the server side default SizeLimit. A bit counter-intuitive in my opinion.
If you want to return all the results, the only way is to set PageSize to a non-zero value and SizeLimit to 0.
I'm stumped..
I'm trying to get the userPrincipalName from AD as follows:
DirectorySearcher search = new DirectorySearcher("LDAP://DCHS");
search.Filter = String.Format("(SAMAccountName={0})", UserName);
SearchResult result = search.FindOne();
DirectoryEntry entry = result.GetDirectoryEntry();
_UPN = entry.Properties["userPrincipalName"][0].ToString();
But this gives me:
Index was out of range. Must be non-negative and less than the size of the collection.
Parameter name: index
Can anyone tell me why this is happening?
EDIT:
This code gets the SSID of the current user. I need to make this work on any user I enter into a text box.
WindowsIdentity windowsId = new WindowsIdentity(WindowsIdentity.GetCurrent().Token);
_SSID = windowsId.User.ToString()
I believe the issue is because you are treating the userPrincipalName entry as an array of values. Try modifying your code as follows:
DirectorySearcher search = new DirectorySearcher("LDAP://DCHS");
search.Filter = String.Format("(SAMAccountName={0})", UserName);
SearchResult result = search.FindOne();
DirectoryEntry entry = result.GetDirectoryEntry();
_UPN = entry.Properties["userPrincipalName"].Value.ToString();
Notice that I changed the last line from [0] to Value. That should fix your issue.
The one thing I would say is that I would do some checking before trying to read this value. There are cases where a user wouldn't have a UPN. In that case, the code would throw an error when you tried to access the field (the field wouldn't exist so it wouldn't be that you just need to make sure it isn't null).
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
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 user by name
UserPrincipal user = UserPrincipal.FindByIdentity(UserName);
if(user != null)
{
string upn = user.UserPrincipalName;
}
The new S.DS.AM makes it really easy to play around with users and groups in AD:
The obvious thing to do to avoid the exception (if that's valid) is to do
if (entry.Properties["userPrincipalName"].Count > 0)
{
_UPN = entry.Properties["userPrincipalName"][0].ToString();
}
but if you were supposed to get a valid result and you aren't then I would check the LDAP connection string and such. There are a few LDAP browsers that you could use (commercial + trial) to get your connection string right.