« Un script est fiable parce qu’il exécute cent créations sans erreur. »
Une automatisation fiable valide les entrées, refuse les ambiguïtés, simule, journalise chaque décision et peut être relancée sans dupliquer les objets.
01Définis le contrat CSV
GivenName,Surname,SamAccountName,UserPrincipalName,Department,Title,TargetOU,Enabled
Alice,Martin,alice.martin,alice.martin@corp.soria.test,Operations,Technicienne,"OU=Users,DC=corp,DC=soria,DC=test",false
Les colonnes, formats, valeurs autorisées et encodage UTF-8 font partie du contrat. Un fichier librement édité sans validation n’est pas une source de vérité suffisante.
02Charge et valide les champs
$rows = Import-Csv 'C:\SORIA-Labs\AD-Identities-GPO-Audit\users-template.csv'
$required = 'GivenName','Surname','SamAccountName','UserPrincipalName','TargetOU','Enabled'
foreach ($row in $rows) {
foreach ($field in $required) {
if ([string]::IsNullOrWhiteSpace($row.$field)) {
throw "Champ requis absent : $field"
}
}
if ($row.UserPrincipalName -notmatch '^[^@]+@corp\.soria\.test$') {
throw "UPN invalide : $($row.UserPrincipalName)"
}
if (-not (Get-ADOrganizationalUnit -Identity $row.TargetOU -ErrorAction SilentlyContinue)) {
throw "OU introuvable : $($row.TargetOU)"
}
}
03Refuse les doublons
$duplicateSam = $rows |
Group-Object SamAccountName |
Where-Object Count -gt 1
if ($duplicateSam) {
throw "SamAccountName dupliqué : $($duplicateSam.Name -join ', ')"
}
foreach ($row in $rows) {
if (Get-ADUser -Filter "SamAccountName -eq '$($row.SamAccountName)'" ) {
Write-Warning "Objet déjà présent : $($row.SamAccountName)"
}
}
04Construis une fonction ShouldProcess
function New-SoriaAdUser {
[CmdletBinding(SupportsShouldProcess, ConfirmImpact = 'High')]
param(
[Parameter(Mandatory)]
[pscustomobject]$Row,
[Parameter(Mandatory)]
[securestring]$InitialPassword
)
if (Get-ADUser -Filter "SamAccountName -eq '$($Row.SamAccountName)'" ) {
return [pscustomobject]@{
SamAccountName = $Row.SamAccountName
Status = 'Skipped'
Detail = 'Already exists'
}
}
if ($PSCmdlet.ShouldProcess($Row.SamAccountName, 'Create AD user')) {
$params = @{
Name = "$($Row.GivenName) $($Row.Surname)"
GivenName = $Row.GivenName
Surname = $Row.Surname
SamAccountName = $Row.SamAccountName
UserPrincipalName = $Row.UserPrincipalName
Department = $Row.Department
Title = $Row.Title
Path = $Row.TargetOU
AccountPassword = $InitialPassword
Enabled = [System.Convert]::ToBoolean($Row.Enabled)
ChangePasswordAtLogon = $true
}
New-ADUser @params
}
}
05Simule tout le lot
$password = Read-Host 'Mot de passe initial' -AsSecureString
$results = foreach ($row in $rows) {
try {
New-SoriaAdUser -Row $row -InitialPassword $password -WhatIf
}
catch {
[pscustomobject]@{
SamAccountName = $row.SamAccountName
Status = 'Error'
Detail = $_.Exception.Message
}
}
}
$results | Export-Csv 'C:\SORIA-Labs\AD-Identities-GPO-Audit\simulation-results.csv' -NoTypeInformation -Encoding UTF8
06Prépare le rollback
Le rollback n’est pas automatiquement « supprimer tous les comptes créés ». Préfère désactiver, marquer avec un identifiant de lot, retirer les groupes et conserver le rapport jusqu’à validation.
Get-ADUser -Filter "Description -like '*SORIA-IMPORT-20260804*'" |
Disable-ADAccount -WhatIf
Écris un import idempotent
Le script doit valider le CSV, simuler par défaut, ignorer les objets déjà conformes, signaler les différences, journaliser chaque ligne et fournir un plan de rollback.
✓Ce que tu retiens
L’automatisation ne supprime pas le contrôle : elle formalise validation, simulation, exécution, preuve et reprise.