-
Notifications
You must be signed in to change notification settings - Fork 13
/
create_vmware_osx_install_dmg.sh
executable file
·302 lines (250 loc) · 11.3 KB
/
create_vmware_osx_install_dmg.sh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
#!/bin/sh
#
# Preparation script for a customized OS X installer for use with VWware Fusion and ESXi
#
# What the script does, in more detail:
#
# 1. Mounts the InstallESD.dmg using a shadow file, so the original DMG is left
# unchanged.
#
# 2. minstallconfig.xml is also copied, which is looked for by the installer environment's
# rc.* files that first load with the system. This allows us to never actually modify the
# BaseSystem.dmg and only drop in these extra files.
#
# 3. Additional installer packages can be added using a first boot package which *must* be named
# First Boot Package Install.pkg, which is added to the OS X install by way of the OSInstall.collection file.
#
# This first boot package can be generated by First Boot Package Install Generator.app, which will
# generate a distribution-style flat package that can be used with OS installs. The instructions
# for using this tool to generate first boot packages are documented here:
# https://github.com/rtrouton/First_Boot_Package_Install_Generator
#
# 4. If desired, a second disk image in .iso format can be generated for use with VMware ESXi
# servers running on Apple hardware.
#
# Original script written by Tim Sutton:
# https://github.com/timsutton/osx-vm-templates/tree/master/prepare_iso
#
# Thanks: (brought over from Tim's original script)
# Idea and much of the implementation thanks to Pepijn Bruienne, who's also provided
# some process notes here: https://gist.github.com/4542016. The sample minstallconfig.xml,
# use of OSInstall.collection and readme documentation provided with Greg Neagle's
# createOSXInstallPkg tool also proved very helpful. (http://code.google.com/p/munki/wiki/InstallingOSX)
#
# User creation via package install method also credited to Greg, and made easy with Per
# Olofsson's CreateUserPkg (http://magervalp.github.io/CreateUserPkg)
#
# Antony Blakey for updates to support OS X 10.11:
# https://github.com/timsutton/osx-vm-templates/issues/40
usage() {
cat <<EOF
Usage:
$(basename "$0") "/path/to/InstallESD.dmg" /path/to/output/directory
$(basename "$0") "/path/to/Install OS X [Name].app" /path/to/output/directory
Description:
Converts an OS X 10.7 and later, or macOS 10.12 and later, installer image to a new image that contains components
used to perform an automated installation. The new image will be named
'OSX_InstallESD_[osversion].dmg.' or macOS_InstallESD_[osversion].dmg.
EOF
}
msg_status() {
echo "\033[0;32m-- $1\033[0m"
}
msg_error() {
echo "\033[0;31m-- $1\033[0m"
}
if [ $# -eq 0 ]; then
usage
exit 1
fi
if [ $(id -u) -ne 0 ]; then
msg_error "This script must be run as root, as it saves a disk image with ownerships enabled."
exit 1
fi
ESD="$1"
if [ ! -e "$ESD" ]; then
msg_error "Input installer image $ESD could not be found! Exiting.."
exit 1
fi
if [ -d "$ESD" ]; then
# we might be an install .app
if [ -e "$ESD/Contents/SharedSupport/InstallESD.dmg" ]; then
ESD="$ESD/Contents/SharedSupport/InstallESD.dmg"
else
msg_error "Can't locate an InstallESD.dmg in this source location $ESD!"
fi
fi
SCRIPT_DIR="$(cd $(dirname "$0"); pwd)"
DEFINITION_DIR="$(cd $SCRIPT_DIR/..; pwd)"
if [ "$2" == "" ]; then
msg_error "Currently an explicit output directory is required as the second argument."
exit 1
else
OUT_DIR="$2"
fi
if [ ! -d "$OUT_DIR" ]; then
msg_status "Destination dir $OUT_DIR doesn't exist, creating.."
mkdir -p "$OUT_DIR"
fi
if [ -e "$ESD.shadow" ]; then
msg_status "Removing old shadow file.."
rm "$ESD.shadow"
fi
# Script will prompt user if they want an additional image in .iso
# format for use with a VMware ESXi server.
echo "Do you also want an ISO disk image for use with VMware ESXi?"
select yn in "Yes" "No"; do
case $yn in
Yes) ISO=1; break;;
No) msg_error "ISO disk image will not be created. Proceeding.."; break;;
esac
done
MNT_ESD=$(/usr/bin/mktemp -d /tmp/vmware-apple-esd.XXXX)
SHADOW_FILE=$(/usr/bin/mktemp /tmp/vmware-apple-shadow.XXXX)
rm "$SHADOW_FILE"
msg_status "Attaching input installer image with shadow file.."
hdiutil attach "$ESD" -mountpoint "$MNT_ESD" -shadow "$SHADOW_FILE" -nobrowse -owners on
if [ $? -ne 0 ]; then
[ ! -e "$ESD" ] && msg_error "Could not find $ESD in $(pwd)"
msg_error "Could not mount $ESD on $MNT_ESD"
exit 1
fi
msg_status "Mounting BaseSystem.."
BASE_SYSTEM_DMG="$MNT_ESD/BaseSystem.dmg"
MNT_BASE_SYSTEM=$(/usr/bin/mktemp -d /tmp/vmware-apple-basesystem.XXXX)
[ ! -e "$BASE_SYSTEM_DMG" ] && msg_error "Could not find BaseSystem.dmg in $MNT_ESD"
hdiutil attach "$BASE_SYSTEM_DMG" -mountpoint "$MNT_BASE_SYSTEM" -nobrowse -owners on
if [ $? -ne 0 ]; then
msg_error "Could not mount $BASE_SYSTEM_DMG on $MNT_BASE_SYSTEM"
exit 1
fi
SYSVER_PLIST_PATH="$MNT_BASE_SYSTEM/System/Library/CoreServices/SystemVersion.plist"
DMG_OS_VERS=$(/usr/libexec/PlistBuddy -c 'Print :ProductVersion' "$SYSVER_PLIST_PATH")
DMG_OS_VERS_MAJOR=$(echo $DMG_OS_VERS | awk -F "." '{print $2}')
DMG_OS_VERS_MINOR=$(echo $DMG_OS_VERS | awk -F "." '{print $3}')
DMG_OS_BUILD=$(/usr/libexec/PlistBuddy -c 'Print :ProductBuildVersion' "$SYSVER_PLIST_PATH")
if [[ $DMG_OS_VERS_MAJOR -ge 12 ]]; then
OSNAME=macOS
else
OSNAME=OSX
fi
msg_status "$OSNAME version detected: 10.$DMG_OS_VERS_MAJOR.$DMG_OS_VERS_MINOR, build $DMG_OS_BUILD"
OUTPUT_DMG="$OUT_DIR/${OSNAME}_InstallESD_${DMG_OS_VERS}_${DMG_OS_BUILD}.dmg"
if [ -e "$OUTPUT_DMG" ]; then
msg_error "Output file $OUTPUT_DMG already exists! We're not going to overwrite it, exiting.."
# hdiutil detach "$MNT_ESD"
hdiutil detach -force "$MNT_ESD"
exit 1
fi
SUPPORT_DIR="$SCRIPT_DIR/support"
# Add First Boot Package Install.pkg to the OS X installer
FIRSTBOOT_PKG="$SUPPORT_DIR/First Boot Package Install.pkg"
if [[ -e "$FIRSTBOOT_PKG" ]]; then
msg_status "$FIRSTBOOT_PKG detected. Proceeding..."
else
msg_error "$FIRSTBOOT_PKG not found! This is needed for the OS to install properly, exiting.."
msg_error "The script is expecting the following:"
msg_error "A. That a first boot installer package is stored in $SUPPORT_DIR."
msg_error "B. That the first boot installer package is named as follows: First Boot Package Install.pkg"
msg_status ""
msg_status "A pre-generated First Boot Package Install.pkg should be stored in $SUPPORT_DIR as a zip file named First_Boot_Package_Install.zip."
msg_status "This first boot package will automatically install all available Apple software updates following the OS installation, but provide no other customization."
msg_status "If you don't want additional customization of the OS installer, just unzip the First_Boot_Package_Install.zip file before running the script."
msg_status ""
msg_status "If you want customization, the first boot package can be generated by First Boot Package Install Generator.app,"
msg_status "which will generate a distribution-style flat package that can be used with $OSNAME installs."
msg_status ""
msg_status "The instructions for using this tool to generate first boot packages are documented here:"
msg_status "https://github.com/rtrouton/First_Boot_Package_Install_Generator"
exit 1
fi
# We'd previously mounted this to check versions
hdiutil detach "$MNT_BASE_SYSTEM"
BASE_SYSTEM_DMG_RW="$(/usr/bin/mktemp /tmp/vmware-apple-basesystem-rw.XXXX).dmg"
msg_status "Creating empty read-write DMG located at $BASE_SYSTEM_DMG_RW.."
hdiutil create -o "$BASE_SYSTEM_DMG_RW" -size 10g -layout SPUD -fs HFS+J
hdiutil attach "$BASE_SYSTEM_DMG_RW" -mountpoint "$MNT_BASE_SYSTEM" -nobrowse -owners on
msg_status "Restoring the BaseSystem to the read-write DMG using asr.."
# This asr restore is needed as of 10.11 DP7 and up. See
# https://github.com/timsutton/osx-vm-templates/issues/40
#
# Note that when the restore completes, the volume is automatically re-mounted
# into /Volumes instead of the previous mountpoint. It is also visible as the
# "-nobrowse" option is not applied.
asr restore --source "$BASE_SYSTEM_DMG" --target "$MNT_BASE_SYSTEM" --noprompt --noverify --erase
# To fix the volume being visible when remounted, check for the new
# volume which is mounted in /Volumes and unmount it.
if [[ -e "/Volumes/OS X Base System" ]]; then
umount "/Volumes/OS X Base System"
elif [[ -e "/Volumes/Mac OS X Base System" ]]; then
umount "/Volumes/Mac OS X Base System"
fi
# Remounting the disk image outside of /Volumes with the '-nobrowse' option.
hdiutil attach "$BASE_SYSTEM_DMG_RW" -mountpoint "$MNT_BASE_SYSTEM" -nobrowse -owners on
if [[ $DMG_OS_VERS_MAJOR -ge 9 ]]; then
BASESYSTEM_OUTPUT_IMAGE="$OUTPUT_DMG"
PACKAGES_DIR="$MNT_BASE_SYSTEM/System/Installation/Packages"
rm "$PACKAGES_DIR"
msg_status "Moving 'Packages' directory from the ESD to BaseSystem.."
mv -v "$MNT_ESD/Packages" "$MNT_BASE_SYSTEM/System/Installation/"
# This isn't strictly required for Mavericks, but Yosemite will consider the
# installer corrupt if this isn't included, because it cannot verify BaseSystem's
# consistency and perform a recovery partition verification
msg_status "Copying in original BaseSystem dmg and chunklist.."
cp "$MNT_ESD/BaseSystem.dmg" "$MNT_BASE_SYSTEM/"
cp "$MNT_ESD/BaseSystem.chunklist" "$MNT_BASE_SYSTEM/"
else
BASESYSTEM_OUTPUT_IMAGE="$MNT_ESD/BaseSystem.dmg"
rm "$BASESYSTEM_OUTPUT_IMAGE"
PACKAGES_DIR="$MNT_ESD/Packages"
fi
# Adding a custom rc.cdrom.local that will automatically erase the VM's
# boot drive. Also adding our auto-setup files: minstallconfig.xml and
# OSInstall.collection
msg_status "Adding automated components.."
CDROM_LOCAL="$MNT_BASE_SYSTEM/private/etc/rc.cdrom.local"
echo "diskutil eraseDisk jhfs+ \"Macintosh HD\" GPTFormat disk0" > "$CDROM_LOCAL"
chmod a+x "$CDROM_LOCAL"
mkdir "$PACKAGES_DIR/Extras"
cp "$SUPPORT_DIR/minstallconfig.xml" "$PACKAGES_DIR/Extras/"
cp "$SUPPORT_DIR/OSInstall.collection" "$PACKAGES_DIR/"
cp -r "$FIRSTBOOT_PKG" "$PACKAGES_DIR/"
rm -rf "$SUPPORT_DIR/tmp"
msg_status "Unmounting BaseSystem.."
hdiutil detach "$MNT_BASE_SYSTEM"
if [ $DMG_OS_VERS_MAJOR -lt 9 ]; then
msg_status "Pre-Mavericks we save back the modified BaseSystem to the root of the ESD."
hdiutil convert -format UDZO -o "$MNT_ESD/BaseSystem.dmg" "$BASE_SYSTEM_DMG_RW"
fi
msg_status "Unmounting.."
hdiutil detach "$MNT_ESD"
msg_status "Converting to .dmg disk image.."
if [[ $DMG_OS_VERS_MAJOR -ge 9 ]]; then
msg_status "On Mavericks and later, the entire modified BaseSystem is our output dmg."
hdiutil convert -format UDZO -o "$OUTPUT_DMG" "$BASE_SYSTEM_DMG_RW"
else
msg_status "Pre-Mavericks we're modifying the original ESD file."
hdiutil convert -format UDZO -o "$OUTPUT_DMG" -shadow "$SHADOW_FILE" "$ESD"
fi
rm -rf "$MNT_ESD" "$SHADOW_FILE" "$BASE_SYSTEM_DMG_RW"
if [[ $ISO = 1 ]]; then
OUTPUT_ISO="$OUT_DIR/${OSNAME}_InstallESD_${DMG_OS_VERS}_${DMG_OS_BUILD}.iso"
msg_status "Converting to .iso disk image...."
/usr/bin/hdiutil convert "$OUTPUT_DMG" -format UDTO -o "$OUTPUT_ISO"
/bin/mv $OUT_DIR/${OSNAME}_InstallESD_${DMG_OS_VERS}_${DMG_OS_BUILD}.iso.cdr "$OUTPUT_ISO"
fi
if [[ -n "$SUDO_UID" ]] && [[ -n "$SUDO_GID" ]]; then
msg_status "Fixing permissions.."
chown -R $SUDO_UID:$SUDO_GID "$OUT_DIR"
fi
msg_status "Checksumming .dmg disk image.."
MD5=$(md5 -q "$OUTPUT_DMG")
msg_status "MD5: $MD5"
msg_status "Built .dmg disk image is located at $OUTPUT_DMG."
if [[ -f "$OUTPUT_ISO" ]]; then
msg_status "Checksumming .iso disk image.."
MD5=$(md5 -q "$OUTPUT_ISO")
msg_status "MD5: $MD5"
msg_status "Built .iso disk image is located at $OUTPUT_ISO."
fi
msg_status "Build process finished."