Active Directory : Comment détecter un changement dans un groupe ?
Sommaire
I. Présentation
Après avoir vu récemment comment détecter un changement au sein des stratégies de groupe, nous allons voir comment détecter un changement dans un groupe de l'Active Directory. Nous n'utiliserons pas de logiciels tiers pour parvenir à réaliser cette surveillance, bien que des solutions existent (notamment chez Netwrix).
L'objectif n'est pas de surveiller le groupe "Secrétariat" mais plutôt les groupes critiques et sensibles, tels que Admins du domaine, les administrateurs de l'entreprise et du schéma, etc... Que ce soit dans le cadre d'une mauvaise manipulation, ou bien si vous êtes la cible d'une attaque, il y a des chances pour qu'un compte utilisateur suspect soit ajouté au sein d'un de ces groupes.
Avec la méthode que nous allons utiliser, qui s'appuie tout simplement sur un script PowerShell, il sera possible de détecter un ajout ou une suppression au sein d'un des groupes surveillés.
Pour parvenir à mes fins, j'ai pris un script existant comme base que j'ai ensuite personnalisé pour obtenir ce que je souhaitais. Voici le lien vers le script original : https://gallery.technet.microsoft.com/scriptcenter/Detect-Changes-to-AD-Group-012c3ffa
II. Comment fonctionne le script "Get-AdGroupMembershipChange.ps1" ?
Retrouvez ma version de ce script, qui reprend comme base le travail mentionné précédemment, sur mon GitHub : Get-AdGroupMembershipChange
Je ne vais pas coller ici le code du script, ça n'aurait pas d'intérêt, je vous invite à le consulter et le récupérer directement depuis le lien.
- Voici quelques informations quant au script :
- Lors de la première exécution, le script va générer un fichier CSV qui sera utilisé comme référence. En effet, à partir de la deuxième exécution, le script va comparer le contenu du fichier CSV avec l'état actuel de l'AD à l'instant t. Le script sait si c'est la première exécution ou non en testant l’existence du fichier CSV de référence.
- Lorsque le script va comparer le CSV de référence et l'état des groupes à l'instant t, il y aura 2 balayages effectués pour la comparaison, un premier dans un sens pour détecter les suppressions éventuelles, et un dans le sens inverse pour détecter les ajouts.
- Pour la partie notification, un e-mail sera envoyé en cas de changement, que ce soit un ajout ou une suppression, au sein de l'un ou de plusieurs des groupes surveillés. Il faudra configurer la partie serveur de messagerie au sein du script directement.
-Si vous ne souhaitez pas recevoir de notification par e-mail, vous pouvez choisir l'affichage en mode console directement au sein d'une table, ou alors un export au sein d'un fichier HTML. Le rapport HTML sera équivalent au contenu du rapport par e-mail.
- Dans la version de base, un e-mail de notification est envoyé par changement détecté. Dans cette version, il y a seulement un e-mail récapitulatif envoyé par exécution.
- Par exemple, une liste de groupes à surveiller :
- Administrateurs de l’entreprise
- Administrateurs du schéma
- Admins du domaine
- Administrateurs
- Opérateurs de sauvegarde
- Les journaux
Ci-dessous un exemple d'exécution du script avec l'ensemble des paramètres, que je vais vous expliquer.
.\Get-AdGroupMembershipChange.ps1 -Email "[email protected]" -SendByMail:$true -ExportAsHTML "C:\Logs\Audit_Get-AdGroupMembershipChange\rapport.html" -LogFilePath "C:\Logs\Audit_Get-AdGroupMembershipChange\Audit_log.csv" -GroupFilePath "C:\Logs\Audit_Get-AdGroupMembershipChange\Audit_list_reference.csv" -Group "Administrateurs de l’entreprise", "Administrateurs du schéma", "Admins du domaine", "Administrateurs", "Opérateurs de sauvegarde"
Finalement, il n'y a pas tant de paramètres que ça... Seulement 4 mais ce sont les valeurs associées qui peuvent rendre la commande longue.
Email : Destinataire pour envoyer la notification par e-mail en cas de changement (rapport HTML dans le corps du mail)
LogFilePath : Le fichier de log pour consigner l'activité du script, format CSV
GroupFilePath : Le fichier de référence qui stocke l'état des groupes audités à l'instant t, format CSV
Group : La liste des groupes à auditer, surveiller
ExportAsHTML : Si vous souhaitez générer un rapport HTML, indiquez le chemin vers le rapport.
SendByMail : Un booléen pour indiquer si oui ou non il faut envoyer le rapport HTML par mail (directement en mode contenu HTML)
Après quelques secondes d'exécution, le verdict va arriver directement dans votre boîte mail 🙂
Au fil des exécutions, le fichier de log va se remplir et vous permettra d'avoir un historique au format texte :
08-18-2017 17:07:23.391+000: The log file [C:\Logs\Audit_Get-AdGroupMembershipChange\Audit_list_reference.csv] does not exist yet. Creating file. 08-18-2017 17:07:23.562+000: Querying Active directory domain for group memberships... 08-18-2017 17:07:23.781+000: Querying the [Administrateurs de l’entreprise] group for members... 08-18-2017 17:07:23.812+000: Found [7] members in the [Administrateurs de l’entreprise] group 08-18-2017 17:07:23.859+000: [Administrateurs de l’entreprise] not found in log file. Dumping all members into it... 08-18-2017 17:07:23.937+000: Reading previous [Administrateurs de l’entreprise] group members... 08-18-2017 17:07:24.16+000: No members have been removed since last check 08-18-2017 17:07:24.31+000: Found [1] members that have been added since last check 08-18-2017 17:07:24.141+000: Emailed change notification to [email protected] 08-18-2017 17:07:24.141+000: Querying the [Administrateurs du schéma] group for members...
...Ou encore :
08-18-2017 17:11:31.394+000: Reading previous [Admins du domaine] group members... 08-18-2017 17:11:31.409+000: Found [2] members that have been removed since last check 08-18-2017 17:11:31.409+000: Emailed change notification to [email protected]
III. Les notifications
Le script génère un rapport au format HTML, qu'il est ensuite possible de consulter facilement, comme vous le verrez sur l'image ci-dessous. J'ai essayé de le faire le plus clair possible, en mettant en évidence les changements, avec d'un côté les ajouts et d'un autre les suppressions.
Le script peut envoyer le contenu du rapport directement dans un e-mail en tant que contenu HTML, ce qui permet d'avoir le compte-rendu directement visible dans sa messagerie, par exemple :
En exécutant ce script via une tâche planifiée de manière régulière sur votre Active Directory, vous serez en mesure de détecter tout comportement suspect au niveau des groupes Active Directory sensibles. Ceci me paraît indispensable alors je vous encourage à mettre en place ce type de surveillance, que ce soit par l'intermédiaire de ce script, ou d'un autre outil/script.
Sinon concernant le script que je vous propose, avez-vous des idées d'amélioration ?
Super travail, merci beaucoup !
Merci Florian,
Je cherchais un script qui me permettrait de cibler lorsqu’on dépasse un nombre X d’usagers dans un groupe. Je serai en mesure de me baser sur celui que tu proposes.
Le but étant de recevoir une notification dans notre billetterie lorsque unp nombre d’usager est atteint, une fonction très utile pour la gestion des licences de type User Cal.
Bonjour !
Ce script est très intéressant, merci pour le partage.
Je suis en train de chercher comment on peut l’améliorer sur 2 aspects :
– Amélioration de la sécurité en se basant sur les GUID des objets utilisateurs vérifiés, plutôt que le logusername
– Tenter d’utiliser un encodage UTF-8 des fichiers CSV. Car aujourd’hui si un utilisateur possède un tréma dans son prénom par ex, le script le détecte en faux positif (utilisateur ajouté puis supprimé)
Bonjour,
script fonctionnel. Merci beaucoup.
J’ai juste un soucis dans mon rapport, il y a des suppressions et ajouts du même compte. Le soucis viens des accents (du coupe, du groupe ou de l’OU).
Bonjour,
Très bon travail.
J’ai le message d’erreur suivant: The « = » operator is missing after a named argument. Le script n’est-il compatible qu’avec PS V3 et supérieur?
Bonjour,
Merci. Quelle est la ligne mentionnée dans le message d’erreur ?
Cordialement,
Florian
Bonjour,
Dès la première ligne (43).
Le message complet est:
The « = » operator is missing after a named argument.
At C:\temp\Get-AdGroupMembershipChange.ps1:43 char:38
+ [CmdletBinding(SupportsShouldProcess) <<<< ]
+ CategoryInfo : ParserError: (:) [], ParseException
+ FullyQualifiedErrorId : MissingEqualsInNamedArgument
Merci.
Hello,
Merci pour ce script bien utile !
J’aimerais le lancer via le planificateur de tâches mais je ne comprends pas comment passer les arguments du script. J’ai tout essayé (via CMD, un autre PS1, …)
Merci d’avance !
Hello Alexis,
Tu dois pouvoir le lancer directement en intégrant les arguments, faut juste la bonne syntaxe. Je vais d’ailleurs publier un article à ce sujet prochainement. Sinon, tu peux utiliser un autre script en tant que lanceur.
Il suffira d’y inclure :
Set-Location "C:/path/to/the/script"
./Get-AdGroupMembershipChange.ps1 -Email....
Ca doit fonctionner 🙂
Bonne soirée
Florian
Bonjour Florian,
Merci de ta réponse, il me manquait le « Set-Location » lorsque j’avais voulu lancer le script à partir d’un autre.
Je viens de modifier ma tâche planifiée en utilisant la syntaxe indiquée dans ton nouvel article (qui vient à point :-)), ça fonctionne parfaitement !
Encore merci et bravo pour ce site qui me sert quotidiennement.
Alexis
Bonjour,
Je viens de tester le script qui fonctionne à merveille pour les logs etc etc sauf qu’en le lançant avec les paramètres il y’en a qui provoque une erreur, le voici : -SendByMail:$true
Voici l’erreur que j’ai :
C:\scripts\Get-AdGroupMembershipChange.ps1 : A parameter cannot be found that matches parameter name ‘SendByMail’.
At line:1 char:72
+ … pChange.ps1 -Email « [email protected] » -SendByMail:$true -E …
+ ~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [Get-AdGroupMembershipChange.ps1], ParameterBindingException
+ FullyQualifiedErrorId : NamedParameterNotFound,Get-AdGroupMembershipChange.ps1
BOnjour,
Merci pour le script il fonctionne a merveille en tache plannifié.
Serait-il possible d’intégré une colonne avec le nom du compte qui a fait l’action d’ajout ou de suppression?
Franchement, c’est juste top!
Un grand merci!
Bonjour à tous.
Peut être mon commentaire n’est pas au bon endroit, mais j’ai une préoccupation :
J’ai l’Active Directory sur Windows Server 2008 R2, le serveur sur lequel ils sont installés est en dégradation.
Je souhaite donc installer Windows Server 2012 sur un autre PC en important l’Active Directory du précedent serveur.
Est ce possible? si oui comment le faire?
Bonjour,
Merci pour ce script pertinent.
Pensez vous qu’il serait possible de créer un script similaire qui analyserait les modifications effectuées au sein de notre AD au niveau de la composition des OU (Blocage de compte – Création de compte – Suppression d’un compte – Déplacement de compte) ?
Par avance merci à vous.
Cordialement.
Bonjour Gérald,
Oui cela me semble envisageable, plus ou moins facilement en fonction de ce que l’on souhaite analyser. La création d’un compte est assez simple puisqu’il y a l’attribut whenCreated. Pour les comptes supprimés, il faudrait analyser le contenu de la corbeille Active Directory. Pour le déplacement de compte, c’est là où à première vue je dirais qu’il faut être capable de tracer quelque part, dans un fichier par exemple, l’OU d’un compte pour pouvoir comparer avec son OU dans l’AD. Un peu plus de travail sur cette partie-là.
Bonne soirée
Florian
Bonjour Florian, Tout d’abord je te REMERCIE pour ces articles techniques détaillés et pertinents ! Aussi, j’ai utilisé ce script de détection de chgt des membres de groupes, et cela fonctionne sur le domaine AD « A » mais pas sur un autre domaine AD « B ». (AD en version 2016 et Framework v4.7 à jour sur l’O/S).
Le msg d’erreur sur le domaine AD « B » est le suivant :
PS C:\Scripts\Audit> .\Get-AdGroupMembershipChange.ps1
cmdlet Get-AdGroupMembershipChange.ps1 at command pipeline position 1
Supply values for the following parameters:
Group[0]: Administrators
Group[1]: DnsAdmins
Group[2]:
C:\Scripts\Audit\Get-AdGroupMembershipChange.ps1 : The server was unable to process the request due to an internal
error. For more information about the error, either turn on IncludeExceptionDetailInFaults (either from
ServiceBehaviorAttribute or from the configuration behavior) on the server in order to send the
exception information back to the client, or turn on tracing as per the Microsoft .NET Framework SDK documentation and
inspect the server trace logs. – Line Number: 161
At line:1 char:1
+ .\Get-AdGroupMembershipChange.ps1
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [Write-Error], WriteErrorException
+ FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException,Get-AdGroupMembershipChange.ps1
Si tu as une idée et/ou remarque car je ne vois pas comment débugger ces erreurs.
Merci d’avance.
Esteban
Hello Esteban,
Jamais eu cette erreur. J’ai fait quelques recherches, cela pourrait être dû à un nom de groupe très long (j’en doute), un nom d’utilisateur ou un groupe qui contient « / » dans le nom ou à un objet orphelin dans l’un des groupes surveillés
Voir ce lien : https://webactivedirectory.com/2016/12/21/get-adprincipalgroupmembership-internal-error/
Est-ce que tu as ça de ton côté ?
Bon courage
Florian
Bonjour,
Merci pour le script, malheureusement il ne fait pas tout ce que je souhaiterai…
Je suis tombé sur PSWinReporting qui a l’air pas mal et mériterait peur être un article 🙂
Cordialement,
GL
Bonjour Florian.
Tout d’abord je te remercie pour cet article.
Je l’ai testé sur mon infra WS2019 et cela fonctionne très bien.
Je ne suis que débutant sous PowerShell et je ne trouve pas de réponse à une question qui concerne ton script en rapport à mon infra.
En effet, j’ai une infra qui comporte plus de 200 Group en admin et autant en chef de projet et Officiers.
Nous avons mis cela en place pour référencer les différents droits sur nos applications.
Existe t il un moyen de remplacer les noms des groupes pour les argument dans Group %officier% par exemple qui reprendrait tous les noms commençant par officier ?
L’ensemble de ces groupes sont dans des répertoire dans l’arborescence AD est il possible de remplacer le Group pour le conteneur des groupes ?
Je ne trouve rien sur internet car je n’ai surement pas la bonne syntaxe pour expliciter mon pb…
D’avance merci.
Bonjour David,
Cela fait un moment que je n’ai pas touché à ce script 🙂
Mais, vu que la liste des groupes à surveiller est définie dans la variable $Group, il faudrait jouer sur le contenu de cette variable. Tu devrais essayer ça :
Ligne 55 : « [Parameter(Mandatory)] » devient « [Parameter()] »
Ligne 56 – Pour récupérer le nom de tous les groupes d’une OU spécifique (DN de l’OU à adapter) :
[string[]]$Group = (Get-ADGroup -Filter * -SearchBase "OU=Personnel,DC=it-connect,DC=local").Name,
Ligne 56 (alternative) – Pour récupérer le nom de tous les groupes où le nom commence par « Officier » :
[string[]]$Group = (Get-ADGroup -Filter 'Name -like "Officier*"').Name,
Je te laisse tester et me redire 😉
Cordialement,
Florian
Hello Florian.
Thanks for the wonderful Script. Noticed that it i simultaneously add the single account multiple Groups, Script shows the correct result. But Same if I remove single account simultaneously from multiple Groups. It is not showing the correct result. it will shows the last removed Group and others removed groups it will not show up in the result.
Please guide me how to address this issue.
Thanks in Advance
Venkatesh VR
Bonjour
Merci pour ce super script !!! il est vraiment pratique 🙂
Bien que tardive voici une option pour corriger le pb de faux positif avec les caractères accentués .
Aux trois endroits ou il ya la fonction Export-Csv ajouter -Encoding UTF8 dans les paramètres, cela force l’utf8 et semble corriger le problème avec les accents.
Export-Csv -Path $GroupFilePath -Encoding UTF8 -NoTypeInformation
Bonjour,
super le script.
Par contre y a t il un moyen d’ajouter une info pour savoir quel compte utilisateur qui aurait fait une modif dans un groupe ?
Merci
Bonjour Florian,
Tout d’abord merci pour ce script.
Je n’arrive pas a comprendre cette erreur:
Impossible de trouver un paramètre correspondant au nom « SendByMail ».
Au caractère Ligne:1 : 161
+ … s-AD-Group\rapport.html » -Email « [email protected] » -SendByMail:$true -L …
+ ~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument : (:) [Detect-Changes-AD-Group.ps1], ParameterBindingException
+ FullyQualifiedErrorId : NamedParameterNotFound,Detect-Changes-AD-Group.ps1
Bonjour,
Petite erreur dans le nom du paramètre.
Il faut mettre « -SendByEmail:$true » et non « -SendByMail:$true ».
Cordialement,
Yannick
Bonjour,
Je rencontre un problème pour auditer les groupes d’administrateurs suivant : « Administrateurs de l’entreprise », « Administrateurs du schéma », « Administrateurs », « Opérateurs de sauvegarde »
Cela fonctionne uniquement avec le groupe : « Admins du domaine » sinon j’ai le message d’erreur ci-dessous :
C:\Scripts\Audit_Group_Change_DomainAdmin\Get-AdGroupMembershipChange.ps1 : Impossible de trouver un objet avec
l’identité «Administrateurs de l’entreprise» sous: «DC=***,DC=***». – Line Number: 161
Au caractère Ligne:1 : 1
+ .\Get-AdGroupMembershipChange.ps1 -Email « alertesinformatiques@ott-im …
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [Write-Error], WriteErrorException
+ FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException,Get-AdGroupMembershipChange.ps1