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}"
81 if mountpoint -q "$mnt_dir" ; then
82 @IMAGEX_PROGNAME@ unmount "$mnt_dir"
89 Usage: $script_name [OPTIONS] IMAGE
91 -i, --iso Make an ISO image instead of a disk image.
92 -o, --only-wim Make neither a disk image nor an ISO image;
93 instead, only make a modified boot.wim file.
94 -W, --windows-dir=DIR Use DIR as the location of the mounted Windows 7
95 or Windows 8 DVD. Default is /mnt/windows,
96 then /mnt/windows7, then /mnt/windows8.
97 -A, --waik-dir=DIR Get the boot files and boot.wim from the ISO of the
98 Windows Automated Installation Kit mounted on DIR
99 instead of from the Windows 7 or Windows 8 DVD.
100 -s, --start-script=FILE Add FILE to the root directory of Windows PE image
101 and adjust \Windows\System32\winpeshl.ini to
102 execute FILE when Windows PE starts up.
103 -w, --wim=WIM Use WIM as the boot.wim file. Defaults to
104 sources/boot.wim in the Windows DVD directory, or
105 F1_WINPE.WIM from the WAIK if --waik-dir is
107 -O, --overlay=DIR Adds all the files in DIR to the Windows PE image.
108 -t, --tmp-dir=DIR Use DIR as the temporary base of the ISO filesystem.
109 Defaults to making one using "mktemp -d".
110 -a, --arch=ARCH Use the Windows PE version from the WAIK that has
111 the CPU architecture ARCH. Possible values:
112 "x86" or "amd64". Default is "x86".
113 -h, --help Display this information.
114 -v, --version Show version information.
116 See \`man mkwinpeimg' for more information.
121 echo "$script_name (wimlib $WIMLIB_VERSION)"
127 process_command_line() {
129 if ! options=$(getopt -o oiw:W:s:O:t:A:a:hv -l \
130 only-wim,iso,wim:,windows-dir:,start-script:,overlay:,tmp-dir:,waik-dir:,arch:,help,version \
140 eval set -- "$options"
141 while [ $# -gt 0 ]; do
151 windows_dir_specified=yes
152 if [ -n "$waik_dir" ]; then
153 echo "ERROR: Cannot specify both --windows-dir and --waik-dir!"
160 if [ -n "$windows_dir" ]; then
161 echo "ERROR: Cannot specify both --windows-dir and --waik-dir!"
184 if [ "$2" == "x86" ]; then
187 # Need to test Itanium images before making it an
188 # option. Note: syslinux is x86 only so can't be used
189 # for the Itanium disk image.
190 #elif [ "$2" == "ia64" ]; then
193 elif [ "$2" == "amd64" ]; then
197 echo "ERROR: $2 is not a valid arch (x86/amd64)"
214 echo "Invalid option \"$1\""
222 if [ $# -ne 1 ]; then
223 echo "You must specify the name of the image file to create!"
224 echo "Run \"$script_name -h\" to see usage information."
232 if [ -z "$windows_dir_specified" ]; then
233 for windows_dir in /mnt/windows /mnt/windows7 /mnt/windows8; do
234 if [ -d "$windows_dir"/sources ]; then
239 if [ ! -d "$windows_dir" ]; then
240 if [ -z "$windows_dir_specified" ]; then
242 ERROR: Could not find the directory that the Windows 7 or 8 ISO image is mounted
243 on! Please specify this directory using the --windows-dir option.
246 echo "ERROR: Could not find the directory \"$windows_dir\"!"
250 if [ ! -d "$windows_dir/sources" ]; then
252 ERROR: The directory "$windows_dir" exists, but it seems that the Windows 7 or 8
253 ISO image is not mounted on it. Please mount the image to continue.
259 check_needed_programs() {
260 if [ -z "$waik_dir" -o -n "$modify_wim" ]; then
261 if ! type -P @IMAGEX_PROGNAME@ &> /dev/null ; then
263 ERROR: To make a customized image of Windows PE, we need the "$imagex" program
264 from "wimlib" so that we can modify the boot.wim file. However, "$imagex"
265 doesn't seem to be installed. Please install "wimlib" to continue.
271 if [ $make = iso ]; then
272 if ! type -P mkisofs &> /dev/null ; then
274 ERROR: To make a bootable ISO image of Windows PE, we need the "mkisofs"
275 program, but it doesn't seem to be installed. Please install the "cdrkit"
276 package to continue, or try omitting the --iso option to make a disk image
277 instead of an ISO image.
281 elif [ $make = disk ] ; then
282 if ! type -P syslinux &> /dev/null ; then
284 ERROR: To make a bootable disk image of Windows PE, we need the "syslinux"
285 program, but it doesn't seem to be installed. Please install the "syslinux"
286 package to continue, or try using the --iso option to make an ISO image instead
292 if ! type -P mformat mcopy &> /dev/null; then
294 ERROR: To make a bootable disk image of Windows PE, we need the "mformat" and
295 "mcopy" programs from the "mtools" package. These programs allow us to
296 format a FAT filesystem and copy files to it without needing root privileges.
297 Please install "mtools" if you want to make a disk image of Windows PE. Or,
298 try using the --iso option to make an ISO image instead of a disk image.
303 if [ -n "$waik_dir" ]; then
304 if ! type -P cabextract &> /dev/null ; then
306 ERROR: The boot files in the Windows Automated Installation Kit (WAIK) are
307 inside cabinet archives. To extract these files, we need the "cabextract"
308 program, but it doesn't seem to be installed. Please install "cabextract" to
317 get_primary_boot_files() {
318 if [ -n "$waik_dir" ]; then
319 # Get boot files from the WAIK.
321 stat_busy "Copying primary boot files from the Windows Automated Installation Kit ($waik_dir, $arch)"
322 if [ $make = iso ]; then
323 cabextract "$waik_dir"/wAIK${arch}.msi -F F_WINPE_${arch}_etfsboot.com -p \
324 > "$tmp_dir"/etfsboot.com || stat_fail
326 cabextract "$waik_dir"/wAIK${arch}.msi -F F${arch_id}_BOOTMGR -p \
327 > "$tmp_dir"/bootmgr || stat_fail
328 cabextract "$waik_dir"/wAIK${arch}.msi -F F_WINPE_${arch}_boot.sdi -p \
329 > "$tmp_dir"/boot/boot.sdi || stat_fail
330 cabextract "$waik_dir"/wAIK${arch}.msi -F F_WINPE_${arch}_bcd -p \
331 > "$tmp_dir"/boot/bcd || stat_fail
334 # Get boot files from the Windows ISO
336 stat_busy "Copying primary boot files from mounted Windows DVD ($windows_dir)"
337 if [ $make = iso ]; then
338 cp "$windows_dir"/boot/etfsboot.com "$tmp_dir" || stat_fail
340 cp "$windows_dir"/bootmgr "$tmp_dir" || stat_fail
341 cp "$windows_dir"/boot/{bcd,boot.sdi} "$tmp_dir"/boot || stat_fail
348 # Copy the WIM over, or export the 2nd image in the WIM in the case of boot.wim
349 # from the Windows DVD.
351 if [ -z "$wim" ]; then
353 # WIM file unspecified- grab it from the WAIK or the Windows DVD
354 if [ -n "$waik_dir" ]; then
356 stat_busy "Extracting boot.wim from \"$waik_dir/WinPE.cab\""
357 cabextract "$waik_dir/WinPE.cab" -F F${arch_id}_WINPE.WIM -p \
358 > "$boot_wim" 2>/dev/null || stat_fail
363 wim="$windows_dir/sources/boot.wim"
364 stat_busy "Exporting image from \"$wim\""
365 "$imagex" export "$windows_dir"/sources/boot.wim 2 \
366 --boot "$boot_wim" || stat_fail
371 stat_busy "Copying $wim to temporary directory"
372 cp "$wim" "$boot_wim"|| stat_fail
381 # Make modifications to the WIM.
382 stat_busy "Mounting "$1" read-write"
384 mkdir -p "$mnt_dir" || stat_fail
385 "$imagex" mountrw "$boot_wim" "$mnt_dir"|| stat_fail
389 if [ -n "$remove_setup" ]; then
390 stat_busy "Renaming setup.exe to prevent it from bothering us"
391 mv "$mnt_dir"/setup.exe{,.bkup} || stat_fail
392 mv "$mnt_dir"/sources/setup.exe{,.bkup} || stat_fail
396 if [ -n "$start_script" ]; then
397 stat_busy "Setting \"$start_script\" as the script to be executed"\
398 "when Windows PE boots"
399 cp "$start_script" "$mnt_dir"|| stat_fail
400 cat > "$mnt_dir/Windows/System32/winpeshl.ini" << EOF
402 %SYSTEMDRIVE%\\$start_script
407 if [ -n "$overlay" ]; then
408 stat_busy "Overlaying \"$overlay\" on the Windows PE filesystem"
409 cp -r "$overlay"/* "$mnt_dir" || stat_fail
413 stat_busy "Rebuilding WIM with changes made"
414 "$imagex" unmount --commit "$mnt_dir" || stat_fail
423 # Make the ISO using the mkisofs command from cdrkit
425 stat_busy "Making ISO image \"$image\""
427 mkisofs -sysid "" -A "" -V "Microsoft Windows PE ($arch)" -d -N \
428 -b etfsboot.com -no-emul-boot -c boot.cat -hide etfsboot.com \
429 -hide boot.cat -quiet -o "$image" "$tmp_dir" || stat_fail
437 stat_busy "Making disk image \"$image\""
439 image_du=$(du -s -b "$tmp_dir" | cut -f 1)
440 image_size=$(( image_du + 10000000 ))
442 mtool_conf="$(mktemp)"
444 dd if=/dev/zero of="$image" count=$(( (image_size + 4095) / 4096)) \
447 cat > "$mtool_conf" << EOF
449 MTOOLS_FAT_COMPATIBILITY=1
454 export MTOOLSRC="$mtool_conf"
456 mformat -h 255 -s 63 -T $(( image_size / 512)) s:
457 mcopy -s "$tmp_dir"/* s:
459 syslinux --install "$image"
460 mcopy /usr/lib/syslinux/chain.c32 s:
461 mcopy - 's:syslinux.cfg' << EOF
465 APPEND ntldr=/bootmgr
472 tmp_dir="$(mktemp -d)"
473 mnt_dir="$tmp_dir"/.boot.wim.mount
474 process_command_line "$@"
475 if [ -z "$waik_dir" ]; then
478 if [ -n "$start_script" -o -n "$overlay" -o -n "$remove_setup" ]; then
481 check_needed_programs
484 if [ $make != wim ]; then
485 mkdir -p "$tmp_dir"/{boot,sources}
486 get_primary_boot_files
489 if [ $make = wim ]; then
492 boot_wim="$tmp_dir"/sources/boot.wim
495 get_boot_wim "$boot_wim"
497 if [ -n "$modify_wim" ]; then
498 modify_boot_wim "$boot_wim" "$mnt_dir"
501 if [ $make = iso ]; then
502 make_iso_img "$image"
503 elif [ $make = disk ]; then
504 make_disk_img "$image"
507 echo "The image ($image) is $(stat -c %s "$image") bytes."