Active Directory et sa programmation

(2  exemples fournis).

Etant donné la richesse des informations contenues dans l’annuaire Active Directory, les raisons de vouloir accéder ou modifier le contenu sont nombreuses.  La création de rapports personnalisés, l’extraction de listes, la modification de champs précis tels que le nom complet pour les normaliser, les téléphones  afin de les adapter à une TOIP sont des exemples pratiques. Le but de cet article est de montrer que « c’est facile, et çà peut rapporter gros ». Non, cela fait surtout gagner beaucoup de temps !

Différents outils sont à connaître avant de partir dans l’inconnu notamment l’outil ADSIEDIT.MSC présent dans les « supports tools ». C’est l’équivalent de « regedit » pour les registres, c'est-à-dire qu’il permet de visualiser les données « brutes » de l’annuaire et du schéma.

Avant de modifier un champ précis, il est important de vérifier la correspondance entre l’affichage dans l’outil « Active Directory Utilisateurs et Ordinateurs ». Modifier le champ sur l’objet souhaité dans l’interface graphique, puis vérifier dans ADSIEDIT  l’objet correspondant.

Les administrateurs de systèmes étant rarement des développeurs, c’est l’outil Vbscript que nous utiliserons pour cette présentation. La version « texte » cscript.exe sera utilisée et forcée par la commande « cscript //h :cscript ».

Si le besoin est uniquement de type rapports ou listes sans modifications, on choisira un accès de type base de données utilisant une connexion, un fournisseur de données (« Provider »)  et des jeux d’enregistrements « recordsets ». Pour pouvoir modifier , un accès direct à l’objet sera nécessaire. Celui-ci permettra un accès complet en lecture et écrire sur l’objet. Souvent, on retrouvera les 2 types d’accès dans les scripts avancés.

Lors de la réalisation d’un script, l’étendue souhaitée est à définir. Par défaut, on pense souvent au domaine courant. Mais, il est possible de réaliser la modification sur la totalité de la forêt !!! C’est à la fois très pratique et très dangereux en cas de modification.

ð  La modification sur un domaine se fera en utilisant le protocole LDAP (389)

ð  La modification sur la forêt se fera en utilisant le protocole GC (3268)

Attention, le catalogue global ne contient qu’une petite partie des données. ADSIEDIT permet de vérifier dans le schéma que l’élément souhaité fait bien partie du catalogue global. Si nécessaire, un élément peut être ajouté au catalogue global.

Set oRecordset = oConnection.Execute("<LDAP://"+StrDomainNC+">; (objectCategory=user); name,displayname,mail,telephonenumber; subtree")

Cette instruction permettra de récupérer le nom, le nom complet, l’adresse principale de messagerie et le numéro de téléphone dans le domaine. Il suffira de remplacer LDAP par GC et de s’assurer que StrDomainNC contient la racine de la forêt pour obtenir une liste globale de tous les utilisateurs.

Voici un exemple de boucle sur les enregistrements :

If Not oRecordset.EOF Then

    While Not oRecordset.EOF

 

' Attention les champs vides (Null) ne peuvent pas être concaténés en chaine de caractères

' Il faut donc les vérifier

      Name=VerifyNull(oRecordset.Fields("Name"))

      DisplayName=VerifyNull(oRecordset.Fields("DisplayName"))

      Mail=VerifyNull(oRecordset.Fields("Mail"))

      Telephonenumber=VerifyNull(oRecordset.Fields("telephonenumber"))

 

      Wscript.echo Name+","+Displayname+","+mail+","+TelephoneNumber

 

      oRecordset.movenext

    Wend

End If

 

Attention, si vous souhaitez tester la valeur de certains champs, ceux-ci doivent avoir été inclus dans l’instruction « Execute ».

 

Un exemple complet peut être trouvé à l’adresse suivante :

http://tdsrv0.deman.local/Documents%20partages/Scripting/VbScript/listUser.vbs.txt

Set oRecordset = oConnection.Execute("<GC://"+StrDomainNC+">;(&(objectCategory=user)(samaccountname="+samAccountName+"));distinguishedName;subtree")

Cette instruction permettra de rechercher le “DistinguishedName” d’un utilisateur dans toute la forêt. Le DistinguishedName est le nom unique d’un objet qui permettra d’atteindre et de modifier la totalité de l’objet.

Le détail de l’instruction de connexion est très important ! Il s’agit d’une seule chaine de caractères composées de 4 parties séparées par des « ; ».

"<GC://"+StrDomainNC+">  : Cette partie indique le plus souvent le domaine sous la forme “dc=domaine,dc=Extension”. Mais, on peut très bien ne souhaiter qu’une OU particulière que l’on indiquera sous la forme « Ou=MesUsers,Dc=Domaine,Dc=Extension ».

(&(objectCategory=user)(samaccountname="+samAccountName+")) : Cette partie permet de sélectionner et/ou rechercher des éléments précis dans la base Active Directory avec des ET (&) et des ou (|).

distinguishedName : il s’agit de la liste des champs souhaités séparés par des virgules.

Subtree : Ce dernier élément permet de définir la « portée de la requête.3 niveaux sont possible.

-           « Subtree » permettra de parcourir tous les sous-niveaux.

-           « Base » ne regardera que le niveau indiqué.

-          « One » ne descendra que d’un seul niveau.

 

 

Si l’on veut introduire des modifications dans la base Active Directory, on ajoutera une fonction à l’intérieur de la boucle. Les raisons sont nombreuses : normaliser les noms complets (nom/prénoms), les numéros de téléphones lors d’un passage à une TOIP, intégrer des données depuis une base Intranet (ou un autre annuaire).

Nous allons prendre l’exemple de la normalisation du nom complet sous la forme « NOM Prénom ».

Tout d’abord, on sélectionnera les utilisateurs et les contacts dans la requête:

(&(objectCategory=user)(objectCategory=contact))

Si l’on veut tester et exclure une OU précise, on pourra tester les champs dans la boucle :

                if not(isnull(oRecordset.Fields("distinguishedName"))) Then

           DnName=oRecordset.Fields("distinguishedName")

           If Instr(ucase(Dnname),"OU=PASTOUCHER")=0 Then

             u=u+1

             UpdateAccount(DnName)

           End if

         end if

Le champ « distinguishedName » sera transmis en paramètre à la fonction UpdateAccount dont nous allons commenté les éléments principaux :

Function UpdateAccount(DnName)
Dim oUser
wscript.echo dnname
set oUser=GetObject("LDAP://"+DnName)

La functionGetObject” permettra d’obtenir un pointeur sur l’objet (ici User) sur lequel toutes les fonctions (methodes) seront applicables et tous les champs seront accessibles.

samaccountname=ouser.samaccountname
sn=oUser.sn
givenname=oUser.givenname
DisplayName=Trim(oUser.DisplayName)

Récupération du login, nom, prénom et NomComplet !!!

Si les conditions sont remplies, on pourra définir la nouvelle valeur 

      NewDisplayName=Ucase(sn)+" "+givenname

Puis réécrire l’information modifiée dans Active Directory :

  oUser.put "DisplayName", NewDisplayName

  oUser.setinfo

 

L’exemple complet se trouve ici : http://tdsrv0.deman.local/Documents%20partages/Scripting/VbScript/majdisplay.vbs.txt.

Attention, afin d’éviter des problèmes de performances sur les contrôleurs de domaine, les opérations sur Active Directory ont été limitées à 1000 enregistrements. Normalement, il faut adapter son développement afin de traiter les opérations par « page » de 1000 enregistrements, ce qui est assez contraignant. En fait, le plus simple est de modifier ce paramètre sur l’un des contrôleurs de domaine à partir duquel  seront lancés tous les scripts. Ce paramètre se change avec l’outil NTDSUTILS dans « ldap policies » après s’être connecté sur le contrôleur de domaine souhaité.

 

Bien entendu, le but n’est pas de réécrire un script depuis zéro. Mais grâce aux indications et aux exemples fournis ici, vous trouverez probablement de nombreuses applications pratiques. De nombreux forums pourront vous aider à rechercher les informations manquantes.