Skip to content

Instantly share code, notes, and snippets.

@bodja
Created June 5, 2026 17:12
Show Gist options
  • Select an option

  • Save bodja/95f00a1d79e0fa1480e734a9b5726c8b to your computer and use it in GitHub Desktop.

Select an option

Save bodja/95f00a1d79e0fa1480e734a9b5726c8b to your computer and use it in GitHub Desktop.
Windows iso to USB
#!/usr/bin/env bash
set -euo pipefail
# Usage:
# ./makewin11.sh list external disks, then exit
# ./makewin11.sh <disk> <iso> build the USB
# <disk> e.g. /dev/disk4 (see the list above)
# <iso> path to the Windows 11 ISO
list_disks() {
echo "External / removable disks:"
echo
# Show only external, physical disks with their size and identifier
diskutil list external physical 2>/dev/null || diskutil list
echo
echo "Pick the whole-disk identifier (e.g. /dev/disk4) that matches your USB by SIZE."
echo "Then run: $0 /dev/diskN /path/to/Win11.iso"
}
# No args (or explicit list flag): show disks and exit
if [ "$#" -eq 0 ] || [ "${1:-}" = "list" ] || [ "${1:-}" = "-l" ]; then
list_disks
exit 0
fi
if [ "$#" -ne 2 ]; then
echo "Usage: $0 <disk> <iso> (run with no args to list disks)" >&2
exit 1
fi
DISK="$1"
ISO="$2"
# Validate the disk: must exist AND be external (guards against wiping an internal drive)
if [ ! -e "$DISK" ]; then
echo "Error: disk '$DISK' not found. Run '$0' with no args to list disks." >&2
exit 1
fi
if ! diskutil info "$DISK" 2>/dev/null | grep -qiE 'Device Location: *External|Internal: *No'; then
echo "Error: '$DISK' does not look like an external disk. Refusing to continue." >&2
echo "Run '$0' with no args to see external disks." >&2
exit 1
fi
if [ ! -f "$ISO" ]; then
echo "Error: ISO '$ISO' not found." >&2
exit 1
fi
# Final confirmation before destroying data
echo "About to ERASE this disk:"
diskutil info "$DISK" | grep -iE 'Device Identifier|Media Name|Disk Size'
echo
read -r -p "Type ERASE to continue: " confirm
[ "$confirm" = "ERASE" ] || { echo "Aborted."; exit 1; }
TMP="$HOME/wim_temp"
USB="/Volumes/WINUSB"
# 1. Wipe + format FAT32 / MBR
diskutil unmountDisk force "$DISK" 2>/dev/null || true
diskutil eraseDisk MS-DOS "WINUSB" MBR "$DISK"
# 2. Mount ISO, capture mount point
MNT=$(hdiutil attach "$ISO" -nobrowse | grep -o '/Volumes/.*' | head -1)
echo "ISO mounted at: $MNT"
# 3. Copy everything except oversized install.wim
rsync -avh --progress --exclude=sources/install.wim "$MNT/" "$USB/"
# 4. Split install.wim on internal SSD first
rm -rf "$TMP"; mkdir -p "$TMP"
wimlib-imagex split "$MNT/sources/install.wim" "$TMP/install.swm" 3800
# 5. Copy split pieces onto the stick
rsync -avh --progress "$TMP"/install*.swm "$USB/sources/"
# 6. Verify: no file over 4GB (should print nothing)
echo "-- files over 4GB (should be empty): --"
find "$USB" \( -name .Spotlight-V100 -o -name .fseventsd \) -prune -o -type f -size +4000000k -print 2>/dev/null
# 7. Verify boot file present
ls -la "$USB/efi/boot/bootx64.efi"
# 8. Cleanup + eject
hdiutil detach "$MNT"
rm -rf "$TMP"
diskutil eject "$DISK"
echo "Done."
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment