Skip to content

Instantly share code, notes, and snippets.

@oyi77
Last active August 9, 2025 11:30
Show Gist options
  • Select an option

  • Save oyi77/b67179998bf8e4c0cae3d464293afa16 to your computer and use it in GitHub Desktop.

Select an option

Save oyi77/b67179998bf8e4c0cae3d464293afa16 to your computer and use it in GitHub Desktop.
How to make Windows Bootable from Mac OS!

Create a Bootable Windows USB on macOS (Full Guide)

This guide shows how to use jaran.sh to prepare a USB installer for Windows on macOS. It covers prerequisites, safety checks, how the script works, customization, and troubleshooting.

Why use this script?

Creating a Windows USB on macOS often fails when install.wim exceeds 4 GB, because FAT32 doesn’t support files that large. This script automatically splits the WIM into .swm parts using wimlib-imagex, while handling modern macOS quirks (read-only FAT32 mounts, Homebrew install, etc.).

Prerequisites

  • macOS (Intel or Apple Silicon)
  • Windows ISO image (Win10/Win11 recommended)
  • USB drive (8 GB+; will be erased)
  • Admin rights for disk operations

Get the code

git clone https://github.com/YOUR_USER/ai-job-apply.git
cd ai-job-apply
chmod +x jaran.sh

Run the script

sudo ./jaran.sh

You will be prompted to:

  1. Provide the path to your ISO if the default is wrong
  2. Choose the target USB disk (e.g., disk2)
  3. Confirm the destructive erase step

The script will:

  • Unmount and erase the USB as FAT32 (GPT by default)
  • Mount the ISO
  • Copy files with rsync (excluding install.wim initially)
  • If install.wim ≥ 4 GB, install wimlib if needed and split it to install.swm
  • Otherwise, copy install.wim directly
  • Detach the ISO and eject the USB

Customize defaults

Open jaran.sh and adjust the header variables:

ISO_PATH="$HOME/Downloads/win7.iso"   # path to your ISO
USB_NAME="WINUSB"                      # volume label for the USB
WIM_SPLIT_CHUNK_MB=3800                 # `.swm` part size (MB)
USE_GPT=true                            # false for MBR

Notes:

  • Use USE_GPT=false if you need legacy BIOS/MBR boot. UEFI systems typically work best with GPT.
  • Split size between 3000 and 4000 MB works well for FAT32.

Safety checklist

  • Double-check the selected disk in diskutil list before confirming; the erase is destructive.
  • Close Finder windows that might auto-mount/eject the USB while the script runs.
  • Use a reliable USB 3.0 or better drive to avoid copy errors.

Troubleshooting

Symptom: rsync fails due to read-only FAT32

  • What happens: On newer macOS (Sonoma+), FAT32 sometimes mounts read-only.
  • Fix: The script attempts a writable remount using diskutil and mount -w -t msdos. If this still fails, try unplugging/re-plugging the USB and rerun.

Symptom: wimlib-imagex not found

  • Fix: The script offers to install Homebrew if missing, then installs wimlib.
  • Manual install: brew install wimlib

Symptom: No sources/install.wim in ISO

  • Fix: Use a Microsoft/official-style ISO. Some customized ISOs omit install.wim.

Symptom: Target PC won’t boot USB

  • For UEFI PCs: Ensure GPT partitioning (USE_GPT=true).
  • For legacy BIOS PCs: Try USE_GPT=false to use MBR.
  • Use the system’s boot menu key (often F12, F8, Esc, or Del) to select the USB.

Symptom: Very slow copy

  • Use a USB 3 port and a fast USB drive.
  • Avoid copying through USB hubs.

Verifying the USB

After completion, the USB should contain a sources folder and either install.wim or install.swm parts. You can spot-check with:

ls -lah /Volumes/WINUSB/sources

One-liner usage (from a Gist)

If you publish jaran.sh as a Gist, you can run it directly:

bash <(curl -fsSL https://gist.githubusercontent.com/oyi77/b67179998bf8e4c0cae3d464293afa16/raw/jaran.sh)

Credits

  • Based on community recipes for preparing Windows USB installers on macOS
  • Automations adapted for modern macOS and wimlib-imagex
#!/usr/bin/env bash
set -euo pipefail
IFS=$'\n\t'
# create_win_usb.sh
# Usage:
# sudo ./create_win_usb.sh
#
# This script automates the process of creating a bootable Windows USB on macOS,
# following the approach from: https://gist.github.com/acarril/8c15f600cf0397dd61161a470f50f669
# It formats the USB (FAT32), copies ISO contents, and if install.wim >4GB it splits
# the WIM using wimlib-imagex into install.swm parts so the FAT32 filesystem accepts them.
# Requires: rsync, hdiutil (macOS), diskutil, (brew -> wimlib-imagex when needed)
# --- CONFIGURATION (edit if you prefer non-interactive use) ---
ISO_PATH="${HOME}/Downloads/win7.iso" # default path — change before running if needed
USB_NAME="WINUSB" # volume name that will be used on the USB stick
WIM_SPLIT_CHUNK_MB=3800 # chunk size for wimlib-imagex split (MB)
USE_GPT=true # set false to use MBR; GPT usually better for modern UEFI
# ---------------------------------------------------------------
# helper prints
die() { echo "ERROR: $*"; exit 1; }
info() { echo "INFO: $*"; }
# Check presence of ISO
if [[ ! -f "$ISO_PATH" ]]; then
echo "ISO not found at: $ISO_PATH"
read -rp "Enter full path to Windows ISO (or ENTER to abort): " alt_iso
[[ -z "$alt_iso" ]] && die "No ISO provided — aborting."
ISO_PATH="$alt_iso"
[[ -f "$ISO_PATH" ]] || die "File still not found: $ISO_PATH"
fi
# Show disks and ask user for USB disk identifier (e.g., disk2)
info "Available disks:"
diskutil list
echo
read -rp "Enter the disk identifier for your USB (example 'disk2') — ALL DATA WILL BE ERASED: " DISKID
[[ -n "$DISKID" ]] || die "No disk identifier provided."
# Confirm
read -rp "Confirm: Erase /dev/$DISKID and create bootable Windows USB? (y/N): " CONF
[[ "$CONF" =~ ^[Yy] ]] || die "Aborted by user."
# Unmount and erase disk
info "Unmounting and erasing /dev/$DISKID..."
diskutil unmountDisk /dev/"$DISKID" || true
if $USE_GPT; then
diskutil eraseDisk MS-DOS "$USB_NAME" GPT /dev/"$DISKID"
else
diskutil eraseDisk MS-DOS "$USB_NAME" MBR /dev/"$DISKID"
fi
# Mount the ISO
info "Mounting ISO: $ISO_PATH"
hdiutil attach "$ISO_PATH" -nobrowse -readonly > /tmp/hdiutil_attach_out.txt || die "Failed to mount ISO."
# Find the mounted ISO volume that contains "sources/install.wim"
ISO_VOLUME=""
while read -r v; do
if [[ -d "/Volumes/$v/sources" && -f "/Volumes/$v/sources/install.wim" ]]; then
ISO_VOLUME="$v"
break
fi
done < <(ls /Volumes)
[[ -n "$ISO_VOLUME" ]] || {
# try alternate patterns (some ISOs mount with CPBA... or names without 'install.wim' initially)
ISO_VOLUME=$(find /Volumes -maxdepth 1 -mindepth 1 -type d -exec bash -c 'test -d "$0/sources" && test -e "$0/sources/install.wim" && basename "$0"' {} \; || true)
}
[[ -n "$ISO_VOLUME" ]] || die "Could not find mounted ISO volume with sources/install.wim. Check the ISO."
info "Mounted ISO volume found: /Volumes/$ISO_VOLUME"
# size of install.wim (if present)
INSTALL_WIM_PATH="/Volumes/$ISO_VOLUME/sources/install.wim"
WIM_SIZE_BYTES=0
if [[ -f "$INSTALL_WIM_PATH" ]]; then
WIM_SIZE_BYTES=$(stat -f%z "$INSTALL_WIM_PATH" 2>/dev/null || stat -c%s "$INSTALL_WIM_PATH" 2>/dev/null || echo 0)
info "install.wim size: $WIM_SIZE_BYTES bytes"
fi
# Copy files excluding install.wim first
info "Copying files from ISO to USB (excluding install.wim if present)..."
RSYNC_CMD=(rsync -avh --progress)
if [[ -f "$INSTALL_WIM_PATH" ]]; then
RSYNC_CMD+=(--exclude=sources/install.wim)
fi
RSYNC_CMD+=("/Volumes/$ISO_VOLUME/" "/Volumes/$USB_NAME/")
"${RSYNC_CMD[@]}" || {
# On some macOS versions FAT32 mount may be read-only. Try remounting writable.
echo
echo "rsync failed. Attempting writable mount workaround (macOS FAT32 read-only on Sonoma+)."
echo "You may be prompted for your password."
sudo diskutil unmount /Volumes/"$USB_NAME" || true
sudo mkdir -p /Volumes/"$USB_NAME"
# Try to find partition node (e.g., disk2s1)
PART_NODE=$(diskutil list | awk -v id="$DISKID" '/'"$DISKID"'/ {p=1} p && /Microsoft Basic Data|DOS_FAT_32/ {print $NF; exit}')
if [[ -z "$PART_NODE" ]]; then
# fallback: assume ${DISKID}s1
PART_NODE="${DISKID}s1"
fi
sudo mount -w -t msdos /dev/"$PART_NODE" /Volumes/"$USB_NAME" || die "Writable mount failed; rsync cannot proceed."
rsync -avh --progress --exclude=sources/install.wim "/Volumes/$ISO_VOLUME/" "/Volumes/$USB_NAME/" || die "rsync failed again."
}
# If install.wim exists and >4GB, split with wimlib-imagex and move parts
FOUR_GB=$((4 * 1024 * 1024 * 1024))
if [[ -f "$INSTALL_WIM_PATH" && "$WIM_SIZE_BYTES" -ge $FOUR_GB ]]; then
info "install.wim is >= 4GB. Will split using wimlib-imagex."
if ! command -v wimlib-imagex >/dev/null 2>&1; then
echo "wimlib-imagex not found. Attempting to install via Homebrew."
if ! command -v brew >/dev/null 2>&1; then
echo "Homebrew not found. Installing Homebrew (you may be prompted)."
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
# ensure brew in PATH for non-interactive shells
eval "$(/opt/homebrew/bin/brew shellenv 2>/dev/null || /usr/local/bin/brew shellenv 2>/dev/null || true)"
fi
brew install wimlib || die "Failed to install wimlib. Please install it manually and re-run."
fi
# ensure target sources dir exists
mkdir -p "/Volumes/$USB_NAME/sources"
info "Splitting install.wim into ${WIM_SPLIT_CHUNK_MB}MB parts..."
wimlib-imagex split "$INSTALL_WIM_PATH" "/Volumes/$USB_NAME/sources/install.swm" "${WIM_SPLIT_CHUNK_MB}" || die "wimlib split failed."
info "Split complete."
elif [[ -f "$INSTALL_WIM_PATH" ]]; then
info "install.wim is <4GB. Copying as-is."
cp "$INSTALL_WIM_PATH" "/Volumes/$USB_NAME/sources/install.wim" || die "Failed copying install.wim"
fi
# Unmount ISO and eject USB
info "Unmounting ISO (/Volumes/$ISO_VOLUME) and ejecting USB..."
hdiutil detach "/Volumes/$ISO_VOLUME" || true
diskutil eject /dev/"$DISKID" || true
info "Done. Bootable Windows USB should be ready."
info "If target machine uses UEFI, boot from the USB (often via Boot Menu F12/Option). For Apple Silicon (M1/M2/M3) Macs, native booting Windows is not supported — consider Parallels or other virtualization."
exit 0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment