Skip to content

Instantly share code, notes, and snippets.

@janlay
Last active December 20, 2019 03:41
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save janlay/ddcd71990e5176d132cd33cadb2e4a15 to your computer and use it in GitHub Desktop.
Save janlay/ddcd71990e5176d132cd33cadb2e4a15 to your computer and use it in GitHub Desktop.
MSUpdate - manually update your Microsoft apps on macOS
#!/bin/bash
# author: janlay@gmail.com
set -e
SERVICE_URL="https://officecdn.microsoft.com/pr/C1297A47-86C4-4C1F-97FA-950631F94777/MacAutoupdate"
USER_AGENT='Microsoft%20AU%20Daemon/4.13.19071800 CFNetwork/1098 Darwin/19.0.0 (x86_64)'
MS_APPS=(
"Microsoft AutoUpdate:0409MSau04"
"Microsoft Edge Canary:0409EDCN01"
"Microsoft Edge Dev:0409EDDV01"
"Microsoft Edge Beta:0409EDBT01"
"Microsoft Word:0409MSWD2019"
"Microsoft Excel:0409XCEL2019"
"Microsoft PowerPoint:0409PPT32019"
)
function read_xml {
grep "<key>$1</key>" -A1 | tail -n1 | cut -d'>' -f2 | cut -d'<' -f1
}
function update {
echo -n "Fetching URL... "
local url="$(curl -fsSL "$SERVICE_URL/$2.xml" | read_xml 'Location')"
[ -z "$url" ] && return 1
echo -e "Done\nDownloading package..."
local return_code=0
RESULT="$(curl -#fLOw 'HTTP code is %{http_code}' -C - "$url")" || return_code=$?
if [ $return_code -gt 0 ]; then
if [ "${RESULT:(-3)}" = '416' ]; then
echo "Already downloaded. This download is treated as successful."
else
return 0
fi
fi
local restart_app=0
if pgrep "$1" > /dev/null; then
restart_app=1
echo "$1 is running and will be restarted after installing update."
osascript -e "tell app \"$APP_PATH\" to quit"
fi
echo -n "Installing... "
local new_app_path="$(sudo installer -store -package "$(basename "$url")" -target / | grep 'will be installed to' | cut -d' ' -f8-)"
echo "Done"
if [[ -n "$new_app_path" && "$new_app_path" != "$APP_PATH" ]]; then
echo "$1 just installed in different location ($new_app_path) and will be moved to the original directory ($(dirname "$APP_PATH")/)."
sudo mv "$APP_PATH" "$APP_PATH.bak"
sudo mv "$new_app_path" "$APP_PATH"
sudo rm -rf "$APP_PATH.bak"
fi
[ $restart_app -eq 0 ] || open -a "$1"
}
function check_version {
local xml="$(curl -fsSL -H "User-Agent: $USER_AGENT" "$SERVICE_URL/$2-chk.xml")"
local release_date="$(echo "$xml" | read_xml 'Date')"
local new_version="$(echo "$xml" | read_xml 'Update Version')"
local old_version="$(/usr/libexec/PlistBuddy -c 'Print :CFBundleVersion' "$APP_PATH/Contents/Info.plist")"
verlt $old_version $new_version || return 1
echo "New version $new_version released at $release_date"
return 0
}
# Compares versions. See https://stackoverflow.com/a/4024263
function verlte {
[ "$1" = "`echo -e "$1\n$2" | sort -V | head -n1`" ]
}
function verlt {
[ "$1" = "$2" ] && return 1 || verlte $1 $2
}
function main {
local working_dir="$TMPDIR"msupdate
mkdir -p "$working_dir"
cd "$working_dir"
echo MSUpdate is working in $(pwd).
[ "$1" = '-force' ] && echo 'All apps will be forced to install.'
for app in "${MS_APPS[@]}"; do
local app_name="${app%%:*}"
local app_code="${app##*:}"
echo -n "$app_name... "
APP_PATH="$(mdfind "kMDItemFSName == '$app_name.app' && kMDItemKind == 'Application'" | head -n1)"
if [ -z "$APP_PATH" ]; then
echo 'Not installed'
[ "$1" = '-force' ] || continue
fi
if ! check_version "$app_name" "$app_code"; then
echo 'Up to date'
[ "$1" = '-force' ] || continue
fi
update "$app_name" "$app_code"
done
cd - > /dev/null
# Cleaning up...
rm -rf "$working_dir"
}
main "$@"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment