mirror of
https://github.com/mtan93/Installomator.git
synced 2026-03-08 05:31:53 +00:00
Merge branch 'argument-refactor' into dev
This commit is contained in:
709
Installomator.sh
709
Installomator.sh
@@ -113,9 +113,54 @@ BLOCKING_PROCESS_ACTION=prompt_user
|
|||||||
#
|
#
|
||||||
|
|
||||||
|
|
||||||
# MARK: functions to help with getting data
|
# MARK: Functions
|
||||||
|
|
||||||
# Logging
|
cleanupAndExit() { # $1 = exit code, $2 message
|
||||||
|
if [[ -n $2 && $1 -ne 0 ]]; then
|
||||||
|
printlog "ERROR: $2"
|
||||||
|
fi
|
||||||
|
if [ "$DEBUG" -eq 0 ]; then
|
||||||
|
# remove the temporary working directory when done
|
||||||
|
printlog "Deleting $tmpDir"
|
||||||
|
rm -Rf "$tmpDir"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -n "$dmgmount" ]; then
|
||||||
|
# unmount disk image
|
||||||
|
printlog "Unmounting $dmgmount"
|
||||||
|
hdiutil detach "$dmgmount"
|
||||||
|
fi
|
||||||
|
printlog "################## End Installomator \n\n"
|
||||||
|
exit "$1"
|
||||||
|
}
|
||||||
|
|
||||||
|
runAsUser() {
|
||||||
|
if [[ $currentUser != "loginwindow" ]]; then
|
||||||
|
uid=$(id -u "$currentUser")
|
||||||
|
launchctl asuser $uid sudo -u $currentUser "$@"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
displaydialog() { # $1: message $2: title
|
||||||
|
message=${1:-"Message"}
|
||||||
|
title=${2:-"Installomator"}
|
||||||
|
runAsUser osascript -e "button returned of (display dialog \"$message\" with title \"$title\" buttons {\"Not Now\", \"Quit and Update\"} default button \"Quit and Update\")"
|
||||||
|
}
|
||||||
|
|
||||||
|
displaynotification() { # $1: message $2: title
|
||||||
|
message=${1:-"Message"}
|
||||||
|
title=${2:-"Notification"}
|
||||||
|
manageaction="/Library/Application Support/JAMF/bin/Management Action.app/Contents/MacOS/Management Action"
|
||||||
|
|
||||||
|
if [[ -x "$manageaction" ]]; then
|
||||||
|
"$manageaction" -message "$message" -title "$title"
|
||||||
|
else
|
||||||
|
runAsUser osascript -e "display notification \"$message\" with title \"$title\""
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# MARK: Logging
|
||||||
log_location="/private/var/log/Installomator.log"
|
log_location="/private/var/log/Installomator.log"
|
||||||
|
|
||||||
printlog(){
|
printlog(){
|
||||||
@@ -159,6 +204,291 @@ downloadURLFromGit() { # $1 git user name, $2 git repo name
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
getAppVersion() {
|
||||||
|
# get all apps matching name
|
||||||
|
applist=$(mdfind "kind:application $appName" -0 )
|
||||||
|
if [[ $applist = "" ]]; then
|
||||||
|
printlog "Spotlight not returning any app, trying manually in /Applications."
|
||||||
|
if [[ -d "/Applications/$appName" ]]; then
|
||||||
|
applist="/Applications/$appName"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
appPathArray=( ${(0)applist} )
|
||||||
|
|
||||||
|
if [[ ${#appPathArray} -gt 0 ]]; then
|
||||||
|
filteredAppPaths=( ${(M)appPathArray:#${targetDir}*} )
|
||||||
|
if [[ ${#filteredAppPaths} -eq 1 ]]; then
|
||||||
|
installedAppPath=$filteredAppPaths[1]
|
||||||
|
appversion=$(mdls -name kMDItemVersion -raw $installedAppPath )
|
||||||
|
printlog "found app at $installedAppPath, version $appversion"
|
||||||
|
else
|
||||||
|
printlog "could not determine location of $appName"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
printlog "could not find $appName"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
checkRunningProcesses() {
|
||||||
|
# don't check in DEBUG mode
|
||||||
|
if [[ $DEBUG -ne 0 ]]; then
|
||||||
|
printlog "DEBUG mode, not checking for blocking processes"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
# try at most 3 times
|
||||||
|
for i in {1..3}; do
|
||||||
|
countedProcesses=0
|
||||||
|
for x in ${blockingProcesses}; do
|
||||||
|
if pgrep -xq "$x"; then
|
||||||
|
printlog "found blocking process $x"
|
||||||
|
|
||||||
|
case $BLOCKING_PROCESS_ACTION in
|
||||||
|
kill)
|
||||||
|
printlog "killing process $x"
|
||||||
|
pkill $x
|
||||||
|
;;
|
||||||
|
prompt_user)
|
||||||
|
button=$(displaydialog "Quit “$x” to continue updating? (Leave this dialogue if you want to activate this update later)." "The application “$x” needs to be updated.")
|
||||||
|
if [[ $button = "Not Now" ]]; then
|
||||||
|
cleanupAndExit 10 "user aborted update"
|
||||||
|
else
|
||||||
|
runAsUser osascript -e "tell app \"$x\" to quit"
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
silent_fail)
|
||||||
|
cleanupAndExit 12 "blocking process '$x' found, aborting"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
countedProcesses=$((countedProcesses + 1))
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
if [[ $countedProcesses -eq 0 ]]; then
|
||||||
|
# no blocking processes, exit the loop early
|
||||||
|
break
|
||||||
|
else
|
||||||
|
# give the user a bit of time to quit apps
|
||||||
|
printlog "waiting 30 seconds for processes to quit"
|
||||||
|
sleep 30
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
if [[ $countedProcesses -ne 0 ]]; then
|
||||||
|
cleanupAndExit 11 "could not quit all processes, aborting..."
|
||||||
|
fi
|
||||||
|
|
||||||
|
printlog "no more blocking processes, continue with update"
|
||||||
|
}
|
||||||
|
|
||||||
|
installAppWithPath() { # $1: path to app to install in $targetDir
|
||||||
|
appPath=${1?:"no path to app"}
|
||||||
|
|
||||||
|
# check if app exists
|
||||||
|
if [ ! -e "$appPath" ]; then
|
||||||
|
cleanupAndExit 8 "could not find: $appPath"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# verify with spctl
|
||||||
|
printlog "Verifying: $appPath"
|
||||||
|
if ! teamID=$(spctl -a -vv "$appPath" 2>&1 | awk '/origin=/ {print $NF }' | tr -d '()' ); then
|
||||||
|
cleanupAndExit 4 "Error verifying $appPath"
|
||||||
|
fi
|
||||||
|
|
||||||
|
printlog "Team ID: $teamID (expected: $expectedTeamID )"
|
||||||
|
|
||||||
|
if [ "$expectedTeamID" != "$teamID" ]; then
|
||||||
|
cleanupAndExit 5 "Team IDs do not match"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# check for root
|
||||||
|
if [ "$(whoami)" != "root" ]; then
|
||||||
|
# not running as root
|
||||||
|
if [ "$DEBUG" -eq 0 ]; then
|
||||||
|
cleanupAndExit 6 "not running as root, exiting"
|
||||||
|
fi
|
||||||
|
|
||||||
|
printlog "DEBUG enabled, skipping copy and chown steps"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# remove existing application
|
||||||
|
if [ -e "$targetDir/$appName" ]; then
|
||||||
|
printlog "Removing existing $targetDir/$appName"
|
||||||
|
rm -Rf "$targetDir/$appName"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# copy app to /Applications
|
||||||
|
printlog "Copy $appPath to $targetDir"
|
||||||
|
if ! ditto "$appPath" "$targetDir/$appName"; then
|
||||||
|
cleanupAndExit 7 "Error while copying"
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
# set ownership to current user
|
||||||
|
if [ "$currentUser" != "loginwindow" ]; then
|
||||||
|
printlog "Changing owner to $currentUser"
|
||||||
|
chown -R "$currentUser" "$targetDir/$appName"
|
||||||
|
else
|
||||||
|
printlog "No user logged in, not changing user"
|
||||||
|
fi
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
mountDMG() {
|
||||||
|
# mount the dmg
|
||||||
|
printlog "Mounting $tmpDir/$archiveName"
|
||||||
|
# always pipe 'Y\n' in case the dmg requires an agreement
|
||||||
|
if ! dmgmount=$(echo 'Y'$'\n' | hdiutil attach "$tmpDir/$archiveName" -nobrowse -readonly | tail -n 1 | cut -c 54- ); then
|
||||||
|
cleanupAndExit 3 "Error mounting $tmpDir/$archiveName"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ ! -e $dmgmount ]]; then
|
||||||
|
printlog "Error mounting $tmpDir/$archiveName"
|
||||||
|
cleanupAndExit 3
|
||||||
|
fi
|
||||||
|
|
||||||
|
printlog "Mounted: $dmgmount"
|
||||||
|
}
|
||||||
|
|
||||||
|
installFromDMG() {
|
||||||
|
mountDMG
|
||||||
|
|
||||||
|
installAppWithPath "$dmgmount/$appName"
|
||||||
|
}
|
||||||
|
|
||||||
|
installFromPKG() {
|
||||||
|
# verify with spctl
|
||||||
|
printlog "Verifying: $archiveName"
|
||||||
|
|
||||||
|
if ! spctlout=$(spctl -a -vv -t install "$archiveName" 2>&1 ); then
|
||||||
|
printlog "Error verifying $archiveName"
|
||||||
|
cleanupAndExit 4
|
||||||
|
fi
|
||||||
|
|
||||||
|
teamID=$(echo $spctlout | awk -F '(' '/origin=/ {print $2 }' | tr -d '()' )
|
||||||
|
|
||||||
|
# Apple signed software has no teamID, grab entire origin instead
|
||||||
|
if [[ -z $teamID ]]; then
|
||||||
|
teamID=$(echo $spctlout | awk -F '=' '/origin=/ {print $NF }')
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
printlog "Team ID: $teamID (expected: $expectedTeamID )"
|
||||||
|
|
||||||
|
if [ "$expectedTeamID" != "$teamID" ]; then
|
||||||
|
printlog "Team IDs do not match!"
|
||||||
|
cleanupAndExit 5
|
||||||
|
fi
|
||||||
|
|
||||||
|
# skip install for DEBUG
|
||||||
|
if [ "$DEBUG" -ne 0 ]; then
|
||||||
|
printlog "DEBUG enabled, skipping installation"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# check for root
|
||||||
|
if [ "$(whoami)" != "root" ]; then
|
||||||
|
# not running as root
|
||||||
|
printlog "not running as root, exiting"
|
||||||
|
cleanupAndExit 6
|
||||||
|
fi
|
||||||
|
|
||||||
|
# install pkg
|
||||||
|
printlog "Installing $archiveName to $targetDir"
|
||||||
|
if ! installer -pkg "$archiveName" -tgt "$targetDir" ; then
|
||||||
|
printlog "error installing $archiveName"
|
||||||
|
cleanupAndExit 9
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
installFromZIP() {
|
||||||
|
# unzip the archive
|
||||||
|
printlog "Unzipping $archiveName"
|
||||||
|
|
||||||
|
# tar -xf "$archiveName"
|
||||||
|
|
||||||
|
# note: when you expand a zip using tar in Mojave the expanded
|
||||||
|
# app will never pass the spctl check
|
||||||
|
|
||||||
|
unzip -o -qq "$archiveName"
|
||||||
|
installAppWithPath "$tmpDir/$appName"
|
||||||
|
}
|
||||||
|
|
||||||
|
installFromTBZ() {
|
||||||
|
# unzip the archive
|
||||||
|
printlog "Unzipping $archiveName"
|
||||||
|
tar -xf "$archiveName"
|
||||||
|
installAppWithPath "$tmpDir/$appName"
|
||||||
|
}
|
||||||
|
|
||||||
|
installPkgInDmg() {
|
||||||
|
mountDMG
|
||||||
|
# locate pkg in dmg
|
||||||
|
if [[ -z $pkgName ]]; then
|
||||||
|
# find first file ending with 'pkg'
|
||||||
|
findfiles=$(find "$dmgmount" -iname "*.pkg" -maxdepth 1 )
|
||||||
|
filearray=( ${(f)findfiles} )
|
||||||
|
if [[ ${#filearray} -eq 0 ]]; then
|
||||||
|
cleanupAndExit 20 "couldn't find pkg in dmg $archiveName"
|
||||||
|
fi
|
||||||
|
archiveName="${filearray[1]}"
|
||||||
|
printlog "found pkg: $archiveName"
|
||||||
|
else
|
||||||
|
# it is now safe to overwrite archiveName for installFromPKG
|
||||||
|
archiveName="$dmgmount/$pkgName"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# installFromPkgs
|
||||||
|
installFromPKG
|
||||||
|
}
|
||||||
|
|
||||||
|
installPkgInZip() {
|
||||||
|
# unzip the archive
|
||||||
|
printlog "Unzipping $archiveName"
|
||||||
|
tar -xf "$archiveName"
|
||||||
|
|
||||||
|
# locate pkg in zip
|
||||||
|
if [[ -z $pkgName ]]; then
|
||||||
|
# find first file starting with $name and ending with 'pkg'
|
||||||
|
findfiles=$(find "$tmpDir" -iname "*.pkg" -maxdepth 1 )
|
||||||
|
filearray=( ${(f)findfiles} )
|
||||||
|
if [[ ${#filearray} -eq 0 ]]; then
|
||||||
|
cleanupAndExit 20 "couldn't find pkg in zip $archiveName"
|
||||||
|
fi
|
||||||
|
archiveName="${filearray[1]}"
|
||||||
|
# it is now safe to overwrite archiveName for installFromPKG
|
||||||
|
printlog "found pkg: $archiveName"
|
||||||
|
else
|
||||||
|
# it is now safe to overwrite archiveName for installFromPKG
|
||||||
|
archiveName="$tmpDir/$pkgName"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# installFromPkgs
|
||||||
|
installFromPKG
|
||||||
|
}
|
||||||
|
|
||||||
|
runUpdateTool() {
|
||||||
|
if [[ -x $updateTool ]]; then
|
||||||
|
printlog "running $updateTool $updateToolArguments"
|
||||||
|
if [[ -n $updateToolRunAsCurrentUser ]]; then
|
||||||
|
runAsUser $updateTool ${updateToolArguments}
|
||||||
|
else
|
||||||
|
$updateTool ${updateToolArguments}
|
||||||
|
fi
|
||||||
|
if [[ $? -ne 0 ]]; then
|
||||||
|
cleanupAndExit 15 "Error running $updateTool"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
printlog "couldn't find $updateTool, continuing normally"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
# MARK: check minimal macOS requirement
|
# MARK: check minimal macOS requirement
|
||||||
autoload is-at-least
|
autoload is-at-least
|
||||||
|
|
||||||
@@ -167,17 +497,28 @@ if ! is-at-least 10.14 $(sw_vers -productVersion); then
|
|||||||
exit 98
|
exit 98
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# MARK: get the label
|
# MARK: argument parsing
|
||||||
if [[ $# -eq 0 ]]; then
|
if [[ $# -eq 0 ]]; then
|
||||||
grep -E '^[a-z0-9\-]*(\)|\|\\)$' "$0" | tr -d ')|\' | grep -v -E '^broken' | grep -v -E '^(longversion|version)$' | sort
|
grep -E '^[a-z0-9\-]*(\)|\|\\)$' "$0" | tr -d ')|\' | grep -v -E '^broken' | grep -v -E '^(longversion|version)$' | sort
|
||||||
exit 0
|
exit 0
|
||||||
elif [[ $# -gt 3 ]]; then
|
elif [[ $1 == "/" ]]; then
|
||||||
# jamf uses $4 for the first custom parameter
|
# jamf uses sends '/' as the first argument
|
||||||
printlog "shifting arguments for Jamf"
|
printlog "shifting arguments for Jamf"
|
||||||
shift 3
|
shift 3
|
||||||
fi
|
fi
|
||||||
|
|
||||||
label=${1:?"no label provided"}
|
while [[ -n $1 ]]; do
|
||||||
|
if [[ $1 =~ ".*\=.*" ]]; then
|
||||||
|
# if an argument contains an = character, send it to eval
|
||||||
|
printlog "setting variable from argument $1"
|
||||||
|
eval $1
|
||||||
|
else
|
||||||
|
# assume it's a label
|
||||||
|
label=$1
|
||||||
|
fi
|
||||||
|
# shift to next argument
|
||||||
|
shift 1
|
||||||
|
done
|
||||||
|
|
||||||
printlog "################## Start Installomator"
|
printlog "################## Start Installomator"
|
||||||
printlog "################## $label"
|
printlog "################## $label"
|
||||||
@@ -1039,6 +1380,27 @@ microsoftdefenderatp)
|
|||||||
updateToolArguments=( --install --apps WDAV00 )
|
updateToolArguments=( --install --apps WDAV00 )
|
||||||
;;
|
;;
|
||||||
|
|
||||||
|
# this description is so you can provide all variables as arguments
|
||||||
|
# it will only check if the required variables are setting
|
||||||
|
valuesfromarguments)
|
||||||
|
if [[ -z $name ]]; then
|
||||||
|
printlog "need to provide 'name'"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
if [[ -z $type ]]; then
|
||||||
|
printlog "need to provide 'type'"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
if [[ -z $downloadURL ]]; then
|
||||||
|
printlog "need to provide 'downloadURL'"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
if [[ -z $expectedTeamID ]]; then
|
||||||
|
printlog "need to provide 'expectedTeamID'"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
|
||||||
|
|
||||||
# these descriptions exist for testing and are intentionally broken
|
# these descriptions exist for testing and are intentionally broken
|
||||||
brokendownloadurl)
|
brokendownloadurl)
|
||||||
@@ -1066,341 +1428,8 @@ brokenteamid)
|
|||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
# MARK: Functions
|
|
||||||
|
|
||||||
cleanupAndExit() { # $1 = exit code, $2 message
|
|
||||||
if [[ -n $2 && $1 -ne 0 ]]; then
|
|
||||||
printlog "ERROR: $2"
|
|
||||||
fi
|
|
||||||
if [ "$DEBUG" -eq 0 ]; then
|
|
||||||
# remove the temporary working directory when done
|
|
||||||
printlog "Deleting $tmpDir"
|
|
||||||
rm -Rf "$tmpDir"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -n "$dmgmount" ]; then
|
|
||||||
# unmount disk image
|
|
||||||
printlog "Unmounting $dmgmount"
|
|
||||||
hdiutil detach "$dmgmount"
|
|
||||||
fi
|
|
||||||
printlog "################## End Installomator \n\n"
|
|
||||||
exit "$1"
|
|
||||||
}
|
|
||||||
|
|
||||||
runAsUser() {
|
|
||||||
if [[ $currentUser != "loginwindow" ]]; then
|
|
||||||
uid=$(id -u "$currentUser")
|
|
||||||
launchctl asuser $uid sudo -u $currentUser "$@"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
displaydialog() { # $1: message $2: title
|
|
||||||
message=${1:-"Message"}
|
|
||||||
title=${2:-"Installomator"}
|
|
||||||
runAsUser osascript -e "button returned of (display dialog \"$message\" with title \"$title\" buttons {\"Not Now\", \"Quit and Update\"} default button \"Quit and Update\")"
|
|
||||||
}
|
|
||||||
|
|
||||||
displaynotification() { # $1: message $2: title
|
|
||||||
message=${1:-"Message"}
|
|
||||||
title=${2:-"Notification"}
|
|
||||||
manageaction="/Library/Application Support/JAMF/bin/Management Action.app/Contents/MacOS/Management Action"
|
|
||||||
|
|
||||||
if [[ -x "$manageaction" ]]; then
|
|
||||||
"$manageaction" -message "$message" -title "$title"
|
|
||||||
else
|
|
||||||
runAsUser osascript -e "display notification \"$message\" with title \"$title\""
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
getAppVersion() {
|
|
||||||
# get all apps matching name
|
|
||||||
applist=$(mdfind "kind:application $appName" -0 )
|
|
||||||
if [[ $applist = "" ]]; then
|
|
||||||
printlog "Spotlight not returning any app, trying manually in /Applications."
|
|
||||||
if [[ -d "/Applications/$appName" ]]; then
|
|
||||||
applist="/Applications/$appName"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
appPathArray=( ${(0)applist} )
|
|
||||||
|
|
||||||
if [[ ${#appPathArray} -gt 0 ]]; then
|
|
||||||
filteredAppPaths=( ${(M)appPathArray:#${targetDir}*} )
|
|
||||||
if [[ ${#filteredAppPaths} -eq 1 ]]; then
|
|
||||||
installedAppPath=$filteredAppPaths[1]
|
|
||||||
appversion=$(mdls -name kMDItemVersion -raw $installedAppPath )
|
|
||||||
printlog "found app at $installedAppPath, version $appversion"
|
|
||||||
else
|
|
||||||
printlog "could not determine location of $appName"
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
printlog "could not find $appName"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
checkRunningProcesses() {
|
|
||||||
# don't check in DEBUG mode
|
|
||||||
if [[ $DEBUG -ne 0 ]]; then
|
|
||||||
printlog "DEBUG mode, not checking for blocking processes"
|
|
||||||
return
|
|
||||||
fi
|
|
||||||
|
|
||||||
# try at most 3 times
|
|
||||||
for i in {1..3}; do
|
|
||||||
countedProcesses=0
|
|
||||||
for x in ${blockingProcesses}; do
|
|
||||||
if pgrep -xq "$x"; then
|
|
||||||
printlog "found blocking process $x"
|
|
||||||
|
|
||||||
case $BLOCKING_PROCESS_ACTION in
|
|
||||||
kill)
|
|
||||||
printlog "killing process $x"
|
|
||||||
pkill $x
|
|
||||||
;;
|
|
||||||
prompt_user)
|
|
||||||
button=$(displaydialog "Quit “$x” to continue updating? (Leave this dialogue if you want to activate this update later)." "The application “$x” needs to be updated.")
|
|
||||||
if [[ $button = "Not Now" ]]; then
|
|
||||||
cleanupAndExit 10 "user aborted update"
|
|
||||||
else
|
|
||||||
runAsUser osascript -e "tell app \"$x\" to quit"
|
|
||||||
fi
|
|
||||||
;;
|
|
||||||
silent_fail)
|
|
||||||
cleanupAndExit 12 "blocking process '$x' found, aborting"
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
countedProcesses=$((countedProcesses + 1))
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
if [[ $countedProcesses -eq 0 ]]; then
|
|
||||||
# no blocking processes, exit the loop early
|
|
||||||
break
|
|
||||||
else
|
|
||||||
# give the user a bit of time to quit apps
|
|
||||||
printlog "waiting 30 seconds for processes to quit"
|
|
||||||
sleep 30
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
if [[ $countedProcesses -ne 0 ]]; then
|
|
||||||
cleanupAndExit 11 "could not quit all processes, aborting..."
|
|
||||||
fi
|
|
||||||
|
|
||||||
printlog "no more blocking processes, continue with update"
|
|
||||||
}
|
|
||||||
|
|
||||||
installAppWithPath() { # $1: path to app to install in $targetDir
|
|
||||||
appPath=${1?:"no path to app"}
|
|
||||||
|
|
||||||
# check if app exists
|
|
||||||
if [ ! -e "$appPath" ]; then
|
|
||||||
cleanupAndExit 8 "could not find: $appPath"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# verify with spctl
|
|
||||||
printlog "Verifying: $appPath"
|
|
||||||
if ! teamID=$(spctl -a -vv "$appPath" 2>&1 | awk '/origin=/ {print $NF }' | tr -d '()' ); then
|
|
||||||
cleanupAndExit 4 "Error verifying $appPath"
|
|
||||||
fi
|
|
||||||
|
|
||||||
printlog "Team ID: $teamID (expected: $expectedTeamID )"
|
|
||||||
|
|
||||||
if [ "$expectedTeamID" != "$teamID" ]; then
|
|
||||||
cleanupAndExit 5 "Team IDs do not match"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# check for root
|
|
||||||
if [ "$(whoami)" != "root" ]; then
|
|
||||||
# not running as root
|
|
||||||
if [ "$DEBUG" -eq 0 ]; then
|
|
||||||
cleanupAndExit 6 "not running as root, exiting"
|
|
||||||
fi
|
|
||||||
|
|
||||||
printlog "DEBUG enabled, skipping copy and chown steps"
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
# remove existing application
|
|
||||||
if [ -e "$targetDir/$appName" ]; then
|
|
||||||
printlog "Removing existing $targetDir/$appName"
|
|
||||||
rm -Rf "$targetDir/$appName"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# copy app to /Applications
|
|
||||||
printlog "Copy $appPath to $targetDir"
|
|
||||||
if ! ditto "$appPath" "$targetDir/$appName"; then
|
|
||||||
cleanupAndExit 7 "Error while copying"
|
|
||||||
fi
|
|
||||||
|
|
||||||
|
|
||||||
# set ownership to current user
|
|
||||||
if [ "$currentUser" != "loginwindow" ]; then
|
|
||||||
printlog "Changing owner to $currentUser"
|
|
||||||
chown -R "$currentUser" "$targetDir/$appName"
|
|
||||||
else
|
|
||||||
printlog "No user logged in, not changing user"
|
|
||||||
fi
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
mountDMG() {
|
|
||||||
# mount the dmg
|
|
||||||
printlog "Mounting $tmpDir/$archiveName"
|
|
||||||
# always pipe 'Y\n' in case the dmg requires an agreement
|
|
||||||
if ! dmgmount=$(echo 'Y'$'\n' | hdiutil attach "$tmpDir/$archiveName" -nobrowse -readonly | tail -n 1 | cut -c 54- ); then
|
|
||||||
cleanupAndExit 3 "Error mounting $tmpDir/$archiveName"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ ! -e $dmgmount ]]; then
|
|
||||||
printlog "Error mounting $tmpDir/$archiveName"
|
|
||||||
cleanupAndExit 3
|
|
||||||
fi
|
|
||||||
|
|
||||||
printlog "Mounted: $dmgmount"
|
|
||||||
}
|
|
||||||
|
|
||||||
installFromDMG() {
|
|
||||||
mountDMG
|
|
||||||
|
|
||||||
installAppWithPath "$dmgmount/$appName"
|
|
||||||
}
|
|
||||||
|
|
||||||
installFromPKG() {
|
|
||||||
# verify with spctl
|
|
||||||
printlog "Verifying: $archiveName"
|
|
||||||
|
|
||||||
if ! spctlout=$(spctl -a -vv -t install "$archiveName" 2>&1 ); then
|
|
||||||
printlog "Error verifying $archiveName"
|
|
||||||
cleanupAndExit 4
|
|
||||||
fi
|
|
||||||
|
|
||||||
teamID=$(echo $spctlout | awk -F '(' '/origin=/ {print $2 }' | tr -d '()' )
|
|
||||||
|
|
||||||
# Apple signed software has no teamID, grab entire origin instead
|
|
||||||
if [[ -z $teamID ]]; then
|
|
||||||
teamID=$(echo $spctlout | awk -F '=' '/origin=/ {print $NF }')
|
|
||||||
fi
|
|
||||||
|
|
||||||
|
|
||||||
printlog "Team ID: $teamID (expected: $expectedTeamID )"
|
|
||||||
|
|
||||||
if [ "$expectedTeamID" != "$teamID" ]; then
|
|
||||||
printlog "Team IDs do not match!"
|
|
||||||
cleanupAndExit 5
|
|
||||||
fi
|
|
||||||
|
|
||||||
# skip install for DEBUG
|
|
||||||
if [ "$DEBUG" -ne 0 ]; then
|
|
||||||
printlog "DEBUG enabled, skipping installation"
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
# check for root
|
|
||||||
if [ "$(whoami)" != "root" ]; then
|
|
||||||
# not running as root
|
|
||||||
printlog "not running as root, exiting"
|
|
||||||
cleanupAndExit 6
|
|
||||||
fi
|
|
||||||
|
|
||||||
# install pkg
|
|
||||||
printlog "Installing $archiveName to $targetDir"
|
|
||||||
if ! installer -pkg "$archiveName" -tgt "$targetDir" ; then
|
|
||||||
printlog "error installing $archiveName"
|
|
||||||
cleanupAndExit 9
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
installFromZIP() {
|
|
||||||
# unzip the archive
|
|
||||||
printlog "Unzipping $archiveName"
|
|
||||||
|
|
||||||
# tar -xf "$archiveName"
|
|
||||||
|
|
||||||
# note: when you expand a zip using tar in Mojave the expanded
|
|
||||||
# app will never pass the spctl check
|
|
||||||
|
|
||||||
unzip -o -qq "$archiveName"
|
|
||||||
installAppWithPath "$tmpDir/$appName"
|
|
||||||
}
|
|
||||||
|
|
||||||
installFromTBZ() {
|
|
||||||
# unzip the archive
|
|
||||||
printlog "Unzipping $archiveName"
|
|
||||||
tar -xf "$archiveName"
|
|
||||||
installAppWithPath "$tmpDir/$appName"
|
|
||||||
}
|
|
||||||
|
|
||||||
installPkgInDmg() {
|
|
||||||
mountDMG
|
|
||||||
# locate pkg in dmg
|
|
||||||
if [[ -z $pkgName ]]; then
|
|
||||||
# find first file ending with 'pkg'
|
|
||||||
findfiles=$(find "$dmgmount" -iname "*.pkg" -maxdepth 1 )
|
|
||||||
filearray=( ${(f)findfiles} )
|
|
||||||
if [[ ${#filearray} -eq 0 ]]; then
|
|
||||||
cleanupAndExit 20 "couldn't find pkg in dmg $archiveName"
|
|
||||||
fi
|
|
||||||
archiveName="${filearray[1]}"
|
|
||||||
printlog "found pkg: $archiveName"
|
|
||||||
else
|
|
||||||
# it is now safe to overwrite archiveName for installFromPKG
|
|
||||||
archiveName="$dmgmount/$pkgName"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# installFromPkgs
|
|
||||||
installFromPKG
|
|
||||||
}
|
|
||||||
|
|
||||||
installPkgInZip() {
|
|
||||||
# unzip the archive
|
|
||||||
printlog "Unzipping $archiveName"
|
|
||||||
tar -xf "$archiveName"
|
|
||||||
|
|
||||||
# locate pkg in zip
|
|
||||||
if [[ -z $pkgName ]]; then
|
|
||||||
# find first file starting with $name and ending with 'pkg'
|
|
||||||
findfiles=$(find "$tmpDir" -iname "*.pkg" -maxdepth 1 )
|
|
||||||
filearray=( ${(f)findfiles} )
|
|
||||||
if [[ ${#filearray} -eq 0 ]]; then
|
|
||||||
cleanupAndExit 20 "couldn't find pkg in zip $archiveName"
|
|
||||||
fi
|
|
||||||
archiveName="${filearray[1]}"
|
|
||||||
# it is now safe to overwrite archiveName for installFromPKG
|
|
||||||
printlog "found pkg: $archiveName"
|
|
||||||
else
|
|
||||||
# it is now safe to overwrite archiveName for installFromPKG
|
|
||||||
archiveName="$tmpDir/$pkgName"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# installFromPkgs
|
|
||||||
installFromPKG
|
|
||||||
}
|
|
||||||
|
|
||||||
runUpdateTool() {
|
|
||||||
if [[ -x $updateTool ]]; then
|
|
||||||
printlog "running $updateTool $updateToolArguments"
|
|
||||||
if [[ -n $updateToolRunAsCurrentUser ]]; then
|
|
||||||
runAsUser $updateTool ${updateToolArguments}
|
|
||||||
else
|
|
||||||
$updateTool ${updateToolArguments}
|
|
||||||
fi
|
|
||||||
if [[ $? -ne 0 ]]; then
|
|
||||||
cleanupAndExit 15 "Error running $updateTool"
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
printlog "couldn't find $updateTool, continuing normally"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# MARK: main code starts here
|
|
||||||
|
|
||||||
|
# MARK: application download and installation starts here
|
||||||
|
|
||||||
|
|
||||||
# MARK: extract info from data
|
# MARK: extract info from data
|
||||||
|
|||||||
Reference in New Issue
Block a user