How do I boot an ISO file from my drive using grub2 on UEFI machines?

There is a bug in grub 2.04 so ensure you have a prior or later version.

Well, the basics for adding an ISO file to grub are the same for an UEFI as for a BIOS machine: edit /etc/grub.d/40_custom and add a menuentry item (GParted is used in this example) to the bottom of the file:

menuentry "GParted Live ISO" {
}

Now we're going to add a variable containing the directory where we stored the ISO (so far, so good: no differences with BIOS machines):

menuentry "GParted Live ISO" {
  set GPartedISOFile="/opt/Live-ISOs/gparted-live-0.31.0-1-amd64.iso"
}

I'm using /opt to store these as I don't like creating directories in the root of my machine and according to the Linux File System Hierarchy that's where optional software should reside anyway.

Before we add the loopback variable, we need to find out on which hard disk the file is stored, so we do a: df --output=source /opt/Live-ISOs/gparted-live-0.31.0-1-amd64.iso | tail -1 and the output on my machine is: /dev/sdb2.

However grub uses (hdX,Y) notation and this is where the difference between UEFI and BIOS machines comes in! So now reboot your machine, go into the grub menu and press C: This will bring you to the grub command prompt with different commands than you're used to but the only one that you need is: ls.

On my machine the output is:

(hd0) (hd1) (hd1,gpt3) (hd1,gpt2) (hd1,gpt1) (hd2) ... (hd3) ...

Huh? 4 drives? I only have 3! And it's not (hd1,4) line on a BIOS but (hd1,gpt3) in UEFI and (hd0) has no partitions at all!

Well, apparently when part of the NVRAM is used as storage and shows up as (hd0) you need to start numbering your drives at 1!  Whereas all the information you find on booting ISO files says you have to start numbering from 0 (on BIOS machines this is always true, this is not necessarily the case on some UEFI machines ! )

So the value for loopback becomes (hd2,gpt2)$GPartedISOFile as the ISO file on my machine was /dev/sdb2 (second drive hd2, second partition gpt2):

menuentry "GParted Live ISO" {
  set GPartedISOFile="/opt/Live-ISOs/gparted-live-0.31.0-1-amd64.iso"
  loopback loop (hd2,gpt2)$GPartedISOFile
}

Another difference is that the linux and initrd on BIOS machines are called linuxefi and initrdefi on UEFI machines, which gives us our final result:

#!/bin/sh
exec tail -n +3 $0
# This file provides an easy way to add custom menu entries.  Simply type the
# menu entries you want to add after this comment.  Be careful not to change
# the 'exec tail' line above.

menuentry "GParted Live ISO" {
  set GPartedISOFile="/opt/Live-ISOs/gparted-live-0.31.0-1-amd64.iso"
  loopback loop (hd2,gpt2)$GPartedISOFile
  linuxefi (loop)/live/vmlinuz boot=live components config findiso=$GPartedISOFile ip=frommedia toram=filesystem.squashfs union=overlay username=user
  initrdefi (loop)/live/initrd.img
}

So now save that file, and update grub with:

update-grub

After all of the above, reboot, go into the grub menu, choose GParted Live ISO and you can now easily boot your ISO without having to hunt for a USB stick ever again!

:-)

CloneZilla Live example (for this question )

menuentry "CloneZilla ISO" {
  set ISOFile="/opt/Live-ISOs/clonezilla-live-20170905-zesty-amd64.iso"
  loopback loop (hd2,gpt2)$ISOFile
  linuxefi (loop)/live/vmlinuz boot=live components config findiso=$ISOFile ip=frommedia toram=filesystem.squashfs union=overlay
  initrdefi (loop)/live/initrd.img
}

An alternative is to just add a configfile to 40_custom like this:

menuentry 'Live ISOs on SSD' {
configfile (hd0,3)/ISO/livecdimage.cfg
} 

menuentry 'Live ISOs on HDD (boot on SSD)' {
configfile (hd1,3)/ISO/livecdimage.cfg
} 

I do this as when I update an ISO, I invariably forget to run sudo update-grub. The above entries never have to change and I can just edit livecdimage.cfg which has the same format as any 40_custom but without header lines, and is in my /ISO folder in my ISO partition.

I do add toram as another boot parameter and on the system with Nvidia add nomodeset boot parameter. But still often have to unmount the /isodevice.

Unable to umount isodevice unmount ISO https://bugs.launchpad.net/ubuntu/+source/ubiquity/+bug/1155216

sudo umount -l -r -f /isodevice

And this is part of my livecdimage.cfg file

# livecdimage.cfg
# Add this to 40_custom to load this file:
# menuentry 'Live ISOs' {
# configfile (hd1,3)/iso/livecdimage.cfg
#} 
# Add iso names to livecdimage.cfg
#for i in `ls *.iso`;do echo "# "$i>>livecdimage.cfg; done;

menuentry "Ubuntu 16.04.4 xenial amd64" {
    set isofile="/ISO/ubuntu-16.04.4-desktop-amd64.iso"
    loopback loop (hd0,3)$isofile 
    linux (loop)/casper/vmlinuz.efi boot=casper iso-scan/filename=$isofile toram
    initrd (loop)/casper/initrd.lz
}

menuentry "Ubuntu 18.04 Bionic amd64" {
    set isofile="/ISO/bionic-desktop-amd64.iso"
    loopback loop (hd0,3)$isofile 
    linux (loop)/casper/vmlinuz.efi boot=casper iso-scan/filename=$isofile toram
    initrd (loop)/casper/initrd.lz
}

# spacer line
menuentry " " {
set root= 
}

menuentry "Reboot" {
    reboot
}

menuentry "Halt" {
    halt
}

mkusb MULTIBOOT HACK

Mkusb makes a great base for custom boot drive projects because of its abilities with both BIOS and UEFI.

This hack boots multiple ISO files including the Windows installer, and has a grub2 menu.

Grub2 menuentries for most OS are available using Google Search and are beyond the scope of this answer.

mkusb defaults

Use mkusb defaults when creating the Persistent USB drive.

mkusb use defaults again

Use mkusb persistence defaults if in doubt, partition size can be adjusted later but takes time.

DUS Console

The DUS Console after install.

GParted Before

GParted before partition modification.

Gparted after

Gparted after modification - Overwrite sdb4, the ISO9660 OS partition and sdb5, the ext2 casper-rw partition, with a FAT32 partition for persistence files.

Persistence partition

Persistence partition - Create an uniquely name folder for each OS, (that requires persistence)

Persistence folder

Persistence folder - Add a casper-rw file and optional home-rw file to each persistence folder. A home-rw file can be made by renaming a casper-rw file. A home-rw file is like a seperate home partition on a Full install, it can be reused after version upgrades.

ISO folder

Create a folder for the ISO files on the NTFS usbdata partition.

ISO folder contents

Add some ISO's to the ISO folder.

GRUB location

grub.cfg location

grub.cfg

Edit grub.cfg to loopmount the ISO files. Include: persistent persistent-path=/<persistent-folder-name>/ if you want persistence. Add rmmod tpm to grub.cfg above the first menuentry.

EDIT 18.04+ In grub specify vmlinuz not vmlinuz.efi and initrd not initrd not initid.lz

sudo parted -ls  /dev/sdb

sudo parted -ls /dev/sdb

sudo lsblk -f  /dev/sdb

sudo lsblk -f /dev/sdb

If a Windows installer is required it is possibly easiest to start with the mkusb "extracting Windows installer" function, (I had to extract the Windows ISO to TAR manually),

mkusb Windows Installer

After installation create a folder for ISO's and if required, folders for persistence, (similar to above procedure).

mkusb Windows grub

Edit /boot/grub/grub.cfg to loopmount any ISO's and specify any persistence folders.

(have not found a way to loopmount a Windows ISO file).

If the above is used as a USB stick it can be used to boot ISO's stored on a Windows only computer. Grub is not required on the internal drive.