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)"
27 # stty will fail when stdin isn't a terminal
29 # stty gives "rows cols"; strip the rows number, we just want columns
30 STAT_COL=${STAT_COL##* }
31 elif tput cols &>/dev/null; then
32 # is /usr/share/terminfo already mounted, and TERM recognized?
35 if (( STAT_COL == 0 )); then
36 # if output was 0 (serial console), set default width to 80
40 # we use 13 characters for our own stuff
41 STAT_COL=$(( STAT_COL - 13 ))
45 RESTORE_POSITION="\e[u"
46 DEL_TEXT="\e[$(( STAT_COL + 4 ))G"
60 printf "${PREFIX_REG} ${1} "
61 printf "${SAVE_POSITION}"
79 if mountpoint -q "$mnt_dir" ; then
80 imagex unmount "$mnt_dir"
87 Usage: $script_name [OPTIONS] IMAGE
89 -i, --iso Make an ISO image instead of a disk image.
90 -o, --only-wim Make neither a disk image nor an ISO image;
91 instead, only make a modified boot.wim file.
92 -W, --windows-dir=DIR Use DIR as the location of the mounted Windows 7
93 or Windows 8 DVD. Default is /mnt/windows,
94 then /mnt/windows7, then /mnt/windows8.
95 -A, --waik-dir=DIR Get the boot files and boot.wim from the ISO of the
96 Windows Automated Installation Kit mounted on DIR
97 instead of from the Windows 7 or Windows 8 DVD.
98 -s, --start-script=FILE Add FILE to the root directory of Windows PE image
99 and adjust \Windows\System32\winpeshl.ini to
100 execute FILE when Windows PE starts up.
101 -w, --wim=WIM Use WIM as the boot.wim file. Defaults to
102 sources/boot.wim in the Windows DVD directory, or
103 F1_WINPE.WIM from the WAIK if --waik-dir is
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 -h, --help Display this information.
109 -v, --version Show version information.
111 See \`man mkwinpeimg' for more information.
116 echo "$script_name (wimlib 0.4.8)"
122 process_command_line() {
124 if ! options=$(getopt -o oiw:W:s:O:t:A:hv -l \
125 only-wim,iso,wim:,windows-dir:,start-script:,overlay:,tmp-dir:,waik-dir:,help,version \
130 eval set -- "$options"
131 while [ $# -gt 0 ]; do
141 windows_dir_specified=yes
142 if [ -n "$waik_dir" ]; then
143 echo "ERROR: Cannot specify both --windows-dir and --waik-dir!"
150 if [ -n "$windows_dir" ]; then
151 echo "ERROR: Cannot specify both --windows-dir and --waik-dir!"
185 echo "Invalid option \"$1\""
192 if [ $# -ne 1 ]; then
193 echo "You must specify the name of the image file to create!"
194 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() {
290 if [ -n "$waik_dir" ]; then
291 # Get boot files from the WAIK.
293 stat_busy "Copying primary boot files from the Windows Automated Installation Kit ($waik_dir)"
294 if [ $make = iso ]; then
295 cabextract "$waik_dir"/wAIKX86.msi -F F_WINPE_X86_etfsboot.com -p \
296 > "$tmp_dir"/etfsboot.com || stat_fail
298 cabextract "$waik_dir"/wAIKX86.msi -F F1_BOOTMGR -p \
299 > "$tmp_dir"/bootmgr || stat_fail
300 cabextract "$waik_dir"/wAIKX86.msi -F F_WINPE_X86_boot.sdi -p \
301 > "$tmp_dir"/boot/boot.sdi || stat_fail
302 cabextract "$waik_dir"/wAIKX86.msi -F F_WINPE_X86_bcd -p \
303 > "$tmp_dir"/boot/bcd || stat_fail
306 # Get boot files from the Windows ISO
308 stat_busy "Copying primary boot files from mounted Windows DVD ($windows_dir)"
309 if [ $make = iso ]; then
310 cp "$windows_dir"/boot/etfsboot.com "$tmp_dir" || stat_fail
312 cp "$windows_dir"/bootmgr "$tmp_dir" || stat_fail
313 cp "$windows_dir"/boot/{bcd,boot.sdi} "$tmp_dir"/boot || stat_fail
320 # Copy the WIM over, or export the 2nd image in the WIM in the case of boot.wim
321 # from the Windows DVD.
323 if [ -z "$wim" ]; then
325 # WIM file unspecified- grab it from the WAIK or the Windows DVD
326 if [ -n "$waik_dir" ]; then
328 stat_busy "Extracting boot.wim from \"$waik_dir/WinPE.cab\""
329 cabextract "$waik_dir/WinPE.cab" -F F1_WINPE.WIM -p \
330 > "$boot_wim" 2>/dev/null || stat_fail
335 wim="$windows_dir/sources/boot.wim"
336 stat_busy "Exporting image from \"$wim\""
337 imagex export "$windows_dir"/sources/boot.wim 2 \
338 --compress --boot "$boot_wim" || stat_fail
343 stat_busy "Copying $wim to temporary directory"
344 cp "$wim" "$boot_wim"|| stat_fail
354 # Make modifications to the WIM.
355 stat_busy "Mounting "$1" read-write"
357 mkdir -p "$mnt_dir" || stat_fail
358 imagex mountrw "$boot_wim" "$mnt_dir"|| stat_fail
362 if [ -n "$remove_setup" ]; then
363 stat_busy "Renaming setup.exe to prevent it from bothering us"
364 mv "$mnt_dir"/setup.exe{,.bkup} || stat_fail
365 mv "$mnt_dir"/sources/setup.exe{,.bkup} || stat_fail
369 if [ -n "$start_script" ]; then
370 stat_busy "Setting \"$start_script\" as the script to be executed"\
371 "when Windows PE boots"
372 cp "$start_script" "$mnt_dir"|| stat_fail
373 cat > "$mnt_dir/Windows/System32/winpeshl.ini" << EOF
375 %SYSTEMDRIVE%\\$start_script
380 if [ -n "$overlay" ]; then
381 stat_busy "Overlaying \"$overlay\" on the Windows PE filesystem"
382 cp -r "$overlay"/* "$mnt_dir" || stat_fail
386 stat_busy "Rebuilding WIM with changes made"
387 imagex unmount --commit "$mnt_dir" || stat_fail
397 # Make the ISO using the mkisofs command from cdrkit
399 stat_busy "Making ISO image \"$image\""
401 mkisofs -sysid "" -A "" -V "Microsoft Windows PE (x86)" -d -N \
402 -b etfsboot.com -no-emul-boot -c boot.cat -hide etfsboot.com \
403 -hide boot.cat -quiet -o "$image" "$tmp_dir" || stat_fail
413 stat_busy "Making disk image \"$image\""
415 image_du=$(du -s -b "$tmp_dir" | cut -f 1)
416 image_size=$(( image_du + 10000000 ))
418 mtool_conf="$(mktemp)"
420 dd if=/dev/zero of="$image" count=$(( (image_size + 4095) / 4096)) \
423 cat > "$mtool_conf" << EOF
425 MTOOLS_FAT_COMPATIBILITY=1
430 export MTOOLSRC="$mtool_conf"
432 mformat -h 255 -s 63 -T $(( image_size / 512)) s:
433 mcopy -s "$tmp_dir"/* s:
435 syslinux --install "$image"
436 mcopy /usr/lib/syslinux/chain.c32 s:
437 mcopy - 's:syslinux.cfg' << EOF
441 APPEND ntldr=/bootmgr
449 tmp_dir="$(mktemp -d)"
450 mnt_dir="$tmp_dir"/.boot.wim.mount
451 process_command_line "$@"
452 if [ -z "$waik_dir" ]; then
455 if [ -n "$start_script" -o -n "$overlay" -o -n "$remove_setup" ]; then
458 check_needed_programs
461 if [ $make != wim ]; then
462 mkdir -p "$tmp_dir"/{boot,sources}
463 get_primary_boot_files
466 if [ $make = wim ]; then
469 boot_wim="$tmp_dir"/sources/boot.wim
472 get_boot_wim "$boot_wim"
474 if [ -n "$modify_wim" ]; then
475 modify_boot_wim "$boot_wim" "$mnt_dir"
478 if [ $make = iso ]; then
479 make_iso_img "$image"
480 elif [ $make = disk ]; then
481 make_disk_img "$image"
484 echo "The image ($image) is $(stat -c %s "$image") bytes."