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 -h, --help Display this information.
110 -v, --version Show version information.
112 See \`man mkwinpeimg' for more information.
117 echo "$script_name (wimlib $WIMLIB_VERSION)"
123 process_command_line() {
125 if ! options=$(getopt -o oiw:W:s:O:t:A:hv -l \
126 only-wim,iso,wim:,windows-dir:,start-script:,overlay:,tmp-dir:,waik-dir:,help,version \
131 eval set -- "$options"
132 while [ $# -gt 0 ]; do
142 windows_dir_specified=yes
143 if [ -n "$waik_dir" ]; then
144 echo "ERROR: Cannot specify both --windows-dir and --waik-dir!"
151 if [ -n "$windows_dir" ]; then
152 echo "ERROR: Cannot specify both --windows-dir and --waik-dir!"
186 echo "Invalid option \"$1\""
193 if [ $# -ne 1 ]; then
194 echo "You must specify the name of the image file to create!"
195 echo "Run \"$script_name -h\" to see usage information."
203 if [ -z "$windows_dir_specified" ]; then
204 for windows_dir in /mnt/windows /mnt/windows7 /mnt/windows8; do
205 if [ -d "$windows_dir"/sources ]; then
210 if [ ! -d "$windows_dir" ]; then
211 if [ -z "$windows_dir_specified" ]; then
213 ERROR: Could not find the directory that the Windows 7 or 8 ISO image is mounted
214 on! Please specify this directory using the --windows-dir option.
217 echo "ERROR: Could not find the directory \"$windows_dir\"!"
221 if [ ! -d "$windows_dir/sources" ]; then
223 ERROR: The directory "$windows_dir" exists, but it seems that the Windows 7 or 8
224 ISO image is not mounted on it. Please mount the image to continue.
230 check_needed_programs() {
231 if [ -z "$waik_dir" -o -n "$modify_wim" ]; then
232 if ! type -P imagex &> /dev/null ; then
234 ERROR: To make a customized image of Windows PE, we need the "imagex" program
235 from WIMLIB so that we can modify the boot.wim file. However, "imagex"
236 doesn't seem to be installed. Please install WIMLIB to continue.
242 if [ $make = iso ]; then
243 if ! type -P mkisofs &> /dev/null ; then
245 ERROR: To make a bootable ISO image of Windows PE, we need the "mkisofs"
246 program, but it doesn't seem to be installed. Please install the "cdrkit"
247 package to continue, or try omitting the --iso option to make a disk image
248 instead of an ISO image.
252 elif [ $make = disk ] ; then
253 if ! type -P syslinux &> /dev/null ; then
255 ERROR: To make a bootable disk image of Windows PE, we need the "syslinux"
256 program, but it doesn't seem to be installed. Please install the "syslinux"
257 package to continue, or try using the --iso option to make an ISO image instead
263 if ! type -P mformat mcopy &> /dev/null; then
265 ERROR: To make a bootable disk image of Windows PE, we need the "mformat" and
266 "mcopy" programs from the "mtools" package. These programs allow us to
267 format a FAT filesystem and copy files to it without needing root privileges.
268 Please install "mtools" if you want to make a disk image of Windows PE. Or,
269 try using the --iso option to make an ISO image instead of a disk image.
274 if [ -n "$waik_dir" ]; then
275 if ! type -P cabextract &> /dev/null ; then
277 ERROR: The boot files in the Windows Automated Installation Kit (WAIK) are
278 inside cabinet archives. To extract these files, we need the "cabextract"
279 program, but it doesn't seem to be installed. Please install "cabextract" to
288 get_primary_boot_files() {
289 if [ -n "$waik_dir" ]; then
290 # Get boot files from the WAIK.
292 stat_busy "Copying primary boot files from the Windows Automated Installation Kit ($waik_dir)"
293 if [ $make = iso ]; then
294 cabextract "$waik_dir"/wAIKX86.msi -F F_WINPE_X86_etfsboot.com -p \
295 > "$tmp_dir"/etfsboot.com || stat_fail
297 cabextract "$waik_dir"/wAIKX86.msi -F F1_BOOTMGR -p \
298 > "$tmp_dir"/bootmgr || stat_fail
299 cabextract "$waik_dir"/wAIKX86.msi -F F_WINPE_X86_boot.sdi -p \
300 > "$tmp_dir"/boot/boot.sdi || stat_fail
301 cabextract "$waik_dir"/wAIKX86.msi -F F_WINPE_X86_bcd -p \
302 > "$tmp_dir"/boot/bcd || stat_fail
305 # Get boot files from the Windows ISO
307 stat_busy "Copying primary boot files from mounted Windows DVD ($windows_dir)"
308 if [ $make = iso ]; then
309 cp "$windows_dir"/boot/etfsboot.com "$tmp_dir" || stat_fail
311 cp "$windows_dir"/bootmgr "$tmp_dir" || stat_fail
312 cp "$windows_dir"/boot/{bcd,boot.sdi} "$tmp_dir"/boot || stat_fail
319 # Copy the WIM over, or export the 2nd image in the WIM in the case of boot.wim
320 # from the Windows DVD.
322 if [ -z "$wim" ]; then
324 # WIM file unspecified- grab it from the WAIK or the Windows DVD
325 if [ -n "$waik_dir" ]; then
327 stat_busy "Extracting boot.wim from \"$waik_dir/WinPE.cab\""
328 cabextract "$waik_dir/WinPE.cab" -F F1_WINPE.WIM -p \
329 > "$boot_wim" 2>/dev/null || stat_fail
334 wim="$windows_dir/sources/boot.wim"
335 stat_busy "Exporting image from \"$wim\""
336 imagex export "$windows_dir"/sources/boot.wim 2 \
337 --boot "$boot_wim" || stat_fail
342 stat_busy "Copying $wim to temporary directory"
343 cp "$wim" "$boot_wim"|| stat_fail
352 # Make modifications to the WIM.
353 stat_busy "Mounting "$1" read-write"
355 mkdir -p "$mnt_dir" || stat_fail
356 imagex mountrw "$boot_wim" "$mnt_dir"|| stat_fail
360 if [ -n "$remove_setup" ]; then
361 stat_busy "Renaming setup.exe to prevent it from bothering us"
362 mv "$mnt_dir"/setup.exe{,.bkup} || stat_fail
363 mv "$mnt_dir"/sources/setup.exe{,.bkup} || stat_fail
367 if [ -n "$start_script" ]; then
368 stat_busy "Setting \"$start_script\" as the script to be executed"\
369 "when Windows PE boots"
370 cp "$start_script" "$mnt_dir"|| stat_fail
371 cat > "$mnt_dir/Windows/System32/winpeshl.ini" << EOF
373 %SYSTEMDRIVE%\\$start_script
378 if [ -n "$overlay" ]; then
379 stat_busy "Overlaying \"$overlay\" on the Windows PE filesystem"
380 cp -r "$overlay"/* "$mnt_dir" || stat_fail
384 stat_busy "Rebuilding WIM with changes made"
385 imagex unmount --commit "$mnt_dir" || stat_fail
394 # Make the ISO using the mkisofs command from cdrkit
396 stat_busy "Making ISO image \"$image\""
398 mkisofs -sysid "" -A "" -V "Microsoft Windows PE (x86)" -d -N \
399 -b etfsboot.com -no-emul-boot -c boot.cat -hide etfsboot.com \
400 -hide boot.cat -quiet -o "$image" "$tmp_dir" || stat_fail
408 stat_busy "Making disk image \"$image\""
410 image_du=$(du -s -b "$tmp_dir" | cut -f 1)
411 image_size=$(( image_du + 10000000 ))
413 mtool_conf="$(mktemp)"
415 dd if=/dev/zero of="$image" count=$(( (image_size + 4095) / 4096)) \
418 cat > "$mtool_conf" << EOF
420 MTOOLS_FAT_COMPATIBILITY=1
425 export MTOOLSRC="$mtool_conf"
427 mformat -h 255 -s 63 -T $(( image_size / 512)) s:
428 mcopy -s "$tmp_dir"/* s:
430 syslinux --install "$image"
431 mcopy /usr/lib/syslinux/chain.c32 s:
432 mcopy - 's:syslinux.cfg' << EOF
436 APPEND ntldr=/bootmgr
443 tmp_dir="$(mktemp -d)"
444 mnt_dir="$tmp_dir"/.boot.wim.mount
445 process_command_line "$@"
446 if [ -z "$waik_dir" ]; then
449 if [ -n "$start_script" -o -n "$overlay" -o -n "$remove_setup" ]; then
452 check_needed_programs
455 if [ $make != wim ]; then
456 mkdir -p "$tmp_dir"/{boot,sources}
457 get_primary_boot_files
460 if [ $make = wim ]; then
463 boot_wim="$tmp_dir"/sources/boot.wim
466 get_boot_wim "$boot_wim"
468 if [ -n "$modify_wim" ]; then
469 modify_boot_wim "$boot_wim" "$mnt_dir"
472 if [ $make = iso ]; then
473 make_iso_img "$image"
474 elif [ $make = disk ]; then
475 make_disk_img "$image"
478 echo "The image ($image) is $(stat -c %s "$image") bytes."