I needed a to install Windows 10 from a USB recently. I’ve described my preferred method of accomplishing this in my recent post A Multi-Boot USB With Ventoy. Before I thought to use Ventoy, I created such an installer following this nifty article How to Create a Bootable Windows 10 USB Drive in Linux. I was surprised by how simple it is do this using functionality built into Ubuntu and GNOME. This made me curious. How exactly do the underlying components function to do this? So, I converted that tutorial to a command-line only version here.

Tutorial

This tutorial documents the steps required to create a Windows 10 USB installer on Ubuntu 20.04 from the command-line. As such, you should be familiar with Linux and the command-line to get the most out of this tutorial. These instructions will work on Fedora just the same except that disks will be mounted to /run/media instead of /media.

  1. Insert a spare flash drive in to your computer.

  2. Locate the device associated with your USB by using the lsblk(8) command.[1]

    ➜ lsblk
    NAME             MAJ:MIN RM   SIZE RO TYPE  MOUNTPOINT
    sda                8:0    0 465.8G  0 disk
    ├─sda1             8:1    0   512M  0 part  /boot/efi
    ├─sda2             8:2    0     2G  0 part
    │ └─cryptoswap   253:1    0     2G  0 crypt [SWAP]
    ├─sda3             8:3    0     2G  0 part
    └─sda4             8:4    0 461.3G  0 part
    sdb                8:16   1  29.9G  0 disk (1)
    └─sdb1             8:17   1  29.9G  0 part  /media/jordan/MyUSB
    zd0              230:0    0   500M  0 disk
    └─keystore-rpool 253:0    0   484M  0 crypt /run/keystore/rpool
    1 sdb here is the 32 Gigabyte flash drive I’ve plugged in to my laptop.
  3. Before proceeding, ensure that nothing important is on the flash drive since it will be overwritten in a minute.

  4. Unmount any mounted partitions on the flash drive.

    As shown in the previous output, sdb1 is mounted at /media/jordan/MyUSB. I unmount this partition with the udisksctl(1) command here.

    ➜ udisksctl unmount -b /dev/sdb1
    Unmounted /dev/sdb1.
  5. Wipe any existing partition tables on the flash drive and generate a new one.

    The set of gdisk commands, consisting of cgdisk(8), gdisk(8), and sgdisk(8), manipulate GUID partition tables, also known as GPT's. Older master boot records, MBR's, are instead managed with fdisk(8) and its similarly named friends. Here, the sgdisk(8) command is used to partition the flash drive using the newer GPT format without requiring any user interaction.

    sudo sgdisk -Z -n 0:0:0 /dev/sdb
    Creating new GPT entries in memory.
    GPT data structures destroyed! You may now partition the disk using fdisk or
    other utilities.
    The operation has completed successfully.

    The -Z flag zaps any existing MBR and GPT partition tables into oblivion. Then, the -n flag creates a new partition given the partition number, starting sector, and ending sector separated by colons. Zeros used here represent default values. The first zero sets the partition number to the next available number, which is one since this is the first partition on the flash drive. The next two zeros designate the starting sector of the largest block and the last sector of that same block, creating a single partition which effectively takes up the entirety of the flash drive.

    The program deceptively prints out what it does in the wrong order. Just know that it does indeed wipe the existing MBR and GPT partitions before creating the new one.

  6. Format the partition as NTFS with the mkntfs(8) tool.

    sudo mkntfs -QL Windows10 /dev/sdb1
    Cluster size has been automatically set to 4096 bytes.
    Creating NTFS volume structures.
    mkntfs completed successfully. Have a nice day.
  7. Mount the newly created partition with udisksctl(1).

    ➜ udisksctl mount -b /dev/sdb1
    Mounted /dev/sdb1 at /media/jordan/Windows10
  8. Download the Windows 10 ISO.

  9. Mount the Windows 10 ISO in order to access its contents.

    gnome-disk-image-mounter(1) makes this a piece of cake and only requires a single argument, the path to the ISO file to mount.

    ➜ gnome-disk-image-mounter ~/Downloads/Win10_*.iso
  10. Use lsblk(8) again in order to find where the ISO is mounted.

    ➜ lsblk
    NAME            MAJ:MIN RM   SIZE RO TYPE  MOUNTPOINT
    loop53            7:53   0   5.7G  1 loop  /media/jordan/CCCOMA_X64FRE_EN-US_DV9 (1)
    sda               8:0    0 465.8G  0 disk
    ├─sda1            8:1    0   512M  0 part  /boot/efi
    ├─sda2            8:2    0     2G  0 part
    │ └─cryptoswap  253:1    0     2G  0 crypt [SWAP]
    ├─sda3            8:3    0     2G  0 part
    └─sda4            8:4    0 461.3G  0 part
    zd0             230:0    0   500M  0 disk
    └─keystore-rpool
                    253:0    0   484M  0 crypt /run/keystore/rpool
    1 Yep, that’s the ISO file mounted as a loop device.
  11. Copy all files from the ISO to the flash drive.

    cp -r /media/$USER/CCCOMA_X64FRE_EN-US_DV9/* /media/$USER/Windows10
  12. Unmount the ISO.

    ➜ udisksctl unmount -b /dev/loop53
    Unmounted /dev/loop53.
  13. Unmount the flash drive.

    ➜ udisksctl unmount -b /dev/sdb1
    Unmounted /dev/sdb1.

Conclusion

You should now have a better idea of some of the underlying components at work when creating a Windows 10 USB installer.


1. Or, use sudo fdisk -l if you prefer.