Masowe przepisanie VMDK pomiędzy maszynami

Jednym z nietypowych wymagań w środowiskach DR (Disaster Recovery) jest możliwość szybkiego przeniesienia dysków VMDK między maszynami wirtualnymi — bez niszczenia danych, bez klonowania, bez długich okien serwisowych. W tym artykule pokażę zestaw skryptów PowerCLI, które pozwalają zautomatyzować ten proces w całości: od przygotowania mapowania CSV, przez migrację dysków, aż po walidację wyników. Nie jest to może najlepszy sposób na DR ale jest to jeden z wielu kroków i potrzebne to było na potrzeby opracowania DRu dla z jednej aplikacji klenta i jak wspomnialem wczesniej to tylko jeden z kroków.

Kod dostępny jest na GitHubie: github.com/sebastiangrugel/PowerCLI — VMDK-reattachment


Problem — po co w ogóle przepinać VMDK?

W typowym scenariuszu failover/failback mamy dwie maszyny wirtualne:

  • VM-PROD01 — maszyna produkcyjna z dyskami z danymi
  • VM-DR01 — maszyna DR, która ma własny dysk systemowy, ale w stanie normalnym nie ma podpiętych dysków z danymi

Gdy ogłaszamy failover, chcemy:

  1. Odpiąć dyski danych od VM-PROD01 (bez kasowania pliku VMDK)
  2. Podpiąć te same dyski do VM-DR01 na konkretnych pozycjach SCSI
  3. Uruchomić VM-DR01 — system widzi dyski tak, jakby zawsze tam były

Po zakończeniu awarii — failback: operacja odwrotna, te same skrypty, zmienione tylko parametry -source i -target.

Kluczowe ograniczenie vSphere: nie można po prostu „przeciągnąć” dysku w GUI na konkretną pozycję SCSI:UNIT. Wysokopoziomowe cmdlety PowerCLI (Add-HardDisk) nie pozwalają wybrać konkretnego slotu. Jedynym sposobem jest bezpośrednie użycie VIM API przez ReconfigVM_Task — dokładnie to robią poniższe skrypty.


Wymagania wstępne

# Zainstaluj moduł PowerCLI (jednorazowo)
Install-Module VMware.PowerCLI -Scope CurrentUser

# Połącz się z vCenter przed uruchomieniem jakiegokolwiek skryptu
Set-PowerCLIConfiguration -InvalidCertificateAction Ignore -Confirm:$false
Connect-VIServer -Server vcenter.twojadomena.local -User administrator@vsphere.local -Password <haslo>

# Weryfikacja połączenia
$global:DefaultVIServer

Wszystkie skrypty wymagają aktywnej sesji $global:DefaultVIServer.


Architektura rozwiązania

Zestaw składa się z czterech skryptów, które współpracują ze sobą:

Skrypt Rola
export-vm-disk-config.ps1 Generuje plik CSV z aktualnego układu dysków maszyny wirtualnej
reattaching-vmdk-v2.ps1 Główny skrypt migracji — odpina dyski ze źródła i podpina do celu wg CSV
cmd-validation.ps1 Waliduje stan obu VM względem CSV — wynik pass/fail per dysk
create-test-disks.ps1 Tworzy testowe dyski z losowym rozmieszczeniem SCSI (do testów laboratoryjnych)

Format CSV — centralny element łączący wszystkie skrypty:

Source VM vSphere Controller,Source VM vSphere UNIT,Target VM vSphere Controller,Target VM vSphere UNIT
0,1,0,1
1,0,1,0
2,13,2,13

Każda kolumna to numer magistrali SCSI (0–3) oraz numer jednostki na tej magistrali. vSphere wewnętrznie używa ControllerKey = 1000 + BusNumber — np. SCSI bus 2 to klucz 1002. Unit 7 jest zawsze zarezerwowany przez vSphere jako SCSI initiator i nigdy nie powinien pojawić się w CSV.


Skrypt 1 — export-vm-disk-config.ps1

Zanim przepiszesz cokolwiek ręcznie, użyj tego skryptu do wygenerowania CSV bezpośrednio z aktualnego układu dysków maszyny produkcyjnej.

Parametry

Parametr Wymagany Domyślnie Opis
-vmName Tak Nazwa maszyny wirtualnej
-outputCsvPath Nie .\reattaching-vmdk-configuration.csv Ścieżka do wygenerowanego pliku CSV
-excludeBootDisk Nie $true Pomija dysk systemowy SCSI 0:0

Użycie

# Generuj CSV z VM-PROD01 (dysk startowy pomijany domyślnie)
.\export-vm-disk-config.ps1 -vmName VM-PROD01

# Własna ścieżka wyjściowa
.\export-vm-disk-config.ps1 -vmName VM-PROD01 -outputCsvPath .\prod-layout.csv

Przykładowy output

VM        : VM-PROD01  |  Power: PoweredOff
Output    : .\reattaching-vmdk-configuration.csv
Boot disk : excluded (SCSI0:0)

  Disk inventory on VM-PROD01:
Name          CapacityGB  SCSI Bus  Unit  Include      UUID
Hard disk 1         0.00         0     0  SKIP (boot)  6000C296-32ce-bfdf-...
Hard disk 2         2.00         0     1  YES          6000C29d-e5de-223b-...
Hard disk 3         2.00         1     0  YES          6000C295-e19a-e4df-...
...

  Exported : 18 disk(s)
  Skipped  : 1 disk(s) (boot disk excluded)

Wygenerowany CSV ustawia source = target (ta sama pozycja). Jeśli na maszynie DR dyski mają lądować na innych slotach — edytujesz kolumny Target ręcznie przed migracją.

Uwaga techniczna: ścieżka zaczynająca się od \filename.csv (bez litery dysku) jest przez PowerShell interpretowana jako korzeń dysku (np. E:\filename.csv). Skrypt wykrywa ten przypadek i kotwi ścieżkę do bieżącego katalogu roboczego.


Skrypt 2 — reattaching-vmdk-v2.ps1

Serce całego rozwiązania. Przepina dyski VMDK między maszynami wirtualnymi zgodnie z mapowaniem w CSV, używając bezpośrednio VIM API.

Parametry

Parametr Wymagany Opis
-source Tak Nazwa VM, z której odpinaemy dyski
-target Tak Nazwa VM, do której podpinamy dyski
-csvPath Tak Ścieżka do pliku CSV z mapowaniem

Użycie

# Failover: przenieś dyski z produkcji na DR
.\reattaching-vmdk-v2.ps1 -source VM-PROD01 -target VM-DR01 -csvPath .\reattaching-vmdk-configuration.csv

# Failback: przywróć dyski z DR na produkcję
.\reattaching-vmdk-v2.ps1 -source VM-DR01 -target VM-PROD01 -csvPath .\reattaching-vmdk-configuration.csv

Przepływ wykonania krok po kroku

  1. Rozwiązuje obie maszyny wirtualne (Get-VM)
  2. Wyświetla aktualny stan obu VM — kontrolery SCSI, dyski, UUID
  3. Pokazuje planowane mapowania z CSV
  4. Pyta o potwierdzenie: Proceed with disk migration? (yes/no)
  5. Robi snapshot typów kontrolerów SCSI na źródle (potrzebne do odtworzenia po migracji)
  6. Tworzy brakujące kontrolery SCSI na maszynie docelowej
  7. Dla każdego wiersza CSV: lokalizuje dysk na źródle → odpina → podpina do celu na wskazanej pozycji
  8. Odtwarza kontrolery SCSI na źródle (vSphere automatycznie usuwa puste kontrolery gdy odpiął się ostatni dysk)
  9. Wyświetla stan obu VM po migracji
  10. Na końcu drukuje łączny czas wykonania (minuty i sekundy)

Przykładowy output

Log  : E:\Scripts\VMDK-reattachment\log\log_20260529_143022.log
Resolving VMs...
  Source : VM-PROD01
  Target : VM-DR01

=== Pre-run State ===
...

Proceed with disk migration? (yes/no): yes

Required SCSI controllers on target: 0, 1, 2
  SCSI controller BusNumber=1 already present on VM-DR01.
  Creating SCSI controller BusNumber=2 (ParaVirtualSCSIController) on VM-DR01...
    -> Done.

Processing disk mappings...
  [VM-PROD01 SCSI0:1] -> [VM-DR01 SCSI0:1]
    Path : [DatastoreNFS01] VM-PROD01/VM-PROD01_1.vmdk (2 GB)
    Detaching from VM-PROD01...
    Attaching to VM-DR01 at SCSI0:1...
    OK.

Restoring vacated SCSI controllers on source (VM-PROD01)...
  BusNumber=1 was auto-removed — recreating as ParaVirtualSCSIController...
    -> Done.

=== Post-run State ===
...

Completed in 2 min 14 sec.

Kluczowe aspekty techniczne

Dlaczego VIM API zamiast cmdletów PowerCLI? Wysoko-poziomowe polecenie Add-HardDisk nie pozwala wybrać konkretnego ControllerKey i UnitNumber. Jedynym sposobem jest bezpośrednie wywołanie ReconfigVM_Task przez $vmView.ReconfigVM_Task($vmConfigSpec).

Dlaczego $null = Get-Task | Wait-Task? Wait-Task zwraca obiekt zrekonfigurowanej maszyny wirtualnej. Bez przechwycenia go do $null obiekt trafia do strumienia wyjściowego PowerShell i psuje kolejne wywołania Format-Table.

Automatyczne usuwanie pustych kontrolerów przez vSphere: gdy ostatni dysk opuszcza kontroler SCSI, vSphere go usuwa. Skrypt śledzi typy kontrolerów przed migracją ($sourceControllerMap) i odtwarza je po zakończeniu.

Logowanie: każde uruchomienie tworzy plik logu w katalogu log\ obok skryptu:

log\log_20260529_143022.log

Log zawiera dosłownie wszystko co widać na ekranie — tabele pre/post, postęp per dysk, ostrzeżenia i błędy.


Skrypt 3 — cmd-validation.ps1

Skrypt walidacyjny do uruchomienia przed i po migracji. Generuje trójsekcyjny raport z kolorowymi wskaźnikami [OK] / [!!] / [??].

Parametry

Parametr Wymagany Domyślnie Opis
-vmA Nie VM-PROD01 VM referencyjna (source of truth)
-vmB Nie VM-DR01 VM sprawdzana
-csvPath Nie .\reattaching-vmdk-configuration.csv Oczekiwane mapowanie dysków

Użycie

# Domyślne: VM-PROD01 vs VM-DR01
.\cmd-validation.ps1

# Własne VM
.\cmd-validation.ps1 -vmA VM-PROD01 -vmB VM-DR01 -csvPath .\my-mapping.csv

Sekcja 1 — Porównanie kontrolerów SCSI

Sprawdza czy oba VM mają te same typy kontrolerów SCSI na każdym numerze magistrali:

=====  SCSI Controller Comparison  =====
  BUS     VM-PROD01 (Reference)          VM-DR01 (Check)                Result
  SCSI0   VirtualLsiLogicSASController   VirtualLsiLogicSASController   [OK]
  SCSI1   ParaVirtualSCSIController      ParaVirtualSCSIController      [OK]
  SCSI2   ParaVirtualSCSIController      (missing)                      [!!]
  Controllers: 2 passed, 2 failed

Sekcja 2 — Walidacja mapowania dysków z CSV

Dla każdego wiersza CSV sprawdza trzy warunki na maszynie sprawdzanej:

Kolumna Co sprawdza
Ctrl Czy wymagany kontroler SCSI istnieje na VM docelowej?
Disk Czy na oczekiwanej pozycji docelowej jest dysk?
UUID Czy UUID dysku na pozycji docelowej odpowiada UUID z pozycji źródłowej?
=====  Disk Mapping Validation  =====
  #    Src Pos    Tgt Pos    UUID @ Src (VM-PROD01)    Ctrl   Disk   UUID @ Tgt (VM-DR01)    UUID  Result
  1    SCSI0:1    SCSI0:1    6000C29d-e5de-223b~       [OK]   [OK]   6000C29d-e5de-223b~     [OK]  [OK]
  2    SCSI1:0    SCSI1:0    6000C295-e19a-e4df~       [OK]   [OK]   6000C295-e19a-e4df~     [OK]  [OK]
  3    SCSI2:13   SCSI2:13   6000C297-7841-f11a~       [!!]   [!!]   (no disk at tgt)        [!!]  [!!]
  Disk mappings: 2 passed, 1 failed

Wskazówka: po udanej migracji z PROD na DR — pozycje źródłowe na PROD będą puste ([??] w kolumnie UUID). To normalne — dyski opuściły źródło.

Sekcja 3 — Cross-reference UUID

Lista wszystkich UUID dysków z obu VM z ich aktualną pozycją. Jeśli ten sam UUID pojawi się na obu maszynach jednocześnie — jest flagowany jako [??] Both VMs. Dysk VMDK nie może być bezpiecznie podpięty do dwóch VM równocześnie.

=====  UUID Cross-Reference  =====
  UUID                                  VM-PROD01 Pos  VM-DR01 Pos  Location
  6000C296-32ce-bfdf-ae61-9cea6f0f6c64  SCSI0:0        -            VM-PROD01 only
  6000C29d-e5de-223b-558a-d810baccc697  -              SCSI0:1      VM-DR01 only
  6000C295-e19a-e4df-bf59-f56917997538  -              SCSI1:0      VM-DR01 only

Legenda

Wskaźnik Znaczenie
[OK] (zielony) Sprawdzenie zaliczone
[!!] (czerwony) Błąd — wymagana interwencja
[??] (żółty) Niejednoznaczne — sprawdź ręcznie

Skrypt 4 — create-test-disks.ps1

Narzędzie laboratoryjne. Tworzy N dysków VMDK na wskazanej VM z losowym rozmieszczeniem na istniejących kontrolerach SCSI, a następnie generuje gotowy CSV dla skryptu migracyjnego.

Parametry

Parametr Wymagany Domyślnie Opis
-vmName Tak Nazwa VM, na której tworzysz dyski
-datastore Tak Nazwa datastore, na którym tworzysz pliki VMDK
-diskCount Nie 15 Liczba dysków do utworzenia
-diskSizeGB Nie 1 Rozmiar każdego dysku w GB
-outputCsvPath Nie .\reattaching-vmdk-configuration.csv Ścieżka do wygenerowanego CSV

Użycie

# Utwórz 15 dysków po 1 GB z losowym rozmieszczeniem SCSI
.\create-test-disks.ps1 -vmName VM-PROD01 -datastore DatastoreNFS01

# Własne parametry
.\create-test-disks.ps1 -vmName VM-PROD01 -datastore DatastoreNFS01 -diskCount 10 -diskSizeGB 2

Przykładowy output

VM        : VM-PROD01
Datastore : DatastoreNFS01
Disks     : 15 x 1 GB

Available SCSI controllers:
Name            Type                       BusNumber
SCSI controller 0  VirtualLsiLogicSASController  0
SCSI controller 1  ParaVirtualSCSIController     1
...

Creating 15 disks with random controller assignment...
  Disk 1  ->  SCSI2:3
    Created: SCSI2:3  |  [DatastoreNFS01] VM-PROD01/VM-PROD01_1.vmdk
  Disk 2  ->  SCSI0:5
    Created: SCSI0:5  |  [DatastoreNFS01] VM-PROD01/VM-PROD01_2.vmdk
  ...

CSV written to : .\reattaching-vmdk-configuration.csv  (15 rows)
Use with      : .\reattaching-vmdk-v2.ps1 -source VM-PROD01 -target <targetVM> -csvPath .\reattaching-vmdk-configuration.csv

Każdy kontroler obsługuje do 15 dysków (sloty 0–15 minus zarezerwowany slot 7). Przy 4 kontrolerach maksimum to 60 dysków.


Typowe workflow

Workflow 1 — Failover PROD → DR

# 1. Sprawdź aktualny stan przed migracją
.\cmd-validation.ps1 -vmA VM-PROD01 -vmB VM-DR01

# 2. Uruchom migrację
.\reattaching-vmdk-v2.ps1 -source VM-PROD01 -target VM-DR01 -csvPath .\reattaching-vmdk-configuration.csv

# 3. Zwaliduj wynik
.\cmd-validation.ps1 -vmA VM-PROD01 -vmB VM-DR01

Workflow 2 — Failback DR → PROD

# Ten sam CSV, zamienione argumenty -source i -target
.\reattaching-vmdk-v2.ps1 -source VM-DR01 -target VM-PROD01 -csvPath .\reattaching-vmdk-configuration.csv

.\cmd-validation.ps1 -vmA VM-DR01 -vmB VM-PROD01

Workflow 3 — Generowanie CSV z istniejącego układu dysków

# Eksportuj aktualny układ dysków VM-PROD01
.\export-vm-disk-config.ps1 -vmName VM-PROD01

# Przejrzyj wygenerowany CSV, następnie uruchom migrację
.\reattaching-vmdk-v2.ps1 -source VM-PROD01 -target VM-DR01 -csvPath .\reattaching-vmdk-configuration.csv

Workflow 4 — Testy laboratoryjne

# Utwórz 15 losowych dysków testowych na VM-PROD01
.\create-test-disks.ps1 -vmName VM-PROD01 -datastore DatastoreNFS01

# Przenieś na VM-DR01
.\reattaching-vmdk-v2.ps1 -source VM-PROD01 -target VM-DR01 -csvPath .\reattaching-vmdk-configuration.csv

# Zwaliduj
.\cmd-validation.ps1

# Cofnij
.\reattaching-vmdk-v2.ps1 -source VM-DR01 -target VM-PROD01 -csvPath .\reattaching-vmdk-configuration.csv

Podsumowanie

Zestaw czterech skryptów rozwiązuje problem, z którym GUI vSphere sobie nie radzi przynajmniej w kontrolowany sposób gdzie łatwo o błąd przy większej licznie dysków. Precyzyjne przenoszenie dysków VMDK między maszynami wirtualnymi na konkretne pozycje SCSI:UNIT, bez kasowania danych, z pełną walidacją przed i po operacji.

Kilka rzeczy, które warto zapamiętać:

  • Dysk systemowy (SCSI 0:0) nigdy nie trafia do CSV — nie można go odpiąć od działającej lub zatrzymanej VM
  • Unit 7 jest zawsze zarezerwowany przez vSphere — nie używaj go w CSV
  • vSphere automatycznie usuwa puste kontrolery SCSI — skrypt je odtwarza po migracji zachowując oryginalny typ
  • Każde uruchomienie migracji zapisuje pełny log do katalogu log\ — zawsze masz zapis tego co się stało
  • Walidacja UUID (cmd-validation.ps1) jest najsilniejszą weryfikacją poprawności migracji — sprawdza nie tylko pozycję, ale tożsamość konkretnego pliku VMDK

Kod dostępny jest na GitHubie: github.com/sebastiangrugel/PowerCLI — VMDK-reattachment. Jeśli masz pytania lub natrafiłeś na przypadek brzegowy, którego skrypty nie obsługują daj znać.

Informacje o nowych artykułach, świecie wirtualizacji i "cloud computingu" prosto na Twojego maila:

Dodam Cię do listy mailowej, z której możesz wypisać się w dowolnym momencie (jeden klik.) | Polityka Prywatności