3 # This script can make a customized bootable image of Windows PE.
5 # Copyright (C) 2012 Eric Biggers
7 # This program is free software: you can redistribute it and/or modify
8 # it under the terms of the GNU General Public License as published by
9 # the Free Software Foundation, either version 3 of the License, or
10 # (at your option) any later version.
13 script_name="$(basename $0)"
19 # stty will fail when stdin isn't a terminal
21 # stty gives "rows cols"; strip the rows number, we just want columns
22 STAT_COL=${STAT_COL##* }
23 elif tput cols &>/dev/null; then
24 # is /usr/share/terminfo already mounted, and TERM recognized?
27 if (( STAT_COL == 0 )); then
28 # if output was 0 (serial console), set default width to 80
32 # we use 13 characters for our own stuff
33 STAT_COL=$(( STAT_COL - 13 ))
37 RESTORE_POSITION="\e[u"
38 DEL_TEXT="\e[$(( STAT_COL + 4 ))G"
52 printf "${PREFIX_REG} ${1} "
53 printf "${SAVE_POSITION}"
71 if mountpoint -q "$mnt_dir" ; then
72 imagex unmount "$mnt_dir"
79 Usage: $script_name [OPTIONS] IMAGE
81 -i, --iso Make an ISO image instead of a disk image.
82 -o, --only-wim Make neither a disk image nor an ISO image;
83 instead, only make a modified boot.wim file.
84 -W, --windows-dir=DIR Use DIR as the location of the mounted Windows 7
85 or Windows 8 DVD. Default is /mnt/windows,
86 then /mnt/windows7, then /mnt/windows8.
87 -A, --waik-dir=DIR Get the boot files and boot.wim from the ISO of the
88 Windows Automated Installation Kit mounted on DIR
89 instead of from the Windows 7 or Windows 8 DVD.
90 -s, --start-script=FILE Add FILE to the root directory of Windows PE image
91 and adjust \Windows\System32\winpeshl.ini to
92 execute FILE when Windows PE starts up.
93 -w, --wim=WIM Use WIM as the boot.wim file. Defaults to
94 sources/boot.wim in the Windows DVD directory, or
95 F1_WINPE.WIM from the WAIK if --waik-dir is
97 -O, --overlay=DIR Adds all the files in DIR to the Windows PE image.
98 -t, --tmp-dir=DIR Use DIR as the temporary base of the ISO filesystem.
99 Defaults to making one using \"mktemp -d\".
100 -h, --help Display this information.
101 -v, --version Show version information.
103 See \`man mkwinpeimg' for more information.
108 echo "$script_name (wimlib 0.4.8)"
114 process_command_line() {
116 if ! options=$(getopt -o oiw:W:s:O:t:A:hv -l \
117 only-wim,iso,wim:,windows-dir:,start-script:,overlay:,tmp-dir:,waik-dir:,help,version \
122 eval set -- "$options"
123 while [ $# -gt 0 ]; do
133 windows_dir_specified=yes
134 if [ -n "$waik_dir" ]; then
135 echo "ERROR: Cannot specify both --windows-dir and --waik-dir!"
142 if [ -n "$windows_dir" ]; then
143 echo "ERROR: Cannot specify both --windows-dir and --waik-dir!"
177 echo "Invalid option \"$1\""
184 if [ $# -ne 1 ]; then
185 echo "You must specify the name of the image file to create!"
186 echo "Run \"$script_name -h\" to see usage information."
195 if [ -z "$windows_dir_specified" ]; then
196 for windows_dir in /mnt/windows /mnt/windows7 /mnt/windows8; do
197 if [ -d "$windows_dir"/sources ]; then
202 if [ ! -d "$windows_dir" ]; then
203 if [ -z "$windows_dir_specified" ]; then
205 ERROR: Could not find the directory that the Windows 7 or 8 ISO image is mounted
206 on! Please specify this directory using the --windows-dir option.
209 echo "ERROR: Could not find the directory \"$windows_dir\"!"
213 if [ ! -d "$windows_dir/sources" ]; then
215 ERROR: The directory "$windows_dir" exists, but it seems that the Windows 7 or 8
216 ISO image is not mounted on it. Please mount the image to continue.
222 check_needed_programs() {
223 if [ -z "$waik_dir" -o -n "$modify_wim" ]; then
224 if ! type -P imagex &> /dev/null ; then
226 ERROR: To make a customized image of Windows PE, we need the \"imagex\" program
227 from WIMLIB so that we can modify the boot.wim file. However, \"imagex\"
228 doesn't seem to be installed. Please install WIMLIB to continue.
234 if [ $make = iso ]; then
235 if ! type -P mkisofs &> /dev/null ; then
237 ERROR: To make a bootable ISO image of Windows PE, we need the \"mkisofs\"
238 program, but it doesn't seem to be installed. Please install the \"cdrkit\"
239 package to continue, or try omitting the --iso option to make a disk image
240 instead of an ISO image.
244 elif [ $make = disk ] ; then
245 if ! type -P syslinux &> /dev/null ; then
247 ERROR: To make a bootable disk image of Windows PE, we need the \"syslinux\"
248 program, but it doesn't seem to be installed. Please install the \"syslinux\"
249 package to continue, or try using the --iso option to make an ISO image instead
255 if ! type -P mformat mcopy &> /dev/null; then
257 ERROR: To make a bootable disk image of Windows PE, we need the \"mformat\" and
258 \"mcopy\" programs from the \"mtools\" package. These programs allow us to
259 format a FAT filesystem and copy files to it without needing root privileges.
260 Please install \"mtools\" if you want to make a disk image of Windows PE. Or,
261 try using the --iso option to make an ISO image instead of a disk image.
266 if [ -n "$waik_dir" ]; then
267 if ! type -P cabextract &> /dev/null ; then
269 ERROR: The boot files in the Windows Automated Installation Kit (WAIK) are
270 inside cabinet archives. To extract these files, we need the \"cabextract\"
271 program, but it doesn't seem to be installed. Please install \"cabextract\" to
280 get_primary_boot_files() {
282 if [ -n "$waik_dir" ]; then
283 # Get boot files from the WAIK.
285 stat_busy "Copying primary boot files from the Windows Automated Installation Kit ($waik_dir)"
286 if [ $make = iso ]; then
287 cabextract "$waik_dir"/wAIKX86.msi -F F_WINPE_X86_etfsboot.com -p \
288 > "$tmp_dir"/etfsboot.com || stat_fail
290 cabextract "$waik_dir"/wAIKX86.msi -F F1_BOOTMGR -p \
291 > "$tmp_dir"/bootmgr || stat_fail
292 cabextract "$waik_dir"/wAIKX86.msi -F F_WINPE_X86_boot.sdi -p \
293 > "$tmp_dir"/boot/boot.sdi || stat_fail
294 cabextract "$waik_dir"/wAIKX86.msi -F F_WINPE_X86_bcd -p \
295 > "$tmp_dir"/boot/bcd || stat_fail
298 # Get boot files from the Windows ISO
300 stat_busy "Copying primary boot files from mounted Windows DVD ($windows_dir)"
301 if [ $make = iso ]; then
302 cp "$windows_dir"/boot/etfsboot.com "$tmp_dir" || stat_fail
304 cp "$windows_dir"/bootmgr "$tmp_dir" || stat_fail
305 cp "$windows_dir"/boot/{bcd,boot.sdi} "$tmp_dir"/boot || stat_fail
312 # Copy the WIM over, or export the 2nd image in the WIM in the case of boot.wim
313 # from the Windows DVD.
315 if [ -z "$wim" ]; then
317 # WIM file unspecified- grab it from the WAIK or the Windows DVD
318 if [ -n "$waik_dir" ]; then
320 stat_busy "Extracting boot.wim from \"$waik_dir/WinPE.cab\""
321 cabextract "$waik_dir/WinPE.cab" -F F1_WINPE.WIM -p \
322 > "$boot_wim" 2>/dev/null || stat_fail
327 wim="$windows_dir/sources/boot.wim"
328 stat_busy "Exporting image from \"$wim\""
329 imagex export "$windows_dir"/sources/boot.wim 2 \
330 --compress --boot "$boot_wim" || stat_fail
335 stat_busy "Copying $wim to temporary directory"
336 cp "$wim" "$boot_wim"|| stat_fail
346 # Make modifications to the WIM.
347 stat_busy "Mounting "$1" read-write"
349 mkdir -p "$mnt_dir" || stat_fail
350 imagex mountrw "$boot_wim" "$mnt_dir"|| stat_fail
354 if [ -n "$remove_setup" ]; then
355 stat_busy "Renaming setup.exe to prevent it from bothering us"
356 mv "$mnt_dir"/setup.exe{,.bkup} || stat_fail
357 mv "$mnt_dir"/sources/setup.exe{,.bkup} || stat_fail
361 if [ -n "$start_script" ]; then
362 stat_busy "Setting \"$start_script\" as the script to be executed"\
363 "when Windows PE boots"
364 cp "$start_script" "$mnt_dir"|| stat_fail
365 cat > "$mnt_dir/Windows/System32/winpeshl.ini" << EOF
367 %SYSTEMDRIVE%\\$start_script
372 if [ -n "$overlay" ]; then
373 stat_busy "Overlaying \"$overlay\" on the Windows PE filesystem"
374 cp -r "$overlay"/* "$mnt_dir" || stat_fail
378 stat_busy "Rebuilding WIM with changes made"
379 imagex unmount --commit "$mnt_dir" || stat_fail
389 # Make the ISO using the mkisofs command from cdrkit
391 stat_busy "Making ISO image \"$image\""
393 mkisofs -sysid "" -A "" -V "Microsoft Windows PE (x86)" -d -N \
394 -b etfsboot.com -no-emul-boot -c boot.cat -hide etfsboot.com \
395 -hide boot.cat -quiet -o "$image" "$tmp_dir" || stat_fail
405 stat_busy "Making disk image \"$image\""
407 image_du=$(du -s -b "$tmp_dir" | cut -f 1)
408 image_size=$(( image_du + 10000000 ))
410 mtool_conf="$(mktemp)"
412 dd if=/dev/zero of="$image" count=$(( (image_size + 4095) / 4096)) \
415 cat > "$mtool_conf" << EOF
417 MTOOLS_FAT_COMPATIBILITY=1
422 export MTOOLSRC="$mtool_conf"
424 mformat -h 255 -s 63 -T $(( image_size / 512)) s:
425 mcopy -s "$tmp_dir"/* s:
427 syslinux --install "$image"
428 mcopy /usr/lib/syslinux/chain.c32 s:
429 mcopy - 's:syslinux.cfg' << EOF
433 APPEND ntldr=/bootmgr
441 tmp_dir="$(mktemp -d)"
442 mnt_dir="$tmp_dir"/.boot.wim.mount
443 process_command_line "$@"
444 if [ -z "$waik_dir" ]; then
447 if [ -n "$start_script" -o -n "$overlay" -o -n "$remove_setup" ]; then
450 check_needed_programs
453 if [ $make != wim ]; then
454 mkdir -p "$tmp_dir"/{boot,sources}
455 get_primary_boot_files
458 if [ $make = wim ]; then
461 boot_wim="$tmp_dir"/sources/boot.wim
464 get_boot_wim "$boot_wim"
466 if [ -n "$modify_wim" ]; then
467 modify_boot_wim "$boot_wim" "$mnt_dir"
470 if [ $make = iso ]; then
471 make_iso_img "$image"
472 elif [ $make = disk ]; then
473 make_disk_img "$image"
476 echo "The image ($image) is $(stat -c %s "$image") bytes."