C# 使用 PrincipalSearcher 查找带有“or”参数的用户

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/10606334/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-09 14:28:50  来源:igfitidea点击:

Using PrincipalSearcher to find users with "or" parameters

c#.netactive-directory

提问by doobist

Is it possible to use System.DirectoryServices.AccountManagement.PrincipalSearcherto search based on multiple parameters using "or" (not "and").

是否可以System.DirectoryServices.AccountManagement.PrincipalSearcher使用“或”(而不是“和”)基于多个参数进行搜索。

i.e.

IE

// This uses an and
//(&(objectCategory=person)(!UserAccountControl:1.2.840.113556.1.4.803:=2)(&(SAMAccountName=tom*)(DisplayName=tom*)))
var searchPrinciple = new UserPrincipal(context);
searchPrinciple.DisplayName =  "tom*";
searchPrinciple.SamAccountName = "tom*";

var searcher = new PrincipalSearcher();
searcher.QueryFilter = searchPrinciple;

var results = searcher.FindAll();

and I would like a search similar to this (in LDAP) using PrincipalSearcher(not DirectorySearcher)

我想使用PrincipalSearcher(not DirectorySearcher) 进行与此类似的搜索(在 LDAP 中)

// (&(objectCategory=person)(!UserAccountControl:1.2.840.113556.1.4.803:=2)(|(SAMAccountName=tom*)(DisplayName=tom*)))

回答by Alan Araya

The FindAll method searches the domain specified in the principal context for objects that have identical properties to those set on the query filter. The FindAll method returns all objects that match the supplied object whereas the FindOne method returns only a single matching principal object. http://msdn.microsoft.com/en-us/library/bb384378(v=vs.90).aspx

FindAll 方法在主体上下文中指定的域中搜索具有与查询过滤器上设置的属性相同的属性的对象。FindAll 方法返回与提供的对象匹配的所有对象,而 FindOne 方法仅返回一个匹配的主体对象。 http://msdn.microsoft.com/en-us/library/bb384378(v=vs.90).aspx

I don't know what you need, but you could do a search by 1 proprety and 1 by other and then use LINQ on the lists to merge,filter and etc...

我不知道您需要什么,但是您可以按 1 个属性和 1 个按其他进行搜索,然后在列表中使用 LINQ 进行合并、过滤等...

回答by Bedouin

It's obviously not possible, here is a workaround:

这显然是不可能的,这是一个解决方法:

List<UserPrincipal> searchPrinciples = new List<UserPrincipal>();
searchPrinciples.Add(new UserPrincipal(context) { DisplayName="tom*"});
searchPrinciples.Add(new UserPrincipal(context) { SamAccountName = "tom*" });
searchPrinciples.Add(new UserPrincipal(context) { MiddleName = "tom*" });
searchPrinciples.Add(new UserPrincipal(context) { GivenName = "tom*" });

List<Principal> results = new List<Principal>();
var searcher = new PrincipalSearcher();
foreach (var item in searchPrinciples)
{
    searcher = new PrincipalSearcher(item);
    results.AddRange(searcher.FindAll());
}

回答by AeroX

Not necessarily as clean as some of the other answers but here is how I've implemented this in a project I'm working on. I wanted both searches to be run async to try and reduce any slow down due to running two AD queries.

不一定像其他一些答案一样干净,但这是我在我正在从事的项目中实现这一点的方式。我希望两个搜索都异步运行,以尝试减少由于运行两个 AD 查询而导致的任何减速。

public async static Task<List<ADUserEntity>> FindUsers(String searchString)
{
    searchString = String.Format("*{0}*", searchString);
    List<ADUserEntity> users = new List<ADUserEntity>();

    using (UserPrincipal searchMaskDisplayname = new UserPrincipal(domainContext) { DisplayName = searchString })
    using (UserPrincipal searchMaskUsername = new UserPrincipal(domainContext) { SamAccountName = searchString })
    using (PrincipalSearcher searcherDisplayname = new PrincipalSearcher(searchMaskDisplayname))
    using (PrincipalSearcher searcherUsername = new PrincipalSearcher(searchMaskUsername))
    using (Task<PrincipalSearchResult<Principal>> taskDisplayname = Task.Run<PrincipalSearchResult<Principal>>(() => searcherDisplayname.FindAll()))
    using (Task<PrincipalSearchResult<Principal>> taskUsername = Task.Run<PrincipalSearchResult<Principal>>(() => searcherUsername.FindAll()))
    {
        foreach (UserPrincipal userPrincipal in (await taskDisplayname).Union(await taskUsername))
            using (userPrincipal)
            {
                users.Add(new ADUserEntity(userPrincipal));
            }
    }

    return users.Distinct().ToList();
}

My ADUserEntity class has an equality check based on the SID. I tried to add the Distinct()on to the Union()of the two searcher results but that didn't work.

我的 ADUserEntity 类具有基于 SID 的相等性检查。我试图将Distinct()加到Union()两个搜索器结果中,但这没有用。

I welcome any constructive criticism on my answer as I'd like to know if there is any way I can improve it.

我欢迎对我的回答提出任何建设性的批评,因为我想知道是否有任何方法可以改进它。

回答by Mohtashim

PrincipalContext pContext = new PrincipalContext(ContextType.Machine, Environment.MachineName);
GroupPrincipal gp = GroupPrincipal.FindByIdentity(pContext, "Administrators");
bool isMember = UserPrincipal.Current.IsMemberOf(gp);

回答by Jaime Still

I know this is kind of late, but this is the construct I use when searching AD:

我知道这有点晚了,但这是我在搜索 AD 时使用的构造:

public static Task<IEnumerable<SomeUserModelClass>> GetUsers(//Whatever filters you want)
{
    return Task.Run(() =>
    {
        PrincipalContext context = new PrincipalContext(ContextType.Domain);
        UserPrincipal principal = new UserPrincipal(context);
        principal.Enabled = true;
        PrincipalSearcher searcher = new PrincipalSearcher(principal);

        var users = searcher.FindAll().Cast<UserPrincipal>()
            .Where(x => x.SomeProperty... // Perform queries)
            .Select(x => new SomeUserModelClass
            {
                userName = x.SamAccountName,
                email = x.UserPrincipalName,
                guid = x.Guid.Value
            }).OrderBy(x => x.userName).AsEnumerable();

        return users;
    });
}