Script to migrate VMWare ESXi Virtual machine to Proxmox VE 7.1

Sun, Jun 19, 2022 5-minute read

Introduction

Migrating virtual machines between platforms can be a pain in the ass to put it mildly.

I have recently decided to migrate from ESXi to Proxmox VE, simply because it allows me downscale my lab from several “BIG” machines into a single machine.

When converting a lot of VM’s from ESXi to Proxmox VE I basically had to write the same commands over and over in the same sequence.

So I decided to create a little wrapper script that can do the bare minimum but might also be useful for others.

Prerequisites

Software is required to allow the migration to happen, but not a lot.

Ovftool is what makes the magic work. It can convert a virtual machine into a ovf package.

Head to vmware’s website and download version 4.4.3 of ovftool.

Copy the downloaded zip VMware-ovftool-4.4.3-18663434-lin.x86_64.zip to your proxmox VE server.

Unzip the archive via the command unzip. If you get a command not found error message simply install unzip via apt-get install unzip

Then you unzip the archive via the command unzip VMware-ovftool-4.4.3-18663434-lin.x86_64.zip

This should create a folder in the current directory called ovftool.

Script

#!/bin/bash

EXE=/tank/tools/ovftool/ovftool
RED='\033[0;31m'
NC='\033[0m' # No Color

TYPE=""
TEMP="/tmp"
HOSTNAME=""
USERNAME="root"
VMNAME=""
DESTINATION=""
VMX=""
VMID=""
CONFIRM=""
CLEAN=""
LOG=""

CheckArguments()
{
  while [[ $# -gt 0 ]]; do
  case $1 in
    --online)
      TYPE="ONLINE"
      shift
      ;;
    --offline)
      TYPE="OFFLINE"
      shift # past argument
      ;;
    --temp)
      TEMP="$2"
      shift # past argument
      shift # past value
      ;;
    --vmx)
      VMX="$2"
      shift # past argument
      shift # past value
      ;;
   --hostname)
      HOSTNAME="$2"
      shift # past argument
      shift # past value
      ;;
   --vmid)
      VMID="$2"
      shift # past argument
      shift # past value
      ;;

   --username)
      USERNAME="$2"
      shift # past argument
      shift # past value
      ;;
   --destination)
      DESTINATION="$2"
      shift # past argument
      shift # past value
      ;;
   --yes)
      CONFIRM="YES"
      shift # past argument
      ;;
   --log)
      LOG="$2"
      shift # past argument
      shift 
      ;;
   --clean)
      CLEAN="YES"
      shift # past argument
      ;;

    --*)
      echo "Unknown option $1"
      exit 1
      ;;
  esac
done  
}

Write()
{
  echo -e "$1"
}

Usage()
{
echo -e "${NC}"
cat << EOT
ESXi -> Proxmox helper script
Simplifies import/export into a single command

Usage: $1 <arguments>

Arguments:
--online                    : For direct online import from ESXi
--offline                   : For import of vmdk from filesystem
--temp <path>               : Where to store temporary files before
                              import into proxmox - defaults to /tmp if not provided
--vmx <vmx>                 : Full path to vmx file
--hostname <hostname>       : hostname for esxi server
--username <username>       : username for esxi - defaults to root if not provided
--vmname  <vmname>          : Name of VM as its presented in ESXi
                              - if name contains spaces enclose it in quotes
--destination <storage id>  : ID of destination storage inside proxmox
--vmid <vmid>               : Destination ID of vm when its imported. Must be unique
--yes                       : Assume yes to all questions
--log <path>                : Full path to log file - if none is provided, no logging is done
--clean                     : Delete ovf file after import into proxmox

Examples:

$0 --offline --temp /tmp --vmx '/mnt/data/esxi/my\ vm/my\ vm.vmx' --destination vms --vmid 300

$0 --online --temp /tmp --hostname vms.root.dom --username john --vmname 'my vm' --destination vms --vmid 300

EOT
}

if [ ! -f $EXE ]
then
  Write "$EXE does not exist"
  exit 2
fi

if [ "$#" -eq "0" ]
then
  Write "${RED}Missing arguments"
  Usage $0
  exit 1
fi

CheckArguments $@

MISSINGARGS=""

if [ "$TYPE" == "" ]
then
  MISSINGARGS="\n--offline or --online"
fi

if [ "$DESTINATION" == "" ]
then
  MISSINGARGS+="\n--destination"
fi

if [ "$VMID" == "" ]
then
  MISSINGARGS+="\n--vmid"
fi

if [ "$MISSINGARGS" != "" ]
then
  Write "Missing required arguments:"
  Write "$MISSINGARGS"
  exit 3
fi


if [ "$TYPE" == "OFFLINE" ]
then
  Write ""
  Write "Ready to import"
  Write "-------------------------------------------------------------"
  Write "Temporary storage   : '$TEMP'"
  Write "VM Storage          : '$DESTINATION'"
  Write "VMX Path            : '$VMX'"
  Write "Destination VM ID   : '$VMID'"
  Write "-------------------------------------------------------------"
   
VMXFILE=$(basename $VMX)
VMNAME=$(basename -s .vmx $VMX)
#  echo "Source vmx:$VMXFILE"
#  echo "Source name:$VMNAME"

  if [ "$CONFIRM" == "" ]
  then
    Write ""
    read -p "Export vm to ovf format? (y/n)" -n 1 -r REPLY
    Write ""
    if [ "$REPLY" != "y"  -a "$REPLY" != "Y" ]
    then
      exit 10
    fi
  fi
  Write "Exporting $VMNAME to $TEMP"
  Write "Eecuting '$EXE $VMX $TEMP'" 
  ARGS=""
  if [ "$LOG" != "" ]
  then
    ARGS="--X:logLevel=verbose --X:logFile=$LOG"
  fi
  $EXE $ARGS --noNvramFile --lax $VMX $TEMP 

  Write ""
  Write "Export complete"
  Write "OVF file should be located in folder $TEMP/$VMNAME/"
  Write ""
  if [ "$CONFIRM" == "" ]
  then
    Write "VM $VMID is ready to be imported from ($TEMP/$VMNAME/$VMNAME.ovf)"
    Write ""
    read -p "Import VM $VMID to proxmox? (y/n)" -n 1 -r REPLY
    Write ""
    if [ "$REPLY" != "y"  -a "$REPLY" != "Y" ]
    then
      exit 10
    fi
  fi

  Write "Importing VM '$VMID' ($TEMP/$VMNAME/$VMNAME.ovf) to storage '$DESTINATION'"
  Write ""
  qm importovf $VMID $TEMP/$VMNAME/$VMNAME.ovf $DESTINATION

  if [ "$CLEAN" == "YES" ]
  then
    rm -rf $TEMP/$VMNAME
  fi
fi

exit 0

Usage

The script has to be located on your PVE server - and the script needs to be modified with a correct path to where you unzipped the ovftool.

When that is done you can simply call the script like this:

./import_esxi.sh --offline --temp /tmp --vmx '/mnt/data/esxi/my\ vm/my\ vm.vmx' --destination vms --vmid 300

./import_esxi.sh --online --temp /tmp --hostname vms.root.dom --username john --vmname 'my vm' --destination vms --vmid 300

Where the first example is if you have already shut down your ESXi server and have access to the datastore - and the second example is when you have the ESXi still running.

The script then either corrects directly to the ESXi server and exports a ovf - or coverts the vmx/vmdk directly to a ovf.

When the export has been done the script will ask whether or not to import the exported vm into proxmox.

Simple.

If you like the script please let me know in the comments below.