moved global variables and functions, reworked cmd-line argument flow
This commit is contained in:
+371
-376
@@ -46,22 +46,6 @@ SYSTEM_UUID="aabbccddeeff00112233445566778899"
|
|||||||
SYSTEM_INTEGRITY_PROTECTION='10' # '10' - enabled, '77' - disabled
|
SYSTEM_INTEGRITY_PROTECTION='10' # '10' - enabled, '77' - disabled
|
||||||
}
|
}
|
||||||
|
|
||||||
# terminal text colors
|
|
||||||
warning_color="\e[48;2;255;0;0m\e[38;2;255;255;255m" # white on red
|
|
||||||
highlight_color="\e[48;2;0;0;9m\e[38;2;255;255;255m" # white on black
|
|
||||||
low_contrast_color="\e[48;2;0;0;9m\e[38;2;128;128;128m" # grey on black
|
|
||||||
default_color="\033[0m"
|
|
||||||
|
|
||||||
# prints positional parameters in low contrast preceded and followed by newline
|
|
||||||
function print_dimly() {
|
|
||||||
printf "\n${low_contrast_color}$@${default_color}\n"
|
|
||||||
}
|
|
||||||
|
|
||||||
# don't need sleep when we can read!
|
|
||||||
function sleep() {
|
|
||||||
read -t "${1}" >/dev/null 2>&1
|
|
||||||
}
|
|
||||||
|
|
||||||
# welcome message
|
# welcome message
|
||||||
function welcome() {
|
function welcome() {
|
||||||
printf '
|
printf '
|
||||||
@@ -303,9 +287,9 @@ if [ -z "$(dmg2img -d 2>/dev/null)" ]; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# set Apple software update catalog URL according to macOS version
|
# set Apple software update catalog URL according to macOS version
|
||||||
HighSierra_sucatalog='https://swscan.apple.com/content/catalogs/others/index-10.13-10.12-10.11-10.10-10.9-mountainlion-lion-snowleopard-leopard.merged-1.sucatalog'
|
HighSierra_sucatalog='https://swscan.apple.com/content/catalogs/others/index-10.13customerseed-10.12-10.11-10.10-10.9-mountainlion-lion-snowleopard-leopard.merged-1.sucatalog'
|
||||||
Mojave_sucatalog='https://swscan.apple.com/content/catalogs/others/index-10.14-10.13-10.12-10.11-10.10-10.9-mountainlion-lion-snowleopard-leopard.merged-1.sucatalog'
|
Mojave_sucatalog='https://swscan.apple.com/content/catalogs/others/index-10.14customerseed-10.13-10.12-10.11-10.10-10.9-mountainlion-lion-snowleopard-leopard.merged-1.sucatalog'
|
||||||
Catalina_sucatalog='https://swscan.apple.com/content/catalogs/others/index-10.15-10.14-10.13-10.12-10.11-10.10-10.9-mountainlion-lion-snowleopard-leopard.merged-1.sucatalog'
|
Catalina_sucatalog='https://swscan.apple.com/content/catalogs/others/index-10.15customerseed-10.15-10.14-10.13-10.12-10.11-10.10-10.9-mountainlion-lion-snowleopard-leopard.merged-1.sucatalog'
|
||||||
if [[ "${macOS_release_name:0:1}" =~ [Cc] ]]; then
|
if [[ "${macOS_release_name:0:1}" =~ [Cc] ]]; then
|
||||||
macOS_release_name="Catalina"
|
macOS_release_name="Catalina"
|
||||||
CFBundleShortVersionString="10.15"
|
CFBundleShortVersionString="10.15"
|
||||||
@@ -689,11 +673,356 @@ VBoxManage setextradata "${vmname}" \
|
|||||||
"VBoxInternal/Devices/smc/0/Config/GetKeyFromRealSMC" 0
|
"VBoxInternal/Devices/smc/0/Config/GetKeyFromRealSMC" 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function populate_virtual_disks() {
|
||||||
|
print_dimly "stage: populate_virtual_disks"
|
||||||
|
# Attach virtual disk images of the base system, installation, and target
|
||||||
|
# to the virtual machine
|
||||||
|
VBoxManage storagectl macOS --remove --name SATA >/dev/null 2>&1
|
||||||
|
VBoxManage storagectl "${vmname}" --add sata --name SATA --hostiocache on >/dev/null 2>&1
|
||||||
|
VBoxManage storageattach "${vmname}" --storagectl SATA --port 0 \
|
||||||
|
--type hdd --nonrotational on --medium "${vmname}.vdi" >/dev/null 2>&1
|
||||||
|
VBoxManage storageattach "${vmname}" --storagectl SATA --port 1 --hotpluggable on \
|
||||||
|
--type hdd --nonrotational on --medium "Install ${macOS_release_name}.vdi" >/dev/null 2>&1
|
||||||
|
VBoxManage storageattach "${vmname}" --storagectl SATA --port 2 --hotpluggable on \
|
||||||
|
--type hdd --nonrotational on --medium "${macOS_release_name}_BaseSystem.vdi" >/dev/null 2>&1
|
||||||
|
VBoxManage storageattach "${vmname}" --storagectl SATA --port 3 \
|
||||||
|
--type dvddrive --medium "${macOS_release_name}_Installation_files.viso" >/dev/null 2>&1
|
||||||
|
|
||||||
|
echo "Starting virtual machine ${vmname}. This should take a couple of minutes."
|
||||||
|
( VBoxManage startvm "${vmname}" >/dev/null 2>&1 )
|
||||||
|
prompt_lang_utils
|
||||||
|
prompt_terminal_ready
|
||||||
|
print_dimly "Please wait"
|
||||||
|
declare_kscd_key_scancode_dictionary
|
||||||
|
# Assigning "physical" disks from largest to smallest to "${disks[]}" array
|
||||||
|
# Partitining largest disk as APFS
|
||||||
|
# Partition second-largest disk as JHFS+
|
||||||
|
kbstring='disks="$(diskutil list | grep -o "\*[0-9][^ ]* GB *disk[0-9]$" | grep -o "[0-9].*" | sort -gr | grep -o disk[0-9] )" && disks=(${disks[@]}) && '\
|
||||||
|
'diskutil partitionDisk "/dev/${disks[0]}" 1 GPT APFS "'"${vmname}"'" R && '\
|
||||||
|
'diskutil partitionDisk "/dev/${disks[1]}" 1 GPT JHFS+ "Install" R && '
|
||||||
|
send_keys
|
||||||
|
# Create secondary base system on the Install disk
|
||||||
|
# and copy macOS install app files to the app directory
|
||||||
|
kbstring='asr restore --source "/Volumes/'"${macOS_release_name:0:5}-files"'/BaseSystem.dmg" --target /Volumes/Install --erase --noprompt && '\
|
||||||
|
'app_path="$(ls -d "/Volumes/"*"Base System 1/Install"*.app)" && '\
|
||||||
|
'install_path="${app_path}/Contents/SharedSupport/" && '\
|
||||||
|
'mkdir -p "${install_path}" && cd "/Volumes/'"${macOS_release_name:0:5}-files/"'" && '\
|
||||||
|
'cp *.chunklist *.plist *.dmg "${install_path}" && '\
|
||||||
|
'echo "" && echo "Copying the several-GB InstallESD.dmg to the installer app directory" && echo "Please wait" && '\
|
||||||
|
'cat InstallESD.part* > "${install_path}/InstallESD.dmg" && '\
|
||||||
|
'sed -i.bak -e "s/InstallESDDmg\.pkg/InstallESD.dmg/" -e "s/pkg\.InstallESDDmg/dmg.InstallESD/" "${install_path}InstallInfo.plist" && '\
|
||||||
|
'sed -i.bak2 -e "/InstallESD\.dmg/{n;N;N;N;d;}" "${install_path}InstallInfo.plist" && '
|
||||||
|
send_keys
|
||||||
|
# shut down the virtual machine
|
||||||
|
kbstring='shutdown -h now'
|
||||||
|
send_keys
|
||||||
|
send_enter
|
||||||
|
printf 'Partitioning the target virtual disk and the installer virtual disk.
|
||||||
|
Loading base system onto the installer virtual disk. Moving installation
|
||||||
|
files to installer virtual disk, updating InstallInfo.plist, and rebooting the
|
||||||
|
virtual machine.
|
||||||
|
|
||||||
|
The virtual machine may report that disk space is critically low; this is fine.
|
||||||
|
|
||||||
|
When the installer virtual disk is finished being populated, the script will
|
||||||
|
shut down the virtual machine. After shutdown, the initial base system will be
|
||||||
|
detached from the VM and released from VirtualBox.
|
||||||
|
|
||||||
|
'"${highlight_color}"'If the partitioning fails, exit the script by pressing CTRL-C.'"${default_color}"
|
||||||
|
print_dimly "Otherwise, please wait."
|
||||||
|
# Detach the original 2GB BaseSystem.vdi
|
||||||
|
while [[ "$( VBoxManage list runningvms )" =~ ^\""${vmname}" ]]; do sleep 2 >/dev/null 2>&1; done;
|
||||||
|
# Release basesystem vdi from VirtualBox configuration
|
||||||
|
VBoxManage storageattach "${vmname}" --storagectl SATA --port 2 --medium none >/dev/null 2>&1
|
||||||
|
VBoxManage closemedium "${macOS_release_name}_BaseSystem.vdi" >/dev/null 2>&1
|
||||||
|
echo "${macOS_release_name}_BaseSystem.vdi detached from the virtual machine"
|
||||||
|
echo "and released from VirtualBox Manager."
|
||||||
|
}
|
||||||
|
|
||||||
|
function populate_macos_target() {
|
||||||
|
print_dimly "stage: populate_macos_target"
|
||||||
|
if [[ "$( VBoxManage list runningvms )" =~ ^\""${vmname}" ]]; then
|
||||||
|
printf "${highlight_color}"'Please '"${warning_color}"'manually'"${highlight_color}"' shut down the virtual machine and press enter to continue.'"${default_color}"
|
||||||
|
clear_input_buffer_then_read
|
||||||
|
fi
|
||||||
|
VBoxManage storagectl macOS --remove --name SATA >/dev/null 2>&1
|
||||||
|
VBoxManage storagectl "${vmname}" --add sata --name SATA --hostiocache on >/dev/null 2>&1
|
||||||
|
VBoxManage storageattach "${vmname}" --storagectl SATA --port 0 \
|
||||||
|
--type hdd --nonrotational on --medium "${vmname}.vdi" >/dev/null 2>&1
|
||||||
|
VBoxManage storageattach "${vmname}" --storagectl SATA --port 1 --hotpluggable on \
|
||||||
|
--type hdd --nonrotational on --medium "Install ${macOS_release_name}.vdi" >/dev/null 2>&1
|
||||||
|
VBoxManage storageattach "${vmname}" --storagectl SATA --port 2 \
|
||||||
|
--type dvddrive --medium "${macOS_release_name}_Installation_files.viso" >/dev/null 2>&1
|
||||||
|
echo "The VM will boot from the populated installer base system virtual disk."
|
||||||
|
( VBoxManage startvm "${vmname}" >/dev/null 2>&1 )
|
||||||
|
prompt_lang_utils
|
||||||
|
prompt_terminal_ready
|
||||||
|
add_another_terminal
|
||||||
|
echo ""
|
||||||
|
echo "The second open Terminal in the virtual machine copies EFI and NVRAM files"
|
||||||
|
echo "to the target EFI partition when the installer finishes preparing."
|
||||||
|
|
||||||
|
# run script concurrently, catch SIGUSR1 when installer finishes preparing
|
||||||
|
declare_kscd_key_scancode_dictionary
|
||||||
|
kbstring='disks="$(diskutil list | grep -o "[0-9][^ ]* GB *disk[0-9]$" | sort -gr | grep -o disk[0-9])"; '\
|
||||||
|
'disks=(${disks[@]}); '\
|
||||||
|
'printf '"'"'trap "exit 0" SIGUSR1; while true; do sleep 10; done;'"'"' | sh && '\
|
||||||
|
'mkdir -p "/Volumes/'"${vmname}"'/tmp/mount_efi" && '\
|
||||||
|
'mount_msdos /dev/${disks[0]}s1 "/Volumes/'"${vmname}"'/tmp/mount_efi" && '\
|
||||||
|
'mkdir -p "/Volumes/'"${vmname}"'/tmp/mount_efi/EFI/driver/" && '\
|
||||||
|
'mkdir -p "/Volumes/'"${vmname}"'/tmp/mount_efi/EFI/NVRAM/" && '\
|
||||||
|
'cp "/Volumes/'"${macOS_release_name:0:5}-files"'/startup.nsh" "/Volumes/'"${vmname}"'/tmp/mount_efi/startup.nsh" && '\
|
||||||
|
'cp "/Volumes/'"${macOS_release_name:0:5}-files"'/"*.bin "/Volumes/'"${vmname}"'/tmp/mount_efi/EFI/NVRAM/" && '\
|
||||||
|
'[ -a "/Volumes'"${macOS_release_name:0:5}-files"'/ApfsDriverLoader.efi" ] && cp "/Volumes/'"${macOS_release_name:0:5}-files"'/"*.efi "/Volumes/'"${vmname}"'/tmp/mount_efi/EFI/driver/" ; '\
|
||||||
|
'installer_pid=$(ps | grep startosinstall | cut -d '"'"' '"'"' -f 3) && '\
|
||||||
|
'kill -SIGUSR1 ${installer_pid}'
|
||||||
|
send_keys
|
||||||
|
send_enter
|
||||||
|
sleep 1
|
||||||
|
cycle_through_terminal_windows
|
||||||
|
|
||||||
|
# Find background process PID, then
|
||||||
|
# start the installer, send SIGUSR1 to concurrent bash script,
|
||||||
|
# the other script copies files to EFI partition,
|
||||||
|
# then sends SIGUSR1 to the installer which restarts the virtual machine
|
||||||
|
echo ""
|
||||||
|
kbstring='background_pid="$(ps | grep '"'"' sh$'"'"' | cut -d '"'"' '"'"' -f 3)" && '\
|
||||||
|
'app_path="$(ls -d /Install*.app)" && '\
|
||||||
|
'cd "/${app_path}/Contents/Resources/" && '\
|
||||||
|
'./startosinstall --agreetolicense --pidtosignal ${background_pid} --rebootdelay 500 --volume "/Volumes/'"${vmname}"'"'
|
||||||
|
send_keys
|
||||||
|
send_enter
|
||||||
|
if [[ ( "${vbox_version:0:1}" -lt 6 ) || ( "${vbox_version:0:1}" = 6 && "${vbox_version:2:1}" = 0 ) ]]; then
|
||||||
|
printf "${highlight_color}"'When the VM reboots, press enter'"${default_color}"' or alternatively
|
||||||
|
manually detach the virtual storage device "'"Install ${macOS_release_name}.vdi"'"
|
||||||
|
to avoid booting into the installer environment again.'
|
||||||
|
clear_input_buffer_then_read
|
||||||
|
VBoxManage controlvm "${vmname}" poweroff >/dev/null 2>&1
|
||||||
|
for (( i=10; i>5; i-- )); do printf ' \r'"${i}"; sleep 0.5; done
|
||||||
|
VBoxManage storagectl macOS --remove --name SATA >/dev/null 2>&1
|
||||||
|
VBoxManage storagectl "${vmname}" --add sata --name SATA --hostiocache on >/dev/null 2>&1
|
||||||
|
VBoxManage storageattach "${vmname}" --storagectl SATA --port 0 \
|
||||||
|
--type hdd --nonrotational on --medium "${vmname}.vdi"
|
||||||
|
echo ""
|
||||||
|
for (( i=5; i>0; i-- )); do printf ' \r'"${i}"; sleep 0.5; done
|
||||||
|
fi
|
||||||
|
printf '
|
||||||
|
|
||||||
|
For further information, see the documentation with the following command:
|
||||||
|
'"${highlight_color}${0}"' documentation'"${default_color}"'
|
||||||
|
|
||||||
|
'"${highlight_color}"'That'"'"'s it! Enjoy your virtual machine.'"${default_color}"'\n'
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function delete_temporary_files() {
|
||||||
|
print_dimly "stage: delete_temporary_files"
|
||||||
|
if [[ "$( VBoxManage list runningvms )" =~ ^\""${vmname}" ]];
|
||||||
|
then
|
||||||
|
printf 'Temporary files may be deleted when the virtual machine is shut down
|
||||||
|
by running the following command at the script'"'"'s working directory:
|
||||||
|
|
||||||
|
'"${0} delete_temporary_files"'\n'
|
||||||
|
else
|
||||||
|
# detach temporary VDIs and attach the macOS target disk
|
||||||
|
VBoxManage storagectl macOS --remove --name SATA >/dev/null 2>&1
|
||||||
|
VBoxManage storagectl "${vmname}" --add sata --name SATA --hostiocache on >/dev/null 2>&1
|
||||||
|
VBoxManage storageattach "${vmname}" --storagectl SATA --port 0 \
|
||||||
|
--type hdd --nonrotational on --medium "${vmname}.vdi"
|
||||||
|
VBoxManage closemedium "Install ${macOS_release_name}.vdi" >/dev/null 2>&1
|
||||||
|
VBoxManage closemedium "${macOS_release_name}_BaseSystem.vdi" >/dev/null 2>&1
|
||||||
|
printf 'The follwing files are safe to delete:
|
||||||
|
"'"${macOS_release_name}_Apple"*'"
|
||||||
|
"'"${macOS_release_name}_BaseSystem"*'"
|
||||||
|
"'"${macOS_release_name}_Install"*'"
|
||||||
|
"'"Install ${macOS_release_name}.vdi"'"
|
||||||
|
"'"${vmname}_"*".bin"'"
|
||||||
|
"'"${vmname}_startup.nsh"'"\n'
|
||||||
|
if [ -w "ApfsDriverLoader.efi" ]; then
|
||||||
|
printf ' "'"ApfsDriverLoader.efi"'"
|
||||||
|
"'"Apple"*".efi"'"
|
||||||
|
"'"AppleSupport-v2.0.4-RELEASE.zip"'"\n'
|
||||||
|
fi
|
||||||
|
if [ -w "dmg2img.exe" ]; then
|
||||||
|
printf ' "'"dmg2img.exe"'"\n'
|
||||||
|
fi
|
||||||
|
echo ""
|
||||||
|
printf "${warning_color}"'Delete temporary files?'"${default_color}"
|
||||||
|
delete=""
|
||||||
|
read -n 1 -p " [y/N] " delete
|
||||||
|
echo ""
|
||||||
|
if [ "${delete,,}" == "y" ]; then
|
||||||
|
rm "${macOS_release_name}_Apple"* \
|
||||||
|
"${macOS_release_name}_BaseSystem"* \
|
||||||
|
"${macOS_release_name}_Install"* \
|
||||||
|
"Install ${macOS_release_name}.vdi" \
|
||||||
|
"${vmname}_"*".bin" \
|
||||||
|
"${vmname}_startup.nsh" 2>/dev/null
|
||||||
|
rm "ApfsDriverLoader.efi" \
|
||||||
|
"Apple"*".efi" \
|
||||||
|
"AppleSupport-v2.0.4-RELEASE.zip" 2>/dev/null
|
||||||
|
rm "dmg2img.exe" 2>/dev/null
|
||||||
|
fi
|
||||||
|
|
||||||
|
fi
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function documentation() {
|
||||||
|
printf "
|
||||||
|
${highlight_color}NAME${default_color}
|
||||||
|
Semi-automatic installer of macOS on VirtualBox
|
||||||
|
|
||||||
|
${highlight_color}DESCRIPTION${default_color}
|
||||||
|
The script downloads, configures, and installs macOS High Sierra, Mojave,
|
||||||
|
and Catalina on VirtualBox 5.2, 6.0, and 6.1. The script is semi-automatic
|
||||||
|
and requires a little user interaction. A default fresh install only
|
||||||
|
requires the user to sit patiently and, ten times, press enter when prompted.
|
||||||
|
|
||||||
|
${highlight_color}USAGE${default_color}
|
||||||
|
${low_contrast_color}${0} [STAGE]... ${default_color}
|
||||||
|
|
||||||
|
The script is divided into stages. Stage titles may be given as command-line
|
||||||
|
arguments for the script. When the script is run with no command-line
|
||||||
|
arguments, each of the available stages, except \"documentation\", is executed
|
||||||
|
in succession in the order listed:
|
||||||
|
${low_contrast_color}${stages}${default_color}
|
||||||
|
When \"documentation\" is the first command-line argument, only the
|
||||||
|
\"documentation\" stage is executed and all other arguments are ignored.
|
||||||
|
|
||||||
|
The four stages \"check_bash_version\", \"check_gnu_coreutils_prefix\",
|
||||||
|
\"set_variables\", and \"check_dependencies\" are always performed when any stage
|
||||||
|
title other than \"documentation\" is specified first, and if the checks pass
|
||||||
|
then the stages specified in the command-line arguments are performed.
|
||||||
|
|
||||||
|
${highlight_color}EXAMPLES${default_color}
|
||||||
|
${low_contrast_color}${0} configure_vm${default_color}
|
||||||
|
|
||||||
|
The above stage might be used after copying an existing VM VDI to a different
|
||||||
|
VirtualBox installation and having the script automatically configure the VM.
|
||||||
|
|
||||||
|
${low_contrast_color}${0} delete_temporary_files${default_color}
|
||||||
|
|
||||||
|
The above stage might be used when no more virtual machines need to be installed,
|
||||||
|
and the temporary files can be deleted.
|
||||||
|
|
||||||
|
${low_contrast_color}${0} "'\\'"${default_color}
|
||||||
|
${low_contrast_color}configure_vm create_nvram_files create_macos_installation_files_viso${default_color}
|
||||||
|
|
||||||
|
The above stages might be used to update the EFI and NVRAM variables required
|
||||||
|
for iCloud and iMessage connectivity and other Apple-connected apps.
|
||||||
|
|
||||||
|
${highlight_color}iCloud and iMessage connectivity${default_color}
|
||||||
|
iCloud, iMessage, and other connected Apple services require a valid device
|
||||||
|
name and serial number, board ID and serial number, and other genuine
|
||||||
|
(or genuine-like) Apple parameters. These parameters may be edited at the top
|
||||||
|
of the script, accompanied by an explanation. Editing them is not required when
|
||||||
|
installing or running macOS, only when connecting to the iCould app, iMessage,
|
||||||
|
and other apps that authenticate the device with Apple.
|
||||||
|
|
||||||
|
The variables needed to be assigned in the script are the following:
|
||||||
|
|
||||||
|
${low_contrast_color}DmiSystemFamily # Model name
|
||||||
|
DmiSystemProduct # Model identifier
|
||||||
|
DmiSystemSerial # System serial number
|
||||||
|
DmiSystemUuid # Hardware UUID
|
||||||
|
DmiOEMVBoxVer # Apple ROM info (major version)
|
||||||
|
DmiOEMVBoxRev # Apple ROM info (revision)
|
||||||
|
DmiBIOSVersion # Boot ROM version
|
||||||
|
DmiBoardProduct # Main Logic Board identifier
|
||||||
|
DmiBoardSerial # Main Logic Board serial (EFI)
|
||||||
|
MLB # Main Logic Board serial (NVRAM)
|
||||||
|
ROM # ROM identifier (NVRAM)
|
||||||
|
SYSTEM_UUID # System identifier (NVRAM)
|
||||||
|
${default_color}
|
||||||
|
The comments at the top of the script specify how to view these variables
|
||||||
|
on a genuine Mac.
|
||||||
|
|
||||||
|
${highlight_color}Applying the EFI and NVRAM parameters${default_color}
|
||||||
|
The EFI and NVRAM parameters may be set in the script before installation by
|
||||||
|
editing them at the top of the script, and applied after the last step of the
|
||||||
|
installation by resetting the virtual machine and booting into the
|
||||||
|
EFI Internal Shell. When resetting or powering up the VM, immediately press
|
||||||
|
Esc when the VirtualBox logo appears. This boots into the EFI Internal Shell or
|
||||||
|
the boot menu. If the boot menu appears, select \"Boot Manager\" and then
|
||||||
|
\"EFI Internal Shell\" and then allow the startup.nsh script to run
|
||||||
|
automatically, applying the EFI and NVRAM variables before booting macOS.
|
||||||
|
|
||||||
|
${highlight_color}Changing the EFI and NVRAM parameters after installation${default_color}
|
||||||
|
The variables mentioned above may be edited and applied to an existing macOS
|
||||||
|
virtual machine by executing the following command and copying the generated
|
||||||
|
files to the macOS EFI partition:
|
||||||
|
|
||||||
|
${low_contrast_color}${0} "'\\'"${default_color}
|
||||||
|
${low_contrast_color}configure_vm create_nvram_files create_macos_installation_files_viso${default_color}
|
||||||
|
|
||||||
|
After running the command, attach the resulting VISO file to the virtual
|
||||||
|
machine's storage through VirtualBox Manager or VBoxManage. Power up the VM
|
||||||
|
and boot macOS, then start Terminal and execute the following commands, making
|
||||||
|
sure to replace \"/Volumes/path/to/VISO/startup.nsh\" with the correct path:
|
||||||
|
|
||||||
|
${low_contrast_color}mkdir EFI
|
||||||
|
sudo su # this will prompt for a password
|
||||||
|
mount_ntfs /dev/disk0s1 EFI
|
||||||
|
cp /Volumes/path/to/VISO/startup.nsh ./EFI/startup.nsh
|
||||||
|
cp /Volumes/path/to/VISO/*.bin ./EFI/
|
||||||
|
${default_color}
|
||||||
|
After copying the files, boot into the EFI Internal Shell as desribed in the
|
||||||
|
section \"Applying the EFI and NVRAM parameters\".
|
||||||
|
|
||||||
|
${highlight_color}Storage size${default_color}
|
||||||
|
The script by default assigns a target virtual disk storage size of 80GB, which
|
||||||
|
is populated to about 15GB on the host on initial installation. After the
|
||||||
|
installation is complete, the storage size may be increased. First increase the
|
||||||
|
virtual disk image size through VirtualBox Manager or VBoxManage, then in
|
||||||
|
Terminal in the virtual machine run ${low_contrast_color}sudo diskutil repairDisk disk0${default_color}, and then
|
||||||
|
${low_contrast_color}sudo diskutil apfs resizeContainer disk1 0${default_color} or from Disk Utility, after
|
||||||
|
repairing the disk from Terminal, delete the \"Free space\" partition so it allows
|
||||||
|
the system APFS container to take up the available space.
|
||||||
|
|
||||||
|
${highlight_color}Graphics controller${default_color}
|
||||||
|
Selecting the VBoxSVGA controller instead of VBoxVGA for the graphics controller may considerably increase graphics performance.
|
||||||
|
|
||||||
|
${highlight_color}Performance and unsupported features${default_color}
|
||||||
|
Developing and maintaining VirtualBox or macOS features is beyond the scope of
|
||||||
|
this script. Some features may behave unexpectedly, such as USB device support,
|
||||||
|
audio support, and other features.
|
||||||
|
|
||||||
|
After successfully creating a working macOS virtual machine, consider importing
|
||||||
|
it into QEMU/KVM so it can run with hardware passthrough at near-native
|
||||||
|
performance. QEMU/KVM requires additional configuration that is beyond the
|
||||||
|
scope of the script.
|
||||||
|
|
||||||
|
For more information visit the URL:
|
||||||
|
${highlight_color}https://github.com/myspaghetti/macos-guest-virtualbox${default_color}
|
||||||
|
|
||||||
|
"
|
||||||
|
}
|
||||||
|
|
||||||
|
# GLOBAL VARIABLES AND FUNCTIONS THAT MIGHT BE CALLED MORE THAN ONCE
|
||||||
|
|
||||||
|
# terminal text colors
|
||||||
|
warning_color="\e[48;2;255;0;0m\e[38;2;255;255;255m" # white on red
|
||||||
|
highlight_color="\e[48;2;0;0;9m\e[38;2;255;255;255m" # white on black
|
||||||
|
low_contrast_color="\e[48;2;0;0;9m\e[38;2;128;128;128m" # grey on black
|
||||||
|
default_color="\033[0m"
|
||||||
|
|
||||||
|
# prints positional parameters in low contrast preceded and followed by newline
|
||||||
|
function print_dimly() {
|
||||||
|
printf "\n${low_contrast_color}$@${default_color}\n"
|
||||||
|
}
|
||||||
|
|
||||||
|
# don't need sleep when we can read!
|
||||||
|
function sleep() {
|
||||||
|
read -t "${1}" >/dev/null 2>&1
|
||||||
|
}
|
||||||
|
|
||||||
|
function declare_kscd_key_scancode_dictionary() {
|
||||||
# QWERTY-to-scancode dictionary. Hex scancodes, keydown and keyup event.
|
# QWERTY-to-scancode dictionary. Hex scancodes, keydown and keyup event.
|
||||||
# Virtualbox Mac scancodes found here:
|
# Virtualbox Mac scancodes found here:
|
||||||
# https://wiki.osdev.org/PS/2_Keyboard#Scan_Code_Set_1
|
# https://wiki.osdev.org/PS/2_Keyboard#Scan_Code_Set_1
|
||||||
# First half of hex code - press, second half - release, unless otherwise specified
|
# First half of hex code - press, second half - release, unless otherwise specified
|
||||||
declare -A ksc=(
|
declare -A kscd=(
|
||||||
["ESC"]="01 81"
|
["ESC"]="01 81"
|
||||||
["1"]="02 82"
|
["1"]="02 82"
|
||||||
["2"]="03 83"
|
["2"]="03 83"
|
||||||
@@ -827,6 +1156,7 @@ declare -A ksc=(
|
|||||||
[">"]="2A 34 B4 AA"
|
[">"]="2A 34 B4 AA"
|
||||||
["?"]="2A 35 B5 AA"
|
["?"]="2A 35 B5 AA"
|
||||||
)
|
)
|
||||||
|
}
|
||||||
|
|
||||||
function clear_input_buffer_then_read() {
|
function clear_input_buffer_then_read() {
|
||||||
while read -d '' -r -t 0; do read -d '' -t 0.1 -n 10000; break; done
|
while read -d '' -r -t 0; do read -d '' -t 0.1 -n 10000; break; done
|
||||||
@@ -836,7 +1166,7 @@ function clear_input_buffer_then_read() {
|
|||||||
# read variable kbstring and convert string to scancodes and send to guest vm
|
# read variable kbstring and convert string to scancodes and send to guest vm
|
||||||
function send_keys() {
|
function send_keys() {
|
||||||
scancode=$(for (( i=0; i < ${#kbstring}; i++ ));
|
scancode=$(for (( i=0; i < ${#kbstring}; i++ ));
|
||||||
do c[i]=${kbstring:i:1}; echo -n ${ksc[${c[i]}]}" "; done)
|
do c[i]=${kbstring:i:1}; echo -n ${kscd[${c[i]}]}" "; done)
|
||||||
VBoxManage controlvm "${vmname}" keyboardputscancode ${scancode} 1>/dev/null 2>&1
|
VBoxManage controlvm "${vmname}" keyboardputscancode ${scancode} 1>/dev/null 2>&1
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -845,7 +1175,7 @@ function send_keys() {
|
|||||||
function send_special() {
|
function send_special() {
|
||||||
scancode=""
|
scancode=""
|
||||||
for keypress in ${kbspecial}; do
|
for keypress in ${kbspecial}; do
|
||||||
scancode="${scancode}${ksc[${keypress}]}"" "
|
scancode="${scancode}${kscd[${keypress}]}"" "
|
||||||
done
|
done
|
||||||
VBoxManage controlvm "${vmname}" keyboardputscancode ${scancode} 1>/dev/null 2>&1
|
VBoxManage controlvm "${vmname}" keyboardputscancode ${scancode} 1>/dev/null 2>&1
|
||||||
}
|
}
|
||||||
@@ -896,218 +1226,8 @@ function cycle_through_terminal_windows() {
|
|||||||
sleep 1
|
sleep 1
|
||||||
}
|
}
|
||||||
|
|
||||||
function populate_virtual_disks() {
|
# command-line argument processing
|
||||||
print_dimly "stage: populate_virtual_disks"
|
stages='
|
||||||
# Attach virtual disk images of the base system, installation, and target
|
|
||||||
# to the virtual machine
|
|
||||||
VBoxManage storagectl macOS --remove --name SATA >/dev/null 2>&1
|
|
||||||
VBoxManage storagectl "${vmname}" --add sata --name SATA --hostiocache on >/dev/null 2>&1
|
|
||||||
VBoxManage storageattach "${vmname}" --storagectl SATA --port 0 \
|
|
||||||
--type hdd --nonrotational on --medium "${vmname}.vdi" >/dev/null 2>&1
|
|
||||||
VBoxManage storageattach "${vmname}" --storagectl SATA --port 1 --hotpluggable on \
|
|
||||||
--type hdd --nonrotational on --medium "Install ${macOS_release_name}.vdi" >/dev/null 2>&1
|
|
||||||
VBoxManage storageattach "${vmname}" --storagectl SATA --port 2 --hotpluggable on \
|
|
||||||
--type hdd --nonrotational on --medium "${macOS_release_name}_BaseSystem.vdi" >/dev/null 2>&1
|
|
||||||
VBoxManage storageattach "${vmname}" --storagectl SATA --port 3 \
|
|
||||||
--type dvddrive --medium "${macOS_release_name}_Installation_files.viso" >/dev/null 2>&1
|
|
||||||
|
|
||||||
echo "Starting virtual machine ${vmname}. This should take a couple of minutes."
|
|
||||||
( VBoxManage startvm "${vmname}" >/dev/null 2>&1 )
|
|
||||||
prompt_lang_utils
|
|
||||||
prompt_terminal_ready
|
|
||||||
print_dimly "Please wait"
|
|
||||||
# Assigning "physical" disks from largest to smallest to "${disks[]}" array
|
|
||||||
# Partitining largest disk as APFS
|
|
||||||
# Partition second-largest disk as JHFS+
|
|
||||||
kbstring='disks="$(diskutil list | grep -o "\*[0-9][^ ]* GB *disk[0-9]$" | grep -o "[0-9].*" | sort -gr | grep -o disk[0-9] )" && disks=(${disks[@]}) && '\
|
|
||||||
'diskutil partitionDisk "/dev/${disks[0]}" 1 GPT APFS "'"${vmname}"'" R && '\
|
|
||||||
'diskutil partitionDisk "/dev/${disks[1]}" 1 GPT JHFS+ "Install" R && '
|
|
||||||
send_keys
|
|
||||||
# Create secondary base system on the Install disk
|
|
||||||
# and copy macOS install app files to the app directory
|
|
||||||
kbstring='asr restore --source "/Volumes/'"${macOS_release_name:0:5}-files"'/BaseSystem.dmg" --target /Volumes/Install --erase --noprompt && '\
|
|
||||||
'app_path="$(ls -d "/Volumes/"*"Base System 1/Install"*.app)" && '\
|
|
||||||
'install_path="${app_path}/Contents/SharedSupport/" && '\
|
|
||||||
'mkdir -p "${install_path}" && cd "/Volumes/'"${macOS_release_name:0:5}-files/"'" && '\
|
|
||||||
'cp *.chunklist *.plist *.dmg "${install_path}" && '\
|
|
||||||
'echo "" && echo "Copying the several-GB InstallESD.dmg to the installer app directory" && echo "Please wait" && '\
|
|
||||||
'cat InstallESD.part* > "${install_path}/InstallESD.dmg" && '\
|
|
||||||
'sed -i.bak -e "s/InstallESDDmg\.pkg/InstallESD.dmg/" -e "s/pkg\.InstallESDDmg/dmg.InstallESD/" "${install_path}InstallInfo.plist" && '\
|
|
||||||
'sed -i.bak2 -e "/InstallESD\.dmg/{n;N;N;N;d;}" "${install_path}InstallInfo.plist" && '
|
|
||||||
send_keys
|
|
||||||
# shut down the virtual machine
|
|
||||||
kbstring='shutdown -h now'
|
|
||||||
send_keys
|
|
||||||
send_enter
|
|
||||||
printf 'Partitioning the target virtual disk and the installer virtual disk.
|
|
||||||
Loading base system onto the installer virtual disk. Moving installation
|
|
||||||
files to installer virtual disk, updating InstallInfo.plist, and rebooting the
|
|
||||||
virtual machine.
|
|
||||||
|
|
||||||
The virtual machine may report that disk space is critically low; this is fine.
|
|
||||||
|
|
||||||
When the installer virtual disk is finished being populated, the script will
|
|
||||||
shut down the virtual machine. After shutdown, the initial base system will be
|
|
||||||
detached from the VM and released from VirtualBox.
|
|
||||||
|
|
||||||
'"${highlight_color}"'If the partitioning fails, exit the script by pressing CTRL-C.'"${default_color}"
|
|
||||||
print_dimly "Otherwise, please wait."
|
|
||||||
# Detach the original 2GB BaseSystem.vdi
|
|
||||||
while [[ "$( VBoxManage list runningvms )" =~ ^\""${vmname}" ]]; do sleep 2 >/dev/null 2>&1; done;
|
|
||||||
# Release basesystem vdi from VirtualBox configuration
|
|
||||||
VBoxManage storageattach "${vmname}" --storagectl SATA --port 2 --medium none >/dev/null 2>&1
|
|
||||||
VBoxManage closemedium "${macOS_release_name}_BaseSystem.vdi" >/dev/null 2>&1
|
|
||||||
echo "${macOS_release_name}_BaseSystem.vdi detached from the virtual machine"
|
|
||||||
echo "and released from VirtualBox Manager."
|
|
||||||
}
|
|
||||||
|
|
||||||
function populate_macos_target() {
|
|
||||||
print_dimly "stage: populate_macos_target"
|
|
||||||
if [[ "$( VBoxManage list runningvms )" =~ ^\""${vmname}" ]]; then
|
|
||||||
printf "${highlight_color}"'Please '"${warning_color}"'manually'"${highlight_color}"' shut down the virtual machine and press enter to continue.'"${default_color}"
|
|
||||||
clear_input_buffer_then_read
|
|
||||||
fi
|
|
||||||
VBoxManage storagectl macOS --remove --name SATA >/dev/null 2>&1
|
|
||||||
VBoxManage storagectl "${vmname}" --add sata --name SATA --hostiocache on >/dev/null 2>&1
|
|
||||||
VBoxManage storageattach "${vmname}" --storagectl SATA --port 0 \
|
|
||||||
--type hdd --nonrotational on --medium "${vmname}.vdi" >/dev/null 2>&1
|
|
||||||
VBoxManage storageattach "${vmname}" --storagectl SATA --port 1 --hotpluggable on \
|
|
||||||
--type hdd --nonrotational on --medium "Install ${macOS_release_name}.vdi" >/dev/null 2>&1
|
|
||||||
VBoxManage storageattach "${vmname}" --storagectl SATA --port 2 \
|
|
||||||
--type dvddrive --medium "${macOS_release_name}_Installation_files.viso" >/dev/null 2>&1
|
|
||||||
echo "The VM will boot from the populated installer base system virtual disk."
|
|
||||||
( VBoxManage startvm "${vmname}" >/dev/null 2>&1 )
|
|
||||||
prompt_lang_utils
|
|
||||||
prompt_terminal_ready
|
|
||||||
add_another_terminal
|
|
||||||
echo ""
|
|
||||||
echo "The second open Terminal in the virtual machine copies EFI and NVRAM files"
|
|
||||||
echo "to the target EFI partition when the installer finishes preparing."
|
|
||||||
|
|
||||||
# run script concurrently, catch SIGUSR1 when installer finishes preparing
|
|
||||||
kbstring='disks="$(diskutil list | grep -o "[0-9][^ ]* GB *disk[0-9]$" | sort -gr | grep -o disk[0-9])"; '\
|
|
||||||
'disks=(${disks[@]}); '\
|
|
||||||
'printf '"'"'trap "exit 0" SIGUSR1; while true; do sleep 10; done;'"'"' | sh && '\
|
|
||||||
'mkdir -p "/Volumes/'"${vmname}"'/tmp/mount_efi" && '\
|
|
||||||
'mount_msdos /dev/${disks[0]}s1 "/Volumes/'"${vmname}"'/tmp/mount_efi" && '\
|
|
||||||
'mkdir -p "/Volumes/'"${vmname}"'/tmp/mount_efi/EFI/driver/" && '\
|
|
||||||
'mkdir -p "/Volumes/'"${vmname}"'/tmp/mount_efi/EFI/NVRAM/" && '\
|
|
||||||
'cp "/Volumes/'"${macOS_release_name:0:5}-files"'/startup.nsh" "/Volumes/'"${vmname}"'/tmp/mount_efi/startup.nsh" && '\
|
|
||||||
'cp "/Volumes/'"${macOS_release_name:0:5}-files"'/"*.bin "/Volumes/'"${vmname}"'/tmp/mount_efi/EFI/NVRAM/" && '\
|
|
||||||
'[ -a "/Volumes'"${macOS_release_name:0:5}-files"'/ApfsDriverLoader.efi" ] && cp "/Volumes/'"${macOS_release_name:0:5}-files"'/"*.efi "/Volumes/'"${vmname}"'/tmp/mount_efi/EFI/driver/" ; '\
|
|
||||||
'installer_pid=$(ps | grep startosinstall | cut -d '"'"' '"'"' -f 3) && '\
|
|
||||||
'kill -SIGUSR1 ${installer_pid}'
|
|
||||||
send_keys
|
|
||||||
send_enter
|
|
||||||
sleep 1
|
|
||||||
cycle_through_terminal_windows
|
|
||||||
|
|
||||||
# Find background process PID, then
|
|
||||||
# start the installer, send SIGUSR1 to concurrent bash script,
|
|
||||||
# the other script copies files to EFI partition,
|
|
||||||
# then sends SIGUSR1 to the installer which restarts the virtual machine
|
|
||||||
echo ""
|
|
||||||
kbstring='background_pid="$(ps | grep '"'"' sh$'"'"' | cut -d '"'"' '"'"' -f 3)" && '\
|
|
||||||
'app_path="$(ls -d /Install*.app)" && '\
|
|
||||||
'cd "/${app_path}/Contents/Resources/" && '\
|
|
||||||
'./startosinstall --agreetolicense --pidtosignal ${background_pid} --rebootdelay 500 --volume "/Volumes/'"${vmname}"'"'
|
|
||||||
send_keys
|
|
||||||
send_enter
|
|
||||||
if [[ ( "${vbox_version:0:1}" -lt 6 ) || ( "${vbox_version:0:1}" = 6 && "${vbox_version:2:1}" = 0 ) ]]; then
|
|
||||||
printf "${highlight_color}"'When the VM reboots, press enter'"${default_color}"' or alternatively
|
|
||||||
manually detach the virtual storage device "'"Install ${macOS_release_name}.vdi"'"
|
|
||||||
to avoid booting into the installer environment again.'
|
|
||||||
clear_input_buffer_then_read
|
|
||||||
VBoxManage controlvm "${vmname}" poweroff >/dev/null 2>&1
|
|
||||||
for (( i=10; i>5; i-- )); do printf ' \r'"${i}"; sleep 0.5; done
|
|
||||||
VBoxManage storagectl macOS --remove --name SATA >/dev/null 2>&1
|
|
||||||
VBoxManage storagectl "${vmname}" --add sata --name SATA --hostiocache on >/dev/null 2>&1
|
|
||||||
VBoxManage storageattach "${vmname}" --storagectl SATA --port 0 \
|
|
||||||
--type hdd --nonrotational on --medium "${vmname}.vdi"
|
|
||||||
echo ""
|
|
||||||
for (( i=5; i>0; i-- )); do printf ' \r'"${i}"; sleep 0.5; done
|
|
||||||
fi
|
|
||||||
printf '
|
|
||||||
|
|
||||||
For further information, see the documentation with the following command:
|
|
||||||
'"${highlight_color}${0}"' documentation'"${default_color}"'
|
|
||||||
|
|
||||||
'"${highlight_color}"'That'"'"'s it! Enjoy your virtual machine.'"${default_color}"'\n'
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
function delete_temporary_files() {
|
|
||||||
print_dimly "stage: delete_temporary_files"
|
|
||||||
if [[ "$( VBoxManage list runningvms )" =~ ^\""${vmname}" ]];
|
|
||||||
then
|
|
||||||
printf 'Temporary files may be deleted when the virtual machine is shut down
|
|
||||||
by running the following command at the script'"'"'s working directory:
|
|
||||||
|
|
||||||
'"${0} delete_temporary_files"'\n'
|
|
||||||
else
|
|
||||||
# detach temporary VDIs and attach the macOS target disk
|
|
||||||
VBoxManage storagectl macOS --remove --name SATA >/dev/null 2>&1
|
|
||||||
VBoxManage storagectl "${vmname}" --add sata --name SATA --hostiocache on >/dev/null 2>&1
|
|
||||||
VBoxManage storageattach "${vmname}" --storagectl SATA --port 0 \
|
|
||||||
--type hdd --nonrotational on --medium "${vmname}.vdi"
|
|
||||||
VBoxManage closemedium "Install ${macOS_release_name}.vdi" >/dev/null 2>&1
|
|
||||||
VBoxManage closemedium "${macOS_release_name}_BaseSystem.vdi" >/dev/null 2>&1
|
|
||||||
printf 'The follwing files are safe to delete:
|
|
||||||
"'"${macOS_release_name}_Apple"*'"
|
|
||||||
"'"${macOS_release_name}_BaseSystem"*'"
|
|
||||||
"'"${macOS_release_name}_Install"*'"
|
|
||||||
"'"Install ${macOS_release_name}.vdi"'"
|
|
||||||
"'"${vmname}_"*".bin"'"
|
|
||||||
"'"${vmname}_startup.nsh"'"\n'
|
|
||||||
if [ -w "ApfsDriverLoader.efi" ]; then
|
|
||||||
printf ' "'"ApfsDriverLoader.efi"'"
|
|
||||||
"'"Apple"*".efi"'"
|
|
||||||
"'"AppleSupport-v2.0.4-RELEASE.zip"'"\n'
|
|
||||||
fi
|
|
||||||
if [ -w "dmg2img.exe" ]; then
|
|
||||||
printf ' "'"dmg2img.exe"'"\n'
|
|
||||||
fi
|
|
||||||
echo ""
|
|
||||||
printf "${warning_color}"'Delete temporary files?'"${default_color}"
|
|
||||||
delete=""
|
|
||||||
read -n 1 -p " [y/N] " delete
|
|
||||||
echo ""
|
|
||||||
if [ "${delete,,}" == "y" ]; then
|
|
||||||
rm "${macOS_release_name}_Apple"* \
|
|
||||||
"${macOS_release_name}_BaseSystem"* \
|
|
||||||
"${macOS_release_name}_Install"* \
|
|
||||||
"Install ${macOS_release_name}.vdi" \
|
|
||||||
"${vmname}_"*".bin" \
|
|
||||||
"${vmname}_startup.nsh" 2>/dev/null
|
|
||||||
rm "ApfsDriverLoader.efi" \
|
|
||||||
"Apple"*".efi" \
|
|
||||||
"AppleSupport-v2.0.4-RELEASE.zip" 2>/dev/null
|
|
||||||
rm "dmg2img.exe" 2>/dev/null
|
|
||||||
fi
|
|
||||||
|
|
||||||
fi
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
function documentation() {
|
|
||||||
printf "
|
|
||||||
${highlight_color}NAME${default_color}
|
|
||||||
Semi-automatic installer of macOS on VirtualBox
|
|
||||||
|
|
||||||
${highlight_color}DESCRIPTION${default_color}
|
|
||||||
The script downloads, configures, and installs macOS High Sierra, Mojave,
|
|
||||||
and Catalina on VirtualBox 5.2, 6.0, and 6.1. The script is semi-automatic
|
|
||||||
and requires a little user interaction. A default fresh install only
|
|
||||||
requires the user to sit patiently and, ten times, press enter when prompted.
|
|
||||||
|
|
||||||
${highlight_color}USAGE${default_color}
|
|
||||||
${low_contrast_color}${0} [STAGE]... ${default_color}
|
|
||||||
|
|
||||||
The script is divided into stages. Stage titles may be given as command-line
|
|
||||||
arguments for the script. When the script is run with no command-line
|
|
||||||
arguments, each of the available stages, except \"documentation\", is executed
|
|
||||||
in succession in the order listed:
|
|
||||||
${low_contrast_color}
|
|
||||||
check_bash_version
|
check_bash_version
|
||||||
check_gnu_coreutils_prefix
|
check_gnu_coreutils_prefix
|
||||||
set_variables
|
set_variables
|
||||||
@@ -1125,145 +1245,20 @@ ${low_contrast_color}
|
|||||||
populate_virtual_disks
|
populate_virtual_disks
|
||||||
populate_macos_target
|
populate_macos_target
|
||||||
delete_temporary_files
|
delete_temporary_files
|
||||||
${default_color}
|
'
|
||||||
When \"documentation\" is the first command-line argument, only the
|
# every stage name must be preceded and followed by a space character
|
||||||
\"documentation\" stage is executed and all other arguments are ignored.
|
# for the command-line argument checking below to work
|
||||||
|
[ -z "${1}" ] && for stage in ${stages}; do ${stage}; done && exit
|
||||||
The four stages \"check_bash_version\", \"check_gnu_coreutils_prefix\",
|
[ "${1}" = "documentation" ] && documentation && exit
|
||||||
\"set_variables\", and \"check_dependencies\" are always performed when any stage
|
for argument in $@; do
|
||||||
title other than \"documentation\" is specified first, and only after the checks
|
[[ "${stages}" != *" ${argument} "* ]] &&
|
||||||
pass the stages specified in the command-line arguments are performed.
|
echo "Can't parse one or more specified arguments. See documentation" &&
|
||||||
|
echo "by entering the following command:" &&
|
||||||
${highlight_color}EXAMPLES${default_color}
|
echo " ${0} documentation" &&
|
||||||
${low_contrast_color}${0} configure_vm${default_color}
|
exit
|
||||||
|
done
|
||||||
The above stage might be used after copying an existing VM VDI to a different
|
check_bash_version
|
||||||
VirtualBox installation and having the script automatically configure the VM.
|
check_gnu_coreutils_prefix
|
||||||
|
set_variables
|
||||||
${low_contrast_color}${0} delete_temporary_files${default_color}
|
check_dependencies
|
||||||
|
for argument in "$@"; do ${argument}; done
|
||||||
The above stage might be used when no more virtual machines need to be installed,
|
|
||||||
and the temporary files can be deleted.
|
|
||||||
|
|
||||||
${low_contrast_color}${0} "'\\'"${default_color}
|
|
||||||
${low_contrast_color}configure_vm create_nvram_files create_macos_installation_files_viso${default_color}
|
|
||||||
|
|
||||||
The above stages might be used to update the EFI and NVRAM variables required
|
|
||||||
for iCloud and iMessage connectivity and other Apple-connected apps.
|
|
||||||
|
|
||||||
${highlight_color}iCloud and iMessage connectivity${default_color}
|
|
||||||
iCloud, iMessage, and other connected Apple services require a valid device
|
|
||||||
name and serial number, board ID and serial number, and other genuine
|
|
||||||
(or genuine-like) Apple parameters. These parameters may be edited at the top
|
|
||||||
of the script, accompanied by an explanation. Editing them is not required when
|
|
||||||
installing or running macOS, only when connecting to the iCould app, iMessage,
|
|
||||||
and other apps that authenticate the device with Apple.
|
|
||||||
|
|
||||||
The variables needed to be assigned in the script are the following:
|
|
||||||
|
|
||||||
${low_contrast_color}DmiSystemFamily # Model name
|
|
||||||
DmiSystemProduct # Model identifier
|
|
||||||
DmiSystemSerial # System serial number
|
|
||||||
DmiSystemUuid # Hardware UUID
|
|
||||||
DmiOEMVBoxVer # Apple ROM info (major version)
|
|
||||||
DmiOEMVBoxRev # Apple ROM info (revision)
|
|
||||||
DmiBIOSVersion # Boot ROM version
|
|
||||||
DmiBoardProduct # Main Logic Board identifier
|
|
||||||
DmiBoardSerial # Main Logic Board serial (EFI)
|
|
||||||
MLB # Main Logic Board serial (NVRAM)
|
|
||||||
ROM # ROM identifier (NVRAM)
|
|
||||||
SYSTEM_UUID # System identifier (NVRAM)
|
|
||||||
${default_color}
|
|
||||||
The comments at the top of the script specify how to view these variables
|
|
||||||
on a genuine Mac.
|
|
||||||
|
|
||||||
${highlight_color}Applying the EFI and NVRAM parameters${default_color}
|
|
||||||
The EFI and NVRAM parameters may be set in the script before installation by
|
|
||||||
editing them at the top of the script, and applied after the last step of the
|
|
||||||
installation by resetting the virtual machine and booting into the
|
|
||||||
EFI Internal Shell. When resetting or powering up the VM, immediately press
|
|
||||||
Esc when the VirtualBox logo appears. This boots into the EFI Internal Shell or
|
|
||||||
the boot menu. If the boot menu appears, select \"Boot Manager\" and then
|
|
||||||
\"EFI Internal Shell\" and then allow the startup.nsh script to run
|
|
||||||
automatically, applying the EFI and NVRAM variables before booting macOS.
|
|
||||||
|
|
||||||
${highlight_color}Changing the EFI and NVRAM parameters after installation${default_color}
|
|
||||||
The variables mentioned above may be edited and applied to an existing macOS
|
|
||||||
virtual machine by executing the following command and copying the generated
|
|
||||||
files to the macOS EFI partition:
|
|
||||||
|
|
||||||
${low_contrast_color}${0} "'\\'"${default_color}
|
|
||||||
${low_contrast_color}configure_vm create_nvram_files create_macos_installation_files_viso${default_color}
|
|
||||||
|
|
||||||
After running the command, attach the resulting VISO file to the virtual
|
|
||||||
machine's storage through VirtualBox Manager or VBoxManage. Power up the VM
|
|
||||||
and boot macOS, then start Terminal and execute the following commands, making
|
|
||||||
sure to replace \"/Volumes/path/to/VISO/startup.nsh\" with the correct path:
|
|
||||||
|
|
||||||
${low_contrast_color}mkdir EFI
|
|
||||||
sudo su # this will prompt for a password
|
|
||||||
mount_ntfs /dev/disk0s1 EFI
|
|
||||||
cp /Volumes/path/to/VISO/startup.nsh ./EFI/startup.nsh
|
|
||||||
cp /Volumes/path/to/VISO/*.bin ./EFI/
|
|
||||||
${default_color}
|
|
||||||
After copying the files, boot into the EFI Internal Shell as desribed in the
|
|
||||||
section \"Applying the EFI and NVRAM parameters\".
|
|
||||||
|
|
||||||
${highlight_color}Storage size${default_color}
|
|
||||||
The script by default assigns a target virtual disk storage size of 80GB, which
|
|
||||||
is populated to about 15GB on the host on initial installation. After the
|
|
||||||
installation is complete, the storage size may be increased. First increase the
|
|
||||||
virtual disk image size through VirtualBox Manager or VBoxManage, then in
|
|
||||||
Terminal in the virtual machine run ${low_contrast_color}sudo diskutil repairDisk disk0${default_color}, and then
|
|
||||||
${low_contrast_color}sudo diskutil apfs resizeContainer disk1 0${default_color} or from Disk Utility, after
|
|
||||||
repairing the disk from Terminal, delete the \"Free space\" partition so it allows
|
|
||||||
the system APFS container to take up the available space.
|
|
||||||
|
|
||||||
${highlight_color}Graphics controller${default_color}
|
|
||||||
Selecting the VBoxSVGA controller instead of VBoxVGA for the graphics controller may considerably increase graphics performance.
|
|
||||||
|
|
||||||
${highlight_color}Performance and unsupported features${default_color}
|
|
||||||
Developing and maintaining VirtualBox or macOS features is beyond the scope of
|
|
||||||
this script. Some features may behave unexpectedly, such as USB device support,
|
|
||||||
audio support, and other features.
|
|
||||||
|
|
||||||
After successfully creating a working macOS virtual machine, consider importing
|
|
||||||
it into QEMU/KVM so it can run with hardware passthrough at near-native
|
|
||||||
performance. QEMU/KVM requires additional configuration that is beyond the
|
|
||||||
scope of the script.
|
|
||||||
|
|
||||||
For more information visit the URL:
|
|
||||||
${highlight_color}https://github.com/myspaghetti/macos-guest-virtualbox${default_color}
|
|
||||||
|
|
||||||
"
|
|
||||||
}
|
|
||||||
|
|
||||||
if [ -z "${1}" ]; then
|
|
||||||
check_bash_version
|
|
||||||
check_gnu_coreutils_prefix
|
|
||||||
set_variables
|
|
||||||
welcome
|
|
||||||
check_dependencies
|
|
||||||
prompt_delete_existing_vm
|
|
||||||
create_vm
|
|
||||||
prepare_macos_installation_files
|
|
||||||
create_nvram_files
|
|
||||||
create_macos_installation_files_viso
|
|
||||||
create_basesystem_vdi
|
|
||||||
create_target_vdi
|
|
||||||
create_install_vdi
|
|
||||||
configure_vm
|
|
||||||
populate_virtual_disks
|
|
||||||
populate_macos_target
|
|
||||||
delete_temporary_files
|
|
||||||
else
|
|
||||||
if [ "${1}" != "documentation" ]; then
|
|
||||||
check_bash_version
|
|
||||||
check_gnu_coreutils_prefix
|
|
||||||
set_variables
|
|
||||||
check_dependencies
|
|
||||||
for argument in "$@"; do ${argument}; done
|
|
||||||
else
|
|
||||||
documentation
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|||||||
Reference in New Issue
Block a user