Bash Script To Make USB Installers From Windows ISOs 2020-12-31
Recently a buddy of mine gave me an old tablet to mess with. I ended up getting it to work reasonably well, but in order to do so I needed a PC with some software on it and that software doesn't run on systemd with GNU utilities and Linux applications. So I had to put Windows 7 on a laptop, and then do the Windows 10 upgrade. One of the most painful parts of this is just creating a working Windows installer USB stick. I tried looking for a reasonable Linux-native application to make this easy... but they're a mess, and they certainly don't exist in the Debian repos. Eventually I found this thornelabs.net post explaining a manual procedure that works.
It has been a couple of days, and I have been using the tablet [a bit], but I figured I should find a way to automate the instructions that worked so I can easily make new USB installers later on if I need to. So, I made a batch script. The bad news is that I had to put in a fair bit of checking for things like non-existent ISO file, incorrect device selection, etcetera. The good news is, I tested it on Buster and it worked just fine.

iso2usb.sh
#!/bin/bash
# Create a Windows USB installer from an ISO file.
# Basically automates these steps: https://thornelabs.net/posts/create-a-bootable-windows-7-or-10-usb-drive-in-linux.html
# Intended for use on apt based systems, tested on Debian Buster.
# Snork: 2020-12-31
export PATH='/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin'
if [ "$#" != "2" ]; then
echo "-----------------------------------------------------------------------"
echo "-- iso2usb: Create a Windows USB installer from an ISO file. --"
echo "-- Syntax: iso2usb </path/to/windows.iso> <usb device> --"
echo "-- Example: iso2usb \"/Downloads/windows10.iso\" \"/dev/sdb\" --"
echo "-- WARNING: This will destroy all data on your USB stick! --"
echo "-----------------------------------------------------------------------"
echo ""
echo "This information may help you determine which device is your USB stick:"
echo ""
lsblk -o NAME,MAJ:MIN,SIZE,FSTYPE,MOUNTPOINT,LABEL,HOTPLUG
else
# Is script being run as root or via sudo?
if [ `id -u` != 0 ]; then
echo "This script needs to be run as root or using sudo so it can write to the USB drive."
else
# Does iso path and name look right?
if [ -f $1 ]; then
echo "ISO exists..."
else
echo "Can't find ISO, must exit"
exit 1
fi
# Does device name look right?
THEDEV=`echo $2 | rev | cut -d "/" -f 1 | rev`
lsblk | grep $THEDEV > /dev/null
if [ $? -ne 0 ]; then
echo "Device $2 does not seem to exist, must exit."
exit 1
fi
echo "Device seems to exist..."
if [[ `echo "$2" | rev | cut -c 1` =~ [0-9] ]]; then
echo "WARNING: Your device name ends with a number which is probably a partition."
echo " You should specify the base device rather than a partition on it."
read -r -p ' Hit Y to continue anyways or N to quit: ' rusure
case "$rusure" in
y|Y) echo "Whatever you say champ..." ;;
*) echo "Gotcha... quitting." && exit 1 ;;
esac
fi
# Are required applications installed?
fdisk --version > /dev/null
if [ $? -ne 0 ]; then
echo "WARNING: fdisk not installed..."
INSFD="true"
fi
mkfs.ntfs --version > /dev/null
if [ $? -ne 0 ]; then
echo "WARNING: ntfs-3g not installed..."
INSMK="true"
fi
ms-sys --version > /dev/null
if [ $? -ne 0 ]; then
echo "WARNING: ms-sys not installed (requires wget, gcc, make, and gettext)..."
INSMS="true"
fi
# Do you want to install the required applications?
if [ "$INSFD" = "1" ] || [ "$INSMK" = "1" ] || [ "$INSMS" = "1" ]; then
echo "WARNING: The required applications listed above are not installed!"
read -r -p ' Hit Y to install dependencies or N to quit: ' rusure
case "$rusure" in
y|Y) echo "Okay champ..." ;;
*) echo "Gotcha... quitting." && exit 3 ;;
esac
apt-get update
if [ $INSFD = 1 ]; then
apt-get install -y fdisk
fi
if [ $INSMK = 1 ]; then
apt-get install -y ntfs-3g
fi
if [ $INSMS = 1 ]; then
apt-get install -y gcc make gettext wget
mkdir /tmp/iso2usb-ms-sys
cd /tmp/iso2usb-ms-sys
wget -O ms-sys-2.7.0.tar.gz https://sourceforge.net/projects/ms-sys/files/ms-sys%20development/2.7.0/ms-sys-2.7.0.tar.gz/download
tar xf ms-sys-2.7.0.tar.gz
cd ms-sys-2.7.0
make
make install
cd /tmp
rm -R iso2usb-ms-sys
fi
fi
fi
# Everything is installed, let's do it!
echo "Last chance to abort, this will destroy all data on $2"
read -r -p "Hit Y to do it or N to quit: " rusure
case "$rusure" in
y|Y) echo "Booyeah do it..." ;;
*) echo "Gotcha... quitting." && exit 4 ;;
esac
echo "Partitioning drive..."
(
echo o # Create a new empty DOS partition table
echo n # Add a new partition
echo p # Primary partition
echo 1 # Partition number
echo # First sector (Accept default: 1)
echo # Last sector (Accept default: varies)
echo t # Set partition type
echo 7 # NTFS
echo a # Set partition bootable
sleep 3 # Wait a few seconds before writing changes
echo w # Write changes
) | fdisk $2
echo "Wait a few seconds before formatting..."
sleep 3
echo "Formatting partition..."
DEVPART="${2}1"
mkfs.ntfs -f $DEVPART
echo "Adding MBR and EBR to drive..."
ms-sys -7 $2
ms-sys -n $DEVPART
echo "Create and mount ISO and USB..."
rm -R /tmp/ss-usb
rm -R /tmp/ss-iso
mkdir -p /tmp/ss-usb
mkdir -p /tmp/ss-iso
mount $DEVPART /tmp/ss-usb
mount -o loop $1 /tmp/ss-iso
echo "Copying files..."
cp -av /tmp/ss-iso/* /tmp/ss-usb
echo "Unmounting ISO and USB..."
echo "Seriously, wait for this to finish..."
umount /tmp/ss-usb
umount /tmp/ss-iso
echo "Done."
fi
If anyone has any suggestions, I'm open to potential changes, just let me know eh.