validar usuario single password obtener ejemplos datos crear conectar con active c# active-directory directoryservices

c# - usuario - system directoryservices dll



Diferencia entre PrincipalSearcher y DirectorySearcher (2)

Veo ejemplos de Active Directory que usan PrincipalSearcher y otros ejemplos que hacen lo mismo pero usan DirectorySearcher . ¿Cuál es la diferencia entre estos dos ejemplos?

Ejemplo usando PrincipalSearcher

PrincipalContext context = new PrincipalContext(ContextType.Domain); PrincipalSearcher search = new PrincipalSearcher(new UserPrincipal(context)); foreach( UserPrincipal user in search.FindAll() ) { if( null != user ) Console.WriteLine(user.DistinguishedName); }

Ejemplo usando DirectorySearcher

DirectorySearcher search = new DirectorySearcher("(&(objectClass=user)(objectCategory=person))"); search.PageSize = 1000; foreach( SearchResult result in search.FindAll() ) { DirectoryEntry user = result.GetDirectoryEntry(); if( null != user ) Console.WriteLine(user.Properties["distinguishedName"].Value.ToString()); }


He pasado mucho tiempo analizando las diferencias entre estos dos. Esto es lo que he aprendido.

  • DirectorySearcher proviene del espacio de nombres System.DirectoryServices .

  • PrincipalSearcher proviene del espacio de nombres System.DirectoryServices.AccountManagement , que se basa en System.DirectoryServices . PrincipalSearcher utiliza internamente DirectorySearcher .

  • El espacio de nombres de AccountManagement (es decir, PrincipalSearcher ) fue diseñado para simplificar la administración de los objetos de Usuario, Grupo y Computadora (es decir, Principales). En teoría, su uso debería ser más fácil de entender y producir menos líneas de código. Aunque en mi práctica hasta ahora, parece depender en gran medida de lo que estás haciendo.

  • DirectorySearcher tiene un nivel más bajo y puede manejar más que solo objetos de Usuario, Grupo y Computadora.

  • Para uso general, cuando trabaja con atributos básicos y solo con algunos objetos, PrincipalSearcher dará como resultado menos líneas de código y un tiempo de ejecución más rápido.

  • La ventaja parece desaparecer cuanto más avanzadas son las tareas que estás haciendo. Por ejemplo, si está esperando más de unos pocos cientos de resultados, deberá obtener el DirectorySearcher subyacente y configurar el PageSize

    DirectorySearcher ds = search.GetUnderlyingSearcher() as DirectorySearcher; if( ds != null ) ds.PageSize = 1000;

  • DirectorySearcher puede ser significativamente más rápido que PrincipalSearcher si hace uso de PropertiesToLoad .

  • DirectorySearcher y las clases similares pueden trabajar con todos los objetos en AD, mientras que PrincipalSearcher es mucho más limitado. Por ejemplo, no puede modificar una unidad organizativa utilizando PrincipalSearcher y clases similares.

Aquí hay una tabla que hice para analizar usando PrincipalSearcher , DirectorySearcher sin usar PropertiesToLoad , y DirectorySearcher con usar PropertiesToLoad . Todas las pruebas ...

  • Utilice un PageSize de PageSize de 1000
  • Consulta un total de 4,278 objetos de usuario.
  • Especifique los siguientes criterios
    • objectClass=user
    • objectCategory=person
    • No es un recurso de programación (es decir !msExchResourceMetaData=ResourceType:Room )
    • Habilitado (es decir !userAccountControl:1.2.840.113556.1.4.803:=2 )


Código para cada prueba

Usando PrincipalSearcher

[DirectoryRdnPrefix("CN")] [DirectoryObjectClass("Person")] public class UserPrincipalEx: UserPrincipal { private AdvancedFiltersEx _advancedFilters; public UserPrincipalEx( PrincipalContext context ): base(context) { this.ExtensionSet("objectCategory","User"); } public new AdvancedFiltersEx AdvancedSearchFilter { get { if( null == _advancedFilters ) _advancedFilters = new AdvancedFiltersEx(this); return _advancedFilters; } } } public class AdvancedFiltersEx: AdvancedFilters { public AdvancedFiltersEx( Principal principal ): base(principal) { } public void Person() { this.AdvancedFilterSet("objectCategory", "person", typeof(string), MatchType.Equals); this.AdvancedFilterSet("msExchResourceMetaData", "ResourceType:Room", typeof(string), MatchType.NotEquals); } } //... for( int i = 0; i < 10; i++ ) { uint count = 0; Stopwatch timer = Stopwatch.StartNew(); PrincipalContext context = new PrincipalContext(ContextType.Domain); UserPrincipalEx filter = new UserPrincipalEx(context); filter.Enabled = true; filter.AdvancedSearchFilter.Person(); PrincipalSearcher search = new PrincipalSearcher(filter); DirectorySearcher ds = search.GetUnderlyingSearcher() as DirectorySearcher; if( ds != null ) ds.PageSize = 1000; foreach( UserPrincipalEx result in search.FindAll() ) { string canonicalName = result.CanonicalName; count++; } timer.Stop(); Console.WriteLine("{0}, {1} ms", count, timer.ElapsedMilliseconds); }


Utilizando DirectorySearcher

for( int i = 0; i < 10; i++ ) { uint count = 0; string queryString = "(&(objectClass=user)(objectCategory=person)(!msExchResourceMetaData=ResourceType:Room)(!userAccountControl:1.2.840.113556.1.4.803:=2))"; Stopwatch timer = Stopwatch.StartNew(); DirectoryEntry entry = new DirectoryEntry(); DirectorySearcher search = new DirectorySearcher(entry,queryString); search.PageSize = 1000; foreach( SearchResult result in search.FindAll() ) { DirectoryEntry user = result.GetDirectoryEntry(); if( user != null ) { user.RefreshCache(new string[]{"canonicalName"}); string canonicalName = user.Properties["canonicalName"].Value.ToString(); count++; } } timer.Stop(); Console.WriteLine("{0}, {1} ms", count, timer.ElapsedMilliseconds); }


Usando DirectorySearcher con PropertiesToLoad

Igual que "Usando DirectorySearcher pero agregue esta línea

search.PropertiesToLoad.AddRange(new string[] { "canonicalName" });

Después

search.PageSize = 1000;


PrincipalSearcher se utiliza para consultar el Directorio de Grupos o Usuarios. DirectorySearcher se utiliza para consultar todo tipo de objetos.

Usé DirectorySearcher para obtener grupos antes de eso. Descubrí PrincipalSearcher así que cuando reemplacé el primero con el último, la velocidad de mi programa mejoró (tal vez fue solo PrincipalSearcher que creó una mejor consulta para mí. Por lo que me importa, PrincipalSearcher fue más fácil Para usar y más adecuado para la tarea de conseguir pricipals.

DirectorySearcher por otro lado, es más general, ya que puede obtener otros tipos de objetos. Esta es la razón por la que no se puede escribir con fuerza como se menciona en los comentarios. PrincipalSearcher tiene que ver con los directores, por lo que tendrá objetos fuertemente tipados que pertenecen a los directores, y es por eso que no es necesario que le diga para obtener un objeto de tipo usuario o grupo, estará implícito en las clases principales que utilizar.