如何从C#中的Active Directory获取自定义字段?

Bri*_*egg 6 c# active-directory

我已经阅读了大量类似的StackOverflow问题但似乎没有解决我看到的问题.如果我使用userprincipalname查询用户,我会返回一个包含34个属性的搜索结果.没有返回任何自定义属性.如果我使用像employeeNumber这样的自定义属性再次查询,我会得到71个属性的结果.包括所有自定义属性.

我的问题是我在运行时没有employeeNumber,只有userprincipalname.我需要一直恢复所有自定义属性.希望这是有道理的.这是我的练习代码:

string sid = "";
using (PrincipalContext context = new PrincipalContext(ContextType.Domain))
{
    UserPrincipal user = UserPrincipal.Current;
    //sid = user.SamAccountName;
    sid = user.UserPrincipalName;
    //sid = user.Sid.ToString();

    DirectoryEntry entry = user.GetUnderlyingObject() as DirectoryEntry;
    if (entry.Properties.Contains("employeeNumber"))
    {
        //this doesn't work
    }
}

DirectoryEntry ldapConnection = new DirectoryEntry("companyname.com");
ldapConnection.Path = "LDAP://DC=companyname,DC=com";
ldapConnection.AuthenticationType = AuthenticationTypes.Secure;

DirectorySearcher search = new DirectorySearcher(ldapConnection);
search.Filter = string.Format("(&(ObjectClass=user)(userprincipalname={0}))", sid); // <-- this doesn't get custom properties
//search.Filter = string.Format("(employeeNumber={0})", "11663"); <-- this works

var result = search.FindOne(); // FindOne();
if (result.Properties.Contains("employeeNumber"))
{
    //this never happens either :(
}
Run Code Online (Sandbox Code Playgroud)

以上永远不会返回employeeNumber字段,但如果我取消注释第二个search.Filter行并按employeeNumber手动搜索,我会找到一个结果,它包含我需要的所有字段.

编辑:我发现了一个很好的MSDN文章下面介绍如何扩展UserPrincipal对象来获取自定义属性.唯一的问题是,每次访问它时它都会给我一个空字符串,即使我已经验证了属性是在AD中设置的!任何帮助表示赞赏.

编辑2:这是自定义主要扩展的代码:

[DirectoryRdnPrefix("CN")]
[DirectoryObjectClass("Person")]
public class UserPrincipalExtension : UserPrincipal
{
    public UserPrincipalExtension(PrincipalContext context)
        : base(context)
    {
    }

    public UserPrincipalExtension(PrincipalContext context, string samAccountName, string password, bool enabled)
        : base(context, samAccountName, password, enabled)
    {
    }

    public static new UserPrincipalExtension FindByIdentity(PrincipalContext context, IdentityType type, string identityValue)
    {
        return (UserPrincipalExtension)FindByIdentityWithType(context, typeof(UserPrincipalExtension), type, identityValue);
    }

    PersonSearchFilter searchFilter;
    new public PersonSearchFilter AdvancedSearchFilter
    {
        get
        {
            if (searchFilter == null)
                searchFilter = new PersonSearchFilter(this);

            return searchFilter;
        }
    }

    [DirectoryProperty("employeeNumber")]
    public string EmployeeNumber
    {
        get
        {
            if (ExtensionGet("employeeNumber").Length != 1)
                return string.Empty;

            return (string)ExtensionGet("employeeNumber")[0];
        }
        set
        {
            ExtensionSet("employeeNumber", value);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

和自定义搜索过滤器:

public class PersonSearchFilter : AdvancedFilters
{
    public PersonSearchFilter(Principal p)
        : base(p)
    {
    }

    public void SAMAccountName(string value, MatchType type)
    {
        this.AdvancedFilterSet("sAMAccountName", value, typeof(string), type);
    }
}
Run Code Online (Sandbox Code Playgroud)

用法:

UserPrincipalExtension filter = new UserPrincipalExtension(context);
filter.AdvancedSearchFilter.SAMAccountName(UserPrincipal.Current.SamAccountName, MatchType.Equals);
PrincipalSearcher search = new PrincipalSearcher(filter);

foreach (var result in search.FindAll())
{
    var q = (UserPrincipalExtension)result;
    var m = q.EmployeeNumber;
}
Run Code Online (Sandbox Code Playgroud)

var m始终为空字符串,即使所有AD条目都有employeeNumber.

编辑:从活动目录: 活动目录

Sco*_*ain 3

我对如何修复你的第二种方法更有信心,所以我会首先回答这个问题。DirectorySearcher.PropertiesToLoad当您搜索要显示的属性时,您需要指定该属性。

DirectorySearcher search = new DirectorySearcher(ldapConnection);
search.Filter = string.Format("(&(ObjectClass=user)(userprincipalname={0}))", sid); 
search.PropertiesToLoad.Add("employeeNumber");

var result = search.FindOne(); // FindOne();
if (result.Properties.Contains("employeeNumber"))
{
    //This should now work.
}
Run Code Online (Sandbox Code Playgroud)

它起作用的原因string.Format("(employeeNumber={0})", "11663");是因为您添加的任何搜索子句都会自动放入 PropertiesToLoad 集合中。


对于您的第一个方法,我认为您需要调用DirectoryEntry.RefreshCache并传入属性才能使其显示。

string sid = "";
using (PrincipalContext context = new PrincipalContext(ContextType.Domain))
{
    UserPrincipal user = UserPrincipal.Current;
    //sid = user.SamAccountName;
    sid = user.UserPrincipalName;
    //sid = user.Sid.ToString();

    DirectoryEntry entry = user.GetUnderlyingObject() as DirectoryEntry;

    entry.RefreshCache(new[] {"employeeNumber"});

    if (entry.Properties.Contains("employeeNumber"))
    {

    }
}
Run Code Online (Sandbox Code Playgroud)

但我不能 100% 确定这是否有效。


对于您的自定义用户主体,我不确定出了什么问题。我看到你正在做的事情和我在一个我知道有效的项目中所做的事情之间的唯一区别是你使用[DirectoryObjectClass("Person")]但我有[DirectoryObjectClass("user")]。也许这就是问题所在

[DirectoryRdnPrefix("CN")]
[DirectoryObjectClass("user")] //Maybe this will fix it???
public class UserPrincipalExtension : UserPrincipal
{
Run Code Online (Sandbox Code Playgroud)