Question Monitoring des groupes AD sensibles

Plus d'informations
il y a 2 ans 11 mois #31555 par Bruce
Bonsoir,

Voici un script qui permet de surveiller vos groupes AD sensibles (administrateurs, admin du domaine, admin du schema...et tous ceux que vous trouvez sensibles suivant votre organisation).

Je me suis inspiré d'un exemple du net que j'ai "amélioré" ou du moins fait correspondre a mes attentes.
Il doit s'exécuter sur un AD obligatoirement.

Pour automatiser la surveillance il faut créer une tache planifiée, et donc je suis passé par une alternative à l'exécution du script en PS1 car parfois j'avais des erreur soit 0x1 soit 0xFFFD0000 au résultat de l'exécution de la tâche planifiée.
Pour cela, vous devrez créer un fichier .bat du même nom que votre .PS1 dans le même répertoire avec à l'intérieur ces commandes:
@echo off
PowerShell.exe -Command -NoProfile -ExecutionPolicy Bypass "%~dpn0.ps1" -Verb RunAs


Dans mon cas la tâche planifiée a  2 déclencheurs, au démarrage en cas de redémarrage du serveur et tous les jours de la semaine à 8h00 avec répétition toutes les 5 minutes pendant 1 jour. Elle s'exécute avec les autorisations maximales même si l'utilisateur n'est pas logué et avec le compte administrateur du domaine.

Vous pouvez tester votre batch en le lançant directement pour voir si il exécute bien le script sans erreur.

Bon maintenant je vous présente le script, si vous voyez des améliorations à y apporter je suis preneur ou même pour optimiser les temps de traitements, je ne suis pas contre les remarques 
#########################################################################################################################
#
#                  NOM: MonitoringGroupAD
#                  VERSION: v2.0
#                  DESCRIPTION: Recherche de modifications des membres de groupe AD "sensibles 
#                  (Administrateurs, Admin du domaine, Admin du schema et tous les autres que vous estimez sensibles"
#
#########################################################################################################################

# ======================================================================================================
# Entrez ici le nom du groupe AD a surveiller
$Grp = "Administrateurs"
# ======================================================================================================
# Activation de Mode TEST: TRUE ou FALSE
$testing = $true
# ======================================================================================================
# Emplacement des fichiers de log
$logpath = "C:\Supervision\Logs\Groupes_AD\"
# ======================================================================================================
# Parametres pour evoi de rapport par mail
$smtpServer="10.X.Y.Z" # IP de votre serveur de mail
$from = "DSI Societe <MonitoringADgroup@votresociete.com>" # adresse de l'expediteur du mail pour votre script
$adminEmailAddr = "hotline@votresociete.com","user1@votresociete.com","user2@votresociete.com"
$testingEmailAddr = "user3@votresociete.com"
$textEncoding = [System.Text.Encoding]::UTF8
# ======================================================================================================

#Verification si execution sur un serveur AD
if (Get-Module -ListAvailable -Name ActiveDirectory) 
{
    Import-Module ActiveDirectory
    Import-Module GroupPolicy
} else 
{
    Write-Host "Programme annulé. Pas de module Active Directory trouvé. Utilisez ce programme sur un controlleur de domaine." -ForegroundColor Red
    throw "Error"
}

#Recupere le nom du script
$ScriptName = $MyInvocation.MyCommand.Name
#Chemin du répertoire contenant le script
$RepScript = [System.IO.Path]::GetDirectoryName($MyInvocation.MyCommand.Definition) 

# Recupération des infos du domaine
$SearchBase = (Get-AdDomainController).defaultpartition  # Resultat: DC=votredomaine,DC=local
$domain = $SearchBase -Split "," | ? {$_ -like "DC=*"}   # Resultat: DC=votredomaine DC=local
$domain = $domain -join "." -replace ("DC=", "")         # Resultat: votredomaine.local
#Nom du serveur d'execution du script
$serveur = [system.environment]::MachineName

#fichier de log en fonction du groupe a surveiller, de l'année et du mois en cours
$prefix = Get-Date -Format "yyyyMM-"
$nomGrp = $Grp -replace (" ","_")
$suffix = ".txt"
$monitorStateFilePath = $logpath + $prefix + $nomGrp + $suffix 

# Initialisation des variables
$oldMembers = $null
$newMembers = $null
$previousMembers = $null
$currentMembers = $null
$nbcurrentMembers = 0
$nbpreviousMembers = 0

# si le fichier de monitoring n'existe pas on le crée
 if (-not (Test-Path $monitorStateFilePath)) # Si le fichier log n'existe pas on le crée
 {
    New-Item -ItemType file -Path $monitorStateFilePath -Force
    $FirstRun = $true
 }else
 {
    $FirstRun = $false
 }

 #Efface l'écran pour faire propre ;)
Clear-Host

# Recuperation des membres actuels du groupe
$currentMembers = Get-AdGroupMember -Identity $Grp | Select-Object -ExpandProperty samAccountName
$nbcurrentMembers = [int]$currentMembers.Count

# Recuperation des membres du groupe depuisle fichier
if ($FirstRun -eq $false)
{
    $previousMembers = Import-Csv -Path $monitorStateFilePath | Sort-Object -Property {[datetime]$_.Time} -Descending | Select-Object -First 1 | Select-Object -ExpandProperty Members
    # Suppression des virgules pour la comparaison des tableaux
    $previousMembers = $previousMembers -split ','
    $nbpreviousMembers = [int]$previousMembers.Count
    # Debut du corps du mail
    $body="
    <p>Domaine: <font color=""0000FF"">$domain</font></br>
    <i>Modification des membres du groupe <b>$Grp</b></i></p>"
}else
{
    $nomdumois = (Get-Culture).DateTimeFormat.GetMonthName((Get-Date).Month)
    $nomdumois = $nomdumois.Substring(0,1).ToUpper() + $nomdumois.Substring(1).ToLower() #1ere lettre en majuscule
    $annee = Get-Date -Format "yyyy"   
    # Sujet du mail
    $subject="$nomdumois $annee - Debut monitoring du groupe $Grp"
    $body="
    <p>Domaine: <font color=""0000FF"">$domain</font></br>
    <i><font color=""FF0000"">Initialisation</font> de la surveillance du groupe <b>$Grp</b></i></br>
    Membres du groupe initial:
    </p><ul>"
    if ($testing -eq $true) 
    {
        Write-Host  -BackgroundColor DarkCyan -ForegroundColor White "MODE TEST: Initialisation de la surveillance du groupe $Grp"
        Write-Host  -BackgroundColor DarkCyan -ForegroundColor White "Il y at $nbcurrentMembers membres dans le groupe"
        Write-Host  -BackgroundColor DarkCyan -ForegroundColor White "Membres actuels du groupe $Grp`n"
    }
    foreach ($member in $currentMembers)
    {
        if ($testing -eq $true) { Write-Host "`t`t`t`t$member" }
        # Ajout des infos dans le mail            
        $body+="<li><b>$member</b></li>"       
    }
    $body+="</ul>"
}

# Format date pour fichier log
$now = Get-Date -UFormat '%m-%d-%y %H:%M'

# Ajout des membres du groupe actuel dans le fichier de log
[pscustomobject]@{
    'Time'    = $now
    'Members' = $currentMembers -join ','
} | Export-Csv -Path $monitorStateFilePath -NoTypeInformation -Append


#Choix du destinataire du mail en fonction du mode Test
if ($testing -eq $true) 
{
    $recipient = $testingEmailAddr
}else
{
    $recipient = $adminEmailAddr
}

#Recherche des modifications dans les membres du groupe
if ($FirstRun -eq $false)
{
    if (Compare-Object -ReferenceObject $previousMembers -DifferenceObject $currentMembers)  # Recherche des utilisateurs rajoutés ou supprimés au groupe   
    {               
        if ($nbcurrentMembers -gt $nbpreviousMembers) # Ajout de membres au groupe
        {            
            if ($testing -eq $true) # Sujet du mail mode Test : Nouveaux membres
            {
                $subject="MODE TEST: Nouveau(x) membre(s) dans le groupe $Grp"
                Write-Host  -BackgroundColor DarkCyan -ForegroundColor White " +++ MODE TEST +++: Nouveau(x) membre(s) dans le groupe $Grp"
            }else
            {
                $subject="URGENT DSI - Nouveau(x) membre(s) dans le groupe $Grp"
            }   
            $newMembers = $currentMembers | Where {($previousMembers -NotContains $_)}
            foreach ($member in $newMembers) # Ajout des membres ajoutés dans le mail 
            {
                if ($testing -eq $true) { Write-Host -BackgroundColor Red -ForegroundColor White "`t$member a été ajouté du groupe $Grp`n" }           
                $body+="L'utilisateur <b>$member</b> <font color=""FF0000"">a été ajouté</font> par rapport au précédent contrôle<br>"       
            }
        }else # Suppression des membres au groupe
        {                     
            if ($testing -eq $true) # Sujet du mail mode Test: Membres supprimés
            {
                $subject="MODE TEST: Suppression de membres dans le groupe $Grp"
                Write-Host  -BackgroundColor DarkCyan -ForegroundColor White " --- MODE TEST ---: Suppression de membres dans le groupe $Grp"
            }else
            {
                $subject="URGENT DSI - Suppression de membres dans le groupe $Grp"
            }            
            $oldMembers = $previousMembers | Where {($currentMembers -NotContains $_)}
            foreach ($member in $oldMembers) # Ajout des membres supprimés dans le mail
            {
                if ($testing -eq $true) { Write-Host -BackgroundColor Red -ForegroundColor White "`t$member a été supprimé du groupe $Grp`n" }
                $body+="L'utilisateur <b>$member</b> <font color=""FF0000"">a été supprimé</font> par rapport au précédent contrôle<br>"
            }
        }        
        if ($testing -eq $true) # Mode Test : Affichage des membres actuels du groupe et ajout des membres au corps du mail
        { 
            Write-Host  -BackgroundColor DarkCyan -ForegroundColor White "Il y at $nbcurrentMembers membres dans le groupe"
            Write-Host  -BackgroundColor DarkCyan -ForegroundColor White "Membres actuels du groupe $Grp`n"
            $body+="Membres actuels du groupe <b>$Grp</b>:
            </p><ul>"
            foreach ($member in $currentMembers)
            {
                Write-Host "`t`t`t`t$member"
                $body+="<li><b>$member</b></li>"    
            }
            $body+="</ul>"
        }
        else
        {
             $body+="Membres actuels du groupe <b>$Grp</b>:
            </p><ul>"
            foreach ($member in $currentMembers)
            {
                $body+="<li><b>$member</b></li>"    
            }
            $body+="</ul>"
        }
    $detectChanges = $true
    }
    else #si aucune difference entre fichier log et membres actuels du groupe
    {
        $detectChanges = $false
        $body="
        <p>Domaine: <font color=""0000FF"">$domain</font></br>
        <i>Aucune modification des membres du groupe <b>$Grp</b></i><br>"
        if ($testing -eq $true) 
        {
            $subject="MODE TEST: $nbcurrentMembers membres actuels dans le groupe $Grp"
            $body+="Membres du groupe:
            </p><ul>"
            Write-Host -BackgroundColor DarkCyan -ForegroundColor White "=== MODE TEST ==="
            Write-Host -BackgroundColor DarkCyan -ForegroundColor White "Aucun changement par rapport au fichier précédent"
            Write-Host -BackgroundColor DarkCyan -ForegroundColor White "Il y at $nbcurrentMembers membres dans le groupe $Grp"
            Write-Host -BackgroundColor DarkCyan -ForegroundColor White "Membres actuels du groupe $Grp`n"           
            foreach ($member in $currentMembers)
            {
                Write-Host "`t`t`t`t$member"
                $body+="<li><b>$member</b></li>"       
            }
            $body+="</ul>"
        }
     }
     # Ajout de pied de fin de mail
     $body+="
     <p>Serveur d'execution du script: <b>$serveur</b><br>
     Nom du script: <font color=""0000FF"">$ScriptName</font><br>
     Localisation du script: <font color=""0000FF"">$RepScript</font><br>
     Emplacement du fichier de log: <font color=""0000FF"">$monitorStateFilePath</font><br><br>    
     L'équipe Support VotreSociete.com<br>
     hotline@votresociete.com<br>
     https://votresociete.com<br></p>"

     # Envoi du mail 
     if (($detectChanges -eq $true) -or (($detectChanges -eq $false)-and ($testing -eq $true)))
     {
        Send-Mailmessage -smtpServer $smtpServer -from $from -to $recipient -subject $subject -body $body -bodyasHTML -Attachments "$monitorStateFilePath" -priority High -Encoding $textEncoding -ErrorAction Stop -ErrorVariable err
     }
}else # 1er démarrage du script
{    
     if ($testing -eq $true) { $subject="MODE TEST: $nomdumois $annee - Début monitoring du groupe $Grp"}    
     # Ajout de pied de fin de mail
     $body+="
     <p>Serveur d'execution du script: <b>$serveur</b><br>
     Nom du script: <font color=""0000FF"">$ScriptName</font><br>
     Localisation du script: <font color=""0000FF"">$RepScript</font><br>
     Emplacement du fichier de log: <font color=""0000FF"">$monitorStateFilePath</font><br><br>    
     L'équipe Support VotreSociete.com<br>
     hotline@votresociete.com<br>
     https://votresociete.com<br></p>"

    # Envoi du mail 
    Send-Mailmessage -smtpServer $smtpServer -from $from -to $recipient -subject $subject -body $body -bodyasHTML -Attachments "$monitorStateFilePath" -priority High -Encoding $textEncoding -ErrorAction Stop -ErrorVariable err
}


 

Connexion ou Créer un compte pour participer à la conversation.

Plus d'informations
il y a 2 ans 10 mois #31638 par Arnaud Petitjean
Merci Bruce pour le partage ! 

Juste une petite remarque au passage...
Plutôt que de tester la présence de modules dans ton code, il peut être préférable - même si je te l'accorde, ton message d'erreur sera plus explicite - d'utiliser la directive #Requires.

Ainsi en écrivant ceci au début de ton script : 
#Requires -Modules ActiveDirectory, GroupPolicy

Cela empêchera l'exécution de ton script si les modules ne sont pas présents sur la machine qui exécute le script.
Pour plus d'informations sur le sujet, consulter la rubrique about_requires

Arnaud

MVP PowerShell et créateur de ce magnifique forum :-)
Auteur de 6 livres PowerShell aux éditions ENI
Fondateur de la société Start-Scripting
Besoin d'une formation PowerShell ?
Les utilisateur(s) suivant ont remercié: Bruce

Connexion ou Créer un compte pour participer à la conversation.

Plus d'informations
il y a 2 ans 10 mois #31639 par Arnaud Petitjean
J'y pense ! Il y a une autre technique qui je pense serait plus efficace... Mais peut-être aussi un peu plus difficile à mettre en oeuvre, quoique...?

Il s'agit de mettre en place un abonnement WMI/CIM directement dans la base CIM (voir Register-CimIndicationEvent ). Ainsi dès qu'une modification a lieu sur le groupe en question (de quelque nature qu'elle soit), on exécute du code PowerShell qui pourrait envoyer un mail ou faire autre chose.

J'ai déjà testé mais pas avec des groupes AD et c'est super efficace comme technique. En plus ça ne consomme pratiquement aucune ressource et c'est beaucoup plus instantané qu'une tâche planifiée.

Bref... à tester ;-)

Arnaud

MVP PowerShell et créateur de ce magnifique forum :-)
Auteur de 6 livres PowerShell aux éditions ENI
Fondateur de la société Start-Scripting
Besoin d'une formation PowerShell ?

Connexion ou Créer un compte pour participer à la conversation.

Plus d'informations
il y a 2 ans 10 mois #31732 par Bruce
Réponse de Bruce sur le sujet Monitoring des groupes AD sensibles
Merci pour les infos dès que j'aurais un peu plus de temps j'essaierai le WMI/CIM, sinon j'aime bien mon message si les modules ne sont pas présents.

Bruce

Connexion ou Créer un compte pour participer à la conversation.

Plus d'informations
il y a 4 mois 6 jours #34517 par Francois Dunoyer
bonjour depuis le temps, est ce que quelqu'un a eu l'occasion de tester les abonnement WMI/CMI ?

et si le script est toujours d'actualité, je proposerait d'utiliser les SID de groupes ( surtout pour ceux bien connus) plutot que les noms
Perso je suis dans un environnement multi-domaines et régulièrement on recupére des config en anglais

Connexion ou Créer un compte pour participer à la conversation.

Plus d'informations
il y a 4 mois 6 jours #34518 par Arnaud Petitjean
Bonjour !

Oui, tu as raison François, il serait effectivement préférable d’utiliser les SID plutôt que des noms de groupes ou d’utilisateurs.

Je suis actuellement en mobilité et je n’ai pas d’exemple de code accessible sous la main, mais si vous avez mes livres, il y a des exemples de code dedans.

Arnaud

MVP PowerShell et créateur de ce magnifique forum :-)
Auteur de 6 livres PowerShell aux éditions ENI
Fondateur de la société Start-Scripting
Besoin d'une formation PowerShell ?
Les utilisateur(s) suivant ont remercié: Francois Dunoyer

Connexion ou Créer un compte pour participer à la conversation.

Temps de génération de la page : 0.120 secondes
Propulsé par Kunena