Skip to main content

Création des GG

agdlp.png

Introduction

Nous allons attaquer la partie des groupes globaux, les créer automatiquement via un script, et y ajouter des membres avec le même principe.

Tableau modèle

Il nous faut d'abord le fichier qui servira de modèle, que l'on mettra à jour, pour faire les modifications.
Le gros avantage est que ce fichier peut-être divisé par service, et distribué aux responsables et directeurs de services pour avoir des infos toujours à jour, sans donner accès à une console d'administration.

Groupe Prenom Nom GG_Direction

Rozennimage.png

LUCAS

GG_Direction

Philippe PALAS GG_Comptablité Bertrand KANMEM GG_Comptablité Céline DUPUI GG_Comptablité Dylan BLOT GG_Comptablité Anthony VORPAL GG_RH Stéphanie ROBERT GG_RH Paul MORINIERE GG_RH Francois PARLAT

Il faut ensuite exporter, ou convertir ce tableau en csv, encodage UTF8, séparateur ";" point virgule.

On obtient alors ce fichier :

Groupe;Prenom;NomGG;Membre
GG_Direction;Rozenn;LUCASORG_GG_DIRECTION;
GG_Direction;Philippe;PALASORG_GG_FINANCE;
GG_Comptablité;Bertrand;KANMEMORG_GG_RH;
GG_Comptablité;Céline;DUPUIORG_GG_IT;
GG_Comptablité;Dylan;BLOTORG_GG_DIRECTION;Alice GG_Comptablité;Anthony;VORPALMARTIN
GG_RH;Stéphanie;ORG_GG_DIRECTION;Thomas ROBERT
GG_RH;Paul;MORINIEREORG_GG_FINANCE;Julie GG_RH;Francois;PARLATLAMBERT
ORG_GG_FINANCE;Nicolas PETIT
ORG_GG_RH;Sophie DURAND
ORG_GG_RH;Marc LEFEVRE
ORG_GG_IT;Lucas MOREAU
ORG_GG_IT;Emma GARNIER
ORG_GG_IT;Hugo CHEVALIER
ORG_GG_COMMUNICATION;
ORG_GG_COMMUNICATION;Clara BERTRAND
ORG_GG_LOGISTIQUE;
ORG_GG_LOGISTIQUE;Antoine RENAUD

Création des GG

Voici à présent le script qui permet de créer tous les GG, dans un seul et même endroit, dans OU=GG,OU=AGDLP,DC=domain,DC=local :

Import-Module<#
ActiveDirectory===============================================================================
SCRIPT : 5.1 - Creation_GG.ps1  (Version 2-passes, robuste)
OBJET  : Creation des Groupes Globaux (GG) + alignement de leurs membres
===============================================================================

PRINCIPE :
  PASS A : Creer tous les groupes globaux (GG et sous-GG) avant ajout des membres
  PASS B : Vider contenu de chaque GG puis injecter les membres (GG puis utilisateurs)

AVANTAGES :
  - Plus aucune erreur "groupe introuvable"
  - Les sous-GG peuvent apparaitre apres les parents dans le CSV
  - Nettoyage des caracteres parasites (nbsp, guillemets, espaces)
  - Sorties visibles sans accents (compatibilite console)
===============================================================================
#>

Param(
    [string]$CSVPath = "C:\AGDLP\ORG_ARBO_GDL.csv",
    [string]$OUPath  = "OU=GG,OU=AGDLP,DC=domain,DC=local",
    [string]$LogFile = "C:\AGDLP\AD_Group_Update_Errors.txt"
)

$ErrorActionPreference = "Stop"

# ----------------------------------------------------------------------------
# CONFIGURATION0. Module AD
# ----------------------------------------------------------------------------
try { Import-Module ActiveDirectory -ErrorAction Stop }
catch {
    Write-Error "Module ActiveDirectory non disponible. Installer RSAT."
    exit 1
}

# ----------------------------------------------------------------------------
# 1. Reset fichier log (UTF-8 BOM)
# ----------------------------------------------------------------------------
$CSVPathutf8Bom = New-Object System.Text.UTF8Encoding($true)
[System.IO.File]::WriteAllText($LogFile, "C:\chemin\vers\GG.csv"", $OUPath  = "OU=GG,OU=AGDLP,DC=domain,DC=local"
$LogFile = "C:\chemin\vers\AD_Group_Update_Errors.txt"utf8Bom)

# Nettoyage du fichier de logs
"" | Out-File $LogFile----------------------------------------------------------------------------
# Import2. sansLecture lignesCSV videsGG
# ----------------------------------------------------------------------------
if (-not (Test-Path $CSVPath)) {
    Write-Error "Fichier CSV introuvable : $CSVPath"
    exit 1
}

$data = Import-Csv -Path $CSVPath -Delimiter ";" |
        Where-Object { $_.GroupeGG -and $_.Groupe.GG.Trim() -ne "" }

if ($data.Count -eq 0) {
    Write-Host "Aucun groupe global a traiter."
    exit 0
}

# Regroupement----------------------------------------------------------------------------
par# 3. Petite fonction de nettoyage (supprime espaces HTML, nbsp, guillemets)
# ----------------------------------------------------------------------------
function Clean-Cell([string]$s) {
    if (-not $s) { return "" }
    $s = $s -replace "&nbsp;", " "
    $s = $s -replace "\u00A0", " "
    $s = $s -replace "\u200B", ""
    $s = $s -replace "[«»“”‘’]", ""
    return ($s -replace "\s+", " ").Trim()
}

foreach ($row in $data) {
    $row.GG     = Clean-Cell $row.GG
    $row.Membre = Clean-Cell $row.Membre
}

# ----------------------------------------------------------------------------
# 4. PASS A : CREATION DE TOUS LES GROUPES (GG + sous-GG references)
# ----------------------------------------------------------------------------

# Ensemble de tous les groupes a creer
$allGG = New-Object System.Collections.Generic.HashSet[string] ([StringComparer]::OrdinalIgnoreCase)

# Tous les GG declares
$data | ForEach-Object { $null = $allGG.Add($_.GG) }

# Tous les GG references comme Membre
foreach ($row in $data) {
    if ($row.Membre -and ($row.Membre -like "*_GG_*")) {
        $null = $allGG.Add($row.Membre)
    }
}

# Correction : pas de .ToArray(), on convertit proprement en tableau PowerShell
$allGGList = @($allGG)

$totalA = $allGGList.Count
$indexA = 0

Write-Host "Pass A : Creation des GG (sans membres) - Total: $totalA"
foreach ($ggName in $allGGList) {
    $indexA++
    Write-Progress -Activity "Pass A - Creation GG" -Status "$indexA / $totalA" -PercentComplete (($indexA/$totalA)*100)

    if ([string]::IsNullOrWhiteSpace($ggName)) { continue }

    $exists = Get-ADGroup -Filter "SamAccountName -eq '$ggName'" `
                      -SearchBase $OUPath `
                      -ErrorAction SilentlyContinue

    if ($exists) { continue }

    try {
        New-ADGroup -Name $ggName -SamAccountName $ggName -Path $OUPath `
            -GroupScope Global -GroupCategory Security -ErrorAction Stop | Out-Null
        Write-Host "Cree : $ggName"
    }
    catch {
        $msg = "Erreur creation du groupe $groupesggName : $_`r`n"
        [System.IO.File]::AppendAllText($LogFile, $msg, $utf8Bom)
        Write-Warning "Creation impossible : $ggName (voir log)"
    }
}

Write-Progress -Activity "Pass A - Creation GG" -Completed

# ----------------------------------------------------------------------------
# 5. PASS B : VIDER et RE-INJECTER les membres
# ----------------------------------------------------------------------------

$groups = $data | Group-Object -Property GroupeGG

$totalB = $groups.Count
$indexB = 0

Write-Host ""
Write-Host "Pass B : Injection des membres dans chaque GG"

foreach ($grp in $groupes)groups) {
    $indexB++
    Write-Progress -Activity "Pass B - Inj. membres" `
        -Status "$indexB / $totalB - $($grp.Name)" `
        -PercentComplete (($indexB/$totalB)*100)

    $GroupName = Clean-Cell $grp.Name.Trim()Name
    Write-Hostif "`n=== Groupe :(-not $GroupNameGroupName) ==="{ continue }

    # ------------------------------------------------------
    Créer# le5.1 groupeReset s'ilmembres n'existedu pasGG
    # ------------------------------------------------------
    try {
        $ADGroupexisting = Get-ADGroup -Identity $GroupName -ErrorAction Stop
        $members = Get-ADGroupMember -Identity $GroupName -ErrorAction SilentlyContinue
        if ($members) {
            Remove-ADGroupMember -Identity $GroupName -Members $members `
                -Confirm:$false -ErrorAction SilentlyContinue
        }
    }
    catch {
        # Si pour une raison obscure il n existe pas, on tente creation tardive
        try {
            $ADGroup =
            New-ADGroup -Name $GroupName `
                        -SamAccountName $GroupName ` -Path $OUPath `
                -GroupScope Global -GroupCategory Security -ErrorAction Stop | Out-Null
        }
        catch {
            $msg = "ERREURErreur créationcreation tardive du groupe '$GroupName'GroupName : $_"_`r`n"
            | Out-File[System.IO.File]::AppendAllText($LogFile, $LogFilemsg, -Append$utf8Bom)
            Write-Warning "Impossible de traiter $GroupName (voir log)"
            continue
        }
    }

    # ------------------------------------------------------
    Ajout# des5.2 Ajouter les membres GROUPE (tous existent depuis Pass A)
    # ------------------------------------------------------
    foreach ($ligneline in $grp.Group) {
        # Colonnes sans accents
        $Prenomm = $ligne.PrenomClean-Cell $Nom    = $ligne.Nom

        # Vérification des champsline.Membre
        if (-not $Prenom -or -not $Nom)m) {
            "Ligne invalide dans CSV : '$($ligne)' (groupe : $GroupName)" | Out-File $LogFile -Append continue }
        #if Construction($m DisplayName-notlike "*_GG_*") { continue }

        $FullNamechild = Get-ADGroup -Identity $m -ErrorAction SilentlyContinue
        if (-not $child) {
            $msg = "$PrenomGroupe membre introuvable (apres Pass A) : $Nom".Trim()m (parent: $GroupName)`r`n"
            [System.IO.File]::AppendAllText($LogFile, $msg, $utf8Bom)
            Write-Warning "GG introuvable : $m -> ignore"
            continue
        }

        Add-ADGroupMember -Identity $GroupName -Members $child -ErrorAction SilentlyContinue
        Write-Host " + RechercheGG : $FullName"m"
    }

    # Recherche------------------------------------------------------
    AD# par5.3 DisplayNameAjouter les membres UTILISATEUR
    # ------------------------------------------------------
    foreach ($line in $Usergrp.Group) {
        $m = Clean-Cell $line.Membre
        if (-not $m) { continue }
        if ($m -like "*_GG_*") { continue }

        $user = Get-ADUser -Filter { DisplayName -eq $FullNamem } -ErrorAction SilentlyContinue
        if (!-not $User)user) {
            $msg = "Utilisateur introuvable : $FullNamem (groupe : $GroupName)"`r`n"
            | Out-File[System.IO.File]::AppendAllText($LogFile, $LogFilemsg, $utf8Bom)
            Write-Warning "Utilisateur introuvable : $m -Append> ignore"
            continue
        }

        # Ajout au groupe
        try {

        Add-ADGroupMember -Identity $GroupName -Members $User.user.SamAccountName `
            -ErrorAction StopSilentlyContinue
        }
        catch {Write-Host "ERREUR ajout+ :USR: $FullName → $GroupName : $_" | Out-File $LogFile -Appendm"
    }
}

}Write-Progress -Activity "Pass B - Inj. membres" -Completed

Write-Host ""
Write-Host "Traitement GG termine avec succes. Voir le log si necessaire : $LogFile" -ForegroundColor Green

Si les utilisateurs existes, il se retrouves dans les groupes GG qui leurs correspondant dans le tableau.
J'ai pendant un moment pensé à faire une ligne par GG et séparer les utilisateurs par une ",", mais cela n'aurait pas été pratique pour les éventuels utilisateurs d'autres services.