2012-05-15 7 views
23

Es posible usar System.DirectoryServices.AccountManagement.PrincipalSearcher para buscar en base a múltiples parámetros usando "o" (no "y").Uso de PrincipalSearcher para buscar usuarios con "o" parámetros

es decir

// 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(); 

y me gustaría una búsqueda similar a esta (en LDAP) utilizando PrincipalSearcher (no DirectorySearcher)

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

Respuesta

-4

El método FindAll busca en el dominio especificado en el director contexto para objetos que tienen propiedades idénticas a las establecidas en el filtro de consulta . El método FindAll devuelve todos los objetos que coinciden con el objeto suministrado , mientras que el método FindOne devuelve solo un único objeto principal coincidente . http://msdn.microsoft.com/en-us/library/bb384378(v=vs.90).aspx

No sé lo que necesita, pero se puede hacer una búsqueda por 1 PROPRETY y 1 por otro y luego utilizar LINQ en las listas de fusionar, filtro y etc ...

+0

Sí, esta es la solución que estoy usando actualmente, esperaba que habría una manera de hacer esto más limpiamente, en una búsqueda. Gracias sin embargo. – doobist

13

es abviously no es posible, aquí hay una workarround:

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()); 
} 
+2

Tendrá que manejar duplicados con esto. Si el nombre para mostrar, el nombre y el nombre de la cuenta contienen el nombre "tom", tendrá duplicados. –

+0

Yo también quería esto, aunque en el punto de múltiples consultas ¿es significativamente menos eficiente? Me pregunto por qué no debería recurrir al DirectorySearcher si no se puede hacer con PrincipalSearcher – PandaWood

4
no

necesariamente tan limpio como algunas de las otras respuestas, pero aquí es cómo he implementado esto en un proyecto que estoy trabajando. Quería que ambas búsquedas se ejecutaran de manera sincronizada para intentar reducir cualquier ralentización debido a la ejecución de dos consultas de 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(); 
} 

Mi clase ADUserEntity tiene una comprobación de igualdad basada en el SID. Traté de agregar el Distinct() al Union() de los dos resultados del buscador pero eso no funcionó.

Agradezco cualquier crítica constructiva a mi respuesta, ya que me gustaría saber si hay alguna manera de mejorarla.

+1

. Para obtener solo usuarios distintos devueltos, puede usar LINQ para agruparlos mediante un identificador (por ejemplo, SID): Reemplazar 'return users.Distinct() .ToList(); 'con' return users.GroupBy (user => user.Sid) .Seleccione (group => group.First()). ToList(); ' –

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

Sé que esto es un poco tarde, pero este es el constructo que uso en la búsqueda de 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; 
    }); 
} 
+0

Básicamente está leyendo todo el directorio, y realizando el filtrado en el cliente. Esto no se escalará para ningún directorio de tamaño mediano y más grande. –

+0

Desde entonces, he agregado, antes de ejecutar la búsqueda, el filtrado al objeto UserPrincipal y el alcance de la búsqueda a una unidad organizativa inicial específica. –

Cuestiones relacionadas