3 # This script can make a customized bootable image of Windows PE.
6 # Copyright (C) 2012, 2013 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")"
23 WIMLIB_VERSION=@VERSION@
24 imagex=@IMAGEX_PROGNAME@
29 # stty will fail when stdin isn't a terminal
31 # stty gives "rows cols"; strip the rows number, we just want columns
32 STAT_COL=${STAT_COL##* }
33 elif tput cols &>/dev/null; then
34 # is /usr/share/terminfo already mounted, and TERM recognized?
37 if (( STAT_COL == 0 )); then
38 # if output was 0 (serial console), set default width to 80
42 # we use 13 characters for our own stuff
43 STAT_COL=$(( STAT_COL - 13 ))
47 RESTORE_POSITION="\e[u"
48 DEL_TEXT="\e[$(( STAT_COL + 4 ))G"
62 printf "${PREFIX_REG} ${1} "
63 printf "${SAVE_POSITION}"
86 Usage: $script_name [OPTIONS] IMAGE
88 -i, --iso Make an ISO image instead of a disk image.
89 -o, --only-wim Make neither a disk image nor an ISO image;
90 instead, only make a modified boot.wim file.
91 -W, --windows-dir=DIR Use DIR as the location of the mounted Windows 7
92 or Windows 8 DVD. Default is /mnt/windows,
93 then /mnt/windows7, then /mnt/windows8.
94 -A, --waik-dir=DIR Get the boot files and boot.wim from the ISO of the
95 Windows Automated Installation Kit mounted on DIR
96 instead of from the Windows 7 or Windows 8 DVD.
97 This also works if the mounted ISO is for the
98 WAIK supplement rather than the WAIK itself.
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. This defaults to the
103 appropriate WIM file from the Windows DVD, WAIK,
105 -O, --overlay=DIR Adds all the files in DIR to the Windows PE image.
106 -t, --tmp-dir=DIR Use DIR as the temporary base of the ISO filesystem.
107 Defaults to making one using "mktemp -d".
108 -a, --arch=ARCH Use the Windows PE version from the WAIK that has
109 the CPU architecture ARCH. Possible values:
110 "x86" or "amd64". Default is "x86".
111 -h, --help Display this information.
112 -v, --version Show version information.
114 See \`man mkwinpeimg' for more information.
119 echo "$script_name (wimlib $WIMLIB_VERSION)"
125 process_command_line() {
127 if ! options=$(getopt -o oiw:W:s:O:t:A:a:hv -l \
128 only-wim,iso,wim:,windows-dir:,start-script:,overlay:,tmp-dir:,waik-dir:,arch:,help,version \
138 eval set -- "$options"
139 while [ $# -gt 0 ]; do
149 windows_dir_specified=yes
150 if [ -n "$waik_dir" ]; then
151 echo "ERROR: Cannot specify both --windows-dir and --waik-dir!"
158 if [ -n "$windows_dir" ]; then
159 echo "ERROR: Cannot specify both --windows-dir and --waik-dir!"
182 if [ "$2" == "x86" ]; then
185 # Need to test Itanium images before making it an
186 # option. Note: syslinux is x86 only so can't be used
187 # for the Itanium disk image.
188 #elif [ "$2" == "ia64" ]; then
191 elif [ "$2" == "amd64" ]; then
195 echo "ERROR: $2 is not a valid arch (x86/amd64)"
212 echo "Invalid option \"$1\""
220 if [ $# -ne 1 ]; then
221 echo "You must specify the name of the image file to create!"
222 echo "Run \"$script_name -h\" to see usage information."
230 if [ -z "$windows_dir_specified" ]; then
231 for windows_dir in /mnt/windows /mnt/windows7 /mnt/windows8; do
232 if [ -d "$windows_dir"/sources ]; then
237 if [ ! -d "$windows_dir" ]; then
238 if [ -z "$windows_dir_specified" ]; then
240 ERROR: Could not find the directory that the Windows 7 or 8 ISO image is mounted
241 on! Please specify this directory using the --windows-dir option.
244 echo "ERROR: Could not find the directory \"$windows_dir\"!"
248 if [ ! -d "$windows_dir/sources" ]; then
250 ERROR: The directory "$windows_dir" exists, but it seems that the Windows 7 or 8
251 ISO image is not mounted on it. Please mount the image to continue.
257 check_needed_programs() {
258 if [ -z "$waik_dir" -o -n "$modify_wim" ]; then
259 if ! type -P @IMAGEX_PROGNAME@ &> /dev/null ; then
261 ERROR: To make a customized image of Windows PE, we need the "$imagex" program
262 from "wimlib" so that we can modify the boot.wim file. However, "$imagex"
263 doesn't seem to be installed. Please install "wimlib" to continue.
269 if [ $make = iso ]; then
270 if ! type -P mkisofs &> /dev/null ; then
272 ERROR: To make a bootable ISO image of Windows PE, we need the "mkisofs"
273 program, but it doesn't seem to be installed. Please install the "cdrkit"
274 package to continue, or try omitting the --iso option to make a disk image
275 instead of an ISO image.
279 elif [ $make = disk ] ; then
280 if ! type -P syslinux &> /dev/null ; then
282 ERROR: To make a bootable disk image of Windows PE, we need the "syslinux"
283 program, but it doesn't seem to be installed. Please install the "syslinux"
284 package to continue, or try using the --iso option to make an ISO image instead
290 if ! type -P mformat mcopy &> /dev/null; then
292 ERROR: To make a bootable disk image of Windows PE, we need the "mformat" and
293 "mcopy" programs from the "mtools" package. These programs allow us to
294 format a FAT filesystem and copy files to it without needing root privileges.
295 Please install "mtools" if you want to make a disk image of Windows PE. Or,
296 try using the --iso option to make an ISO image instead of a disk image.
301 if [ -n "$waik_dir" ] && [ -f "$waik_dir"/wAIK${arch}.msi ]; then
302 if ! type -P cabextract &> /dev/null ; then
304 ERROR: The boot files in the Windows Automated Installation Kit (WAIK) are
305 inside cabinet archives. To extract these files, we need the "cabextract"
306 program, but it doesn't seem to be installed. Please install "cabextract" to
315 get_primary_boot_files() {
316 if [ -n "$waik_dir" ]; then
317 # Get boot files from the WAIK.
318 stat_busy "Copying primary boot files from the Windows Automated Installation Kit ($waik_dir, $arch)"
320 if [ -f "$waik_dir"/wAIK${arch}.msi ]; then
321 if [ $make = iso ]; then
322 cabextract "$waik_dir"/wAIK${arch}.msi -F F_WINPE_${arch}_etfsboot.com -p \
323 > "$tmp_dir"/etfsboot.com || stat_fail
325 cabextract "$waik_dir"/wAIK${arch}.msi -F F${arch_id}_BOOTMGR -p \
326 > "$tmp_dir"/bootmgr || stat_fail
327 cabextract "$waik_dir"/wAIK${arch}.msi -F F_WINPE_${arch}_boot.sdi -p \
328 > "$tmp_dir"/boot/boot.sdi || stat_fail
329 cabextract "$waik_dir"/wAIK${arch}.msi -F F_WINPE_${arch}_bcd -p \
330 > "$tmp_dir"/boot/bcd || stat_fail
331 # The WAIK supplement disc has a different structure
333 # Note: fuseiso, mount default to map=normal i.e. lowercase
334 if [ $make = iso ]; then
335 cp "$waik_dir"/${arch,,}/boot/etfsboot.com $tmp_dir/etfsboot.com || stat_fail
337 cp "$waik_dir"/${arch,,}/bootmgr $tmp_dir/bootmgr || stat_fail
338 cp "$waik_dir"/${arch,,}/boot/boot.sdi $tmp_dir/boot/boot.sdi || stat_fail
339 cp "$waik_dir"/${arch,,}/boot/bcd $tmp_dir/boot/bcd || stat_fail
343 # Get boot files from the Windows ISO
345 stat_busy "Copying primary boot files from mounted Windows DVD ($windows_dir)"
346 if [ $make = iso ]; then
347 cp "$windows_dir"/boot/etfsboot.com "$tmp_dir" || stat_fail
349 cp "$windows_dir"/bootmgr "$tmp_dir" || stat_fail
350 cp "$windows_dir"/boot/{bcd,boot.sdi} "$tmp_dir"/boot || stat_fail
357 # Copy the WIM over, or export the 2nd image in the WIM in the case of boot.wim
358 # from the Windows DVD.
360 if [ -z "$wim" ]; then
362 # WIM file unspecified- grab it from the WAIK or the Windows DVD
363 if [ -n "$waik_dir" ]; then
365 if [ -f "$waik_dir/WinPE.cab" ]; then
366 stat_busy "Extracting boot.wim from \"$waik_dir/WinPE.cab\""
367 cabextract "$waik_dir/WinPE.cab" -F F${arch_id}_WINPE.WIM -p \
368 > "$boot_wim" 2>/dev/null || stat_fail
369 # WAIK supplement has different layout
371 stat_busy "Copying boot.wim from \"${waik_dir}/${arch,,}/winpe.wim\""
372 cp "$waik_dir"/${arch,,}/winpe.wim "$boot_wim" || stat_fail
379 wim="$windows_dir/sources/boot.wim"
380 stat_busy "Exporting image from \"$wim\""
381 "$imagex" export "$windows_dir"/sources/boot.wim 2 \
382 --boot "$boot_wim" || stat_fail
387 stat_busy "Copying $wim to temporary directory"
388 cp "$wim" "$boot_wim"|| stat_fail
393 # Make modifications to the WIM.
398 exec 3>"$tmp_dir/__mkwinpeimg.update.cmds"
400 if [ -n "$remove_setup" ]; then
401 stat_busy "Renaming setup.exe to prevent it from bothering us"
403 rename /setup.exe /setup.exe.orig
404 rename /sources/setup.exe /sources/setup.exe.orig
409 if [ -n "$start_script" ]; then
410 stat_busy "Setting \"$start_script\" as the script to be executed when Windows PE boots"
411 cp "$start_script" "$tmp_dir/$start_script"
412 cat > "$tmp_dir/__mkwinpeimg.winpeshl.ini" <<- EOF
414 %SYSTEMDRIVE%\\$start_script
417 add '$tmp_dir/$start_script' '/$start_script'
418 delete --force /Windows/System32/winpeshl.ini
419 add '$tmp_dir/__mkwinpeimg.winpeshl.ini' /Windows/System32/winpeshl.ini
424 if [ -n "$overlay" ]; then
425 stat_busy "Overlaying \"$overlay\" on the Windows PE filesystem"
434 stat_busy "Rebuilding WIM with changes made"
435 "$imagex" update "$boot_wim" --rebuild \
436 < "$tmp_dir/__mkwinpeimg.update.cmds" > /dev/null || stat_fail
443 # Make the ISO using the mkisofs command from cdrkit
445 stat_busy "Making ISO image \"$image\""
447 mkisofs -sysid "" -A "" -V "Microsoft Windows PE ($arch)" -d -N \
448 -b etfsboot.com -no-emul-boot -c boot.cat -hide etfsboot.com \
449 -hide boot.cat -quiet -o "$image" "$tmp_dir" || stat_fail
457 stat_busy "Making disk image \"$image\""
459 image_du=$(du -s -b "$tmp_dir" | cut -f 1)
460 image_size=$(( image_du + 10000000 ))
462 mtool_conf="$(mktemp)"
464 dd if=/dev/zero of="$image" count=$(( (image_size + 4095) / 4096)) \
467 cat > "$mtool_conf" <<- EOF
469 MTOOLS_FAT_COMPATIBILITY=1
474 export MTOOLSRC="$mtool_conf"
476 mformat -h 255 -s 63 -T $(( image_size / 512)) s:
477 mcopy -s "$tmp_dir"/* s:
479 syslinux --install "$image"
480 mcopy /usr/lib/syslinux/chain.c32 s:
481 mcopy - 's:syslinux.cfg' <<- EOF
485 APPEND ntldr=/bootmgr
492 tmp_dir="$(mktemp -d)"
493 process_command_line "$@"
494 if [ -z "$waik_dir" ]; then
497 if [ -n "$start_script" -o -n "$overlay" -o -n "$remove_setup" ]; then
500 check_needed_programs
503 if [ $make != wim ]; then
504 mkdir -p "$tmp_dir"/{boot,sources}
505 get_primary_boot_files
508 if [ $make = wim ]; then
511 boot_wim="$tmp_dir"/sources/boot.wim
514 get_boot_wim "$boot_wim"
516 if [ -n "$modify_wim" ]; then
517 modify_boot_wim "$boot_wim" "$tmp_dir"
520 if [ $make = iso ]; then
521 make_iso_img "$image"
522 elif [ $make = disk ]; then
523 make_disk_img "$image"
526 echo "The image ($image) is $(stat -c %s "$image") bytes."