Autant l'administration et l'extraction de données peut se faire simplement sur une messagerie Microsoft Exchange en passant par Powershell, autant pour Domino la plus simple extraction de données via un script PS peut se transformer en véritable calvaire.

Pourquoi faire?

Dans le cadre d'une de mes missions, j'ai du lister les modifications faites sur les groupes de distribution sur une messagerie Lotus Domino... et autant vous dire que ça n'a pas été une partie de plaisir (ce qui en soit, est toujours sympathique... un peu de difficulté est d'autant plus gratifiant une fois surmontée!).

Comment faire?

Après avoir tenté d'attaquer directement sur le serveur en passant par un objet com Lotus.Notessession et ouvert directement la base Names.nsf , je me suis rendu compte que le serveur entier devenait instable... cause ou conséquence de cette ouverture de fichier via Powershell? Difficile à dire... Mais lorsque l'on regarde la commande .Open() qui permet d'ouvrir la base, on se rends compte qu'elle se "verrouille" pour le restant des utilisateurs. Et bien sur, aucune commande .Close() n'existe ...

Pour éviter de bloquer complètement le service de messagerie, j'ai du donc me tourner vers le LDAP de Domino pour obtenir l'intégralité des groupes et leurs contenu. J'ai longuement cherché comment faire, et j'ai finalement trouvé (merci Internet) le début de piste nécessaire pour la création de la connexion authentifiée, le restant se déroulant avec plus de facilité.

Ce script est fait pour fonctionner en tâche planifiée, et à chaque lancement, compare le contenu de la requête précédente, préalablement enregistrée dans un fichier XML avec le contenu de la nouvelle. Il détecte les ajouts dans chaque groupe en comparant la liste des membres, il vérifie les groupes dans la liste précédente et la nouvelle pour détecter les créations et suppressions de groupes et les lister dans un fichier CSV.


Script final

Vous pouvez télécharger le script depuis mon répertoire git personnel

$debugging = $false #a mettre sur truepour avoir des infos sur la zone de code qui crée l'enregistrement
$date = Get-Date -Format "dd/MM/yyyy HH:mm:ss"
set-location $([Environment]::GetFolderPath("Mydocuments")) #se place dans le repertoire "mes documents" de l'utilisateur actuel
try 
  {
 $base = Import-Clixml referencegroupes.xml
 }
catch 
 {
 Write-Host "Le fichier de réference n'existe pas, ou n'est pas disponible , il sera regénéré à la fin de ce script. Aucun fichier de modification ne se créera."
 }

#ce bloc crée un message pour signifier qu'il n'a pas pu accéder au fichier de base. Si c'est le premier lancement, ou si le fichier n'est plus accessible, il le recréera avec ce que le script aura récuperé

$base = $base | Sort-Object -Property groupe -Unique

$Connection = New-Object -Com "ADODB.Connection" #création d'un objet de connexion
$Connection.Provider = "ADsDSOObject" #On spécifie que c'est une connexion LDAP
$Connection.Properties.Item("User ID")="CN=Nicolas LANG,O=Ma Société" #authentifiant à préciser
$Connection.Properties.Item("Password")="P@ssw0rd!" #Votre mot de passe
$Connection.Open("Active Directory Provider") #Nous mettons en place la connexion avec les identifiants précisés
$Command = New-Object -Com "ADODB.Command" #on initialise la commande qui sera fournie à la connexion $Connection
$Command.ActiveConnection = $Connection #On lie la commande à la connexion
$Query = "SELECT displayname, mail, member FROM 'LDAP://lotusserveur.mondomaine.com' WHERE objectclass='dominogroup'" #nous enregistrons un texte qui précise que nous selectionnons les propriétés displayname mail et member sur le serveur LDAP précisé de ce qui est un dominogroup
$Command.Commandtext = $Query 
$Command.Commandtimeout = 60 #Ce timeout est le temps de validité de la commande avant qu'elle soit précisée comme perdue. Si votre base est imposante ou que votre connexion vers le serveur est lente, augmentez la valeur.
$execute = $Command.execute() #On execute la commande et on l'enregistre dans $execute
$tab = @() #on crée un tableau qui recueillera les données
$execute.MoveFirst() #nous nous déplaçons au premier enregistrement

function ajoutligne ($groupe=$null,$ajout=$null,$retrait=$null,$creation=$null,$suppression=$null,$reference="???") #Cette fonction permettra d'ajouter dans chaque colonne l'attribut et la valeur désirée
{

   $obj = New-Object PSOBJECT
   $obj | add-member -MemberType NoteProperty -Name "Date" -Value $date
   $obj | add-member -MemberType NoteProperty -Name "Groupe" -Value $groupe
   $obj | add-member -MemberType NoteProperty -Name "Ajout de" -Value $ajout
   $obj | add-member -MemberType NoteProperty -Name "Retrait de" -Value $retrait
   $obj | add-member -MemberType NoteProperty -Name "Création" -Value $creation
   $obj | add-member -MemberType NoteProperty -Name "Suppression" -Value $suppression
   if ($debugging -eq $true) {$obj | add-member -MemberType NoteProperty -Name "Debbuging only" -Value $reference}
   return $obj
}
while ($execute.eof -eq $false) #cette boucle s'execute tant que nous ne sommes pas arrivés sur le EOF (End Of File) qui indique la fin des enregistrements. Une valeur BOF (Begin Of File) existe pour préciser le premier enregistrement.
{
 $member = $execute.Fields | Where-Object {$_.name -eq "member"} #nous selectionnons dans l'element de la boucle la valeur "member"
 $displayname = $execute.Fields | Where-Object {$_.name -eq "displayname"} #idem pour displayname
 $addresse = $execute.Fields | Where-Object {$_.name -eq "mail"} #idem pour mail

 if ($member.Value -isnot [System.DBNull]) #Pour un enregistrement de base de donnée vide, $null n'est pas valide. Le type pour une entrée vide est [System.DBNull]
  {
  $objet = New-Object PSOBJECT
  $objet |add-member -Name "Groupe" -MemberType NoteProperty -Value $($displayname.value)
  $objet |Add-Member -Name "Adresse" -MemberType NoteProperty -Value $($addresse.value)
  $objet |add-member -Name "Membres" -MemberType NoteProperty -Value $($member.value)
  $tab += $objet
  }

 $execute.MoveNext()

}
if ($base -eq $null) #crée la première reference si elle n'existe pas
 {
 $tab | Export-Clixml referencegroupes.xml
 #(get-date).toshortdatestring()+";"+(get-date).toshorttimestring()+";Ecriture du fichier de reference" >> debug.txt
 }
else #execute le script s'il trouve la première reference
{  $tab = $tab |Sort-Object -Property Groupe -Unique
  $tab | Export-Clixml newbase.xml
  #(get-date).toshortdatestring()+";"+(get-date).toshorttimestring()+";Ecriture du fichier de comparaison" >> debug.txt

 $newbase = Import-Clixml newbase.xml

 $recap =@()

 foreach ($entree in $base)
 {

  if ($newbase.groupe -notcontains $entree.groupe) #si la nouvelle base ne comporte pas le groupe, alors c'est qu'il est supprimé
   {
   $recap += ajoutligne -groupe $entree.groupe -suppression $true -reference '$newbase.groupe -contains $entree.groupe'
   }
  else #si le groupe existe, on en vérifie les utilisateurs en appelant l'autre base
  {
  $comparaison = $newbase | Where-Object {$_.groupe -eq $entree.groupe}
  $changements = $null
  $changements = Compare-Object $entree.membres $comparaison.membres

  foreach ($changement in $changements)
   {

   if ($changement.sideindicator -eq "=>") 
    {

    $recap += ajoutligne -groupe $entree.groupe -ajout $changement.inputobject -reference '$changement.sideindicator -eq "=>"'
    }
   else
    {

    $recap += ajoutligne -groupe $entree.groupe -retrait $changement.inputobject -reference 'else ($changement.sideindicator -eq "<=")'
    }
   } # fin foreach ($changement in $changements)
  } #fin else
  } #foreach ($groupe in $entree.groupe)

 foreach ($entree in $newbase)
 {

  if ($base.groupe -notcontains $entree.groupe) #si l'ancienne base ne comporte pas le groupe, alors c'est qu'il est crée
   {
   $recap += ajoutligne -groupe $entree.groupe -creation $true -reference '$base.groupe -notcontains $entree.groupe'
   }

 } # foreach ($entree in $newbase)

 $recap | Export-Csv "Changements comptes.csv" -Encoding UTF8 -notypeinformation -Append -Delimiter ";" #export du fichier de suivi des modifications sur le compte
 Move-Item -Path newbase.xml -destination referencegroupes.xml -Force #remplacement du fichier 
} #fin else

Ainsi, nous avons un fichier CSV qui se met automatiquement à jour en marquant les ajouts et retraits de membres d'un groupe, création et suppression d'un groupe.

Ajouter un commentaire

Article précédent Article suivant