Reputation: 3498
I would like to get some additional AD attributes from the AD user. I want to use PrincipalSearcher
instead of DirectorySearcher
.
What I did was get the underlyingSearcher of the PrincipalSearcher and called FindOne() method. I don't like to use GetUnderlyingSearcher from PrincipalSearcher, but apparently it works.
The code works, but I'm wondering if there is a way to read additional properties/Ad attributes from Principal
Principal match = principalSearcher.FindOne();
Additionally could below code have some problems because we are using the underlyingSearcher (DirectorySearcher) methods.
I find PrincipalSearcher
more higher level and also if I would use DirectorySearcher the ldapPath must be defined e.g. var ldapPath = "DC=corp,DC=ad,DC=example,DC=com";
It's just less lines of code.
public AdSimpleObject GetUser(string userName, string domainName)
{
PrincipalContext principalContext = new PrincipalContext(ContextType.Domain, domainName);
UserPrincipal userPrincipal = new UserPrincipal(principalContext);
userPrincipal.SamAccountName = userName; // where condition
using (PrincipalSearcher principalSearcher = new PrincipalSearcher(userPrincipal))
{
using (DirectorySearcher ds = (DirectorySearcher)principalSearcher.GetUnderlyingSearcher())
{
// get only properties we need, therefore search performance is increased
ds.PropertiesToLoad.Clear();
ds.PropertiesToLoad.AddRange(new string[]
{
"sAMAccountType",
"sAMAccountName",
"userPrincipalName",
"msDS-PrincipalName"
});
SearchResult match = ds.FindOne();
if (match != null)
{
AdSimpleObject ado = this.CreateAdSimpleObject(match);
return ado;
}
return null;
}
}
}
public class AdSimpleObject
{
public string AdsPath { get; set; }
public int SamAccountType { get; set; }
public string SamAccountName { get; set; }
public string MsDsPrincipalName { get; set; }
public string UserPrincipalName { get; set; }
}
private AdSimpleObject CreateAdSimpleObject(SearchResult searchItem)
{
ResultPropertyCollection props = searchItem.Properties;
string adsPath = props["adspath"]?.OfType<string>().ToList().FirstOrDefault() ?? string.Empty;
int samAccountType = props["sAMAccountType"]?.OfType<int>().ToList().FirstOrDefault() ?? 0;
string samAccountName = props["sAMAccountName"]?.OfType<string>().ToList().FirstOrDefault() ?? string.Empty;
string userPrincipalName = props["userPrincipalName"]?.OfType<string>().ToList().FirstOrDefault() ?? string.Empty;
string msDsPrincipalName = props["msDS-PrincipalName"]?.OfType<string>().ToList().FirstOrDefault() ?? string.Empty;
return new AdSimpleObject
{
AdsPath = adsPath,
SamAccountType = samAccountType,
SamAccountName = samAccountName,
UserPrincipalName = userPrincipalName,
MsDsPrincipalName = msDsPrincipalName
};
}
Upvotes: 1
Views: 1714
Reputation: 40988
I'm wondering if there is a way to read additional properties/Ad attributes from
Principal
You would use the DirectoryEntry
object returned from Principal.GetUnderlyingObject
:
Principal match = principalSearcher.FindOne();
var de = (DirectoryEntry) match.GetUnderlyingObject();
de.RefreshCache(new string[] {"someAttribute"});
var someAttribute = de.Properties["someAttribute"].Value;
Doing this will go back out to AD to get the attributes, instead of using the data that was retrieved in the search. The use of RefreshCache
is to tell it to only get the attributes you are interested in. Otherwsie, if you use DirectoryEntry.Properties
right away, it will go out to AD and get all attributes that have a value, which is unlikely what you need, and will just take extra time for no reason.
Additionally could below code have some problems because we are using the underlyingSearcher (DirectorySearcher) methods.
Not at all. That code is no different than just making your own DirectorySearcher
and using it. In fact, with the way you've written this code, there is no real point to using UserPrincipal
/PrincipalSearcher
at all. The only thing it's done for you is build the query string.
The whole AccountManagement
namespace is just a wrapper around DirectoryEntry
/DirectorySearcher
. It makes things easier for the programmer (in some cases, not all), but it does so at the cost of performance.
If you use DirectoryEntry
/DirectorySearcher
yourself directly, you have far more control over how much data is retrieved from AD, and how often network requests are made. Those translate into less time taken. If you're just searching for one account, then it won't make much of a difference. But if you're searching for large groups of users, or looping over a large list of users, it can make a huge difference.
I wrote an article about optimizing performance when talking to AD (specifically with DirectoryEntry
/DirectorySearcher
): Active Directory: Better performance
Upvotes: 3