2012-05-15 13 views
23

Czy można użyć System.DirectoryServices.AccountManagement.PrincipalSearcher do wyszukiwania na podstawie wielu parametrów za pomocą "lub" (nie "i").Korzystanie z PrincipalSearcher w celu znalezienia użytkowników z "lub" parametrami

tj

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

i chciałbym poszukiwania podobnego do tego (w LDAP) korzystając PrincipalSearcher (nie DirectorySearcher)

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

Odpowiedz

-4

Metoda FindAll przeszukuje domenę podaną w mocodawcy kontekst dla obiektów o identycznych właściwościach niż ustawione w filtrze zapytań . Metoda FindAll zwraca wszystkie obiekty, które pasują do dostarczonego obiektu , natomiast metoda FindOne zwraca tylko jeden zgodny obiekt główny zgodny z . http://msdn.microsoft.com/en-us/library/bb384378(v=vs.90).aspx

Nie wiem, co trzeba, ale można zrobić wyszukiwania przez 1 proprety i 1 innych, a następnie użyć LINQ na listach do scalania, filtr i etc ...

+0

Tak, to jest obejście Obecnie używam, miałem nadzieję nie byłoby sposób zrobić to czysto, w jednym wyszukiwaniu. W każdym razie dzięki. – doobist

13

to abviously niemożliwe, tu jest 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

Będziesz musiał obsługiwać duplikaty używając tego. Jeśli wyświetlana nazwa, imię i nazwa konta zawierają nazwę "tom", będziesz mieć duplikaty. –

+0

Ja też tego chciałem, chociaż w punkcie wielu zapytań jest znacznie mniej wydajne? Zastanawiam się, dlaczego nie powinienem po prostu wrócić do DirectorySearchera, jeśli nie można tego zrobić przy użyciu PrincipalSearcher – PandaWood

4

niekoniecznie tak czysty, jak w niektórych innych odpowiedzi, ale tutaj jest jak mam to realizowane w projekcie pracuję nad. Chciałem, aby oba wyszukiwania były uruchamiane asynchronicznie, aby zmniejszyć spowolnienie spowodowane uruchomieniem dwóch zapytań 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(); 
} 

Moja klasa ADUserEntity ma kontrolę równości na podstawie identyfikatora SID. Próbowałem dodać Distinct() do Union() dwóch wyników wyszukiwania, ale to nie zadziałało.

Z zadowoleniem przyjmuję każdą konstruktywną krytykę mojej odpowiedzi, ponieważ chciałbym wiedzieć, czy jest jakikolwiek sposób, aby ją poprawić.

+1

Aby uzyskać tylko różnych użytkowników, możesz użyć LINQ do grupowania według identyfikatora (np. SID): Zastąp 'return users.Distinct() .ToList(); 'z' return users.GroupBy (user => user.Sid). Wybierz (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

Wiem, że to trochę późno, ale jest to konstrukt korzystać przy szukaniu 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

Zasadniczo czytasz cały katalog, i przeprowadzanie filtrowania w kliencie. Nie będzie to skalowalne dla żadnego katalogu średniej wielkości i większego. –

+0

Od tego czasu dodałem, przed wykonaniem wyszukiwania, filtrowanie do obiektu UserPrincipal i zawężenie zakresu wyszukiwania do konkretnej początkowej jednostki organizacyjnej. –

Powiązane problemy