Guide technique ANYSYS · vérifié le 26 octobre 2026

Sortir de VMware : inventaire, blocages et plan de vagues

Modèle d'essai de la machine analytique de Charles Babbage
Modèle d'essai de la machine analytique de Charles BabbageDaderot, Wikimedia Commons, CC0 · Crédits

Avant de choisir Hyper-V, Nutanix AHV ou Proxmox VE, il faut savoir ce que contient réellement le parc : disques indépendants, RDM, vTPM, snapshots oubliés, dépendances réseau. Ce guide fournit le script d’inventaire PowerCLI que nous utilisons, la matrice des blocages connus par outil de conversion et la méthode de découpage en vagues.

01 / Principe

Pourquoi l’inventaire vient avant l’outil

Les outils de conversion se valent sur les VM simples. Les projets dérapent sur les exceptions : une VM avec un disque en mode indépendant que l’outil refuse, un serveur applicatif dont la licence est liée à l’identifiant BIOS, un cluster à disques partagés qu’aucun convertisseur ne sait déplacer, un poste chiffré par BitLocker dont la clé était scellée dans un vTPM.

Ces cas se détectent à froid, en lecture seule, depuis vCenter. Le choix de l’outil (et parfois de la cible) découle de leur nombre et de leur nature. Un inventaire produit en début de projet sert ensuite de référence pour chaque vague.

  • Ce qui est automatisable : configuration matérielle virtuelle, disques, réseau, état des VMware Tools, snapshots, chiffrement.
  • Ce qui ne l’est pas : la criticité métier, les fenêtres d’intervention, les dépendances applicatives implicites, les contrats de support. Ces informations se collectent en entretien avec les responsables applicatifs.

02 / Inventaire

Le script d’inventaire PowerCLI

Le script ci-dessous produit un CSV (séparateur point-virgule, lisible directement dans Excel) avec une ligne par VM et une colonne Blockers qui résume les points à traiter. Il ne modifie rien : un compte vCenter en lecture seule suffit.

Get-VMwareMigrationInventory.ps1PowerShell · 125 lignesTélécharger
<#
.SYNOPSIS
    Read-only inventory of a vCenter estate before a hypervisor migration.

.DESCRIPTION
    Exports one row per VM with the attributes that decide how (and whether) a VM
    can be converted: firmware, Secure Boot, vTPM, encryption, VMware Tools state,
    CBT, snapshots, disk modes, RDMs, shared/multi-writer disks, SCSI bus sharing,
    PCI passthrough, vSAN placement, networks and guest IPs.
    A "Blockers" column lists the findings that need a decision before conversion.

    The script only reads. It never changes a VM, a snapshot or a setting.

.PARAMETER Server
    vCenter FQDN or IP.

.PARAMETER OutFile
    CSV path. Defaults to .\vmware-inventory-<date>.csv

.EXAMPLE
    .\Get-VMwareMigrationInventory.ps1 -Server vcenter.contoso.local
    Prompts for credentials, then writes the CSV in the current folder.

.NOTES
    Requires the PowerCLI core module VMware.VimAutomation.Core. PowerCLI 9 and later ship
    as VCF.PowerCLI (Install-Module VCF.PowerCLI -Scope CurrentUser); older estates use
    VMware.PowerCLI 13.x. Tested with VMware.VimAutomation.Core 13.5.1.
    A read-only vCenter role is enough.
    Source: ANYSYS ICT, https://www.anysys.be/articles/
#>
[CmdletBinding()]
param(
    [Parameter(Mandatory)]
    [string]$Server,

    [pscredential]$Credential = (Get-Credential -Message "vCenter (read-only account)"),

    [string]$OutFile = (Join-Path (Get-Location) ("vmware-inventory-{0:yyyyMMdd-HHmm}.csv" -f (Get-Date)))
)

$ErrorActionPreference = 'Stop'
Import-Module VMware.VimAutomation.Core -ErrorAction Stop

# Do not touch the global PowerCLI configuration: the setting below only lives in this session.
Set-PowerCLIConfiguration -Scope Session -InvalidCertificateAction Warn -Confirm:$false | Out-Null
$vi = Connect-VIServer -Server $Server -Credential $Credential

try {
    $rows = foreach ($vm in Get-VM -Server $vi | Sort-Object Name) {
        $cfg      = $vm.ExtensionData.Config
        $devices  = @($cfg.Hardware.Device | Where-Object { $null -ne $_ })
        $disks    = @(Get-HardDisk -VM $vm)
        $nics     = @(Get-NetworkAdapter -VM $vm)
        $snaps    = @(Get-Snapshot -VM $vm)
        $scsi     = @(Get-ScsiController -VM $vm)
        $dsNames  = @($disks | ForEach-Object { ($_.Filename -split '\]')[0].TrimStart('[') } | Sort-Object -Unique)
        $dsTypes  = @($dsNames | ForEach-Object { (Get-Datastore -Name $_ -Server $vi).Type } | Sort-Object -Unique)

        $independent = @($disks | Where-Object { $_.Persistence -like 'Independent*' })
        $rdmPhysical = @($disks | Where-Object { $_.DiskType -eq 'RawPhysical' })
        $rdmVirtual  = @($disks | Where-Object { $_.DiskType -eq 'RawVirtual' })
        $multiWriter = @($disks | Where-Object { $_.ExtensionData.Backing.Sharing -eq 'sharingMultiWriter' })
        $busSharing  = @($scsi  | Where-Object { $_.BusSharingMode -ne 'NoSharing' })
        $ideKeys     = @($devices | Where-Object { $_ -is [VMware.Vim.VirtualIDEController] } | ForEach-Object Key)
        $ideDisks    = @($disks | Where-Object { $ideKeys -contains $_.ExtensionData.ControllerKey })
        $passthrough = @($devices | Where-Object { $_ -is [VMware.Vim.VirtualPCIPassthrough] })
        $vtpm        = @($devices | Where-Object { $_.GetType().Name -eq 'VirtualTPM' })
        $encrypted   = $null -ne $cfg.KeyId

        $blockers = [System.Collections.Generic.List[string]]::new()
        if ($snaps.Count)           { $blockers.Add("snapshots($($snaps.Count))") }
        if ($independent.Count)     { $blockers.Add('independent-disk') }
        if ($rdmPhysical.Count)     { $blockers.Add('rdm-physical') }
        if ($rdmVirtual.Count)      { $blockers.Add('rdm-virtual') }
        if ($multiWriter.Count)     { $blockers.Add('multi-writer') }
        if ($busSharing.Count)      { $blockers.Add('scsi-bus-sharing') }
        if ($ideDisks.Count)        { $blockers.Add('ide-disk') }
        if ($passthrough.Count)     { $blockers.Add('pci-passthrough') }
        if ($vtpm.Count)            { $blockers.Add('vtpm') }
        if ($encrypted)             { $blockers.Add('vm-encryption') }
        if ($dsTypes -contains 'vsan') { $blockers.Add('vsan') }
        if (-not $cfg.ChangeTrackingEnabled) { $blockers.Add('cbt-off') }
        if ($vm.ExtensionData.Guest.ToolsRunningStatus -ne 'guestToolsRunning') { $blockers.Add('tools-not-running') }

        [pscustomobject]@{
            Name            = $vm.Name
            PowerState      = $vm.PowerState
            GuestOS         = $vm.ExtensionData.Guest.GuestFullName
            ConfiguredOS    = $cfg.GuestFullName
            HardwareVersion = $vm.HardwareVersion
            Firmware        = $cfg.Firmware
            SecureBoot      = [bool]$cfg.BootOptions.EfiSecureBootEnabled
            vTPM            = [bool]$vtpm.Count
            Encrypted       = $encrypted
            NumCpu          = $vm.NumCpu
            MemoryGB        = $vm.MemoryGB
            ProvisionedGB   = [math]::Round($vm.ProvisionedSpaceGB, 1)
            UsedGB          = [math]::Round($vm.UsedSpaceGB, 1)
            Disks           = $disks.Count
            DiskDetail      = ($disks | ForEach-Object { '{0}:{1}GB:{2}:{3}' -f $_.Name, [math]::Round($_.CapacityGB, 1), $_.StorageFormat, $_.Persistence }) -join ' | '
            ScsiTypes       = ($scsi.Type | Sort-Object -Unique) -join ','
            Datastores      = $dsNames -join ','
            DatastoreTypes  = $dsTypes -join ','
            Snapshots       = $snaps.Count
            CBT             = [bool]$cfg.ChangeTrackingEnabled
            ToolsStatus     = $vm.ExtensionData.Guest.ToolsRunningStatus
            ToolsVersion    = $vm.ExtensionData.Guest.ToolsVersionStatus2
            Networks        = ($nics.NetworkName | Sort-Object -Unique) -join ','
            NicTypes        = ($nics.Type | Sort-Object -Unique) -join ','
            MacAddresses    = $nics.MacAddress -join ','
            GuestIPs        = (@($vm.Guest.IPAddress) -join ',')
            Host            = $vm.VMHost.Name
            Folder          = $vm.Folder.Name
            Notes           = ($vm.Notes -replace '\r?\n', ' ')
            Blockers        = $blockers -join ';'
        }
    }

    $rows | Export-Csv -Path $OutFile -NoTypeInformation -Encoding UTF8 -Delimiter ';'
    Write-Host ("{0} VMs exported to {1}" -f @($rows).Count, $OutFile)
    Write-Host ("{0} VMs carry at least one blocker" -f @($rows | Where-Object Blockers).Count)
}
finally {
    Disconnect-VIServer -Server $vi -Confirm:$false
}

Prérequis : le module VMware.VimAutomation.Core. Depuis PowerCLI 9, l’ensemble est publié sous le nom VCF.PowerCLI ; les environnements plus anciens utilisent VMware.PowerCLI 13.x. Le paramétrage du certificat n’est appliqué qu’à la session et ne modifie pas votre configuration PowerCLI.

PowerShell
Install-Module VCF.PowerCLI -Scope CurrentUser
.\Get-VMwareMigrationInventory.ps1 -Server vcenter.contoso.local
# Filtrer ensuite les VM qui demandent une décision
Import-Csv .\vmware-inventory-*.csv -Delimiter ';' | Where-Object Blockers | Format-Table Name, Blockers -AutoSize

Lire la colonne Blockers

CodeSignificationCe qu’il faut décider
snapshots(n)Snapshots présents sur la VMConsolider avant la synchronisation. Un snapshot ancien est aussi un risque d’espace disque pendant la réplication.
independent-diskDisque en mode indépendant (persistant ou non)Repasser en mode dépendant si possible, ou migrer ce disque autrement (copie de données).
rdm-physical / rdm-virtualLUN présentée directement à la VMConvertir en disque virtuel ou reprendre la LUN côté cible (iSCSI, passthrough). Rarement automatique.
multi-writer / scsi-bus-sharingDisques partagés entre plusieurs VM (clusters, Oracle RAC)Reconstruire le cluster sur la cible. Aucun convertisseur ne déplace un cluster à disques partagés en l’état.
ide-diskDisque sur contrôleur IDESCVMM refuse ces VM ; ailleurs, vérifier le contrôleur de démarrage côté cible.
pci-passthroughPériphérique PCI attribué à la VMPrévoir l’équivalent matériel côté cible ou garder la VM hors périmètre.
vtpmTPM virtuel présentRécupérer les clés de récupération BitLocker avant de bouger : l’état du vTPM ne suit pas d’un hyperviseur à l’autre.
vm-encryptionVM chiffrée par vSphereRetirer la stratégie de chiffrement avant conversion : les outils lisent des disques en clair.
vsanDisques sur un datastore vSANPlusieurs outils refusent vSAN : déplacer les disques sur un autre datastore (Storage vMotion) avant conversion.
cbt-offChanged Block Tracking désactivéLes outils à réplication incrémentale en ont besoin : l’activer (cycle d’alimentation requis) ou accepter une copie à froid.
tools-not-runningVMware Tools absents ou arrêtésLes préparations automatiques d’invité (adresse IP, pilotes) en dépendent.

03 / Compatibilité

Matrice des blocages par outil

Ce tableau ne reprend que ce que les éditeurs documentent explicitement à la date de vérification. « Non documenté » signifie qu’il faut valider le cas sur une VM pilote, pas que cela fonctionne.

État au 26 octobre 2026, d’après la documentation de chaque éditeur (voir sources).
SituationWAC VM ConversionSCVMMNutanix MoveProxmox VE import
Statut de l’outilPréversion (conditions des extensions en préversion)Produit supporté (VMM 2022 UR2+, 2025)Produit supportéProduit supporté (PVE 8 et plus)
Copie à chaudOui (synchro initiale puis delta CBT)Non : VM source éteinteOui (seeding puis incrémental)Non, mais import « live » possible
Datastore vSANNonNonNon documentéNon (déplacer les disques avant)
Disque indépendantNon documentéNon documentéNonNon documenté
Disques partagés, multi-writerNon documentéNon documentéNonNon documenté
Disque IDENon documentéNonNon documentéNon documenté
vTPMNon documentéNon documentévTPM recréé, contenu perduÉtat non migrable
VM chiffréeNon documentéNon documentéNon documentéNon (retirer le chiffrement)
VMware ToolsNon désinstallés automatiquementÀ désinstaller avantRequis et en cours d’exécution pour la préparation autoÀ retirer avant
Volumétrie par lot10 VM10 en parallèle par couple source/ciblePlans de migrationImports à sérialiser

04 / Dépendances

Cartographier les dépendances

Une VM qui démarre correctement peut casser une application si l’ordre de bascule ignore ses dépendances : base de données, partage de fichiers, licence réseau, relais SMTP, flux vers une machine qui reste sur VMware pendant plusieurs semaines.

Sur les serveurs Windows, un relevé des connexions établies, répété sur un cycle métier complet (inclure une fin de mois), donne une base factuelle. C’est un échantillon : les flux rares (batch trimestriel, sauvegarde) doivent être confirmés avec les équipes.

PowerShell
# Relevé des connexions établies sur une liste de serveurs (WinRM requis)
$servers = Get-Content .\servers.txt
Invoke-Command -ComputerName $servers -ScriptBlock {
    Get-NetTCPConnection -State Established |
        Where-Object { $_.RemoteAddress -notmatch '^(127\.|::1)' } |
        Select-Object LocalPort, RemoteAddress, RemotePort,
            @{ n = 'Process'; e = { (Get-Process -Id $_.OwningProcess -ErrorAction SilentlyContinue).ProcessName } }
} | Group-Object PSComputerName, RemoteAddress, RemotePort, Process -NoElement |
    Sort-Object Count -Descending |
    Export-Csv .\flows.csv -NoTypeInformation -Delimiter ';'

Côté vSphere, notez aussi ce qui ne voyage pas avec la VM : règles d’affinité et d’anti-affinité DRS, pools de ressources, réservations, tags utilisés par les sauvegardes, alarmes. Chacun doit avoir son équivalent sur la cible, ou être abandonné en connaissance de cause.

05 / Planification

Découper en vagues

  1. 01

    Vague 0, pilote : 5 à 10 VM représentatives (Windows et Linux, BIOS et UEFI, petites et volumineuses), non critiques mais réellement utilisées. Elle valide l’outil, la cible, le réseau et le déroulé.

  2. 02

    Vagues d’infrastructure : serveurs à faibles dépendances (utilitaires, serveurs d’impression, frontaux).

  3. 03

    Vagues applicatives : une application et toutes ses VM ensemble, dans l’ordre des dépendances.

  4. 04

    Dernière vague : bases de données et applications critiques, une fois le déroulé rodé.

Pour chaque vague, écrivez avant la bascule : la fenêtre d’intervention, la personne qui valide côté métier, les tests applicatifs à exécuter, le critère de retour arrière et l’heure limite pour le décider. Ce dernier point est le plus souvent oublié : passé le moment où les utilisateurs écrivent des données sur la nouvelle plateforme, revenir en arrière implique de perdre ou de reprendre ces données.

06 / Continuité

Sauvegardes et retour arrière

  • Avant : une sauvegarde réussie et un test de restauration de chaque VM de la vague. Une sauvegarde jamais restaurée n’est pas un plan de retour arrière.
  • Pendant : la VM source est éteinte, renommée et ses cartes réseau déconnectées au démarrage, pour qu’un redémarrage accidentel ne crée pas de conflit d’adresse IP.
  • Après : les travaux de sauvegarde sont recréés sur la cible ; la première sauvegarde est complète. Les chaînes de l’ancienne plateforme restent consultables pendant leur durée de rétention.
  • Conservation : la VM source est gardée éteinte pendant une période définie (deux à quatre semaines est courant) et supprimée seulement après plusieurs sauvegardes réussies sur la cible.
PowerShell
# PowerCLI : neutraliser la VM source juste après la bascule
$vm = Get-VM -Name 'APP01'
Get-NetworkAdapter -VM $vm | Set-NetworkAdapter -StartConnected:$false -Confirm:$false
Set-VM -VM $vm -Name ('APP01-MIGRATED-{0:yyyyMMdd}' -f (Get-Date)) -Confirm:$false

Le guide recette post-migration fournit les scripts de relevé avant/après qui servent de critère objectif de validation.

07 / Contrats

Licences et support éditeur

  • Windows Server : la licence se calcule par cœur physique des hôtes cibles. L’édition Standard couvre deux environnements virtuels par hôte entièrement licencié, Datacenter un nombre illimité. Un changement de matériel est l’occasion de refaire ce calcul.
  • Logiciels liés au matériel : certaines licences se basent sur l’adresse MAC, l’UUID ou le numéro de série BIOS. Ces identifiants changent ou sont partiellement conservés selon l’outil. Exemple documenté : avec l’extension WAC, le BIOS GUID de la VM Hyper-V ne correspond pas à celui de la source tant qu’il n’est pas mis à jour manuellement (Microsoft fournit un script dans sa FAQ). À vérifier avec l’éditeur avant la vague concernée.
  • Appliances virtuelles (pare-feu, équilibreurs, NAS virtuels) : la plupart sont livrées par l’éditeur dans un format par hyperviseur. On redéploie l’image prévue pour la cible et on restaure la configuration.
  • Déclarations de support : vérifiez que l’éditeur de chaque application critique supporte la cible (version d’hyperviseur incluse).

08 / Cibles

Choisir la cible

CiblePoints fortsPoints d’attentionGuide
Hyper-VInclus dans Windows Server, compétences souvent présentes, intégration Active Directory et VeeamOutil de conversion officiel en préversion ; cluster et stockage (S2D ou SAN) à concevoirVMware vers Hyper-V
Nutanix AHVOutil Move mature, plateforme hyperconvergée intégrée, réplication à chaudMatériel et licences Nutanix, matrice de versions Move à respecterVMware vers Nutanix AHV
Proxmox VELicence libre, assistant d’import ESXi intégré, coût d’entrée faibleSupport par abonnement, pilotes VirtIO à préparer, compétences Linux requisesVMware vers Proxmox VE

09 / Références

Sources