Skip to content

Commit f00431c

Browse files
committed
more preflight checks, NO_CLEANUP; fixes #3
1 parent b68e0d6 commit f00431c

File tree

4 files changed

+163
-50
lines changed

4 files changed

+163
-50
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
# Changes
22

3+
## 1.1.0 - 2025-11-19
4+
5+
1. Additional preflight checks were added to warn if trying to run this script on anything besides macOS (it's only designed and tested there) as well as error if "hdiutil" is missing.
6+
7+
2. The `NO_CLEANUP` environment variable was added to prevent the temporary directory from being removed on error or completion.
8+
39
## 1.0.0 - 2024-10-15
410

511
This is the first actual release. Before this point, windows-esd-to-iso was a rolling repository. All changes here are from the original version.

LICENSE.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
Copyright (c) 2023, 2024 Mattie Behrens.
1+
Copyright (c) 2023, 2024, 2025 Mattie Behrens.
22

33
Permission is hereby granted, free of charge, to any person obtaining
44
a copy of this software and associated documentation files (the
@@ -17,4 +17,4 @@ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
1717
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
1818
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
1919
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20-
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

README.md

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,12 @@ windows-esd-to-iso ESD_FILE
1818

1919
Converts the ESD in ESD_FILE to ISO format.
2020

21+
On completion or on error, this tool removes its temporary directory (which can be large.) If you don't want this, set `NO_CLEANUP` to any value:
22+
23+
```
24+
NO_CLEANUP=1 windows-esd-to-iso ESD_FILE
25+
```
26+
2127
## How it works
2228

2329
[windows-esd-to-iso](./windows-esd-to-iso) will use the wimlib tools to inspect, deconstruct, and assemble into an installation tree the images inside an ESD.
@@ -35,11 +41,7 @@ If the script exits for any reason—successful or otherwise—the temporary dir
3541

3642
## Downloading ESDs
3743

38-
There are a few ways you can get an ESD to convert with this tool.
39-
40-
- [My own download-windows-esd tool](https://github.com/mattieb/download-windows-esd) will get the Windows 11 ESD catalog from Microsoft, then download any ESD you wish that is referenced in that catalog and verify its SHA1 checksum.
41-
- Paul Rockwell's [w11arm_esd2iso](https://communities.vmware.com/t5/VMware-Fusion-Documents/w11arm-esd2iso-a-utility-to-create-Windows-11-ARM-ISOs-from/ta-p/2957381) does both downloading and conversion of ARM images in a single shot.
42-
- Bogdan's [ESD to ISO on macOS](https://gist.github.com/b0gdanw/e36ea84828dbd19e03eff6158f1fc77c) explains how to get and search through the catalog and download manually.
44+
You can use [download-windows-esd](https://github.com/mattieb/download-windows-esd) to get the Windows 11 ESD catalog from Microsoft, then download any ESD you wish that is referenced in that catalog and verify its checksum.
4345

4446
## Converting to USB drives
4547

windows-esd-to-iso

Lines changed: 148 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,18 @@
11
#!/bin/sh
2-
#
3-
# Copyright (c) 2023, 2024 Mattie Behrens.
4-
#
2+
#
3+
# Copyright (c) 2023, 2024, 2025 Mattie Behrens.
4+
#
55
# Permission is hereby granted, free of charge, to any person obtaining
66
# a copy of this software and associated documentation files (the
77
# "Software"), to deal in the Software without restriction, including
88
# without limitation the rights to use, copy, modify, merge, publish,
99
# distribute, sublicense, and/or sell copies of the Software, and to
1010
# permit persons to whom the Software is furnished to do so, subject
1111
# to the following conditions:
12-
#
12+
#
1313
# The above copyright notice and this permission notice shall be
1414
# included in all copies or substantial portions of the Software.
15-
#
15+
#
1616
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
1717
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
1818
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
@@ -22,75 +22,178 @@
2222
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
2323
#
2424

25-
# Color support from portable-color <https://mattiebee.dev/portable-color>
25+
# MARK: color support
26+
# <https://mattiebee.dev/dye>
2627

27-
_try_color() {
28-
[ -n "${NO_COLOR}" ] && return 1
29-
[ -n "${CLICOLOR_FORCE}" ] && return 0
28+
dye_detect() {
29+
command -v tput >/dev/null || return 1
30+
test -n "${NO_COLOR-}" && return 1
31+
test -n "${CLICOLOR_FORCE-}" && return
3032
test -t 1 || return 1
31-
[ -n "${CLICOLOR}" ] && return 0
33+
test -n "${CLICOLOR-}" && return
34+
test "${1-}" = "default-off" && return 1
3235
return 0
3336
}
34-
setup_color() {
35-
TPUT=$(which tput 2>/dev/null) && _try_color || TPUT=true
36-
}
37-
_qtput() {
38-
[ -z "${TPUT}" ] && return 0 # if not set up, don't do anything
39-
"${TPUT}" "$@" 2>/dev/null || true
37+
38+
dye_out() (
39+
_1="$1"
40+
_2="${2-}"
41+
test -n "$1" && shift
42+
test -n "${1-}" && shift
43+
if [ -z "${DYE_COLORS-}" ]; then
44+
printf "%s" "$*"
45+
return
46+
fi
47+
if [ -z "${_2}" ] || [ -z "${1-}" ]; then
48+
eval "tput ${_1}" || true
49+
return
50+
fi
51+
eval "tput ${_1}" || true
52+
printf "%s" "$*"
53+
eval "tput ${_2}" || true
54+
)
55+
56+
dye_color() (
57+
case "$1" in
58+
black) echo 0 ;;
59+
red) echo 1 ;;
60+
green) echo 2 ;;
61+
yellow) echo 3 ;;
62+
blue) echo 4 ;;
63+
magenta) echo 5 ;;
64+
cyan) echo 6 ;;
65+
white | brightgray) echo 7 ;;
66+
gray) echo 8 ;;
67+
bright*)
68+
base="$(dye_color "${1##*bright}")"
69+
echo "$((8 + base))"
70+
;;
71+
'' | *[!0-9]*) return 1 ;;
72+
*) echo "$1" ;;
73+
esac
74+
)
75+
76+
dye_synth() {
77+
if [ "${DYE_COLORS}" = "8" ] && [ "$1" -ge 8 ] && [ "$1" -le 15 ]; then
78+
echo $(($1 - 8))
79+
return 1
80+
fi
81+
echo "$1"
4082
}
41-
_twrap() {
42-
output="$1"
43-
shift
44-
_qtput "$@"
45-
printf %s "$output"
46-
_qtput sgr0
83+
84+
dye() {
85+
if [ "$1" = "setup" ]; then
86+
shift
87+
dye_detect "$@" && DYE_COLORS="$(tput colors)"
88+
return 0
89+
fi
90+
91+
(
92+
_1="$1"
93+
shift
94+
case "${_1}" in
95+
fg)
96+
c="$(dye_color "$1")" || return
97+
c="$(dye_synth "${c}")" || dye_out bold
98+
shift
99+
dye_out "setaf ${c}" "sgr0" "$@"
100+
;;
101+
bg)
102+
c="$(dye_color "$1")" || return
103+
c="$(dye_synth "${c}")" || true
104+
shift
105+
dye_out "setab ${c}" "sgr0" "$@"
106+
;;
107+
dim) dye_out "dim" "sgr0" "$@" ;;
108+
bold) dye_out "bold" "sgr0" "$@" ;;
109+
reverse) dye_out "rev" "sgr0" "$@" ;;
110+
reset) dye_out "sgr0" ;;
111+
i | italic) dye_out "sitm" "ritm" "$@" ;;
112+
so | standout) dye_out "smso" "rmso" "$@" ;;
113+
u | ul | underline) dye_out "smul" "rmul" "$@" ;;
114+
begin) dye "$@" ;;
115+
end)
116+
case "$1" in
117+
i | italic) dye_out "ritm" ;;
118+
so | standout) dye_out "rmso" ;;
119+
u | ul | underline) dye_out "rmul" ;;
120+
*) return 1 ;;
121+
esac
122+
;;
123+
*)
124+
dye fg "${_1}" "$@"
125+
;;
126+
esac
127+
)
47128
}
48-
bold() { _twrap "$1" bold; }
49-
red() { _twrap "$1" setaf 1; }
50-
green() { _twrap "$1" setaf 2; }
51-
blue() { _twrap "$1" setaf 4; }
52129

53-
print_task() { echo "$(green "==>") $(bold "$@")"; }
54-
print_subtask() { echo "$(blue "==>") $(bold "$@")"; }
130+
# MARK: user interface
55131

56-
set -e
57-
setup_color
132+
print_task() { echo "$(dye green "==>") $(dye bold "$*")"; }
133+
print_subtask() { echo "$(dye blue "==>") $(dye bold "$*")"; }
134+
print_error() { echo "$(dye red "Error:") $*"; }
135+
print_warning() { echo "$(dye yellow "Warning:") $*"; }
58136

59-
if [ -z "$1" ] || [ "$1" = "-h" ]; then
60-
echo "$(red "Usage:") $(basename "$0") ESD"
137+
set -eu
138+
139+
dye setup
140+
141+
# MARK: preflight checks
142+
143+
script="$(basename "$0")"
144+
145+
if [ "$(uname)" != "Darwin" ]; then
146+
print_warning "$(dye bold "${script}") is currently for macOS and may not work here"
147+
fi
148+
149+
if [ -z "${1-}" ] || [ "$1" = "-h" ]; then
150+
echo "$(dye red "Usage:") ${script} ESD"
61151
exit 0
62152
fi
63153

64-
check_tool() {
154+
check_wimlib_tool() {
65155
if ! which "$1" >/dev/null; then
66-
echo "$(red "Error:") wimlib tools not found"
156+
print_error "wimlib tools not found"
67157
exit 1
68158
fi
69159
}
70-
check_tool wiminfo
71-
check_tool wimapply
72-
check_tool wimexport
160+
check_wimlib_tool wiminfo
161+
check_wimlib_tool wimapply
162+
check_wimlib_tool wimexport
163+
164+
if ! which hdiutil >/dev/null; then
165+
print_error "hdiutil (a standard macOS tool) not found"
166+
exit 1
167+
fi
73168

74169
esd="$1"
75170

76171
if [ ! -f "${esd}" ]; then
77-
echo "$(red "Error:") ${esd} not found"
172+
print_error "$(dye green "${esd}") not found"
78173
exit 2
79174
fi
80175

176+
# MARK: cleanup exit hook
177+
81178
tmpdir=$(mktemp -d)
82179

83180
__cleanup() {
84-
print_task "Cleaning up $(green "${tmpdir}")"
85-
rm -rf "${tmpdir}"
181+
if [ -z "${NO_CLEANUP-}" ]; then
182+
print_task "Cleaning up $(dye green "${tmpdir}")"
183+
rm -rf "${tmpdir}"
184+
else
185+
print_warning "NO_CLEANUP was set; $(dye green "${tmpdir}") will not be removed"
186+
fi
86187
}
87188
trap __cleanup EXIT
88189

89-
print_task "Exporting images from $(green "${esd}")"
190+
# MARK: export images
191+
192+
print_task "Exporting images from $(dye green "${esd}")"
90193

91194
image_count=$(wiminfo "${esd}" --header | grep '^Image Count' | cut -d= -f 2)
92195
if ! [ "${image_count}" -gt 0 ] 2>/dev/null; then
93-
echo "$(red "Error:") could not get ${esd} image count"
196+
print_error "could not get image count"
94197
exit 3
95198
fi
96199
echo "Found ${image_count} images."
@@ -115,11 +218,13 @@ for index in $(seq 4 "${image_count}"); do
115218
--compress=LZMS --chunk-size 128K --recompress
116219
done
117220

221+
# MARK: create ISO
222+
118223
basename="$(basename "${esd}" .esd)"
119224
iso="${basename}.iso"
120225

121226
rm -f "${iso}"
122-
print_task "Creating ${iso}"
227+
print_task "Creating $(dye green "${iso}")"
123228
hdiutil makehybrid \
124229
-o "${iso}" \
125230
-iso -udf \

0 commit comments

Comments
 (0)