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

VMware vers Hyper-V : plan de migration et PowerShell

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

Le déroulé complet que nous appliquons pour migrer des VM vSphere vers Hyper-V sur Windows Server 2022 ou 2025 : choix de l’outil, préparation de la cible et des invités, bascule, corrections post-migration et retour arrière, avec les commandes PowerShell correspondantes.

01 / Périmètre

Périmètre et prérequis

Source : vCenter 6.x, 7.x ou 8.x. Cible : Hyper-V sur Windows Server 2022 ou 2025, en hôte seul ou en cluster de basculement (stockage S2D ou SAN). Pour Azure Local, Microsoft oriente vers Azure Migrate et non vers les outils décrits ici.

Ce guide suppose l’inventaire réalisé et les blocages traités : voir Sortir de VMware : inventaire, blocages et plan de vagues.

02 / Outils

Choisir l’outil de conversion

WAC VM ConversionSCVMM (New-SCV2V)Veeam Instant Recovery
StatutExtension gratuite en préversion, régie par les conditions de licence des extensions en préversion de Windows Admin CenterProduit supporté ; VMM 2022 UR2 ou plus récent recommandé (conversion jusqu’à quatre fois plus rapide)Fonction de Veeam Backup & Replication
PrincipeCopie initiale à chaud, puis delta par CBT ; à la bascule, arrêt de la source et dernier deltaConversion à froid : la VM source doit être éteinteLa VM démarre sur Hyper-V depuis la sauvegarde VMware, puis ses disques sont migrés vers le stockage de production
InterruptionCourte (dernier delta)Durée de la copie complèteCourte au démarrage, performances réduites jusqu’à la fin de la migration des disques
Limites documentéesvCenter 6.x à 8.x ; lots de 10 VM ; pas de vSAN ; pas d’Azure Local ; mémoire configurée en statique ; VMware Tools non désinstallés automatiquement ; BIOS GUID différent de la sourcePas de vSAN ; pas de disques IDE ; VMware Tools désinstallés avant ; 10 conversions parallèles par couple source/destination recommandéesNécessite des sauvegardes Veeam des VM VMware et la licence correspondante
Quand l’utiliserPetits et moyens parcs, fenêtres courtes, sans SCVMMEnvironnements déjà gérés par SCVMM, VM tolérant une copie à froidParc déjà sauvegardé par Veeam, besoin de redémarrage rapide

Prérequis de l’extension WAC

  • Passerelle Windows Admin Center version 2410 (build 2.4.12.10) ou plus récente.
  • PowerCLI installé sur la passerelle.
  • VMware VDDK 8.0.3 exactement, extrait dans C:\Program Files\WindowsAdminCenter\Service\VDDK. Microsoft indique qu’aucune autre version n’est supportée.
  • Redistribuables Visual C++ 2013 et 2015.
  • Rôle Hyper-V sur la cible, compte membre des administrateurs locaux ou du groupe Administrateurs Hyper-V.
  • Pour Linux : pilotes Hyper-V installés avant la migration (Microsoft renvoie aux Linux Integration Services ; sur les distributions récentes, les pilotes sont dans le noyau et doivent être présents dans l’initramfs, voir plus bas).

03 / Cible

Préparer les hôtes Hyper-V

Sur chaque nœud : rôle Hyper-V, clustering si nécessaire, un commutateur virtuel avec association intégrée (SET) pour les VM. Les noms de cartes réseau sont ceux renvoyés par Get-NetAdapter.

PowerShell
# Sur chaque noeud (redémarrage requis)
Install-WindowsFeature -Name Hyper-V, Failover-Clustering -IncludeManagementTools -Restart

# Commutateur SET dédié aux VM (deux cartes physiques)
New-VMSwitch -Name 'SET-VM' -NetAdapterName 'NIC1', 'NIC2' -EnableEmbeddedTeaming $true -AllowManagementOS $false

# Validation avant création du cluster (à exécuter avant toute mise en production)
Test-Cluster -Node 'HV01', 'HV02'
New-Cluster -Name 'HVCL01' -Node 'HV01', 'HV02' -StaticAddress '10.0.10.50'
  • Réseau : reproduire les VLAN des groupes de ports vSphere (le mapping se fait ensuite VM par VM).
  • Stockage : volumes partagés de cluster (CSV) dimensionnés avec la marge nécessaire à la conversion de disques dynamiques en disques fixes, si vous le prévoyez.
  • Processeurs : si les nœuds n’ont pas exactement la même génération de CPU, la compatibilité processeur devra être activée sur les VM pour permettre la migration à chaud.
  • Sauvegarde : le travail de sauvegarde Hyper-V doit exister avant la première bascule, pas après.

04 / Invités

Préparer les VM sources

Windows

  1. 01

    Prendre un relevé de référence avec Get-MigrationBaseline.ps1 (voir le guide de recette).

  2. 02

    Passer la stratégie SAN en OnlineAll pour que les disques de données ne reviennent pas hors ligne après la conversion. SCVMM documente ce comportement ; il concerne en pratique toute conversion.

  3. 03

    Si BitLocker est actif, sauvegarder les mots de passe de récupération : un vTPM ne se transporte pas d’un hyperviseur à l’autre.

  4. 04

    Désinstaller les VMware Tools dans la fenêtre de bascule (voir ci-dessous).

PowerShell
# Dans l'invité, en administrateur
Set-StorageSetting -NewDiskPolicy OnlineAll
Get-StorageSetting | Select-Object NewDiskPolicy

# BitLocker : afficher les protecteurs de récupération à mettre en lieu sûr
Get-BitLockerVolume | ForEach-Object {
    $mountPoint = $_.MountPoint
    $_.KeyProtector | Where-Object KeyProtectorType -eq 'RecoveryPassword' |
        Select-Object @{ n = 'Volume'; e = { $mountPoint } }, KeyProtectorId, RecoveryPassword
}

VMware Tools : quand et comment

Broadcom indique que les VMware Tools doivent être désinstallés avant la migration : sur un autre hyperviseur, le programme de désinstallation échoue (erreur MSI 1603, contrôle VM_CheckRequirements). SCVMM l’exige également, et l’extension WAC ne les désinstalle pas automatiquement.

PowerShell
# Dans l'invité : désinstallation silencieuse des VMware Tools (installation MSI)
$tools = Get-ItemProperty 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*' |
    Where-Object DisplayName -eq 'VMware Tools'
if ($tools) {
    Start-Process -FilePath msiexec.exe -ArgumentList "/x $($tools.PSChildName) /qn /norestart" -Wait
}

Linux

Les pilotes hv_vmbus, hv_storvsc et hv_netvsc doivent être dans l’initramfs avant la conversion, sinon la VM ne trouve pas son disque au démarrage. Les distributions de la famille RHEL génèrent souvent un initramfs « hostonly » qui ne contient que les pilotes du matériel VMware. Le script suivant vérifie, et ajoute sur demande, les pilotes manquants (dracut ou initramfs-tools).

prepare-linux-initramfs.shShell POSIX · 95 lignesTélécharger
#!/bin/sh
# prepare-linux-initramfs.sh
#
# Checks (default) or adds (--apply) the storage and network drivers a Linux guest
# needs in its initramfs to boot on the target hypervisor, BEFORE the conversion.
#   hyperv : hv_vmbus hv_storvsc hv_netvsc
#   virtio : virtio_pci virtio_blk virtio_scsi virtio_net   (Nutanix AHV, Proxmox VE, KVM)
#
# Supports dracut (RHEL, Rocky, Alma, SUSE, Fedora) and initramfs-tools (Debian, Ubuntu).
# Drivers built into the kernel (=y) need nothing and are reported as such.
#
# Usage:  sudo sh prepare-linux-initramfs.sh hyperv            # check only
#         sudo sh prepare-linux-initramfs.sh virtio --apply    # add missing drivers, rebuild
#
# Take a snapshot or a backup first. Rebuilding the initramfs of the running kernel is a
# boot-critical change: keep the previous kernel entry available in the boot menu.
# Source: ANYSYS ICT, https://www.anysys.be/articles/

set -eu

TARGET="${1:-}"
MODE="${2:-check}"
KVER="${KVER:-$(uname -r)}"

case "$TARGET" in
  hyperv) MODULES="hv_vmbus hv_storvsc hv_netvsc" ;;
  virtio) MODULES="virtio_pci virtio_blk virtio_scsi virtio_net" ;;
  *) echo "usage: $0 hyperv|virtio [--apply]" >&2; exit 2 ;;
esac

if command -v dracut >/dev/null 2>&1 && [ ! -d /etc/initramfs-tools ]; then
  TOOL=dracut
elif [ -d /etc/initramfs-tools ]; then
  TOOL=initramfs-tools
else
  echo "Neither dracut nor initramfs-tools found: prepare this guest manually." >&2
  exit 3
fi

BUILTIN="/lib/modules/$KVER/modules.builtin"

# RHEL family names the image initramfs-<kver>.img, Debian family initrd.img-<kver>.
if [ -f "/boot/initramfs-$KVER.img" ]; then
  IMG="/boot/initramfs-$KVER.img"
else
  IMG="/boot/initrd.img-$KVER"
fi

list_initramfs() {
  if [ "$TOOL" = dracut ]; then
    lsinitrd "$IMG" 2>/dev/null
  else
    lsinitramfs "$IMG" 2>/dev/null
  fi
}

CONTENT="$(list_initramfs || true)"
MISSING=""
for m in $MODULES; do
  if [ -f "$BUILTIN" ] && grep -q "/$m.ko" "$BUILTIN"; then
    echo "builtin   $m"
  elif printf '%s\n' "$CONTENT" | grep -q "/$m.ko"; then
    echo "present   $m"
  else
    echo "MISSING   $m"
    MISSING="$MISSING $m"
  fi
done

echo "kernel=$KVER tool=$TOOL image=$IMG target=$TARGET"

if [ -z "$MISSING" ]; then
  echo "Nothing to do."
  exit 0
fi

if [ "$MODE" != "--apply" ]; then
  echo "Run again with --apply to add:$MISSING"
  exit 1
fi

if [ "$TOOL" = dracut ]; then
  CONF="/etc/dracut.conf.d/90-migration-$TARGET.conf"
  echo "add_drivers+=\"$MISSING \"" > "$CONF"
  echo "wrote $CONF"
  dracut -f "$IMG" "$KVER"
else
  for m in $MISSING; do
    grep -qx "$m" /etc/initramfs-tools/modules || echo "$m" >> /etc/initramfs-tools/modules
  done
  echo "updated /etc/initramfs-tools/modules"
  update-initramfs -u -k "$KVER"
fi

echo "Rebuilt. Verify with: $0 $TARGET"
Shell
sudo sh prepare-linux-initramfs.sh hyperv            # contrôle seul, code retour 1 si un pilote manque
sudo sh prepare-linux-initramfs.sh hyperv --apply    # ajoute et reconstruit l'initramfs du noyau courant
  • Le nom de l’interface réseau change (par exemple ens192 vers eth0) : une configuration NetworkManager ou netplan liée au nom de l’interface ne s’appliquera plus. Liez-la à l’adresse MAC ou préparez le fichier cible.
  • VM Linux en génération 2 avec Secure Boot : le modèle MicrosoftUEFICertificateAuthority est requis (voir corrections côté hôte).

05 / Bascule

Déroulé de bascule

MomentActionValidation
J-7Synchronisation initiale (WAC) ou test de conversion d’une copie (SCVMM). Relevé de référence dans l’invité.Synchronisation terminée sans erreur de Change ID
J-1Sauvegarde complète et test de restauration. Gel des changements applicatifs. Communication aux utilisateurs.Point de restauration identifié
H-0Arrêt des services applicatifs, désinstallation des VMware Tools, lancement de la migration (dernier delta) ou arrêt et conversion.Source éteinte
H+0Neutraliser la source : cartes réseau non connectées au démarrage, VM renommée.Source impossible à redémarrer par erreur sur le réseau
H+1Démarrage sur Hyper-V, corrections invité, relevé après migration et comparaison.Compare-MigrationBaseline.ps1 sans échec
H+2Tests applicatifs par le métier. Décision go / no-go avant l’heure limite de retour arrière.Validation écrite du responsable applicatif

Pour SCVMM, la conversion se pilote aussi en PowerShell. Exemple minimal à adapter, d’après l’exemple 1 de la documentation New-SCV2V :

PowerShell
# Module VirtualMachineManager, sur un poste disposant de la console VMM
# L'hôte ESXi doit être géré par VMM ; la VM source doit être éteinte
$esxHost = Get-SCVMHost -ComputerName 'esxi01.contoso.local'
$vmHost  = Get-SCVMHost -ComputerName 'HV01.contoso.local'
$vm      = Get-SCVirtualMachine -VMHost $esxHost -Name 'APP01'
New-SCV2V -VM $vm -VMHost $vmHost -Name 'APP01' -Path 'C:\ClusterStorage\Volume1' -RunAsynchronously

06 / Hôte

Corrections côté hôte

Le rapport suivant liste, pour chaque VM, ce qui demande en général une correction après conversion. Il ne modifie rien.

Get-HyperVMigrationReport.ps1PowerShell · 67 lignesTélécharger
<#
.SYNOPSIS
    Read-only health report of virtual machines on a Hyper-V host after a migration.

.DESCRIPTION
    One row per VM with what typically needs fixing after a VMware conversion:
    generation, configuration version, static vs dynamic memory, processor compatibility
    for live migration, Secure Boot template, disk format (dynamic/fixed) and location,
    switch / VLAN, MAC mode, integration services turned off, leftover checkpoints,
    cluster role and heartbeat. Nothing is changed.

.PARAMETER VMName
    One or more VM names. Defaults to every VM on the host.

.EXAMPLE
    .\Get-HyperVMigrationReport.ps1 | Out-GridView

.EXAMPLE
    .\Get-HyperVMigrationReport.ps1 -VMName APP01,SQL01 | Export-Csv .\hyperv-report.csv -NoTypeInformation -Delimiter ';'

.NOTES
    Windows Server 2016 or later with the Hyper-V PowerShell module. Run on the host.
    Integration service names are localized: the script reports them as returned.
    Source: ANYSYS ICT, https://www.anysys.be/articles/
#>
[CmdletBinding()]
param(
    [string[]]$VMName = '*'
)

$ErrorActionPreference = 'Stop'

foreach ($vm in Get-VM -Name $VMName) {
    $fw    = if ($vm.Generation -eq 2) { Get-VMFirmware -VM $vm } else { $null }
    $cpu   = Get-VMProcessor -VM $vm
    $mem   = Get-VMMemory -VM $vm
    $nics  = @(Get-VMNetworkAdapter -VM $vm)
    $hdds  = @(Get-VMHardDiskDrive -VM $vm)
    $vhds  = @($hdds | Where-Object Path | ForEach-Object { Get-VHD -Path $_.Path -ErrorAction SilentlyContinue })
    $snaps = @(Get-VMSnapshot -VM $vm)
    $isOff = @(Get-VMIntegrationService -VM $vm | Where-Object { -not $_.Enabled } | ForEach-Object Name)

    [pscustomobject]@{
        Name               = $vm.Name
        State              = $vm.State
        Heartbeat          = $vm.Heartbeat
        Generation         = $vm.Generation
        ConfigVersion      = $vm.Version
        Clustered          = $vm.IsClustered
        vCPU               = $cpu.Count
        CpuCompatibility   = $cpu.CompatibilityForMigrationEnabled
        DynamicMemory      = $mem.DynamicMemoryEnabled
        StartupMemoryGB    = [math]::Round($mem.Startup / 1GB, 1)
        SecureBoot         = if ($fw) { $fw.SecureBoot } else { 'n/a (Gen1)' }
        SecureBootTemplate = if ($fw) { $fw.SecureBootTemplate } else { '' }
        Disks              = $hdds.Count
        VhdTypes           = ($vhds.VhdType | Sort-Object -Unique) -join ','
        VhdPaths           = ($hdds.Path) -join ' | '
        Switches           = ($nics.SwitchName | Sort-Object -Unique) -join ','
        Vlans              = ($nics | ForEach-Object { $v = Get-VMNetworkAdapterVlan -VMNetworkAdapter $_; '{0}:{1}' -f $v.OperationMode, $v.AccessVlanId }) -join ','
        DynamicMac         = ($nics.DynamicMacAddressEnabled | Sort-Object -Unique) -join ','
        MacAddresses       = ($nics.MacAddress) -join ','
        GuestIPs           = (@($nics.IPAddresses) -join ',')
        IntegrationOff     = $isOff -join ','
        Checkpoints        = $snaps.Count
    }
}

Corrections usuelles. La plupart exigent la VM éteinte :

PowerShell
Stop-VM -Name 'APP01'

# WAC crée la mémoire en statique : réactiver la mémoire dynamique si la charge le permet
Set-VMMemory -VMName 'APP01' -DynamicMemoryEnabled $true -MinimumBytes 2GB -StartupBytes 4GB -MaximumBytes 8GB

# Migration à chaud entre noeuds de générations CPU différentes
Set-VMProcessor -VMName 'APP01' -CompatibilityForMigrationEnabled $true

# VLAN du port de la VM
Set-VMNetworkAdapterVlan -VMName 'APP01' -Access -VlanId 20

# Linux en génération 2 avec Secure Boot
Set-VMFirmware -VMName 'LNX01' -SecureBootTemplate MicrosoftUEFICertificateAuthority

# Disque dynamique vers fixe (espace disque complet requis sur la destination)
Convert-VHD -Path 'C:\ClusterStorage\Volume1\APP01\APP01.vhdx' -DestinationPath 'C:\ClusterStorage\Volume1\APP01\APP01-fixed.vhdx' -VHDType Fixed

Start-VM -Name 'APP01'

En cluster, la VM doit résider sur un volume partagé avant d’être rendue hautement disponible :

PowerShell
Move-VMStorage -VMName 'APP01' -DestinationStoragePath 'C:\ClusterStorage\Volume1\APP01'
Add-ClusterVirtualMachineRole -VMName 'APP01'

# Une fois la validation métier signée : supprimer les points de contrôle de travail
Get-VMSnapshot -VMName 'APP01' | Remove-VMSnapshot

07 / Invité

Corrections dans l’invité

Trois problèmes reviennent sur presque toutes les VM Windows converties :

  • Carte réseau fantôme : l’ancienne carte VMXNET3 reste enregistrée avec son adresse IP statique ; Windows refuse alors d’attribuer la même adresse à la nouvelle carte.
  • Disques hors ligne : si la stratégie SAN n’a pas été modifiée avant, les disques de données sont hors ligne.
  • Restes des VMware Tools : services et pilotes si la désinstallation n’a pas été faite avant.
PowerShell
# Cartes réseau non présentes (fantômes)
Get-PnpDevice -Class Net | Where-Object Status -eq 'Unknown' | Format-Table FriendlyName, InstanceId -AutoSize
# Suppression (pnputil /remove-device : Windows Server 2022 et versions ultérieures)
pnputil /remove-device "<InstanceId>"

# Disques hors ligne ou en lecture seule
Get-Disk | Where-Object IsOffline | Set-Disk -IsOffline $false
Get-Disk | Where-Object IsReadOnly | Set-Disk -IsReadOnly $false

Sur Windows Server 2019 et versions antérieures, la carte fantôme se supprime depuis le Gestionnaire de périphériques (affichage des périphériques cachés). Pour des VMware Tools restés installés, Broadcom recommande d’abord l’utilitaire Microsoft de résolution des problèmes d’installation et de désinstallation, puis en dernier recours le nettoyage manuel de la KB 315629. Ce nettoyage modifie le registre, n’est pas officiellement supporté et ne s’applique qu’après une sauvegarde complète de la VM.

Terminez par la comparaison avec le relevé de référence : recette post-migration Windows.

08 / Retour arrière

Retour arrière

Le retour arrière est simple tant que la source n’a pas été modifiée et que les utilisateurs n’ont pas écrit de données sur la cible. Au-delà, il faut reprendre ces données : c’est pourquoi l’heure limite de décision est fixée dans le plan de vague.

Hyper-V
# Sur l'hôte Hyper-V : arrêter la VM migrée et l'isoler du réseau
Stop-VM -Name 'APP01' -Force
Disconnect-VMNetworkAdapter -VMName 'APP01'
PowerCLI
# Session PowerCLI distincte (Get-VM, Set-VM et Start-VM existent aussi dans le module Hyper-V)
$vm = Get-VM -Name 'APP01-MIGRATED-*'
Set-VM -VM $vm -Name 'APP01' -Confirm:$false
Get-NetworkAdapter -VM $vm | Set-NetworkAdapter -StartConnected:$true -Confirm:$false
Start-VM -VM $vm

Si les VMware Tools ont été désinstallés, réinstallez-les depuis la console vSphere pour retrouver le pilote VMXNET3. Ce cas doit avoir été répété sur la VM pilote : c’est la seule manière de connaître la durée réelle d’un retour arrière.

09 / Références

Sources