Création des GG
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.
Il faut ensuite exporter, ou convertir ce tableau en csv, encodage UTF8, séparateur ";" point virgule.
On obtient alors ce fichier :
GG;Membre
ORG_GG_DIRECTION;
ORG_GG_FINANCE;
ORG_GG_RH;
ORG_GG_IT;
ORG_GG_DIRECTION;Alice MARTIN
ORG_GG_DIRECTION;Thomas ROBERT
ORG_GG_FINANCE;Julie LAMBERT
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 :
<#
===============================================================================
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"
# ----------------------------------------------------------------------------
# 0. 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)
# ----------------------------------------------------------------------------
$utf8Bom = New-Object System.Text.UTF8Encoding($true)
[System.IO.File]::WriteAllText($LogFile, "", $utf8Bom)
# ----------------------------------------------------------------------------
# 2. Lecture CSV GG
# ----------------------------------------------------------------------------
if (-not (Test-Path $CSVPath)) {
Write-Error "Fichier CSV introuvable : $CSVPath"
exit 1
}
$data = Import-Csv -Path $CSVPath -Delimiter ";" |
Where-Object { $_.GG -and $_.GG.Trim() -ne "" }
if ($data.Count -eq 0) {
Write-Host "Aucun groupe global a traiter."
exit 0
}
# ----------------------------------------------------------------------------
# 3. Petite fonction de nettoyage (supprime espaces HTML, nbsp, guillemets)
# ----------------------------------------------------------------------------
function Clean-Cell([string]$s) {
if (-not $s) { return "" }
$s = $s -replace " ", " "
$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 $ggName : $_`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 GG
$totalB = $groups.Count
$indexB = 0
Write-Host ""
Write-Host "Pass B : Injection des membres dans chaque GG"
foreach ($grp in $groups) {
$indexB++
Write-Progress -Activity "Pass B - Inj. membres" `
-Status "$indexB / $totalB - $($grp.Name)" `
-PercentComplete (($indexB/$totalB)*100)
$GroupName = Clean-Cell $grp.Name
if (-not $GroupName) { continue }
# ------------------------------------------------------
# 5.1 Reset membres du GG
# ------------------------------------------------------
try {
$existing = 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 {
New-ADGroup -Name $GroupName -SamAccountName $GroupName -Path $OUPath `
-GroupScope Global -GroupCategory Security -ErrorAction Stop | Out-Null
}
catch {
$msg = "Erreur creation tardive du groupe $GroupName : $_`r`n"
[System.IO.File]::AppendAllText($LogFile, $msg, $utf8Bom)
Write-Warning "Impossible de traiter $GroupName (voir log)"
continue
}
}
# ------------------------------------------------------
# 5.2 Ajouter les membres GROUPE (tous existent depuis Pass A)
# ------------------------------------------------------
foreach ($line in $grp.Group) {
$m = Clean-Cell $line.Membre
if (-not $m) { continue }
if ($m -notlike "*_GG_*") { continue }
$child = Get-ADGroup -Identity $m -ErrorAction SilentlyContinue
if (-not $child) {
$msg = "Groupe membre introuvable (apres Pass A) : $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 " + GG : $m"
}
# ------------------------------------------------------
# 5.3 Ajouter les membres UTILISATEUR
# ------------------------------------------------------
foreach ($line in $grp.Group) {
$m = Clean-Cell $line.Membre
if (-not $m) { continue }
if ($m -like "*_GG_*") { continue }
$user = Get-ADUser -Filter { DisplayName -eq $m } -ErrorAction SilentlyContinue
if (-not $user) {
$msg = "Utilisateur introuvable : $m (groupe : $GroupName)`r`n"
[System.IO.File]::AppendAllText($LogFile, $msg, $utf8Bom)
Write-Warning "Utilisateur introuvable : $m -> ignore"
continue
}
Add-ADGroupMember -Identity $GroupName -Members $user.SamAccountName `
-ErrorAction SilentlyContinue
Write-Host " + USR: $m"
}
}
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.


No comments to display
No comments to display