# Interagindo com AD usando Código C#

**URL:** <https://community.latromi.com.br/t/interagindo-com-ad-usando-codigo-c/372>\
**Category:** Tutoriais\
**Tags:** csharp, active-directory, form\
**Created:** [Fevereiro 3, 2020, 4:24pm UTC](https://community.latromi.com.br/t/interagindo-com-ad-usando-codigo-c/372 "2020-02-03T16:24:29Z")\
**Posts on this page:** 1\
**Page:** 1

<div class="post-metadata">

**Author:** ![daniel.giacomelli](https://community.latromi.com.br/user_avatar/community.latromi.com.br/daniel.giacomelli/32/1476_2.png) [@daniel.giacomelli](https://community.latromi.com.br/u/daniel.giacomelli)\
**Post date:** [Fevereiro 3, 2020, 4:24pm UTC](https://community.latromi.com.br/t/interagindo-com-ad-usando-codigo-c/372/1 "2020-02-03T16:24:29Z")

</div>

Este tópico mostra como interagir com o Active Directory do Windows através dos Comandos C# do Formulário Dinâmico.

## Banco de Dados

Para iniciar, vamos criar uma tabela para gravar os usuários do AD em nosso banco de dados:

```sql
CREATE TABLE adusers
(
   username VARCHAR(60) NOT NULL,                                                
   commonname VARCHAR(255),
   displayname VARCHAR(255),
   email VARCHAR(100),
   CONSTRAINT pk_adusers_usrname PRIMARY KEY (username)
);

```

## Obtendo Usuários

A rotina baixo pode ser chamada em qualquer procedimento do Formulário Dinâmico.  
Para isso, clique no botão direito do mouse sobre o procedimento, vá até o menu _Ação → Executar Comando C#_

 ![image](https://community.latromi.com.br/uploads/default/original/1X/0eb5fc140aecaeea36c98714ee8f15598cd03c43.png)

O código C# abaixo usa a biblioteca [System.DirectoryServices](https://docs.microsoft.com/pt-br/dotnet/api/system.directoryservices?view=netframework-4.5) do .NET Framework para acessar as informações do AD. Como essa biblioteca não está referenciada no projeto, ela é chamada via Reflection, usando o método `LoadAssembly` do SDK do Latromi para carregar a DLL e o método `Activator.CreateInstance(...)` do .NET para instanciar as classes `DirectoryEntry` e `DirectorySearcher`.

Os campos que serão gravados são:

- Nome de Usuário 🔑
- Nome Comum
- Nome de Exibição
- E-mail

O código faz primeiro um `UPDATE`. Se nenhum registro foi afetado, então faz um `INSERT`.

```cs
using System.Reflection;
using System.Collections;
using LATROMI.Extensions;
using System.Data;

// Informar os dados do usuário para autenticar no AD e realizar as operações.
// Preferencialmente um administrador.
string adUser = "usuario_administrador";
string adUserPassword = "senha_do_usuario";
string adUserDomain = "dominio";
// Fully qualified domain name ou FQDN é o nome de domínio que especifica a posição do nó na hierarquia do Domain Name System (DNS). 
// Um FQDN é estruturado da seguinte forma: "host.3rd-level-domain.2nd-level-domain.top-level-domain". O número de níveis em um FQDN não é fixo
string adFQDN = "dominio.com.br";

string adUserAndDomain = string.Concat(adUserDomain, @"\", adUser);
string ldapAddress = "LDAP://" + adFQDN;

// Validações
if (string.IsNullOrEmpty(adUser)) throw new InvalidOperationException("Nome de usuário não informado.");
if (string.IsNullOrEmpty(adUserPassword)) throw new InvalidOperationException("Senha de usuário não informada.");
if (string.IsNullOrEmpty(adUserDomain)) throw new InvalidOperationException("Domínio de usuário não informado.");
if (string.IsNullOrEmpty(adFQDN)) throw new InvalidOperationException("FQDN não informado.");

var directoryServicesAssembly = LoadAssembly("System.DirectoryServices.dll");
var directoryEntryType = directoryServicesAssembly.GetType("System.DirectoryServices.DirectoryEntry");
var directorySearchType = directoryServicesAssembly.GetType("System.DirectoryServices.DirectorySearcher");

dynamic directoryEntry = Activator.CreateInstance(directoryEntryType, ldapAddress, adUserAndDomain, adUserPassword);

//Carrega o objeto nativo do AD para forçar a autenticação.    
var obj = directoryEntry.NativeObject;

dynamic search = Activator.CreateInstance(directorySearchType, directoryEntry);

search.Filter = "(&(objectClass=user)(objectCategory=person))";
search.PageSize = 100;

var properties = (IList)search.PropertiesToLoad;

// Seleciona as propriedades que serão carregadas
//
properties.Add("cn"); //Common Name
properties.Add("samaccountname");
properties.Add("usergroup");
properties.Add("displayname");//first name
properties.Add("userPrincipalName");
properties.Add("memberOf"); // groups
properties.Add("userAccountControl");
//
// Informações referentes às funções do usuário.
properties.Add("title");
properties.Add("department");
properties.Add("company");
properties.Add("manager");
//
// Informações referente aos contatos do usuário.
properties.Add("telephoneNumber");
properties.Add("mail");
//
// Informações referentes ao endereço do usuário.
properties.Add("streetAddress");
properties.Add("l"); // City
properties.Add("st"); // State
properties.Add("postalCode");
properties.Add("co"); //Country

var searchResultCollection = search.FindAll();

if (searchResultCollection != null)
{
    // Abre a conexão 
    using (var connection = Database.CreateConnection("Teste AD"))
    {
        // Abre a Conexão
        connection.Open();
        
        foreach(object searchResult in searchResultCollection)
        {
            dynamic resultObj = searchResult;
            
            // Obtém os dados
            string username = (string)resultObj.Properties["samaccountname"][0];
            string commonName = (string)resultObj.Properties["cn"][0];
            // Display Name e Email podem não estar presentes no AD, 
            // portanto é importante verificar se existe para evitar erros
            string displayName = resultObj.Properties.Contains("displayname") == true 
                        ? (string)resultObj.Properties["displayname"][0]
                        : null;
                //
            string email = resultObj.Properties.Contains("mail") == true
                        ? (string)resultObj.Properties["mail"][0]
                        : null;
            
            // Salva no banco de dados
            var commandParameters = new Dictionary<string, object> 
            {
                ["@username"] = username.ToUpper(),
                ["@commonname"] = commonName,
                ["@displayname"] = displayName ?? Convert.DBNull,
                ["@email"] = email ?? Convert.DBNull
            };
            
            int affectedRows = connection.ExecuteNonQuery( 
                "UPDATE adusers SET "+
                " commonname = @commonname " +
                " , displayname = @displayname " +
                " , email = @email " +
                " WHERE username = @username", commandParameters);
                
            // Se nenhuma linha foi afetada pelo UPDATE,
            // então faz o INSERT do usuario
            if (affectedRows <= 0) 
            {
                connection.ExecuteNonQuery(
                    "INSERT INTO adusers (username, commonname, displayname, email) " +
                    "VALUES (@username, @commonname, @displayname, @email)", commandParameters);
            }
        }
    }
}

```

## Obtendo um usuário Específico

Para listar todos os usuários, o filtro usando na classe `DirectorySearcher` é este:

```cs
search.Filter = "(&(objectClass=user)(objectCategory=person))";

```

Para obter os dados de um usuário específico, sem precisar percorrer todos os outros usuários, basta substituir o filtro por:

```cs
search.Filter = "(SAMAccountName=" + "nome_de_usuario" + ")";

```
