2015-07-01 3 views
5

Ho letto molte domande simili StackOverflow ma nessuna sembra risolvere il problema che sto vedendo. Se interrogo un utente utilizzando nomeprincipale utente, restituisco un risultato di ricerca con esattamente 34 proprietà. Nessuna delle proprietà personalizzate viene restituita. Se interrogo ancora utilizzando una proprietà personalizzata come employeeNumber, restituisco un risultato con 71 proprietà. Tutte le proprietà personalizzate sono incluse.Come posso ottenere un campo personalizzato da Active Directory in C#?

Il mio problema è che io non ho il employeeNumber in fase di esecuzione, solo il UserPrincipalName. Ho bisogno di recuperare tutte le proprietà personalizzate tutto il tempo. Spero che abbia senso. Ecco il mio codice di pratica:

string sid = ""; 
using (PrincipalContext context = new PrincipalContext(ContextType.Domain)) 
{ 
    UserPrincipal user = UserPrincipal.Current; 
    //sid = user.SamAccountName; 
    sid = user.UserPrincipalName; 
    //sid = user.Sid.ToString(); 

    DirectoryEntry entry = user.GetUnderlyingObject() as DirectoryEntry; 
    if (entry.Properties.Contains("employeeNumber")) 
    { 
     //this doesn't work 
    } 
} 

DirectoryEntry ldapConnection = new DirectoryEntry("companyname.com"); 
ldapConnection.Path = "LDAP://DC=companyname,DC=com"; 
ldapConnection.AuthenticationType = AuthenticationTypes.Secure; 

DirectorySearcher search = new DirectorySearcher(ldapConnection); 
search.Filter = string.Format("(&(ObjectClass=user)(userprincipalname={0}))", sid); // <-- this doesn't get custom properties 
//search.Filter = string.Format("(employeeNumber={0})", "11663"); <-- this works 

var result = search.FindOne(); // FindOne(); 
if (result.Properties.Contains("employeeNumber")) 
{ 
    //this never happens either :(
} 

È possibile che questo non restituisce il campo employeeNumber, ma se io rimuovere il commento dalla seconda linea search.Filter e cercare manualmente employeeNumber trovo un risultato e contiene tutti i campi di cui ho bisogno.

MODIFICA: ho trovato un ottimo articolo MSDN Here che descrive come estendere l'oggetto UserPrincipal per ottenere attributi personalizzati. L'unico problema è che mi sta dando una stringa vuota ogni volta che accedo, anche se ho verificato che la proprietà è impostata in AD! Qualsiasi aiuto è apprezzato.

EDIT 2: Ecco il codice per l'estensione principal personalizzato:

[DirectoryRdnPrefix("CN")] 
[DirectoryObjectClass("Person")] 
public class UserPrincipalExtension : UserPrincipal 
{ 
    public UserPrincipalExtension(PrincipalContext context) 
     : base(context) 
    { 
    } 

    public UserPrincipalExtension(PrincipalContext context, string samAccountName, string password, bool enabled) 
     : base(context, samAccountName, password, enabled) 
    { 
    } 

    public static new UserPrincipalExtension FindByIdentity(PrincipalContext context, IdentityType type, string identityValue) 
    { 
     return (UserPrincipalExtension)FindByIdentityWithType(context, typeof(UserPrincipalExtension), type, identityValue); 
    } 

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

      return searchFilter; 
     } 
    } 

    [DirectoryProperty("employeeNumber")] 
    public string EmployeeNumber 
    { 
     get 
     { 
      if (ExtensionGet("employeeNumber").Length != 1) 
       return string.Empty; 

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

E il filtro di ricerca personalizzato:

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

    public void SAMAccountName(string value, MatchType type) 
    { 
     this.AdvancedFilterSet("sAMAccountName", value, typeof(string), type); 
    } 
} 

Usage:

UserPrincipalExtension filter = new UserPrincipalExtension(context); 
filter.AdvancedSearchFilter.SAMAccountName(UserPrincipal.Current.SamAccountName, MatchType.Equals); 
PrincipalSearcher search = new PrincipalSearcher(filter); 

foreach (var result in search.FindAll()) 
{ 
    var q = (UserPrincipalExtension)result; 
    var m = q.EmployeeNumber; 
} 

var m è sempre un stringa vuota anche se TUTTE le voci AD hanno un numero dipendente.

EDIT: Da Active Directory: Active Directory

risposta

1

Sono più confidente nel modo di risolvere il tuo secondo metodo così io risponderò che prima. È necessario specificare la proprietà in DirectorySearcher.PropertiesToLoad quando si cerca la proprietà da mostrare.

DirectorySearcher search = new DirectorySearcher(ldapConnection); 
search.Filter = string.Format("(&(ObjectClass=user)(userprincipalname={0}))", sid); 
search.PropertiesToLoad.Add("employeeNumber"); 

var result = search.FindOne(); // FindOne(); 
if (result.Properties.Contains("employeeNumber")) 
{ 
    //This should now work. 
} 

La ragione ha funzionato per string.Format("(employeeNumber={0})", "11663"); è perché qualsiasi clausola di ricerca si aggiunge automaticamente viene messo in alla raccolta PropertiesToLoad.


Per il vostro primo metodo, penso che è necessario chiamare DirectoryEntry.RefreshCache e passare la proprietà per farlo vedere.

string sid = ""; 
using (PrincipalContext context = new PrincipalContext(ContextType.Domain)) 
{ 
    UserPrincipal user = UserPrincipal.Current; 
    //sid = user.SamAccountName; 
    sid = user.UserPrincipalName; 
    //sid = user.Sid.ToString(); 

    DirectoryEntry entry = user.GetUnderlyingObject() as DirectoryEntry; 

    entry.RefreshCache(new[] {"employeeNumber"}); 

    if (entry.Properties.Contains("employeeNumber")) 
    { 

    } 
} 

Ma non sono sicuro al 100% se funzionerà o meno.


Per la vostra principale utente personalizzata, io non sono sicuro di ciò che è sbagliato. L'unica differenza che vedo tra quello che stai facendo e quello che ho in un progetto che fa quello che so funziona è che tu usi [DirectoryObjectClass("Person")] ma ho [DirectoryObjectClass("user")].Forse questo è il problema

[DirectoryRdnPrefix("CN")] 
[DirectoryObjectClass("user")] //Maybe this will fix it??? 
public class UserPrincipalExtension : UserPrincipal 
{ 
+0

Grazie mille per le idee ma purtroppo non hanno funzionato. La cache di aggiornamento era una buona idea, ma il valore era ancora una stringa vuota. L'altra idea in cui si imposta PropertiesToLoad è stata una grande idea ma non ha funzionato. Ho anche ripreso un po 'il tuo ragionamento e ho aggiunto employeeNumber alla mia query per provare a forzare il caricamento, in questo modo: search.Filter = string.Format ("(& (ObjectClass = user) (| (employeeNumber = 99999) (userprincipalname = {0}))) ", sid); <- puoi vedere il mio impiegato fasulloNumero nella mia condizione OR. Nessuna fortuna con entrambi i casi. – BrianLegg

+0

Hmm. Sei sicuro al 100% che il dipendente che stai recuperando abbia un valore in quella proprietà. Non lo so, ma forse non viene visualizzato se non è impostato alcun valore. Dai un'occhiata a [questa mia vecchia domanda] (http://stackoverflow.com/questions/14566887/how-to-set-a-binary-attribute-when-using-a-accountmanagement-extension-class), forse potrebbe darti un'idea. –

+0

Ho appena controllato ed è lì. Ho interrogato per dipendente 11663 (me stesso) e ho recuperato un oggetto con 71 proprietà. EmployeeNumber era uno di loro. Ho interrogato nuovamente usando il mio nome, poi il mio sid, poi il mio userprincipalname e tutti e 3 mi hanno restituito lo stesso oggetto, ma meno la proprietà del numero del dipendente. Controllerò la tua vecchia domanda, grazie. – BrianLegg