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 ARCH version (x86 or amd64)
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
186 elif [ "$2" == "amd64" ]; then
191 echo "ERROR: $2 is not a valid arch (x86/amd64)"
208 echo "Invalid option \"$1\""
216 if [ $# -ne 1 ]; then
217 echo "You must specify the name of the image file to create!"
218 echo "Run \"$script_name -h\" to see usage information."
226 if [ -z "$windows_dir_specified" ]; then
227 for windows_dir in /mnt/windows /mnt/windows7 /mnt/windows8; do
228 if [ -d "$windows_dir"/sources ]; then
233 if [ ! -d "$windows_dir" ]; then
234 if [ -z "$windows_dir_specified" ]; then
236 ERROR: Could not find the directory that the Windows 7 or 8 ISO image is mounted
237 on! Please specify this directory using the --windows-dir option.
240 echo "ERROR: Could not find the directory \"$windows_dir\"!"
244 if [ ! -d "$windows_dir/sources" ]; then
246 ERROR: The directory "$windows_dir" exists, but it seems that the Windows 7 or 8
247 ISO image is not mounted on it. Please mount the image to continue.
253 check_needed_programs() {
254 if [ -z "$waik_dir" -o -n "$modify_wim" ]; then
255 if ! type -P imagex &> /dev/null ; then
257 ERROR: To make a customized image of Windows PE, we need the "imagex" program
258 from WIMLIB so that we can modify the boot.wim file. However, "imagex"
259 doesn't seem to be installed. Please install WIMLIB to continue.
265 if [ $make = iso ]; then
266 if ! type -P mkisofs &> /dev/null ; then
268 ERROR: To make a bootable ISO image of Windows PE, we need the "mkisofs"
269 program, but it doesn't seem to be installed. Please install the "cdrkit"
270 package to continue, or try omitting the --iso option to make a disk image
271 instead of an ISO image.
275 elif [ $make = disk ] ; then
276 if ! type -P syslinux &> /dev/null ; then
278 ERROR: To make a bootable disk image of Windows PE, we need the "syslinux"
279 program, but it doesn't seem to be installed. Please install the "syslinux"
280 package to continue, or try using the --iso option to make an ISO image instead
286 if ! type -P mformat mcopy &> /dev/null; then
288 ERROR: To make a bootable disk image of Windows PE, we need the "mformat" and
289 "mcopy" programs from the "mtools" package. These programs allow us to
290 format a FAT filesystem and copy files to it without needing root privileges.
291 Please install "mtools" if you want to make a disk image of Windows PE. Or,
292 try using the --iso option to make an ISO image instead of a disk image.
297 if [ -n "$waik_dir" ]; then
298 if ! type -P cabextract &> /dev/null ; then
300 ERROR: The boot files in the Windows Automated Installation Kit (WAIK) are
301 inside cabinet archives. To extract these files, we need the "cabextract"
302 program, but it doesn't seem to be installed. Please install "cabextract" to
311 get_primary_boot_files() {
312 if [ -n "$waik_dir" ]; then
313 # Get boot files from the WAIK.
315 stat_busy "Copying primary boot files from the Windows Automated Installation Kit ($waik_dir, $arch)"
316 if [ $make = iso ]; then
317 cabextract "$waik_dir"/wAIK${arch}.msi -F F_WINPE_${arch}_etfsboot.com -p \
318 > "$tmp_dir"/etfsboot.com || stat_fail
320 cabextract "$waik_dir"/wAIK${arch}.msi -F F${arch_id}_BOOTMGR -p \
321 > "$tmp_dir"/bootmgr || stat_fail
322 cabextract "$waik_dir"/wAIK${arch}.msi -F F_WINPE_${arch}_boot.sdi -p \
323 > "$tmp_dir"/boot/boot.sdi || stat_fail
324 cabextract "$waik_dir"/wAIK${arch}.msi -F F_WINPE_${arch}_bcd -p \
325 > "$tmp_dir"/boot/bcd || stat_fail
328 # Get boot files from the Windows ISO
330 stat_busy "Copying primary boot files from mounted Windows DVD ($windows_dir)"
331 if [ $make = iso ]; then
332 cp "$windows_dir"/boot/etfsboot.com "$tmp_dir" || stat_fail
334 cp "$windows_dir"/bootmgr "$tmp_dir" || stat_fail
335 cp "$windows_dir"/boot/{bcd,boot.sdi} "$tmp_dir"/boot || stat_fail
342 # Copy the WIM over, or export the 2nd image in the WIM in the case of boot.wim
343 # from the Windows DVD.
345 if [ -z "$wim" ]; then
347 # WIM file unspecified- grab it from the WAIK or the Windows DVD
348 if [ -n "$waik_dir" ]; then
350 stat_busy "Extracting boot.wim from \"$waik_dir/WinPE.cab\""
351 cabextract "$waik_dir/WinPE.cab" -F F${arch_id}_WINPE.WIM -p \
352 > "$boot_wim" 2>/dev/null || stat_fail
357 wim="$windows_dir/sources/boot.wim"
358 stat_busy "Exporting image from \"$wim\""
359 imagex export "$windows_dir"/sources/boot.wim 2 \
360 --boot "$boot_wim" || stat_fail
365 stat_busy "Copying $wim to temporary directory"
366 cp "$wim" "$boot_wim"|| stat_fail
375 # Make modifications to the WIM.
376 stat_busy "Mounting "$1" read-write"
378 mkdir -p "$mnt_dir" || stat_fail
379 imagex mountrw "$boot_wim" "$mnt_dir"|| stat_fail
383 if [ -n "$remove_setup" ]; then
384 stat_busy "Renaming setup.exe to prevent it from bothering us"
385 mv "$mnt_dir"/setup.exe{,.bkup} || stat_fail
386 mv "$mnt_dir"/sources/setup.exe{,.bkup} || stat_fail
390 if [ -n "$start_script" ]; then
391 stat_busy "Setting \"$start_script\" as the script to be executed"\
392 "when Windows PE boots"
393 cp "$start_script" "$mnt_dir"|| stat_fail
394 cat > "$mnt_dir/Windows/System32/winpeshl.ini" << EOF
396 %SYSTEMDRIVE%\\$start_script
401 if [ -n "$overlay" ]; then
402 stat_busy "Overlaying \"$overlay\" on the Windows PE filesystem"
403 cp -r "$overlay"/* "$mnt_dir" || stat_fail
407 stat_busy "Rebuilding WIM with changes made"
408 imagex unmount --commit "$mnt_dir" || stat_fail
417 # Make the ISO using the mkisofs command from cdrkit
419 stat_busy "Making ISO image \"$image\""
421 mkisofs -sysid "" -A "" -V "Microsoft Windows PE (x86)" -d -N \
422 -b etfsboot.com -no-emul-boot -c boot.cat -hide etfsboot.com \
423 -hide boot.cat -quiet -o "$image" "$tmp_dir" || stat_fail
431 stat_busy "Making disk image \"$image\""
433 image_du=$(du -s -b "$tmp_dir" | cut -f 1)
434 image_size=$(( image_du + 10000000 ))
436 mtool_conf="$(mktemp)"
438 dd if=/dev/zero of="$image" count=$(( (image_size + 4095) / 4096)) \
441 cat > "$mtool_conf" << EOF
443 MTOOLS_FAT_COMPATIBILITY=1
448 export MTOOLSRC="$mtool_conf"
450 mformat -h 255 -s 63 -T $(( image_size / 512)) s:
451 mcopy -s "$tmp_dir"/* s:
453 syslinux --install "$image"
454 mcopy /usr/lib/syslinux/chain.c32 s:
455 mcopy - 's:syslinux.cfg' << EOF
459 APPEND ntldr=/bootmgr
466 tmp_dir="$(mktemp -d)"
467 mnt_dir="$tmp_dir"/.boot.wim.mount
468 process_command_line "$@"
469 if [ -z "$waik_dir" ]; then
472 if [ -n "$start_script" -o -n "$overlay" -o -n "$remove_setup" ]; then
475 check_needed_programs
478 if [ $make != wim ]; then
479 mkdir -p "$tmp_dir"/{boot,sources}
480 get_primary_boot_files
483 if [ $make = wim ]; then
486 boot_wim="$tmp_dir"/sources/boot.wim
489 get_boot_wim "$boot_wim"
491 if [ -n "$modify_wim" ]; then
492 modify_boot_wim "$boot_wim" "$mnt_dir"
495 if [ $make = iso ]; then
496 make_iso_img "$image"
497 elif [ $make = disk ]; then
498 make_disk_img "$image"
501 echo "The image ($image) is $(stat -c %s "$image") bytes."