Chaîne AVHDX divergente dans Hyper‑V (Windows Server 2022) : cinq checkpoints 5‑9 pointant vers le même parent (4) perturbent Veeam et font « disparaître » des données. Voici des procédures sûres, scripts PowerShell et check‑list pour fusionner sans perte et remettre la sauvegarde d’équerre.
Contexte et problème à résoudre
Vous administrez une VM Hyper‑V (Windows Server 2022) qui dispose d’une chaîne de disques différenciés (checkpoints) longue et, surtout, divergente. Le tronc est linéaire (AVHDX 1 → 2 → 3 → 4
), mais cinq autres diff (5 à 9) pointent tous vers le même parent (4). Cette topologie n’est pas un simple « collier de perles » mais un arbre : chaque AVHDX 5‑9 est une branche sœur. Dans ce cas de figure, un merge séquentiel classique écrase le parent à chaque passage et rend les autres enfants illisibles. Effet de bord observé : Veeam sauvegarde un partage de fichiers mais perd la cohérence de la chaîne, d’où une « disparition » apparente de données.
VHDX (base)
└─ AVHDX 1
└─ AVHDX 2
└─ AVHDX 3
└─ AVHDX 4 <-- parent commun
├─ AVHDX 5
├─ AVHDX 6
├─ AVHDX 7
├─ AVHDX 8
└─ AVHDX 9
Pourquoi cette topologie casse la sauvegarde
- Règle des disques différenciés : un AVHDX est un delta qui dépend de l’empreinte exacte de son parent. Si le parent change après la création de l’enfant, l’enfant ne « reconnaît » plus son parent.
- Branches sœurs : 5‑9 sont indépendants les uns des autres. Fusionner 9→4 modifie 4 ; dès lors, 8/7/6/5 ne correspondent plus au parent attendu : montages impossibles, erreurs d’inspection, données inaccessibles.
- Veeam & checkpoints : selon le mode de sauvegarde et l’état des checkpoints (production vs standard, résidus, orphelins), Veeam peut ne plus suivre correctement la chaîne et ne capturer qu’un snapshot logique du partage, pas la totalité des deltas utiles.
Diagnostic rapide : établir la cartographie exacte
Avant toute action destructive, dressez l’état des lieux hors ligne (VM arrêtée si possible) :
- Inventaire des fichiers : repérez le répertoire de stockage de la VM (CSV, SMB 3, volume local). Sauvegardez la liste des VHDX/AVHDX.
dir D:\VMs\VM01\*.vhdx,*.avhdx /s > D:\VMs\VM01\_inventaire.txt
- Inspection PowerShell : récupérez ParentPath, dates et tailles.
$root = 'D:\VMs\VM01'
Get-ChildItem $root -Filter *.avhdx -Recurse |
Sort-Object LastWriteTime |
ForEach-Object {
$v = Get-VHD -Path $_.FullName
[pscustomobject]@{
Child = $_.FullName
ParentPath = $v.ParentPath
IsDifferencing = $v.VhdFormat
FileSizeGB = [math]::Round($v.FileSize/1GB,2)
VirtualSizeGB = [math]::Round($v.Size/1GB,2)
Modified = $_.LastWriteTime
}
} | Format-Table -Auto
- Identifier la branche utile : triez par
LastWriteTime
pour repérer l’AVHDX le plus récent (souvent 9). Montez chaque branche en lecture seule pour confirmer la présence de données uniques.
# Exemple de montage RO d'une branche
$path = 'D:\VMs\VM01\AVHDX9.avhdx'
$vh = Mount-VHD -Path $path -ReadOnly -PassThru
$disk = $vh | Get-Disk
# Attribuer une lettre de lecteur si besoin
$part = $disk | Get-Partition | Where-Object DriveLetter -ne $null | Select-Object -First 1
if (-not $part) { ($disk | Get-Partition | Select-Object -First 1) | Add-PartitionAccessPath -AssignDriveLetter }
Get-Volume -DiskNumber $disk.Number
# ...inspection...
Dismount-VHD -Path $path
Difficultés identifiées
- Chaîne divergente : les disques 5‑9 ne forment pas une suite linéaire mais des branches sœurs — un « merge en série » échoue mécaniquement.
- Risque de perte : fusionner successivement des enfants vers le même parent écrase l’état du parent après chaque merge. Les autres enfants deviennent orphelins.
- Sauvegarde incomplète : la sauvegarde « voit » le partage mais ne suit plus la totalité de la chaîne différenciée, d’où lacunes et « données manquantes ».
Stratégies de fusion comparées
Approche | Principe | Ordre conseillé | Avantages | Limites |
---|---|---|---|---|
Fusion sélective (réponse initiale) | Choisir le plus récent (9) et le fusionner dans 4, puis 8→4, etc. | 9→4, 8→4, 7→4, 6→4, 5→4 | Rapide si l’on ne garde qu’une branche | Écrase chaque fois le parent 4 ; les autres branches deviennent orphelines. |
Fusion vers un nouveau disque (méthode sûre) | Merge-VHD -Path <enfant> -DestinationPath <nouveau.vhdx> -Mode Full | Un enfant à la fois, ordre indifférent | Garde une copie intégrale de chaque branche ; zéro écrasement | Nécessite plus d’espace et de temps. |
Méthode « copie puis comparaison » (solution réellement appliquée) | 1) Sauvegarder 4. 2) Fusionner 9→4. 3) Monter le résultat, copier les écarts. 4) Restaurer 4 et recommencer avec 8, 7, … | 9→4, restauration, 8→4, etc. | Permet de récupérer toutes les données | Très fastidieux si beaucoup de disques. |
Procédure recommandée (sûre) : Fusionner chaque branche vers un nouveau VHDX
Objectif : conserver chaque branche intacte, produire des disques « pleins » autonomes, puis choisir en connaissance de cause la consolidation finale.
Impératif : arrêtez la VM, désactivez toute tâche de sauvegarde et copiez à froid tous les fichiers VHDX/AVHDX. Conservez ces sauvegardes jusqu’à validation complète.
Étapes détaillées
- Préparer l’espace : prévoir un volume libre ≥ à la taille logique utilisée par chaque branche (souvent proche de la taille disque invitée). Laisser 10‑20 % de marge pour la consolidation.
- Fusionner une branche : répétez pour 5, 6, 7, 8, 9 (ordre indifférent).
# Dossier de sortie
$dest = 'D:\VMs\VM01\Branches-merge'
New-Item -ItemType Directory -Path $dest -Force | Out-Null
# Exemple pour AVHDX9
$child = 'D:\VMs\VM01\AVHDX9.avhdx'
$out = Join-Path $dest 'VM01-branch9-merged.vhdx'
Merge-VHD -Path $child -DestinationPath $out -Mode Full -Confirm:$false
- Vérifier le disque résultant : inspectez, montez en lecture seule, contrôlez partitions et données.
Get-VHD -Path $out | Format-List *
$vh = Mount-VHD -Path $out -ReadOnly -PassThru
Get-Volume -DiskNumber ($vh | Get-Disk).Number
Dismount-VHD -Path $out
- (Option) Optimiser/Convertir : si besoin de compacter :
Optimize-VHD -Path $out -Mode Full
- Répéter pour toutes les branches. Vous obtenez une collection de VHDX autonomes (aucun ParentPath).
- Choisir la version fonctionnelle : montez chaque VHDX, listez les différences (date/volume) et retenez celui qui contient toutes les données requises.
- Attacher à la VM : remplacez le disque système ou data de la VM par le VHDX retenu. Conservez les autres en archivage jusqu’à la fin de la recette.
Variantes en GUI
- Hyper‑V Manager → Edit Disk → sélection de l’AVHDX enfant → Merge → To a new virtual hard disk. Répétez pour 5‑9.
- Inspect Disk (GUI) : utile pour valider le ParentPath et l’intégrité avant toute opération.
Procédure appliquée « copie puis comparaison » : récupérer toutes les données sans cloner chaque branche
Cette méthode est pertinente si l’espace est contraint ou si vous devez consolider rapidement tout le contenu utile en partant d’un parent commun (4).
- Copie de sécurité du parent 4 (fichier physique) et point de restauration hors ligne.
- Merge 9 → 4 (vers le parent). Attention : 5‑8 deviendront alors orphelins temporairement.
- Monter le résultat (ex‑4) ; copier seulement les écarts vers un espace de consolidation.
# Exemple de copie « diff only » prudente (pas de suppression côté destination)
robocopy X:\ Y:\ /E /XO /XN /XC /COPY:DAT /DCOPY:T /R:1 /W:1 /MT:16 /NFL /NDL /NP /LOG:robocopy-9.log
- Restaurer le parent 4 à son état précédent (copie à froid effectuée à l’étape 1).
- Répéter avec 8 → 4, 7 → 4, 6 → 4, 5 → 4, en copiant à chaque fois les ajouts/modifications vers l’espace de consolidation.
- À la fin, fabriquer un VHDX final (nouveau disque) et y déposer les données consolidées, ou fusionner la branche la plus fidèle et y injecter les fichiers restants.
Astuce : faites un « dry‑run » avant chaque copie :
robocopy X:\ Y:\ /E /L /XO /XN /XC
L’option /L
liste sans copier ; vérifiez les écarts détectés.
Procédure expéditive « fusion sélective » : quand elle peut suffire
Si vous avez identifié une branche unique à conserver (ex. 9 est la vérité fonctionnelle) et que les autres sont obsolètes :
- Sauvegarder 4 et 9.
- Merge 9 → 4 (vers le parent) : le nouvel état de 4 devient l’état final.
- Déclarer 5‑8 obsolètes et archiver les fichiers (ne pas tenter de les monter sur le nouveau 4).
- Relancer une sauvegarde complète.
Avantage : rapidité. Risque : si une petite portion de données utiles existait dans 8 (mais pas dans 9), elle sera perdue. Ne choisissez cette voie que si vous êtes certain de la redondance.
Recommandations pratiques incontournables
- Sauvegarde avant toute manipulation : conservez chaque AVHDX + le parent VHDX original (copie à froid).
- Privilégier « Merge to New VHD » (Hyper‑V Manager) ou
Merge‑VHD -Mode Full
avec un chemin de destination différent ; ainsi chaque branche reste intacte. - Identifier la branche utile :
Get‑VHD -Path *.avhdx | Sort‑Object LastWriteTime
pour repérer le plus récent.- Montez chaque branche, inspectez son contenu et n’en gardez qu’une si les autres ne contiennent pas de données uniques.
- Travailler hors ligne (VM arrêtée) : simplifie et sécurise l’opération. La fusion « live » n’est utile que si le service doit absolument rester disponible.
- Nettoyage post‑fusion :
- Vérifiez la cohérence avec Inspect Disk (GUI) ou
Get‑VHD
. - Détruisez les checkpoints résiduels (Remove‑VMSnapshot).
- Relancez une sauvegarde complète (full) pour repartir sur une base saine.
- Vérifiez la cohérence avec Inspect Disk (GUI) ou
- Prévention :
- Automatisez la suppression des checkpoints après chaque sauvegarde (scripts PowerShell ou paramètres du logiciel de backup).
- Surveillez la présence d’AVHDX orphelins (rapport quotidien).
- Assurez un espace disque suffisant pour éviter des chaînes trop profondes.
Check‑list opérationnelle (pas à pas)
Étape | Commande/Action | Critère de succès | Plan B |
---|---|---|---|
Arrêt de la VM | Stop‑VM <NomVM> | État Off | Pause cluster si CSV, maintenance host |
Inventaire | Get‑ChildItem *.vhdx,*.avhdx | Liste complète sauvegardée | Shadow copy du volume de stockage |
Cartographie | Get‑VHD -Path *.avhdx | ParentPath validé | GUI : Inspect Disk |
Choix stratégie | Fusion vers nouveau VHDX | Pas d’écrasement de 4 | Méthode copie‑comparaison |
Merge branche | Merge‑VHD -Mode Full | VHDX autonome (ParentPath vide) | Hyper‑V Manager → Edit Disk → Merge |
Vérification | Mount‑VHD (RO), Get‑Volume | Partitions lisibles | CHKDSK / Scan offline |
Rattacher à la VM | Set‑VMHardDiskDrive | Démarrage OK | Revenir à l’ancien disque, log console |
Nettoyage | Remove‑VMSnapshot, purge AVHDX | Plus aucun AVHDX | Archiver 30 jours |
Full backup | Exécuter job full | Chaîne saine | Export‑VM (clone) avant full |
Scripts utiles (audit et merge)
Audit des AVHDX orphelins et de la chronologie
$root = 'D:\VMs\VM01'
Get-ChildItem $root -Filter *.avhdx -Recurse |
ForEach-Object {
$v = Get-VHD -Path $_.FullName
[pscustomobject]@{
AVHDX = $_.Name
ParentExists = if ($v.ParentPath) { Test-Path $v.ParentPath } else { $false }
ParentPath = $v.ParentPath
FileSizeGB = [math]::Round($v.FileSize/1GB,2)
Modified = $_.LastWriteTime
}
} | Sort-Object Modified | Format-Table -Auto
Fonction d’industrialisation d’un merge « vers nouveau VHDX »
function Merge-BranchToNewVhd {
param(
[Parameter(Mandatory=$true)] [string] $ChildPath,
[Parameter(Mandatory=$true)] [string] $DestinationFolder
)
if (-not (Test-Path $ChildPath)) { throw "Introuvable : $ChildPath" }
if (-not (Test-Path $DestinationFolder)) { New-Item -ItemType Directory -Path $DestinationFolder | Out-Null }
$baseName = [IO.Path]::GetFileNameWithoutExtension($ChildPath)
$dest = Join-Path $DestinationFolder "$baseName-merged.vhdx"
Write-Host "Fusion de $ChildPath → $dest"
Merge-VHD -Path $ChildPath -DestinationPath $dest -Mode Full -Confirm:$false
$info = Get-VHD -Path $dest
if ($info.ParentPath) { throw "Le disque $dest n'est pas autonome (ParentPath ≠ vide)" }
return $dest
}
# Exemple d'usage
$targets = @(
'D:\VMs\VM01\AVHDX5.avhdx',
'D:\VMs\VM01\AVHDX6.avhdx',
'D:\VMs\VM01\AVHDX7.avhdx',
'D:\VMs\VM01\AVHDX8.avhdx',
'D:\VMs\VM01\AVHDX9.avhdx'
)
$destFolder = 'D:\VMs\VM01\Merged'
$merged = foreach ($t in $targets) { Merge-BranchToNewVhd -ChildPath $t -DestinationFolder $destFolder }
$merged
Remettre la VM en production (consolidation finale)
- Choisir le disque final parmi les VHDX fusionnés (ou le VHDX reconstruit via copie‑comparaison) : montez‑le, faites un ultime contrôle des données et de la cohérence applicative (bases, journaux).
- Basculer la VM :
- Retirer en toute sécurité le disque actuel (checkpoint) du contrôleur virtuel.
- Attacher le VHDX final (Set‑VMHardDiskDrive ou GUI).
- Vérifier l’ordre de boot (UEFI/Gen2) si c’est le disque système.
- Démarrage et tests : services, journaux d’événements, intégrité applicative.
- Nouvelle sauvegarde complète : créez un point zéro propre pour la nouvelle chaîne.
Nettoyage post‑fusion
- Inspect Disk (ou
Get‑VHD
) : confirmez qu’aucun AVHDX n’est encore rattaché à la VM. - Détruire les checkpoints résiduels :
Get‑VMSnapshot -VMName <VM> | Remove‑VMSnapshot
. - Archiver puis supprimer les anciens AVHDX/VHDX non utilisés après une période de sécurité (ex. 30 jours).
Prévention : durcir le runbook pour ne plus revivre ça
- Politique de checkpoints : jamais de checkpoints persistants. Les checkpoints de production ne doivent vivre que le temps d’une sauvegarde.
- Jobs de sauvegarde : configurez la suppression des checkpoints en fin de job et des alertes en cas d’échec de consolidation.
- Surveillance quotidienne : un script qui reporte toute présence d’AVHDX > 24 h ou toute divergence de parent.
- Capacité : gardez 20–30 % d’espace libre sur les volumes qui hébergent VHDX/AVHDX (les merges grossissent temporairement).
- Procédure CSV/Cluster : standardisez les étapes (pause du rôle, orchestration multi‑nœuds) pour éviter des accès concurrents lors des merges.
FAQ express
Q : Puis‑je fusionner plusieurs enfants directement dans le même parent ?
R : Techniquement oui, mais chaque fusion écrase l’état du parent. Les autres enfants deviennent orphelins. C’est dangereux si des données uniques existent dans ces branches.
Q : L’ordre des merges a‑t‑il de l’importance ?
R : Oui uniquement si vous mergez vers le parent (ex. 9→4, puis 8→4). Si vous mergez vers un nouveau VHDX, l’ordre est indifférent.
Q : Comment vérifier qu’un VHDX final est autonome ?
R : Get‑VHD -Path <fichier.vhdx>
doit afficher un ParentPath vide (ou non applicable). L’inspection GUI « Inspect Disk » doit confirmer l’absence de parent.
Q : Puis‑je faire tout cela « à chaud » ?
R : Mieux vaut l’éviter. La fusion « live » augmente les risques (accès concurrent, I/O). Privilégiez une fenêtre de maintenance.
Points clés à retenir
- Lorsque plusieurs AVHDX partagent le même parent, ils sont indépendants ; fusionner l’un modifie (ou remplace) le parent et rend les autres impropres à la lecture.
- La méthode la plus sûre consiste à fusionner chaque branche vers un nouveau disque avant de décider de la consolidation finale.
- Le choix de l’ordre (du plus récent au plus ancien) n’a d’impact que si l’on souhaite écraser le parent ; sinon, l’ordre importe peu.
- Documenter et automatiser la gestion des checkpoints réduit radicalement le risque de répéter ce scénario.
Modèle de procédure (prêt à l’emploi)
# 0) Sauvegarde à froid des VHDX/AVHDX
# 1) Cartographie
Get-ChildItem *.avhdx | ForEach-Object { Get-VHD -Path $_.FullName | Select Path, ParentPath }
# 2) Fusion sûre pour chaque branche (5-9)
$branches = 5..9 | ForEach-Object { "D:\VMs\VM01\AVHDX$_.avhdx" }
$dest = "D:\VMs\VM01\Merged"
$merged = @()
foreach ($b in $branches) {
$name = [IO.Path]::GetFileNameWithoutExtension($b)
$out = Join-Path $dest "$name-merged.vhdx"
Merge-VHD -Path $b -DestinationPath $out -Mode Full
$merged += $out
}
# 3) Contrôle d'autonomie
$merged | ForEach-Object { Get-VHD -Path $_ | Select Path, ParentPath }
# 4) Choix du disque final, attachement à la VM
# 5) Remove-VMSnapshot, purge des résidus
# 6) Full backup
Estimation d’espace et de temps : savoir dimensionner
Un merge vers un nouveau VHDX requiert approximativement l’espace de la taille logique utilisée par le disque invité, plus une marge pour l’overhead VHDX. Si votre VM a un disque de 500 Go dont 300 Go occupés, prévoyez ~320 Go libres par branche à fusionner. Ajoutez 10–20 % de marge pour être confortable lors des vérifications et copies complémentaires. Le temps dépend du support (I/O séquentielles), du nombre de fichiers fragmentés et de la compression/déduplication éventuelle (évitez de merger directement sur un volume dédupliqué).
Erreurs fréquentes à éviter
- Reconnecter un enfant sur le mauvais parent (block size/ID différents) : corruption immédiate. Toujours valider ParentPath avec
Get‑VHD
. - Exécuter un job de sauvegarde pendant la consolidation : risque de nouveaux checkpoints au milieu du merge.
- Manque d’espace en cours d’opération : provoque des échecs partiels et des disques « à moitié » fusionnés.
- Supprimer des AVHDX avant validation : conservez‑les jusqu’à la fin de la recette et la réussite du full backup.
- Oublier les volumes CSV/SMB : coordonnez avec le cluster et les verrous de fichiers. Utilisez une fenêtre de maintenance.
En synthèse : face à un arbre de checkpoints où plusieurs AVHDX (5‑9) partagent le parent 4, traitez chaque branche comme une réalité alternative indépendante. Fusionnez‑les vers de nouveaux VHDX, comparez, puis consolidez sereinement. C’est un peu plus long… et infiniment plus sûr.