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."
202 if [ -z "$windows_dir_specified" ]; then
203 for windows_dir in /mnt/windows /mnt/windows7 /mnt/windows8; do
204 if [ -d "$windows_dir"/sources ]; then
209 if [ ! -d "$windows_dir" ]; then
210 if [ -z "$windows_dir_specified" ]; then
212 ERROR: Could not find the directory that the Windows 7 or 8 ISO image is mounted
213 on! Please specify this directory using the --windows-dir option.
216 echo "ERROR: Could not find the directory \"$windows_dir\"!"
220 if [ ! -d "$windows_dir/sources" ]; then
222 ERROR: The directory "$windows_dir" exists, but it seems that the Windows 7 or 8
223 ISO image is not mounted on it. Please mount the image to continue.
229 check_needed_programs() {
230 if [ -z "$waik_dir" -o -n "$modify_wim" ]; then
231 if ! type -P imagex &> /dev/null ; then
233 ERROR: To make a customized image of Windows PE, we need the "imagex" program
234 from WIMLIB so that we can modify the boot.wim file. However, "imagex"
235 doesn't seem to be installed. Please install WIMLIB to continue.
241 if [ $make = iso ]; then
242 if ! type -P mkisofs &> /dev/null ; then
244 ERROR: To make a bootable ISO image of Windows PE, we need the "mkisofs"
245 program, but it doesn't seem to be installed. Please install the "cdrkit"
246 package to continue, or try omitting the --iso option to make a disk image
247 instead of an ISO image.
251 elif [ $make = disk ] ; then
252 if ! type -P syslinux &> /dev/null ; then
254 ERROR: To make a bootable disk image of Windows PE, we need the "syslinux"
255 program, but it doesn't seem to be installed. Please install the "syslinux"
256 package to continue, or try using the --iso option to make an ISO image instead
262 if ! type -P mformat mcopy &> /dev/null; then
264 ERROR: To make a bootable disk image of Windows PE, we need the "mformat" and
265 "mcopy" programs from the "mtools" package. These programs allow us to
266 format a FAT filesystem and copy files to it without needing root privileges.
267 Please install "mtools" if you want to make a disk image of Windows PE. Or,
268 try using the --iso option to make an ISO image instead of a disk image.
273 if [ -n "$waik_dir" ]; then
274 if ! type -P cabextract &> /dev/null ; then
276 ERROR: The boot files in the Windows Automated Installation Kit (WAIK) are
277 inside cabinet archives. To extract these files, we need the "cabextract"
278 program, but it doesn't seem to be installed. Please install "cabextract" to
287 get_primary_boot_files() {
288 if [ -n "$waik_dir" ]; then
289 # Get boot files from the WAIK.
291 stat_busy "Copying primary boot files from the Windows Automated Installation Kit ($waik_dir)"
292 if [ $make = iso ]; then
293 cabextract "$waik_dir"/wAIKX86.msi -F F_WINPE_X86_etfsboot.com -p \
294 > "$tmp_dir"/etfsboot.com || stat_fail
296 cabextract "$waik_dir"/wAIKX86.msi -F F1_BOOTMGR -p \
297 > "$tmp_dir"/bootmgr || stat_fail
298 cabextract "$waik_dir"/wAIKX86.msi -F F_WINPE_X86_boot.sdi -p \
299 > "$tmp_dir"/boot/boot.sdi || stat_fail
300 cabextract "$waik_dir"/wAIKX86.msi -F F_WINPE_X86_bcd -p \
301 > "$tmp_dir"/boot/bcd || stat_fail
304 # Get boot files from the Windows ISO
306 stat_busy "Copying primary boot files from mounted Windows DVD ($windows_dir)"
307 if [ $make = iso ]; then
308 cp "$windows_dir"/boot/etfsboot.com "$tmp_dir" || stat_fail
310 cp "$windows_dir"/bootmgr "$tmp_dir" || stat_fail
311 cp "$windows_dir"/boot/{bcd,boot.sdi} "$tmp_dir"/boot || stat_fail
318 # Copy the WIM over, or export the 2nd image in the WIM in the case of boot.wim
319 # from the Windows DVD.
321 if [ -z "$wim" ]; then
323 # WIM file unspecified- grab it from the WAIK or the Windows DVD
324 if [ -n "$waik_dir" ]; then
326 stat_busy "Extracting boot.wim from \"$waik_dir/WinPE.cab\""
327 cabextract "$waik_dir/WinPE.cab" -F F1_WINPE.WIM -p \
328 > "$boot_wim" 2>/dev/null || stat_fail
333 wim="$windows_dir/sources/boot.wim"
334 stat_busy "Exporting image from \"$wim\""
335 imagex export "$windows_dir"/sources/boot.wim 2 \
336 --boot "$boot_wim" || stat_fail
341 stat_busy "Copying $wim to temporary directory"
342 cp "$wim" "$boot_wim"|| stat_fail
351 # Make modifications to the WIM.
352 stat_busy "Mounting "$1" read-write"
354 mkdir -p "$mnt_dir" || stat_fail
355 imagex mountrw "$boot_wim" "$mnt_dir"|| stat_fail
359 if [ -n "$remove_setup" ]; then
360 stat_busy "Renaming setup.exe to prevent it from bothering us"
361 mv "$mnt_dir"/setup.exe{,.bkup} || stat_fail
362 mv "$mnt_dir"/sources/setup.exe{,.bkup} || stat_fail
366 if [ -n "$start_script" ]; then
367 stat_busy "Setting \"$start_script\" as the script to be executed"\
368 "when Windows PE boots"
369 cp "$start_script" "$mnt_dir"|| stat_fail
370 cat > "$mnt_dir/Windows/System32/winpeshl.ini" << EOF
372 %SYSTEMDRIVE%\\$start_script
377 if [ -n "$overlay" ]; then
378 stat_busy "Overlaying \"$overlay\" on the Windows PE filesystem"
379 cp -r "$overlay"/* "$mnt_dir" || stat_fail
383 stat_busy "Rebuilding WIM with changes made"
384 imagex unmount --commit "$mnt_dir" || stat_fail
393 # Make the ISO using the mkisofs command from cdrkit
395 stat_busy "Making ISO image \"$image\""
397 mkisofs -sysid "" -A "" -V "Microsoft Windows PE (x86)" -d -N \
398 -b etfsboot.com -no-emul-boot -c boot.cat -hide etfsboot.com \
399 -hide boot.cat -quiet -o "$image" "$tmp_dir" || stat_fail
407 stat_busy "Making disk image \"$image\""
409 image_du=$(du -s -b "$tmp_dir" | cut -f 1)
410 image_size=$(( image_du + 10000000 ))
412 mtool_conf="$(mktemp)"
414 dd if=/dev/zero of="$image" count=$(( (image_size + 4095) / 4096)) \
417 cat > "$mtool_conf" << EOF
419 MTOOLS_FAT_COMPATIBILITY=1
424 export MTOOLSRC="$mtool_conf"
426 mformat -h 255 -s 63 -T $(( image_size / 512)) s:
427 mcopy -s "$tmp_dir"/* s:
429 syslinux --install "$image"
430 mcopy /usr/lib/syslinux/chain.c32 s:
431 mcopy - 's:syslinux.cfg' << EOF
435 APPEND ntldr=/bootmgr
442 tmp_dir="$(mktemp -d)"
443 mnt_dir="$tmp_dir"/.boot.wim.mount
444 process_command_line "$@"
445 if [ -z "$waik_dir" ]; then
448 if [ -n "$start_script" -o -n "$overlay" -o -n "$remove_setup" ]; then
451 check_needed_programs
454 if [ $make != wim ]; then
455 mkdir -p "$tmp_dir"/{boot,sources}
456 get_primary_boot_files
459 if [ $make = wim ]; then
462 boot_wim="$tmp_dir"/sources/boot.wim
465 get_boot_wim "$boot_wim"
467 if [ -n "$modify_wim" ]; then
468 modify_boot_wim "$boot_wim" "$mnt_dir"
471 if [ $make = iso ]; then
472 make_iso_img "$image"
473 elif [ $make = disk ]; then
474 make_disk_img "$image"
477 echo "The image ($image) is $(stat -c %s "$image") bytes."