Skip to content

Instantly share code, notes, and snippets.

@jvarn
Last active August 22, 2024 07:57
Show Gist options
  • Save jvarn/dff123cea56bfd6875095c051ac19593 to your computer and use it in GitHub Desktop.
Save jvarn/dff123cea56bfd6875095c051ac19593 to your computer and use it in GitHub Desktop.
Make Windows USB Installer on Mac
#!/bin/bash
# Installs Homebrew and Wimlib if not already installed,
# then formats and prepares an external USB device as
# a bootable Windows installer from your Windows ISO.
#
# Usage: ./make_windows_usb.sh windows_installer.iso
# (first make executable with: chmod u+x ./make_windows_usb.sh)
#
# Insert a single external USB target device before running.
# Do not use blindly – bad things can happen.
#######################################################################################
# Colours
BoldRed='\033[1;31m' # Critical Errors
BoldGreen='\033[1;32m' # Success Messages
BoldYellow='\033[1;33m' # Warnings or User Prompts
BoldBlue='\033[1;34m' # Information or Status Messages
NoColour='\033[0m' # Reset Colour
#######################################################################################
# Errors
# Using an array to store error messages
errors[0]="${BoldRed}No ISO image specified.${NoColour}\nUsage: ./make_windows_usb.sh windows_installer.iso"
errors[1]="${BoldRed}Please make sure you have exactly one USB storage device attached.${NoColour}\nusb_disk_count devices found"
errors[2]="${BoldRed}Fatal Error:${NoColour} There was a problem formatting the disk."
errors[3]="${BoldRed}Fatal Error:${NoColour} There was a problem rsyncing the files."
errors[4]="${BoldRed}Fatal Error:${NoColour} There was a problem creating the installation files."
errors[5]="${BoldRed}Error:${NoColour} There was a problem ejecting the USB device."
errors[6]="${BoldRed}Error:${NoColour} There was a problem unmounting the ISO."
#######################################################################################
# Sanity Check
if [ $# -eq 0 ]; then
echo -e ${errors[0]}
exit 1
fi
usb_disk_count=$(diskutil list | grep "external" | awk 'END {print NR}')
if [ ! $usb_disk_count -eq 1 ]; then
echo -e ${errors[1]} | sed "s/usb_disk_count/$usb_disk_count/g"
exit 1
fi
#######################################################################################
# Homebrew
echo -e "${BoldBlue}Preparing Homebrew.${NoColour}"
which -s brew
if [[ $? != 0 ]] ; then
echo -e "${BoldYellow}Installing Homebrew.${NoColour}"
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install.sh)"
else
echo -e "${BoldBlue}Making sure Homebrew is up-to-date.${NoColour}"
brew update &>/dev/null
fi
#######################################################################################
# Wimlib
echo -e "${BoldBlue}Preparing Wimlib.${NoColour}"
lib="wimlib"
lib_exec="wimlib-imagex"
which -s $lib_exec
if [[ $? != 0 ]] ; then
echo -e "${BoldYellow}Installing Wimlib.${NoColour}"
brew install $lib
else
echo -e "${BoldBlue}Making sure Wimlib is up-to-date.${NoColour}"
brew outdated $lib &>/dev/null || brew install $lib
fi
#######################################################################################
# ISO Disc Image
echo -e "${BoldBlue}Preparing ISO.${NoColour}"
image_file="$1"
IFS=$'\n' read -d'\n' iso_dev_entry iso_mount_point < <(
hdiutil mount "${image_file}" | awk '{print $1; print $2}'
)
echo -e "${BoldBlue}ISO mounted at ${iso_mount_point}.${NoColour}"
#######################################################################################
# USB Drive File Copy
echo -e "${BoldBlue}Preparing USB.${NoColour}"
usb_disk=$(diskutil list | grep "external" | head -n 1 | awk '{print $1}')
usb_label="WINDOWS"
usb_mount_point="/Volumes/$usb_label"
echo -e "${BoldYellow}Ready to format $usb_disk.${NoColour}"
read -p "Press any key to continue or ctrl-c to abort."
# Format USB drive
diskutil eraseDisk MS-DOS "${usb_label}" MBR ${usb_disk} || { echo -e ${errors[2]}; exit 1; }
echo -e "${BoldBlue}USB formatted. Checking mount status...${NoColour}"
diskutil list # Debugging output to check mount status
# Rsync - Copy files to USB
echo -e "${BoldYellow}Ready to start writing contents of $image_file to $usb_disk.${NoColour}"
read -p "Press any key to copy source files to USB (step 1)."
rsync -avh --progress --exclude=sources/install.wim ${iso_mount_point}/ ${usb_mount_point} || { echo -e ${errors[3]}; exit 1; }
echo -e "${BoldBlue}Rsync complete. Ready to split install.wim...${NoColour}"
# Wimlib - Split install.wim into smaller files
read -p "Press any key to copy files to USB (step 2)."
wimlib-imagex split "$iso_mount_point/sources/install.wim" "$usb_mount_point/sources/install.swm" 3800 || { echo -e ${errors[4]}; exit 1; }
# Eject the mounted volumes
echo -e "${BoldBlue}All done.${NoColour}"
read -p "Press any key to eject mounted volumes or ctrl-c to abort."
hdiutil eject ${usb_mount_point} || { echo -e ${errors[5]}; }
hdiutil eject ${iso_mount_point} || { echo -e ${errors[6]}; }
echo -e "${BoldGreen}All done!${NoColour}"
echo "You can unplug the USB drive now."
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment