Skip to content

Instantly share code, notes, and snippets.

@gustavohenrique
Created April 27, 2020 11:07
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save gustavohenrique/6e2f8d72fac59383d7e6e01f28114fdc to your computer and use it in GitHub Desktop.
Save gustavohenrique/6e2f8d72fac59383d7e6e01f28114fdc to your computer and use it in GitHub Desktop.
Create a Windows USB install stick using Linux machine
#!/usr/bin/bash
# uses (modified) WoeUSB's "listUsb" to get all USB devices
# WoeUSB, listUsb: Copyright © 2013 Colin GILLE / congelli501
# WoeUSB, listUsb: Copyright © 2017 slacka et. al.
# uses (modified) Janne Korhonen's installer script
# https://ypcs.fi/howto/2018/12/01/windowsiso/
#
#
# Dependencies: apt-get install wimtools parted rsync wimtools
declare -a USB_DEVICES=()
ISO_FILE=$1
function createUsbInstaller() {
DEVICE=$1
DEVICE_DIR="$(echo $DEVICE | cut -d ' ' -f1)"
TEMP_DIR="$(mktemp -d winimage-XXXXXX)"
MOUNT_TEMP_DIR="$(mktemp -d winmount-XXXXXX)"
SOURCE="./$MOUNT_TEMP_DIR/mounted_iso"
TARGET="./$MOUNT_TEMP_DIR/mounted_usb"
# Directory for mounting the ISO image
mkdir "${SOURCE}"
# Directory for mounting the USB stick
mkdir "${TARGET}"
# Create GPT partition table, one FAT32 partition that uses 100% of available space
# first create msdos table to ensure that existing table is purged
echo "Creating partitions..."
parted --script "${DEVICE_DIR}" \
mklabel msdos \
mklabel gpt \
mkpart primary fat32 1 100% \
set 1 msftdata on &
wait && sleep 5
# Just to make sure that partition is correctly formatted as FAT32
mkfs.vfat "${DEVICE_DIR}1"
# Mount Windows ISO image for file copying
mount -oloop "${ISO_FILE}" "${SOURCE}"
# Mount USB stick, partition 1
mount "${DEVICE_DIR}1" "${TARGET}"
# Copy all files from ISO image to temporary directory
rsync -avh --no-o --no-g "${SOURCE}/" "${TEMP_DIR}/"
# Split the install.wim file to smaller parts (max 250MB), to temporary directory
wimlib-imagex split "${TEMP_DIR}/sources/install.wim" "${TEMP_DIR}/sources/install.swm" 250
# Finally, copy resulting data structure, without large file (install.wim) to the USB stick
rsync -avh --no-o --no-g --exclude="install.wim" "${TEMP_DIR}/" "${TARGET}/"
# Ensure that everything has been written to disk
sync
sync
# Unmount, your stick is ready now
umount "${SOURCE}"
umount "${TARGET}"
rm -rf "${TEMP_DIR}"
rm -rf "${MOUNT_TEMP_DIR}"
echo "DONE"
exit
}
set -o errexit
set -o errtrace
set -o nounset
set -o pipefail
# Show all devices, not just removable ones
declare -i show_all_devices=0
if [ "$#" -ge 1 ] \
&& [ "$1" = 'all' ]; then
show_all_devices=1
fi
is_removable_and_writable_device(){
local block_device_name="$1"
local -r sysfs_block_device_dir="/sys/block/${block_device_name}"
# We consider device not removable if the removable sysfs item not exist
if [ -f "${sysfs_block_device_dir}/removable" ] \
&& [ "$(cat "${sysfs_block_device_dir}/removable")" -eq 1 ]\
&& [ "$(cat "${sysfs_block_device_dir}/ro")" -eq 0 ]; then
return 0
else
return 1
fi
}
declare block_device
declare device_capacity
declare device_model
while read block_device_name; do
if grep --extended-regexp "^sr.*$|^cdrom.*$" <<< "${block_device_name}" >/dev/null; then
# Known non-target blacklist
continue
# NOTE: We might not need this check at all as loop devices also has removable sysfs entry
# elif grep '^loop.*$' <<< "${block_device_name}" >/dev/null; then
# if [ "${show_all_devices}" -eq 0 ]; then
# continue
# fi
elif ! is_removable_and_writable_device "${block_device_name}"; then
if [ "${show_all_devices}" -eq 0 ]; then
continue
fi
fi
# FIXME: Needs a more reliable detection mechanism instead of simply assuming it is under /dev
block_device="/dev/${block_device_name}"
device_capacity="$(\
lsblk\
--output SIZE\
--noheadings\
--nodeps\
"${block_device}"\
)"
device_model="$(\
lsblk\
--output MODEL\
--noheadings\
--nodeps\
"${block_device}"\
| sed 's/\s//g'
)"
# It's possible that the device has no model(e.g. loop device)
# Push USB device to USB_DEVICES
if [ -n "${device_model}" ]; then
USB_DEVICES+=( "${block_device} (${device_model}, $device_capacity)" )
else
USB_DEVICES+=( "${block_device} ($device_capacity)" )
fi
done < <(lsblk --output NAME --noheadings --nodeps)
echo "Target device:"
select device in "${USB_DEVICES[@]}" "Exit"; do
case $device in
/dev/*)
echo "$device selected"
createUsbInstaller $device
;;
"Exit")
break
;;
*)
echo "Invalid option $REPLY"
;;
esac
done
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment