2012-05-15 12 views
23

È possibile utilizzare System.DirectoryServices.AccountManagement.PrincipalSearcher per eseguire la ricerca in base a più parametri utilizzando "o" (non "e").Utilizzo di PrincipalSearcher per trovare utenti con parametri "o"

cioè

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

e vorrei una ricerca simile a questo (in LDAP) utilizzando PrincipalSearcher (non DirectorySearcher)

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

risposta

-4

Il metodo FindAll ricerche il dominio specificato nel principale contesto per oggetti con proprietà identiche a quelle impostate nel filtro di query . Il metodo FindAll restituisce tutti gli oggetti che corrispondono all'oggetto fornito mentre il metodo FindOne restituisce solo un oggetto principale corrispondente corrispondente. http://msdn.microsoft.com/en-us/library/bb384378(v=vs.90).aspx

Non so che cosa avete bisogno, ma si potrebbe fare una ricerca per 1 proprety e 1 da altri e quindi utilizzare LINQ nelle liste di fondere, filtro e ecc ...

+0

Sì, questa è la soluzione Attualmente sto usando, speravo ci sarebbe stato un modo per farlo più pulito, in una ricerca. Grazie comunque. – doobist

13

E 'abviously non è possibile, ecco un 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

Dovrai gestire i duplicati usando questo. Se il nome visualizzato, il nome e il nome dell'account contengono tutti il ​​nome "tom", avrai duplicati. –

+0

Volevo anche questo, anche se al punto di più query è significativamente meno performante? Mi chiedo perché non dovrei ricorrere a DirectorySearcher se non può essere fatto con PrincipalSearcher – PandaWood

4
non

necessariamente pulita come alcune delle altre risposte, ma qui è come ho implementato questo in un progetto su cui sto lavorando. Volevo che entrambe le ricerche fossero eseguite in modo asincrono per cercare di ridurre qualsiasi rallentamento dovuto all'esecuzione di due query di Active Directory.

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

La mia classe ADUserEntity ha un controllo di uguaglianza in base al SID. Ho provato ad aggiungere Distinct() allo Union() dei due risultati di ricerca ma non ha funzionato.

Accolgo con favore qualsiasi critica costruttiva sulla mia risposta in quanto mi piacerebbe sapere se c'è un modo per migliorarlo.

+1

Per ottenere solo utenti distinti restituiti, puoi usare LINQ per raggruppare con un identificatore (es. SID): Sostituisci 'return users.Distinct() .ToList(); 'con' return users.GroupBy (user => user.Sid) .Select (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

So che questo è un po 'tardi, ma questo è il costrutto che uso durante la ricerca dC:

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

Stai praticamente leggendo l'intera directory, e eseguire il filtraggio nel client. Questo non si ridimensionerà per qualsiasi directory di medie dimensioni e più grande. –

+0

Da allora ho aggiunto, prima di eseguire la ricerca, il filtraggio all'oggetto UserPrincipal e il restringimento dell'ambito della ricerca a una specifica OU iniziale. –

Problemi correlati