I'm building a Hyper-V (on Win10 and Win2016) Ubuntu base image with Packer. The machine builds fine and I can boot the exported virtual machine without issues. However, if I create a new virtual machine with the newly created virtual hard-drive it fails to boot with a message saying

No x64-based UEFI boot loader was found

I gathered from Ben Armstrong's blog that this has to do with the fact that the UEFI boot files are not written to disk in the correct place.

I have updated my preseed file to generate an EFI drive and a boot drive, however I cannot figure out what to add to the preseed file, or the boot command, to install the required files in the EFI / boot drives so that I can use the virtual hard-drive with Gen 2 Hyper-V virtual machines.

My packer configuration looks like:

    "variables": {
        "admin_username": "admin",
        "admin_password": "admin",

        "dir_deploy": null,
        "dir_http_user": null,
        "dir_scripts_user": null,
        "dir_temp": null,

        "iso_checksum": null,
        "iso_url": null,

        "vm_name": "not_really_a_vm_name",
        "vm_ram_size_in_mb": "2048",
        "vm_switch_name": "this_switch_does_not_exist",
        "vm_switch_vlan": ""
    "builders": [
            "boot_wait": "5s",
            "boot_command": [
                "set gfxpayload=1024x768<enter>",
                "linux /install/vmlinuz ",
                "preseed/url=http://${NetworkHostIpAddressForPreseed}:{{.HTTPPort}}/preseed.cfg ",
                "debian-installer=en_US auto locale=en_US kbd-chooser/method=us ",
                "hostname={{.Name}} ",
                "fb=false debconf/frontend=noninteractive ",
                "keyboard-configuration/modelcode=SKIP keyboard-configuration/layout=USA ",
                "keyboard-configuration/variant=USA console-setup/ask_detect=false <enter>",
                "initrd /install/initrd.gz<enter>",
            "communicator": "ssh",
            "enable_secure_boot": false,
            "generation": 2,
            "guest_additions_mode": "disable",
            "http_directory": "{{ user `dir_http_user` }}",
            "iso_url": "{{user `iso_url`}}",
            "iso_checksum_type": "sha256",
            "iso_checksum": "{{user `iso_checksum`}}",
            "iso_target_path": "{{ user `dir_temp` }}/packer",
            "output_directory": "{{ user `dir_temp` }}/{{ user `vm_name` }}",
            "ram_size": "{{user `vm_ram_size_in_mb`}}",
            "shutdown_command": "echo '{{user `admin_password`}}' | sudo -S -E shutdown -P now",
            "ssh_password": "{{user `admin_password`}}",
            "ssh_timeout": "4h",
            "ssh_username": "{{user `admin_username`}}",
            "switch_name": "{{user `vm_switch_name`}}",
            "type": "hyperv-iso",
            "vm_name": "{{ user `vm_name` }}"
    "provisioners": [
            "type": "shell",
            "execute_command": "echo '{{user `admin_password`}}' | sudo -S -E sh {{.Path}}",
            "scripts": [
                "{{ user `dir_scripts_user` }}/ubuntu/update.sh",
                "{{ user `dir_scripts_user` }}/ubuntu/network.sh",
                "{{ user `dir_scripts_user` }}/ubuntu/cleanup.sh",
                "{{ user `dir_scripts_user` }}/ubuntu/sysprep.sh"

And the preseed file looks like:

# preseed configuration file for Ubuntu.
# Based on: https://help.ubuntu.com/lts/installation-guide/armhf/apbs04.html

# *** Localization ***
# Originally from: https://help.ubuntu.com/lts/installation-guide/armhf/apbs04.html#preseed-l10n

d-i debian-installer/locale string en_US.utf8
d-i console-setup/ask_detect boolean false
d-i console-setup/layout string us

d-i kbd-chooser/method select American English

# *** Network configuration ***
# Originally from: https://help.ubuntu.com/lts/installation-guide/armhf/apbs04.html#preseed-network

d-i netcfg/choose_interface select auto
d-i netcfg/dhcp_failed note ignore
d-i netcfg/dhcp_options select Configure network manually
d-i netcfg/confirm_static boolean true
d-i netcfg/get_hostname string unassigned-hostname
d-i netcfg/get_domain string unassigned-domain
d-i netcfg/wireless_wep string

# *** Account setup ***
# Originally from: https://help.ubuntu.com/lts/installation-guide/armhf/apbs04.html#preseed-account

d-i passwd/user-fullname string admin
d-i passwd/username string admin
d-i passwd/user-password password password
d-i passwd/user-password-again password password
d-i user-setup/encrypt-home boolean false
d-i user-setup/allow-password-weak boolean true
d-i user-setup/encrypt-home boolean false

# *** Clock and time zone setup ***
# Originally from: https://help.ubuntu.com/lts/installation-guide/armhf/apbs04.html#preseed-time

d-i clock-setup/utc boolean true
d-i clock-setup/utc-auto boolean true
d-i time/zone string UTC

# *** Partitioning ***
# Originally from: https://help.ubuntu.com/lts/installation-guide/armhf/apbs04.html#preseed-partman

d-i partman/choose_partition select finish
d-i partman/confirm boolean true
d-i partman/confirm_nooverwrite boolean true
d-i partman-auto/method string lvm
d-i partman-auto/purge_lvm_from_device boolean true
d-i partman-lvm/device_remove_lvm boolean true
d-i partman-lvm/device_remove_lvm_span boolean true
d-i partman-lvm/confirm boolean true
d-i partman-lvm/confirm_nooverwrite boolean true
d-i partman-auto-lvm/guided_size string max
d-i partman-auto-lvm/new_vg_name string system
d-i partman-auto/choose_recipe select grub-efi-boot-root
d-i partman-partitioning/confirm_write_new_label boolean true
d-i partman/default_filesystem string ext4

d-i partman-auto/expert_recipe string       \
    grub-efi-boot-root ::                   \
        1 1 1 free                          \
            $bios_boot{ }                   \
            method{ biosgrub }              \
        .                                   \
        256 256 256 fat32                   \
            $primary{ }                     \
            method{ efi }                   \
            format{ }                       \
        .                                   \
        512 512 512 ext4                    \
            $primary{ }                     \
            $bootable{ }                    \
            method{ format }                \
            format{ }                       \
            use_filesystem{ }               \
            filesystem{ ext4 }              \
            mountpoint{ /boot }             \
        .                                   \
        4096 4096 4096 linux-swap           \
            $lvmok{ }                       \
            method{ swap }                  \
            format{ }                       \
        .                                   \
        10000 20000 -1 ext4                 \
            $lvmok{ }                       \
            method{ format }                \
            format{ }                       \
            use_filesystem{ }               \
            filesystem{ ext4 }              \
            mountpoint{ / }                 \

d-i partman-partitioning/no_bootable_gpt_biosgrub boolean false
d-i partman-partitioning/no_bootable_gpt_efi boolean false

# enforce usage of GPT - a must have to use EFI!
d-i partman-basicfilesystems/choose_label string gpt
d-i partman-basicfilesystems/default_label string gpt
d-i partman-partitioning/choose_label string gpt
d-i partman-partitioning/default_label string gpt
d-i partman/choose_label string gpt
d-i partman/default_label string gpt

# Keep that one set to true so we end up with a UEFI enabled
# system. If set to false, /var/lib/partman/uefi_ignore will be touched
d-i partman-efi/non_efi_system boolean true

# *** base system installation ***
# Originally from: https://help.ubuntu.com/lts/installation-guide/armhf/apbs04.html#preseed-apt

d-i base-installer/kernel/override-image string linux-server

# *** Package selection ***
# originally from: https://help.ubuntu.com/lts/installation-guide/armhf/apbs04.html#preseed-pkgsel

tasksel tasksel/first multiselect standard, ubuntu-server

# Minimum packages (see postinstall.sh). This includes the hyper-v tools
d-i pkgsel/include string openssh-server ntp linux-tools-$(uname -r) linux-cloud-tools-$(uname -r) linux-cloud-tools-common
d-i pkgsel/upgrade select none
d-i pkgsel/update-policy select none
d-i pkgsel/install-language-support boolean false

# Boot loader installation

d-i grub-installer/only_debian boolean true
d-i grub-installer/with_other_os boolean true
d-i grub-installer/bootdev  string /dev/sda

# grub-install –target=x86_64-efi –efi-directory=/boot/efi –no-nvram –removable

# *** Preseed other packages ***

d-i debconf debconf/frontend select Noninteractive
d-i finish-install/reboot_in_progress note

choose-mirror-bin mirror/http/proxy string

Setting d-i grub-installer/force-efi-extra-removable boolean true will install Grub as EFI/boot/bootx64.efi, however Grub isn't signed with the Microsoft key, and so this will break Secure Boot, if you are using it.

Another approach is to use this, which copies the Shim + Grub setup that is installed in EFI/ubuntu

d-i preseed/late_command string \
    mkdir -p /target/boot/efi/EFI/BOOT && \
    cp /target/boot/efi/EFI/ubuntu/* /target/boot/efi/EFI/BOOT && \
    cd /target/boot/efi/EFI/BOOT/ && mv shimx64.efi BOOTX64.EFI

EDIT: Note that /target is the file system of the target system so this path should not appear in the disk section of the preseed file.

| improve this answer | |
  • Am I correct in assuming that using the latter approach will allow me to use secure boot? – Petrik Sep 26 '17 at 18:32
  • 1
    Yes it should do. Note that I've edited the code, as what I had before was not correct. I'm also seeing a strange issue where images created from the disk image boot with a black screen, but appear to work fine subsequently. – Peter Russell Sep 27 '17 at 14:45
  • I finally tested this and it works as advertised. I fixed an incorrect path in the example as an /efi section was missing. – Petrik Jan 5 '18 at 5:41

By adding the following line to the preseed file makes GRUB install an UEFI bootstrapper to the efi partition

d-i grub-installer/force-efi-extra-removable boolean true

With that line added the UEFI bootstrapper ends up on the virtual hard-drive meaning that it's possible to reuse the drive separately from the virtual machine configuration.

| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.