從 VMware 搬到 Proxmox VE 的工具很多,PVE 自己也內建了 ESXi 匯入精靈。但反過來的需求其實也不少:把 PVE 上做好的虛擬機交給客戶,而客戶用的是 VMware 或 Hyper-V。
例如我們幫客戶建好一台 Graylog 或監控主機,客戶的環境是 ESXi;或是要交付一台測試機給用 Hyper-V 的單位。手動轉檔要處理磁碟格式、硬體版本、韌體類型、網路卡,每次都要查一輪。所以我寫了兩支腳本,直接在 PVE 節點上執行,一行指令就把 VM 轉成對方能匯入的格式,還會順便產生給客戶看的匯入說明:
- jt_pve2ova:轉成 OVA,給 VMware ESXi、Workstation,或其他支援 OVA 的虛擬化平台
- jt_pve2hyperv:轉成 動態 VHDX,並產生 Hyper-V 用的 PowerShell 自動建立腳本
兩支工具比較
| 項目 | jt_pve2ova | jt_pve2hyperv |
|---|---|---|
| 目標平台 | VMware ESXi 6.5~8.0、Workstation,其他支援 OVA 的平台 | Microsoft Hyper-V(Windows 10/11 Pro、Windows Server 2016 以上) |
| 輸出 | .ova(內含精簡佈建的 VMDK) | 動態 .vhdx + .ps1 建立腳本 |
| 額外需要 | VMware OVF Tool | 不需要,qemu-img 直接產生 |
| 韌體 | 依 PVE 的 bios: 寫入 BIOS 或 UEFI | ovmf 對應 Gen 2,其他對應 Gen 1 |
| 給客戶的文件 | 中英文匯入說明 | 中文或英文操作說明+ PowerShell 腳本 |
| 支援的儲存 | RBD(Ceph)、dir、ZFS、LVM、LVM-thin | 同左 |
兩支的共同點:
- 磁碟路徑一律透過
pvesm path解析,Ceph RBD 會得到完整的 librbd 連線資訊,qemu-img可以直接讀 - PVE 9 上 VM 關機時 LVM 的 LV 可能是未啟用的狀態,腳本會自動啟用
- 轉換前先估算空間(加 20% 緩衝),不夠就中止
- 轉換前先檢查輸出檔是否已存在,存在就自動加
_N後綴,不會轉了半小時才發現覆蓋不了 - 讀取 VM 設定時會略過快照區段,只取目前的設定
轉換前準備
先關機
注意:轉換前務必先把來源 VM 關機。腳本會直接讀取磁碟,VM 還在執行的話,轉出來的磁碟內容不一致,到了對方那邊可能開不了機或資料損毀。
Windows 客體的開機碟
PVE 上的 Windows VM 如果開機碟是 VirtIO,搬到 VMware 或 Hyper-V 後會因為沒有對應的驅動程式而藍屏(INACCESSIBLE_BOOT_DEVICE)。建議轉換前:
- 先在 PVE 上把開機碟改成 SATA 或 IDE,確認能正常開機
- 或在 Windows 裡先裝好目標平台的驅動程式
網路設定
目標平台的網路卡和 PVE 的 virtio-net 不同,客體會看到一張新的網路卡,固定 IP 的主機要在對方環境重新設定,Linux 客體的網路介面名稱也可能改變。
jt_pve2ova:轉成 OVA
安裝 OVF Tool
OVA 打包需要 VMware 的 OVF Tool,從 Broadcom 開發者網站下載 Linux 版(需要登入 Broadcom 帳號),解壓縮到 /opt/:
cd /opt
unzip VMware-ovftool-x.x.x-xxxxxxxx-lin.x86_64.zip
ls /opt/ovftool/ovftool
安裝腳本
curl -Lo /opt/jt_pve2ova.sh "https://raw.githubusercontent.com/jasoncheng7115/it-scripts/refs/heads/master/jt_pve2ova/jt_pve2ova.sh"
chmod +x /opt/jt_pve2ova.sh
用法
/opt/jt_pve2ova.sh <VMID> <WORK_DIR> <ESXI_VERSION> [MODE]
| 參數 | 說明 |
|---|---|
VMID | PVE 的 VM ID |
WORK_DIR | 暫存與輸出目錄,要有足夠空間 |
ESXI_VERSION | 目標 ESXi 版本:8.0u2、8.0、7.0u3、7.0u1、7.0、6.7、6.5 |
MODE | clean(預設,打包後刪掉暫存的 VMX/VMDK)、keep(保留)、vmx(只產生 VMX,不轉磁碟) |
# 轉成 ESXi 8.0 用的 OVA
/opt/jt_pve2ova.sh 203 /vmimage/tmp 8.0
# 轉成 ESXi 6.7 用的 OVA,保留 VMX/VMDK
/opt/jt_pve2ova.sh 105 /export/ova 6.7 keep
目標版本一定要選對
OVA 裡的虛擬硬體版本(virtualHW)比對方的 ESXi 新,對方就匯入不了,所以第三個參數要填對方實際的 ESXi 版本:
| ESXi 版本 | virtualHW | Manifest 雜湊 |
|---|---|---|
| 8.0u2 以上 | 21 | SHA256 |
| 8.0 | 20 | SHA256 |
| 7.0u2、7.0u3 | 19 | SHA256 |
| 7.0u1 | 18 | SHA256 |
| 7.0 | 17 | SHA256 |
| 6.7 | 14 | SHA1 |
| 6.5 | 13 | SHA1 |
ESXi 6.5、6.7 不接受新版 OVF Tool 預設的 SHA256 manifest,會報 Invalid OVF manifest,腳本選這兩個版本時會自動改用 SHA1。
轉換過程
INFO: Target ESXi 8.0 -> virtualHW 20
INFO: VM 'web01' BIOS=bios vCPU=4 (sockets=1, cores=4) RAM=8192 MB
INFO: Added disk /vmimage/images/203/vm-203-disk-0.qcow2 (45097156608 bytes, format=qcow2)
INFO: Required space ~55G, available 1.4T
INFO: Converting disks to streamOptimized VMDK...
INFO: [0/1] ... -> disk0.vmdk (100.00/100%)
INFO: VMX generated -> /vmimage/tmp/web01_esxi8.0.vmx
INFO: Packing OVA with ovftool...
SUCCESS: OVA ready -> /vmimage/tmp/web01_esxi8.0.ova
INFO: Import guide (EN) -> /vmimage/tmp/web01_esxi8.0_import_guide_en.txt
INFO: Import guide (ZH) -> /vmimage/tmp/web01_esxi8.0_import_guide_zh-TW.txt
磁碟會轉成 streamOptimized 格式的 VMDK,OVF Tool 再以精簡佈建(--diskMode=thin)打包,OVA 只會佔實際使用的空間,傳給客戶比較省時間。
輸出檔案
| 檔案 | 用途 |
|---|---|
web01_esxi8.0.ova | 給對方匯入的 OVA |
web01_esxi8.0_import_guide_en.txt | 英文匯入說明 |
web01_esxi8.0_import_guide_zh-TW.txt | 中文匯入說明 |
檔名帶了目標 ESXi 版本,同一台 VM 轉給不同客戶時不會搞混。匯入說明包含 vSphere 網頁介面與 ovftool 指令兩種方式的步驟、VM 規格摘要與常見問題,可以直接附給客戶。
匯入到 VMware 與其他平台
- ESXi / vCenter:「部署 OVF 範本」,選擇 OVA 檔案即可
- VMware Workstation:「檔案 → 開啟」選擇 OVA
- VirtualBox 等其他平台:OVA 是開放格式,一般可以直接匯入;不過腳本的測試以 ESXi 6.5~8.0 與 Workstation 17 為主,其他平台請先實際測試
匯入後的 VM 硬體:SCSI 控制器是 LSI Logic、網路卡是 vmxnet3,客體裡要安裝 VMware Tools(Linux 用 open-vm-tools)網路卡才會有驅動。
jt_pve2hyperv:轉成 Hyper-V VHDX
安裝
這支不需要 OVF Tool,只要 PVE 內建的 qemu-img:
curl -Lo /opt/jt_pve2hyperv.sh "https://raw.githubusercontent.com/jasoncheng7115/it-scripts/refs/heads/master/jt_pve2hyperv/jt_pve2hyperv.sh"
chmod +x /opt/jt_pve2hyperv.sh
用法
/opt/jt_pve2hyperv.sh <VMID> <WORK_DIR> <LANG> [MODE]
| 參數 | 說明 |
|---|---|
VMID | PVE 的 VM ID |
WORK_DIR | 輸出目錄,需要約磁碟總量 1.2 倍的空間 |
LANG | 說明文件語言:en 或 zh-TW |
MODE | all(預設,轉磁碟+說明+ PS1)、guide(只產生說明與 PS1,不轉磁碟) |
# 轉換 VM 203,產生中文說明
/opt/jt_pve2hyperv.sh 203 /vmimage/tmp zh-TW
# 只產生說明與 PS1,先看看客戶會拿到什麼
/opt/jt_pve2hyperv.sh 203 /vmimage/tmp zh-TW guide
guide 模式很實用:磁碟轉換可能要很久,可以先產生說明文件確認內容,再正式轉換。
韌體與世代對應
PVE bios: | Hyper-V | 說明 |
|---|---|---|
ovmf | 第 2 代(UEFI) | Linux 客體會自動關閉 Secure Boot |
| 預設(SeaBIOS) | 第 1 代(BIOS) |
世代一定要和來源的韌體相符,選錯就開不了機。Linux 在第 2 代 VM 上預設的 Secure Boot 範本常會擋住開機,產生的 PS1 會自動關掉。
輸出檔案
| 檔案 | 用途 |
|---|---|
web01_disk0.vhdx、web01_disk1.vhdx | 動態 VHDX,一顆磁碟一個檔案 |
web01_hyperv_setup_guide.txt | 給客戶的操作說明 |
web01_hyperv_create.ps1 | 在 Hyper-V 主機上自動建立 VM 的 PowerShell 腳本 |
web01_notes.txt | PVE 上的 VM 備註,建立 VM 時會帶入 |
VM 名稱會先轉成只有英數字的安全字串,PS1 也刻意維持純 ASCII、不帶 BOM,在各種語系的 Windows 上都能直接執行;PVE 備註裡的中文另外存成 UTF-8 的 _notes.txt,執行時用 Set-VM -Notes 套用。
客戶端的操作
把所有 .vhdx、.ps1、_notes.txt 複製到 Hyper-V 主機的同一個資料夾,以系統管理員身分開啟 PowerShell:
Set-ExecutionPolicy -Scope Process -ExecutionPolicy Bypass
cd C:\HyperV\web01
.\web01_hyperv_create.ps1
-Scope Process 只對這個 PowerShell 視窗放寬,關掉就恢復,不會改到系統設定。腳本可以加參數:
| 參數 | 說明 | 預設 |
|---|---|---|
-VMName | VM 名稱 | 來源 VM 名稱 |
-VHDXPath | VHDX 所在資料夾 | 目前目錄 |
-SwitchName | 虛擬交換器 | Default Switch |
-Force | 同名 VM 已存在時先刪除再建立 | 不刪除 |
.\web01_hyperv_create.ps1 -SwitchName "External-LAN"
PS1 建立 VM 前會先檢查 Hyper-V 是否可用、虛擬交換器與每顆 VHDX 是否存在,任何一項不符就中止,不會留下建到一半的 VM。
注意:Windows Server 沒有 Default Switch(那是 Windows 10/11 才有的),在 Server 上執行要先建立 External 或 Internal 交換器,再用 -SwitchName 指定。
常見問題
| 狀況 | 處理方式 |
|---|---|
ESXi 匯入時 Unsupported hardware family vmx-XX | 轉換時選的 ESXi 版本比對方新,用正確版本重新轉換 |
ESXi 匯入時 Invalid OVF manifest | ESXi 6.5/6.7 要用 SHA1,轉換時版本參數要填 6.5 或 6.7 |
ovftool not found | 確認 /opt/ovftool/ovftool 存在且可執行 |
| 開機進入 UEFI shell、找不到開機裝置 | 來源與目標的韌體不一致;Hyper-V 要確認世代,Linux 第 2 代要關 Secure Boot |
Windows 藍屏 INACCESSIBLE_BOOT_DEVICE | 來源開機碟是 VirtIO,先在 PVE 改成 SATA/IDE 再轉 |
| 匯入後網路不通 | 網路卡是新的:VMware 要裝 VMware Tools,Hyper-V 要重設 IP |
| Ceph RBD 連線錯誤 | 確認 pvesm path <storage>:<vol> 能正常解析,且其中的 conf、keyring 檔案可讀 |
| PVE 9 上 LV 未啟用 | 腳本會自動啟用,失敗時手動 lvchange -ay |
結論
把 VM 從 PVE 交付給 VMware 或 Hyper-V 的客戶,麻煩的不是轉磁碟本身,而是硬體版本、韌體、網路卡、驅動這些細節。這兩支腳本把我實際遇過的問題都寫進去了,轉出來的檔案加上自動產生的說明文件,直接交給客戶就能匯入。
另外,這兩支都是在 PVE 節點上以 root 執行,執行前建議先看過腳本內容,第一次使用也先拿一台測試 VM 走一遍完整流程。
參考資料
- jt_pve2ova(GitHub)
https://github.com/jasoncheng7115/it-scripts/tree/master/jt_pve2ova - jt_pve2hyperv(GitHub)
https://github.com/jasoncheng7115/it-scripts/tree/master/jt_pve2hyperv - Broadcom:Open Virtualization Format Tool(OVF Tool)
https://developer.broadcom.com/tools/open-virtualization-format-ovf-tool/latest - Broadcom KB:ESXi/ESX hosts and compatible virtual machine hardware versions
https://knowledge.broadcom.com/external/article?legacyId=2007240 - Microsoft Learn:Should I create a generation 1 or 2 virtual machine in Hyper-V?
https://learn.microsoft.com/en-us/windows-server/virtualization/hyper-v/plan/should-i-create-a-generation-1-or-2-virtual-machine-in-hyper-v



