Cybersécurité & Systèmes

Sécurisation des Scripts de Sauvegarde PowerShell

Refonte des scripts de sauvegarde vers un NAS : suppression des mots de passe en clair, stockage des secrets via DPAPI (Export-Clixml), exécution fiable avec Robocopy et déploiement industrialisé des tâches planifiées.

Session 2026 Production Admin Réseau
Documentation et ressources

Contexte et Objectifs

Contexte et Risque

Les postes industriels exécutaient des scripts de copie vers un partage central ; la revue de sécurité a révélé une exposition critique des identifiants. Les machines produisent des données via un logiciel métier ; un script PowerShell les synchronise vers un NAS centralisé avec Robocopy. L'accès au partage était scripté avec des identifiants intégrés au fichier, ce qui violait le principe de moindre privilège et exposait le SI en cas de compromission d'un poste.

# Exemple illustratif de la faille (valeurs fictives)
$User = "DOMAINE\svc_backup"
$PlainPassword = "MotDePasse_Exemple_NePasFaire"
$SecurePass = ConvertTo-SecureString $PlainPassword -AsPlainText -Force
$cred = New-Object PSCredential($User, $SecurePass)
New-PSDrive -Name "Z" -PSProvider FileSystem -Root "\\NAS-ENTREPRISE\backup\[SITE]" -Credential $cred
robocopy "D:\DonneesMetier" "Z:\Sauvegardes" /E

Objectifs du Projet

  • Éliminer les secrets : aucun mot de passe lisible dans le code source, les dépôts ou le disque en clair.
  • Chiffrement DPAPI : utilisation de Export-Clixml pour lier les identifiants au compte Windows et à la machine.
  • Continuité : conserver la même fréquence et la même destination de sauvegarde, sans régression fonctionnelle.
  • Journalisation : tracer les exécutions (niveaux, horodatage) pour le support et l'audit.

Environnement Technique

  • PowerShell 5.1
  • DPAPI (Export-Clixml)
  • Robocopy
  • NAS (partage réseau)
  • Active Directory
  • PSDrive (lecteurs mappés)
  • Tâches planifiées Windows
  • Machines industrielles

Réalisation des tâches

Six étapes : de l'audit à l'automatisation du déploiement des tâches planifiées.

1. Audit des scripts existants

Recensement des scripts par emplacement logique (sites / rôles), inventaire des comptes utilisés et repérage systématique des chaînes sensibles (ConvertTo-SecureString -AsPlainText, concaténation de mots de passe, fichiers .ps1 modifiables par des profils non admin).

2. Commande INIT — chiffrement DPAPI

Création d'un dossier masqué sous le profil utilisateur et export d'un SecureString chiffré par DPAPI. Le fichier XML n'est pas réutilisable sur une autre machine ni sous un autre compte Windows.

$credDir = Join-Path $HOME ".backup_creds"
if (-not (Test-Path -LiteralPath $credDir)) {
    $null = New-Item -ItemType Directory -Path $credDir -Force
    $dirItem = Get-Item -LiteralPath $credDir
    $dirItem.Attributes = $dirItem.Attributes -bor [System.IO.FileAttributes]::Hidden
}
$xmlPath = Join-Path $credDir "nas_credential.xml"
Read-Host "Mot de passe du compte de service (fictif)" -AsSecureString |
    Export-Clixml -Path $xmlPath

3. Réécriture des scripts — chargement sécurisé

Les scripts de production importent le secret via Import-Clixml et reconstruisent un PSCredential. Si l'INIT n'a pas été exécutée, un message explicite évite un échec silencieux.

$credFile = Join-Path $HOME ".backup_creds\nas_credential.xml"
if (-not (Test-Path -LiteralPath $credFile)) {
    Write-Error "Fichier d'identifiants introuvable. Exécutez d'abord le script INIT sur ce poste sous le compte d'exécution de la tâche planifiée."
    exit 1
}
$secureFromDisk = Import-Clixml -Path $credFile
$userName = "DOMAINE\svc_backup"
$cred = New-Object System.Management.Automation.PSCredential($userName, $secureFromDisk)

4. Mappage réseau et Robocopy

Suppression préalable du lecteur logique pour éviter les conflits, création du PSDrive avec les identifiants chargés, puis copie avec Robocopy. Les codes de sortie sont qualifiés : une valeur strictement inférieure à 8 est considérée comme succès.

$driveName = "Z"
if (Get-PSDrive -Name $driveName -ErrorAction SilentlyContinue) {
    Remove-PSDrive -Name $driveName -Force -ErrorAction SilentlyContinue
}
$nasRoot = "\\NAS-EXEMPLE\partage\sauvegardes\SITE_GENERIQUE"
New-PSDrive -Name $driveName -PSProvider FileSystem -Root $nasRoot -Credential $cred -Scope Script | Out-Null

$src = "D:\DonneesMetier"
$dst = "${driveName}:\"
& robocopy $src $dst /E /FFT /COPY:DAT /Z /R:3 /W:5 /XJ
$rc = $LASTEXITCODE
if ($rc -ge 8) {
    throw "Robocopy en échec (code $rc)"
}
# Codes 0–7 : succès ou situation sans erreur bloquante (documentation Microsoft)

5. Journalisation structurée

Fonction Write-Log avec quatre niveaux (OK, ECHEC, WARN, INFO), horodatage au format dd/MM/yyyy HH:mm:ss, couleurs en console. Un try/catch non bloquant tente de copier le fichier de log vers le NAS sans faire échouer la sauvegarde si le partage est momentanément indisponible.

$script:LogFile = Join-Path $env:ProgramData "BackupMetier\sauvegarde.log"
$logDir = Split-Path $script:LogFile
if (-not (Test-Path $logDir)) { New-Item -ItemType Directory -Path $logDir -Force | Out-Null }

function Write-Log {
    param([ValidateSet('OK','ECHEC','WARN','INFO')][string]$Level, [string]$Message)
    $ts = Get-Date -Format 'dd/MM/yyyy HH:mm:ss'
    $line = "[$ts] [$Level] $Message"
    switch ($Level) {
        'OK'    { Write-Host $line -ForegroundColor Green }
        'ECHEC' { Write-Host $line -ForegroundColor Red }
        'WARN'  { Write-Host $line -ForegroundColor Yellow }
        'INFO'  { Write-Host $line -ForegroundColor Cyan }
    }
    Add-Content -Path $script:LogFile -Value $line
}

try {
    Copy-Item -Path $script:LogFile -Destination "\\NAS-EXEMPLE\partage\logs\poste_generique.log" -Force
} catch {
    Write-Log -Level WARN "Copie du log vers le NAS impossible : $($_.Exception.Message)"
}

6. Script de création de tâche planifiée

Un second script PowerShell enregistre la tâche en local (New-ScheduledTask) avec déclencheur (quotidien), compte d'exécution et chemin du script principal. Intérêt : éviter une configuration manuelle poste par poste lors du déploiement sur de nombreuses machines industrielles, homogénéiser les paramètres et réduire les erreurs humaines.

$taskName = "Sauvegarde_Metier_PS"
$scriptPath = "C:\Outils\Sauvegarde\Invoke-BackupSecurise.ps1"
$action = New-ScheduledTaskAction -Execute "powershell.exe" -Argument "-NoProfile -ExecutionPolicy Bypass -File `"$scriptPath`""
$trigger = New-ScheduledTaskTrigger -Daily -At "02:15"
$principal = New-ScheduledTaskPrincipal -UserId "DOMAINE\svc_backup" -LogonType Password -RunLevel Highest
$settings = New-ScheduledTaskSettingsSet -AllowStartIfOnBatteries -DontStopIfGoingOnBatteries -StartWhenAvailable
Register-ScheduledTask -TaskName $taskName -Action $action -Trigger $trigger -Principal $principal -Settings $settings -Force

Difficultés rencontrées

Lien DPAPI au compte de service

Si la tâche planifiée s'exécute sous un compte différent de celui qui a lancé l'INIT, le déchiffrement peut échouer sans message explicite selon le contexte.

Difficulté : échec silencieux ou erreur peu parlante lors de Import-Clixml.

Solution : procédure documentée — l'INIT doit être exécutée sous le même compte que la tâche planifiée, sur chaque machine concernée.

Compétence : Sécurité & procédures

Codes de sortie Robocopy

Robocopy renvoie par exemple 1 lorsque des fichiers ont été copiés avec succès, ce que PowerShell peut interpréter comme une erreur si l'on teste uniquement $? ou 0.

Difficulté : faux positifs « échec » alors que la copie est correcte.

Solution : qualification explicite — succès si code de sortie strictement inférieur à 8 ; sinon traitement d'erreur.

Compétence : Scripting & fiabilité

Déploiement multi-machines

Chaque poste industriel nécessite une INIT sous le bon compte ; multiplier les opérations manuelles augmente le risque d'oubli ou de mauvais compte.

Difficulté : répétition de la procédure sur un parc hétérogène.

Solution : script de création de tâche planifiée + checklist ; automatisation du déploiement des paramètres pour limiter les erreurs humaines.

Compétence : Déploiement & E5

Compétences E5 mobilisées

Gérer le patrimoine informatique (Patrimoine) Audit et recensement des scripts, conformité sécurité — inventaire des scripts par site et suppression des secrets en clair dans les fichiers déployés.
Répondre aux incidents (Incidents) Identification et correction d'une faille de sécurité — traitement de l'exposition des mots de passe et mise en place du modèle DPAPI + procédures.
Mettre à disposition un service (Service) Déploiement des scripts sécurisés sur les machines — bascule progressive des postes industriels vers les nouveaux scripts et tâches planifiées.
Travailler en mode projet (Projet) Planification par phases et déploiement multi-sites — audit, conception, tests pilotes puis généralisation sur l'ensemble des emplacements concernés.
Développement professionnel (Veille) Montée en compétence sur DPAPI et sécurité des secrets — maîtrise de SecureString, Export-Clixml et bonnes pratiques Windows.

Bilan personnel

Résultat. Les mots de passe ne figurent plus dans le code source ; les secrets sont chiffrés par DPAPI et liés au compte d'exécution. Les sauvegardes sont journalisées et le déploiement des tâches planifiées est reproductible grâce au script d'enregistrement.

Compétences développées

  • DPAPI / SecureString : Export-Clixml et Import-Clixml pour retirer les secrets du code.
  • Gestion des secrets Windows hors coffre centralisé, liés au compte machine.
  • Refactorisation PowerShell et séparation INIT / exécution planifiée.
  • Codes de sortie Robocopy et qualification des succès (strictement inférieur à 8).
  • Automatisation du déploiement via Register-ScheduledTask.

Améliorations possibles

  • Coffre-fort centralisé (type Vault) pour les comptes de service.
  • Supervision : remontée des codes de retour vers un outil de monitoring.
  • Rotation automatique des identifiants et revue périodique des ACL sur le NAS.

Ressources & documentation