3 # This script can make a customized bootable image of Windows PE.
6 # Copyright (C) 2012 Eric Biggers
8 # This program is free software: you can redistribute it and/or modify
9 # it under the terms of the GNU General Public License as published by
10 # the Free Software Foundation, either version 3 of the License, or
11 # (at your option) any later version.
13 # This program is distributed in the hope that it will be useful,
14 # but WITHOUT ANY WARRANTY; without even the implied warranty of
15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 # GNU General Public License for more details.
18 # You should have received a copy of the GNU General Public License
19 # along with this program. If not, see <http://www.gnu.org/licenses/>.
21 script_name="$(basename $0)"
28 # stty will fail when stdin isn't a terminal
30 # stty gives "rows cols"; strip the rows number, we just want columns
31 STAT_COL=${STAT_COL##* }
32 elif tput cols &>/dev/null; then
33 # is /usr/share/terminfo already mounted, and TERM recognized?
36 if (( STAT_COL == 0 )); then
37 # if output was 0 (serial console), set default width to 80
41 # we use 13 characters for our own stuff
42 STAT_COL=$(( STAT_COL - 13 ))
46 RESTORE_POSITION="\e[u"
47 DEL_TEXT="\e[$(( STAT_COL + 4 ))G"
61 printf "${PREFIX_REG} ${1} "
62 printf "${SAVE_POSITION}"
80 if mountpoint -q "$mnt_dir" ; then
81 imagex unmount "$mnt_dir"
88 Usage: $script_name [OPTIONS] IMAGE
90 -i, --iso Make an ISO image instead of a disk image.
91 -o, --only-wim Make neither a disk image nor an ISO image;
92 instead, only make a modified boot.wim file.
93 -W, --windows-dir=DIR Use DIR as the location of the mounted Windows 7
94 or Windows 8 DVD. Default is /mnt/windows,
95 then /mnt/windows7, then /mnt/windows8.
96 -A, --waik-dir=DIR Get the boot files and boot.wim from the ISO of the
97 Windows Automated Installation Kit mounted on DIR
98 instead of from the Windows 7 or Windows 8 DVD.
99 -s, --start-script=FILE Add FILE to the root directory of Windows PE image
100 and adjust \Windows\System32\winpeshl.ini to
101 execute FILE when Windows PE starts up.
102 -w, --wim=WIM Use WIM as the boot.wim file. Defaults to
103 sources/boot.wim in the Windows DVD directory, or
104 F1_WINPE.WIM from the WAIK if --waik-dir is
106 -O, --overlay=DIR Adds all the files in DIR to the Windows PE image.
107 -t, --tmp-dir=DIR Use DIR as the temporary base of the ISO filesystem.
108 Defaults to making one using "mktemp -d".
109 -a, --arch=ARCH Use the Windows PE version from the WAIK that has
110 the CPU architecture ARCH. Possible values:
111 "x86", "amd64", or "ia64". Default is "x86".
112 -h, --help Display this information.
113 -v, --version Show version information.
115 See \`man mkwinpeimg' for more information.
120 echo "$script_name (wimlib $WIMLIB_VERSION)"
126 process_command_line() {
128 if ! options=$(getopt -o oiw:W:s:O:t:A:a:hv -l \
129 only-wim,iso,wim:,windows-dir:,start-script:,overlay:,tmp-dir:,waik-dir:,arch:,help,version \
139 eval set -- "$options"
140 while [ $# -gt 0 ]; do
150 windows_dir_specified=yes
151 if [ -n "$waik_dir" ]; then
152 echo "ERROR: Cannot specify both --windows-dir and --waik-dir!"
159 if [ -n "$windows_dir" ]; then
160 echo "ERROR: Cannot specify both --windows-dir and --waik-dir!"
183 if [ "$2" == "x86" ]; then
186 elif [ "$2" == "ia64" ]; then
189 elif [ "$2" == "amd64" ]; then
193 echo "ERROR: $2 is not a valid arch (x86/amd64/ia64)"
210 echo "Invalid option \"$1\""
218 if [ $# -ne 1 ]; then
219 echo "You must specify the name of the image file to create!"
220 echo "Run \"$script_name -h\" to see usage information."
228 if [ -z "$windows_dir_specified" ]; then
229 for windows_dir in /mnt/windows /mnt/windows7 /mnt/windows8; do
230 if [ -d "$windows_dir"/sources ]; then
235 if [ ! -d "$windows_dir" ]; then
236 if [ -z "$windows_dir_specified" ]; then
238 ERROR: Could not find the directory that the Windows 7 or 8 ISO image is mounted
239 on! Please specify this directory using the --windows-dir option.
242 echo "ERROR: Could not find the directory \"$windows_dir\"!"
246 if [ ! -d "$windows_dir/sources" ]; then
248 ERROR: The directory "$windows_dir" exists, but it seems that the Windows 7 or 8
249 ISO image is not mounted on it. Please mount the image to continue.
255 check_needed_programs() {
256 if [ -z "$waik_dir" -o -n "$modify_wim" ]; then
257 if ! type -P imagex &> /dev/null ; then
259 ERROR: To make a customized image of Windows PE, we need the "imagex" program
260 from WIMLIB so that we can modify the boot.wim file. However, "imagex"
261 doesn't seem to be installed. Please install WIMLIB to continue.
267 if [ $make = iso ]; then
268 if ! type -P mkisofs &> /dev/null ; then
270 ERROR: To make a bootable ISO image of Windows PE, we need the "mkisofs"
271 program, but it doesn't seem to be installed. Please install the "cdrkit"
272 package to continue, or try omitting the --iso option to make a disk image
273 instead of an ISO image.
277 elif [ $make = disk ] ; then
278 if ! type -P syslinux &> /dev/null ; then
280 ERROR: To make a bootable disk image of Windows PE, we need the "syslinux"
281 program, but it doesn't seem to be installed. Please install the "syslinux"
282 package to continue, or try using the --iso option to make an ISO image instead
288 if ! type -P mformat mcopy &> /dev/null; then
290 ERROR: To make a bootable disk image of Windows PE, we need the "mformat" and
291 "mcopy" programs from the "mtools" package. These programs allow us to
292 format a FAT filesystem and copy files to it without needing root privileges.
293 Please install "mtools" if you want to make a disk image of Windows PE. Or,
294 try using the --iso option to make an ISO image instead of a disk image.
299 if [ -n "$waik_dir" ]; then
300 if ! type -P cabextract &> /dev/null ; then
302 ERROR: The boot files in the Windows Automated Installation Kit (WAIK) are
303 inside cabinet archives. To extract these files, we need the "cabextract"
304 program, but it doesn't seem to be installed. Please install "cabextract" to
313 get_primary_boot_files() {
314 if [ -n "$waik_dir" ]; then
315 # Get boot files from the WAIK.
317 stat_busy "Copying primary boot files from the Windows Automated Installation Kit ($waik_dir, $arch)"
318 if [ $make = iso ]; then
319 cabextract "$waik_dir"/wAIK${arch}.msi -F F_WINPE_${arch}_etfsboot.com -p \
320 > "$tmp_dir"/etfsboot.com || stat_fail
322 cabextract "$waik_dir"/wAIK${arch}.msi -F F${arch_id}_BOOTMGR -p \
323 > "$tmp_dir"/bootmgr || stat_fail
324 cabextract "$waik_dir"/wAIK${arch}.msi -F F_WINPE_${arch}_boot.sdi -p \
325 > "$tmp_dir"/boot/boot.sdi || stat_fail
326 cabextract "$waik_dir"/wAIK${arch}.msi -F F_WINPE_${arch}_bcd -p \
327 > "$tmp_dir"/boot/bcd || stat_fail
330 # Get boot files from the Windows ISO
332 stat_busy "Copying primary boot files from mounted Windows DVD ($windows_dir)"
333 if [ $make = iso ]; then
334 cp "$windows_dir"/boot/etfsboot.com "$tmp_dir" || stat_fail
336 cp "$windows_dir"/bootmgr "$tmp_dir" || stat_fail
337 cp "$windows_dir"/boot/{bcd,boot.sdi} "$tmp_dir"/boot || stat_fail
344 # Copy the WIM over, or export the 2nd image in the WIM in the case of boot.wim
345 # from the Windows DVD.
347 if [ -z "$wim" ]; then
349 # WIM file unspecified- grab it from the WAIK or the Windows DVD
350 if [ -n "$waik_dir" ]; then
352 stat_busy "Extracting boot.wim from \"$waik_dir/WinPE.cab\""
353 cabextract "$waik_dir/WinPE.cab" -F F${arch_id}_WINPE.WIM -p \
354 > "$boot_wim" 2>/dev/null || stat_fail
359 wim="$windows_dir/sources/boot.wim"
360 stat_busy "Exporting image from \"$wim\""
361 imagex export "$windows_dir"/sources/boot.wim 2 \
362 --boot "$boot_wim" || stat_fail
367 stat_busy "Copying $wim to temporary directory"
368 cp "$wim" "$boot_wim"|| stat_fail
377 # Make modifications to the WIM.
378 stat_busy "Mounting "$1" read-write"
380 mkdir -p "$mnt_dir" || stat_fail
381 imagex mountrw "$boot_wim" "$mnt_dir"|| stat_fail
385 if [ -n "$remove_setup" ]; then
386 stat_busy "Renaming setup.exe to prevent it from bothering us"
387 mv "$mnt_dir"/setup.exe{,.bkup} || stat_fail
388 mv "$mnt_dir"/sources/setup.exe{,.bkup} || stat_fail
392 if [ -n "$start_script" ]; then
393 stat_busy "Setting \"$start_script\" as the script to be executed"\
394 "when Windows PE boots"
395 cp "$start_script" "$mnt_dir"|| stat_fail
396 cat > "$mnt_dir/Windows/System32/winpeshl.ini" << EOF
398 %SYSTEMDRIVE%\\$start_script
403 if [ -n "$overlay" ]; then
404 stat_busy "Overlaying \"$overlay\" on the Windows PE filesystem"
405 cp -r "$overlay"/* "$mnt_dir" || stat_fail
409 stat_busy "Rebuilding WIM with changes made"
410 imagex unmount --commit "$mnt_dir" || stat_fail
419 # Make the ISO using the mkisofs command from cdrkit
421 stat_busy "Making ISO image \"$image\""
423 mkisofs -sysid "" -A "" -V "Microsoft Windows PE (x86)" -d -N \
424 -b etfsboot.com -no-emul-boot -c boot.cat -hide etfsboot.com \
425 -hide boot.cat -quiet -o "$image" "$tmp_dir" || stat_fail
433 stat_busy "Making disk image \"$image\""
435 image_du=$(du -s -b "$tmp_dir" | cut -f 1)
436 image_size=$(( image_du + 10000000 ))
438 mtool_conf="$(mktemp)"
440 dd if=/dev/zero of="$image" count=$(( (image_size + 4095) / 4096)) \
443 cat > "$mtool_conf" << EOF
445 MTOOLS_FAT_COMPATIBILITY=1
450 export MTOOLSRC="$mtool_conf"
452 mformat -h 255 -s 63 -T $(( image_size / 512)) s:
453 mcopy -s "$tmp_dir"/* s:
455 syslinux --install "$image"
456 mcopy /usr/lib/syslinux/chain.c32 s:
457 mcopy - 's:syslinux.cfg' << EOF
461 APPEND ntldr=/bootmgr
468 tmp_dir="$(mktemp -d)"
469 mnt_dir="$tmp_dir"/.boot.wim.mount
470 process_command_line "$@"
471 if [ -z "$waik_dir" ]; then
474 if [ -n "$start_script" -o -n "$overlay" -o -n "$remove_setup" ]; then
477 check_needed_programs
480 if [ $make != wim ]; then
481 mkdir -p "$tmp_dir"/{boot,sources}
482 get_primary_boot_files
485 if [ $make = wim ]; then
488 boot_wim="$tmp_dir"/sources/boot.wim
491 get_boot_wim "$boot_wim"
493 if [ -n "$modify_wim" ]; then
494 modify_boot_wim "$boot_wim" "$mnt_dir"
497 if [ $make = iso ]; then
498 make_iso_img "$image"
499 elif [ $make = disk ]; then
500 make_disk_img "$image"
503 echo "The image ($image) is $(stat -c %s "$image") bytes."