Skip to content

Instantly share code, notes, and snippets.

@ChaosJohn
Forked from jetfir3/download_fusion.sh
Created July 12, 2025 13:58
Show Gist options
  • Save ChaosJohn/14cfcde4c3d659738919be149bd85d28 to your computer and use it in GitHub Desktop.
Save ChaosJohn/14cfcde4c3d659738919be149bd85d28 to your computer and use it in GitHub Desktop.
Download VMware Fusion Pro Without a Broadcom Account
#!/usr/bin/env bash
# Download VMware Fusion for macOS without Broadcom account
#
# Use '-k' to keep the download file compressed, exiting after download.
# Use '-v VERSION' to specify desired version (13.0.0 or higher required).
BASE_URL="https://softwareupdate-prod.broadcom.com/cds/vmw-desktop"
CDN_MIRROR="softwareupdate-prod.broadcom.com:443:softwareupdate-prod.broadcom.com.cdn.cloudflare.net:443"
read -r -d '' XML_DATA << 'EOF'
<metalist>
<metadata>
<version>13.0.0</version>
<url>fusion/13.0.1/21139760/universal/core/</url>
</metadata>
<metadata>
<version>13.0.0</version>
<url>fusion/13.5.0/22583790/universal/core/</url>
</metadata>
<metadata>
<version>13.0.0</version>
<url>fusion/13.6.0/24238079/universal/core/</url>
</metadata>
<metadata>
<version>13.0.0</version>
<url>fusion/13.6.1/24319021/universal/core/</url>
</metadata>
<metadata>
<version>13.0.0</version>
<url>fusion/13.6.2/24409261/universal/core/</url>
</metadata>
<metadata>
<version>13.0.0</version>
<url>fusion/13.6.3/24585314/universal/core/</url>
</metadata>
<metadata>
<version>13.0.0</version>
<url>fusion/13.5.2/23775688/universal/core/</url>
</metadata>
<metadata>
<version>13.0.0</version>
<url>fusion/13.5.1/23298085/universal/core/</url>
</metadata>
<metadata>
<version>13.0.0</version>
<url>fusion/13.0.2/21581413/universal/core/</url>
</metadata>
<metadata>
<version>13.0.0</version>
<url>fusion/13.0.0/20802013/universal/core/</url>
</metadata>
</metalist>
EOF
KEEP_COMPRESSED=false
USER_VERSION=""
VERSION=""
BUILD=""
while getopts "kv:" opt; do
case $opt in
k) KEEP_COMPRESSED=true ;;
v) USER_VERSION=$OPTARG ;;
*) echo "Usage: $0 [-k] [-v VERSION]" >&2; exit 1 ;;
esac
done
requirements_check() {
command -v curl >/dev/null 2>&1 || { echo "Error: curl is required but not installed." >&2; exit 1; }
command -v grep >/dev/null 2>&1 || { echo "Error: grep is required but not installed." >&2; exit 1; }
command -v awk >/dev/null 2>&1 || { echo "Error: awk is required but not installed." >&2; exit 1; }
command -v sed >/dev/null 2>&1 || { echo "Error: sed is required but not installed." >&2; exit 1; }
command -v tar >/dev/null 2>&1 || { echo "Error: tar is required but not installed." >&2; exit 1; }
command -v sort >/dev/null 2>&1 || { echo "Error: sort is required but not installed." >&2; exit 1; }
command -v unzip >/dev/null 2>&1 || { echo "Error: unzip is required but not installed." >&2; exit 1; }
}
macos_requirements_check() {
(("${OSTYPE:6:2}" < 20)) && { echo "Warning: VMware Fusion v13.0.0+ requires macOS 11 or higher." >&2; return 1; } || return 0
}
requirements_check
if sort --version 2>/dev/null | grep -q "GNU coreutils"; then
SORT_CMD="sort -V"
SORT_UNIQUE_CMD="sort -uV"
else
SORT_CMD="sort -t. -k1,1n -k2,2n -k3,3n -k4,4n"
SORT_UNIQUE_CMD="sort -t. -k1,1n -k2,2n -k3,3n -k4,4n -u"
fi
if [[ $(uname | tr '[:upper:]' '[:lower:]') != "darwin"* ]]; then
KEEP_COMPRESSED=true
echo "Warning: Not running on macOS. Keeping file compressed." >&2
else
macos_requirements_check || { echo "Proceeding with download, but installation may fail due to macOS version." >&2; }
fi
version_gte() {
printf '%s\n%s\n' "$1" "$2" | eval "$SORT_CMD" | head -n 1 | grep -q "^$2$"
}
get_base_versions() {
echo "$XML_DATA" | awk '
BEGIN {FS="[<>]"}
/<version>/ {
if ($3 ~ /^[0-9]+\.0\.0$/) {
print $3;
}
}' | eval "$SORT_UNIQUE_CMD"
}
get_full_versions_and_builds() {
local selected_base_major="$1"
local major_version_prefix=$(echo "$selected_base_major" | cut -d'.' -f1)
echo "$XML_DATA" | awk -v target_major="$major_version_prefix" '
BEGIN {
in_metadata = 0;
current_version_tag = "";
}
/<metadata>/ { in_metadata = 1; current_version_tag = ""; }
/<\/metadata>/ { in_metadata = 0; }
in_metadata && /<version>/ {
current_version_tag = $0;
gsub(/.*<version>|<\/version>.*/, "", current_version_tag);
}
in_metadata && /<url>/ {
url_tag=$0;
gsub(/.*<url>fusion\/|<\/url>.*/, "", url_tag);
split(url_tag, parts, "/");
if (current_version_tag == target_major ".0.0" && parts[1] ~ "^" target_major "\\..*") {
print parts[1], parts[2];
}
}' | eval "$SORT_UNIQUE_CMD"
}
get_specific_version_and_build() {
local target_version="$1"
local target_major_prefix=$(echo "$target_version" | cut -d'.' -f1)
echo "$XML_DATA" | awk -v target_ver="$target_version" -v target_major_prefix_awk="$target_major_prefix" '
BEGIN {
FS="[<>]";
current_version_tag_content = "";
}
/<metadata>/ { current_version_tag_content = ""; }
/<version>/ { current_version_tag_content = $3; }
/<url>/ {
if (current_version_tag_content == target_major_prefix_awk ".0.0") {
split($3, url_parts, "/");
full_version = url_parts[2];
build_number = url_parts[3];
if (full_version == target_ver) {
print full_version, build_number;
exit;
}
}
}'
}
check_url() {
local url=$1
curl -s --head --connect-to "$CDN_MIRROR" "$url" | head -n 1 | grep "200" >/dev/null
}
if [[ -n "$USER_VERSION" ]]; then
version_gte "${USER_VERSION}" "13.0.0" || { echo "Error: Specified version ${USER_VERSION} is not supported. Fusion 13.0.0 or higher is required." >&2; exit 1; }
read -r VERSION BUILD <<< "$(get_specific_version_and_build "$USER_VERSION")"
[[ -z "$VERSION" || -z "$BUILD" ]] && { echo "Error: Version ${USER_VERSION} not found in the embedded XML data or URL format is unexpected." >&2; exit 1; }
else
#echo "Available base versions:"
#mapfile -t base_versions_array < <(get_base_versions)
#[[ ${#base_versions_array[@]} -eq 0 ]] && { echo "No base versions found in XML data. Exiting." >&2; exit 1; }
#PS3="Select a base version: "
#select base_version_selected in "${base_versions_array[@]}"; do
# [[ -n "$base_version_selected" ]] && break || echo "Invalid selection. Please try again."
#done
base_version_selected="13.0.0"
echo "Available versions for base version $base_version_selected:"
full_versions_builds_array=()
while IFS= read -r line; do
full_versions_builds_array+=("$line")
done < <(get_full_versions_and_builds "$base_version_selected")
[[ ${#full_versions_builds_array[@]} -eq 0 ]] && { echo "No full versions found for base version $base_version_selected. Exiting." >&2; exit 1; }
declare -a display_full_versions
for item in "${full_versions_builds_array[@]}"; do
display_full_versions+=("$(echo "$item" | awk '{print $1}')")
done
IFS=$'\n' sorted_display_full_versions=($(printf "%s\n" "${display_full_versions[@]}" | eval "$SORT_CMD"))
unset IFS
PS3="Select a full version: "
select full_version_selected in "${sorted_display_full_versions[@]}"; do
[[ -n "$full_version_selected" ]] && break || echo "Invalid selection. Please try again."
done
for item in "${full_versions_builds_array[@]}"; do
read -r ver build_num <<< "$item"
[[ "$ver" == "$full_version_selected" ]] && { BUILD="$build_num"; break; }
done
[[ -z "$BUILD" ]] && { echo "Error: Could not find build number for version '$full_version_selected'. This can happen if selection is invalid." >&2; exit 1; }
VERSION="$full_version_selected"
fi
echo "Selected version: $VERSION with build: $BUILD"
DOWNLOAD_URL="${BASE_URL}/fusion/${VERSION}/${BUILD}/universal/core/com.vmware.fusion.zip.tar"
DOWNLOAD_DIR="${HOME}/Downloads"
DOWNLOAD_FILE="${DOWNLOAD_DIR}/com.vmware.fusion-${VERSION}-${BUILD}.zip.tar"
UNZIP_DIR="${DOWNLOAD_DIR}/com.vmware.fusion-${VERSION}-${BUILD}"
APP_PATH="${UNZIP_DIR}/VMware Fusion.app"
echo "Downloading VMware Fusion v${VERSION} (${BUILD})..."
mkdir -p "${DOWNLOAD_DIR}"
check_url "$DOWNLOAD_URL" || { echo "Error: Installer file not found at $DOWNLOAD_URL even via CDN. Please check the version/build or XML data." >&2; exit 1; }
curl -k -q --progress-bar -f -o "${DOWNLOAD_FILE}" --connect-to "$CDN_MIRROR" "${DOWNLOAD_URL}" || {
echo "Error: Download failed for ${DOWNLOAD_URL}." >&2
exit 1
}
${KEEP_COMPRESSED} && { echo -e "\nFinished. Downloaded file location: ${DOWNLOAD_FILE}"; exit 0; }
echo "Extracting tar..."
mkdir -p "${UNZIP_DIR}"
tar -xf "${DOWNLOAD_FILE}" -C "${UNZIP_DIR}" || {
echo "Error: Extraction of tar file failed and may be corrupt." >&2
echo "Downloaded file location: ${DOWNLOAD_FILE}" >&2
rm -rf "${UNZIP_DIR}"
exit 1
}
echo "Extracting zip..."
unzip -q "${UNZIP_DIR}/com.vmware.fusion.zip" "payload/VMware Fusion.app/*" -d "${UNZIP_DIR}" || {
echo "Error: Extraction of zip file failed and may be corrupt." >&2
echo "Downloaded file location: ${DOWNLOAD_FILE}" >&2
rm -rf "${UNZIP_DIR}"
exit 1
}
echo "Cleaning up..."
mv "${UNZIP_DIR}/payload/VMware Fusion.app" "${APP_PATH}"
xattr -dr com.apple.quarantine "${APP_PATH}" &>/dev/null
rm -rf "${DOWNLOAD_FILE}" "${UNZIP_DIR}/com.vmware.fusion.zip" "${UNZIP_DIR}/descriptor.xml" "${UNZIP_DIR}/payload" 2>/dev/null
LICENSE_FILES=$(ls -1 "/Library/Preferences/VMware Fusion/license-fusion"* 2>/dev/null)
[[ -n "${LICENSE_FILES}" ]] && {
echo -e "\nNotice: Existing license file(s) found.\nDeletion is required if converting to \"Free for Personal Use\" model.\nTo remove:" >&2
for LICENSE_FILE in ${LICENSE_FILES}; do
echo "sudo rm \"${LICENSE_FILE}\"" >&2
done
}
echo -e "\nFinished. You can now move the app into the desired location.\nVMware Fusion.app location: ${APP_PATH}"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment