2012-03-02 10 views
18

Ho utilizzato con successo il codice AccountManagement per recuperare le informazioni di base di AD, ma restituisce solo un insieme molto limitato di informazioni sull'oggetto restituito. Come posso ottenere informazioni estese da AD utilizzando la funzionalità AccountManagement. In particolare il titolo del lavoro o il titolo come sembra essere chiamato nella mia istanza di annuncio.Ottieni il titolo di lavoro utilizzando System.DirectoryServices.AccountManagement

So come farlo utilizzando i vecchi DirectoryServices ma mi piacerebbe sapere come farlo utilizzando il nuovo spazio dei nomi.

risposta

32

Sì, il set predefinito di proprietà su UserPrincipal è piuttosto limitato, ma la parte migliore è: c'è una storia di estensibilità ordinata!

È necessario definire una classe decrescente da UserPrincipal e quindi è possibile ottenere molto facilmente l'accesso a molte più proprietà, se necessario.

Lo scheletro sarebbe simile a questa:

namespace ADExtended 
{ 
    [DirectoryRdnPrefix("CN")] 
    [DirectoryObjectClass("User")] 
    public class UserPrincipalEx : UserPrincipal 
    { 
     // Inplement the constructor using the base class constructor. 
     public UserPrincipalEx(PrincipalContext context) : base(context) 
     { } 

     // Implement the constructor with initialization parameters.  
     public UserPrincipalEx(PrincipalContext context, 
          string samAccountName, 
          string password, 
          bool enabled) : base(context, samAccountName, password, enabled) 
     {} 

     UserPrincipalExSearchFilter searchFilter; 

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

       return searchFilter; 
      } 
     } 

     // Create the "Title" property.  
     [DirectoryProperty("title")] 
     public string Title 
     { 
      get 
      { 
       if (ExtensionGet("title").Length != 1) 
        return string.Empty; 

       return (string)ExtensionGet("title")[0]; 
      } 
      set { ExtensionSet("title", value); } 
     } 

     // Implement the overloaded search method FindByIdentity. 
     public static new UserPrincipalEx FindByIdentity(PrincipalContext context, string identityValue) 
     { 
      return (UserPrincipalEx)FindByIdentityWithType(context, typeof(UserPrincipalEx), identityValue); 
     } 

     // Implement the overloaded search method FindByIdentity. 
     public static new UserPrincipalEx FindByIdentity(PrincipalContext context, IdentityType identityType, string identityValue) 
     { 
      return (UserPrincipalEx)FindByIdentityWithType(context, typeof(UserPrincipalEx), identityType, identityValue); 
     } 
    } 
} 

E questo è davvero quasi tutto quello che c'è! I ExtensionGet e ExtensionSet metodi consentono di "raggiungere down" nella voce di directory sottostante e afferrare tutti gli attributi che potrebbe essere interessato a ....

Ora, nel codice, utilizzare il nuovo UserPrincipalEx classe invece di UserPrincipal :

using (PrincipalContext ctx = new PrincipalContext(ContextType.Domain)) 
{ 
    // Search the directory for the new object. 
    UserPrincipalEx myUser = UserPrincipalEx.FindByIdentity(ctx, "someUserName"); 

    if(myUser != null) 
    { 
     // get the title which is now available on your "myUser" object! 
     string title = myUser.Title; 
    } 
} 

Leggi tutto sulla System.DirectoryServices.AccountManagement spazio dei nomi e la sua storia estensibilità qui:

Aggiornamento: scusate: ecco la classe UserPrincipalExSearchFilter - mancata quella nel post originale. E 'solo mostra la capacità di estendere anche i filtri di ricerca, se necessario:

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

    public void LogonCount(int value, MatchType mt) 
    { 
     this.AdvancedFilterSet("LogonCount", value, typeof(int), mt); 
    } 
} 
+0

Da dove viene questo tipo (UserPrincipalExSearchFilter) viene? Devo creare questo tipo usando il modello sopra? In realtà ho tirato fuori quelle poche righe di codice e sembra funzionare perfettamente (a meno che mi manchi qualcosa). – Jay

+0

@Jay: scusami - il mio male - ho dimenticato di includere questo. Aggiornato la mia risposta. –

+0

@ marc_s. Grazie per aver sottolineato il punto di estensibilità (i metodi protetti ExtensionGet/Set), immagino che valga la pena di guardare più vicino a casa a volte !!) In ogni caso, siete a conoscenza dei problemi di sicurezza/config necessari, per usare l'oggetto prinicpal derivato. Ho implementato la sottocategoria sopra e ottengo un'eccezione nella lettura "Gli oggetti principali di tipo UserPrincpalEx non possono essere utilizzati per interrogare questo negozio". Qualche idea? Grazie. – brumScouse

7

per aumentare il sopra ho messo incinta un metodo di estensione da chiamare ExtensionGet. Usa la riflessione per ottenere il metodo protetto che altrimenti dovresti ereditare. Potrebbe essere necessario utilizzare questo se si stanno ritornando UserPrincipalObjects da Groups.Members, ad esempio

public static class AccountManagmentExtensions 
{ 
    public static string ExtensionGet(this UserPrincipal up, string key) 
    { 
     string value = null; 
     MethodInfo mi = up.GetType() 
      .GetMethod("ExtensionGet", BindingFlags.NonPublic | BindingFlags.Instance); 

     Func<UserPrincipal, string, object[]> extensionGet = (k,v) => 
      ((object[])mi.Invoke(k, new object[] { v })); 

     if (extensionGet(up,key).Length > 0) 
     { 
      value = (string)extensionGet(up, key)[0]; 
     } 

     return value; 
    } 
} 
+0

+1 questo è un trucco molto utile. ero tipo "oh ora ho bisogno di sottoclasse!" Stai solo girando attorno al fatto che il metodo è protetto e progettato per essere accessibile attraverso una sottoclasse. Mi ricorda un argomento che ho scritto su come puoi utilizzare la riflessione .NET per "violare" i concetti di OOP: http://mazdev.blogspot.ae/2011/05/breaching-object-oriented-programming.html – Mzn

+0

Qual è il valore della chiave non è un valore stringa. come 'System._comObject' nella proprietà' accountExpires'. –

Problemi correlati