mirror of
https://github.com/mtan93/Installomator.git
synced 2026-03-15 21:03:13 +00:00
Compare commits
68 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4d4e22379e | ||
|
|
fc01e2f8de | ||
|
|
4283329b25 | ||
|
|
2e207f6982 | ||
|
|
b99d3b50f4 | ||
|
|
c669250d8c | ||
|
|
76a38cdffc | ||
|
|
c53e49d406 | ||
|
|
125fadd4f4 | ||
|
|
53f043ede5 | ||
|
|
3530130b48 | ||
|
|
71fe13b311 | ||
|
|
2c613803b5 | ||
|
|
edff222adc | ||
|
|
4a124f2151 | ||
|
|
977e46d33f | ||
|
|
5bfeddbecf | ||
|
|
0dd63eae75 | ||
|
|
dff5b8c61a | ||
|
|
57da0331bf | ||
|
|
96c998413f | ||
|
|
933c51e00f | ||
|
|
cd9247360a | ||
|
|
a0d93f1799 | ||
|
|
138301f61e | ||
|
|
901f99459a | ||
|
|
f653833dc2 | ||
|
|
eb802b9a95 | ||
|
|
04a2c74dd8 | ||
|
|
4d49e51789 | ||
|
|
2e07291c60 | ||
|
|
5c5dadfe9b | ||
|
|
bd49d7ca97 | ||
|
|
3d4c1b45c9 | ||
|
|
961816236f | ||
|
|
be0f0a9cd0 | ||
|
|
22bd79af0e | ||
|
|
912a0e0046 | ||
|
|
5059673fc7 | ||
|
|
8a56d05a8a | ||
|
|
65d8996118 | ||
|
|
ef27dfde6d | ||
|
|
e81c8114b4 | ||
|
|
d84ce01eb5 | ||
|
|
09d0230256 | ||
|
|
c65df61524 | ||
|
|
5dff7ee718 | ||
|
|
555a7631b9 | ||
|
|
9c96b5a764 | ||
|
|
2ddbd2ab1e | ||
|
|
ec7e479372 | ||
|
|
a32b5fc0a2 | ||
|
|
2d1777ca6e | ||
|
|
37b36c8c13 | ||
|
|
9508357243 | ||
|
|
c99aabccbb | ||
|
|
a4df3399b4 | ||
|
|
7438aa403c | ||
|
|
965cf310e4 | ||
|
|
da5f99639a | ||
|
|
65f5c57772 | ||
|
|
42ec528870 | ||
|
|
7f264733a7 | ||
|
|
0a96de8449 | ||
|
|
7d6f4db736 | ||
|
|
adf34cb6f3 | ||
|
|
8544796b75 | ||
|
|
315398b3fc |
11
CHANGELOG.md
11
CHANGELOG.md
@@ -1,4 +1,13 @@
|
|||||||
## v0.3 - 2020-07-
|
## v0.4 - 2020-10-19
|
||||||
|
|
||||||
|
- you can now set script variables as an argument in the form `VARIABLE=value`. More detail on this in the README file, 'Configuration from Arguments.' (#26, #50, #72, and #73)
|
||||||
|
- change `downloadFromGit` to match file types better (#58)
|
||||||
|
- implemented a workaround for changed behavior of `xpath` in Big Sur (#80)
|
||||||
|
- added an option `prompt_user_the_kill` to `BLOCKING_PROCESS_ACTION` which will kill the process after the third unsuccessful attempt to quit (#78, thanks Patrick Atoon @raptor399)
|
||||||
|
- added several new labels for total of 116
|
||||||
|
|
||||||
|
|
||||||
|
## v0.3 - 2020-07-23
|
||||||
|
|
||||||
- added several new labels for total of 98
|
- added several new labels for total of 98
|
||||||
- removed the powershell labels, since the installer is not notarized
|
- removed the powershell labels, since the installer is not notarized
|
||||||
|
|||||||
889
Installomator.sh
889
Installomator.sh
@@ -8,8 +8,8 @@
|
|||||||
# inspired by the download scripts from William Smith and Sander Schram
|
# inspired by the download scripts from William Smith and Sander Schram
|
||||||
# with additional ideas and contribution from Isaac Ordonez, Mann consulting
|
# with additional ideas and contribution from Isaac Ordonez, Mann consulting
|
||||||
|
|
||||||
VERSION='0.3'
|
VERSION='0.4'
|
||||||
VERSIONDATE='20200609'
|
VERSIONDATE='20201019'
|
||||||
|
|
||||||
export PATH=/usr/bin:/bin:/usr/sbin:/sbin
|
export PATH=/usr/bin:/bin:/usr/sbin:/sbin
|
||||||
|
|
||||||
@@ -35,6 +35,9 @@ BLOCKING_PROCESS_ACTION=prompt_user
|
|||||||
# - silent_fail exit script without prompt or installation
|
# - silent_fail exit script without prompt or installation
|
||||||
# - prompt_user show a user dialog for each blocking process found
|
# - prompt_user show a user dialog for each blocking process found
|
||||||
# abort after three attempts to quit
|
# abort after three attempts to quit
|
||||||
|
# - prompt_user_then_kill
|
||||||
|
# show a user dialog for each blocking process found,
|
||||||
|
# attempt to quit two times, kill the process finally
|
||||||
# - kill kill process without prompting or giving the user a chance to save
|
# - kill kill process without prompting or giving the user a chance to save
|
||||||
|
|
||||||
|
|
||||||
@@ -113,9 +116,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(){
|
||||||
@@ -147,7 +195,7 @@ downloadURLFromGit() { # $1 git user name, $2 git repo name
|
|||||||
| awk -F '"' "/browser_download_url/ && /$archiveName/ { print \$4 }")
|
| awk -F '"' "/browser_download_url/ && /$archiveName/ { print \$4 }")
|
||||||
else
|
else
|
||||||
downloadURL=$(curl --silent --fail "https://api.github.com/repos/$gitusername/$gitreponame/releases/latest" \
|
downloadURL=$(curl --silent --fail "https://api.github.com/repos/$gitusername/$gitreponame/releases/latest" \
|
||||||
| awk -F '"' "/browser_download_url/ && /$filetype/ { print \$4 }")
|
| awk -F '"' "/browser_download_url/ && /$filetype\"/ { print \$4 }")
|
||||||
fi
|
fi
|
||||||
if [ -z "$downloadURL" ]; then
|
if [ -z "$downloadURL" ]; then
|
||||||
printlog "could not retrieve download URL for $gitusername/$gitreponame"
|
printlog "could not retrieve download URL for $gitusername/$gitreponame"
|
||||||
@@ -159,6 +207,312 @@ downloadURLFromGit() { # $1 git user name, $2 git repo name
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
xpath() {
|
||||||
|
# the xpath tool changes in Big Sur and now requires the `-e` option
|
||||||
|
if [[ $(sw_vers -buildVersion) > "20A" ]]; then
|
||||||
|
/usr/bin/xpath -e $@
|
||||||
|
else
|
||||||
|
/usr/bin/xpath $@
|
||||||
|
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|prompt_user_then_kill)
|
||||||
|
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
|
||||||
|
if [[ $i = 3 && $BLOCKING_PROCESS_ACTION = "prompt_user_then_kill" ]]; then
|
||||||
|
printlog "killing process $x"
|
||||||
|
pkill $x
|
||||||
|
else
|
||||||
|
printlog "telling app $x to quit"
|
||||||
|
runAsUser osascript -e "tell app \"$x\" to quit"
|
||||||
|
fi
|
||||||
|
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"
|
||||||
|
|
||||||
|
# note: githubdesktop fails spctl verification when expanded
|
||||||
|
# with unzip
|
||||||
|
|
||||||
|
ditto -x -k "$archiveName" "$tmpDir"
|
||||||
|
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 +521,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.*|longversion|version|valuesfromarguments)$' | 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"
|
||||||
@@ -441,13 +806,13 @@ webexteams)
|
|||||||
downloadURL="https://binaries.webex.com/WebexTeamsDesktop-MACOS-Gold/WebexTeams.dmg"
|
downloadURL="https://binaries.webex.com/WebexTeamsDesktop-MACOS-Gold/WebexTeams.dmg"
|
||||||
expectedTeamID="DE8Y96K9QP"
|
expectedTeamID="DE8Y96K9QP"
|
||||||
;;
|
;;
|
||||||
#citrixworkspace)
|
citrixworkspace)
|
||||||
# credit: Erik Stam (@erikstam)
|
#credit: Erik Stam (@erikstam) and #Philipp on MacAdmins Slack
|
||||||
#name="Citrix Workspace"
|
name="Citrix Workspace"
|
||||||
#type="pkgInDmg"
|
type="pkgInDmg"
|
||||||
#downloadURL="https://downloads.citrix.com/17596/CitrixWorkspaceApp.dmg?__gda__=1588183500_fc68033aef7d6d163d8b8309b964f1de"
|
downloadURL="https:"$(curl -s -L "https://www.citrix.com/downloads/workspace-app/mac/workspace-app-for-mac-latest.html#ctx-dl-eula-external" | grep "dmg?" | sed "s/.*rel=.\(.*\)..id=.*/\1/")
|
||||||
#expectedTeamID="S272Y5R93J"
|
expectedTeamID="S272Y5R93J"
|
||||||
#;;
|
;;
|
||||||
privileges)
|
privileges)
|
||||||
# credit: Erik Stam (@erikstam)
|
# credit: Erik Stam (@erikstam)
|
||||||
name="Privileges"
|
name="Privileges"
|
||||||
@@ -640,8 +1005,8 @@ brave)
|
|||||||
# credit: @securitygeneration
|
# credit: @securitygeneration
|
||||||
name="Brave Browser"
|
name="Brave Browser"
|
||||||
type="dmg"
|
type="dmg"
|
||||||
downloadURL="https://laptop-updates.brave.com/latest/osx"
|
downloadURL=$(curl --location --fail --silent "https://updates.bravesoftware.com/sparkle/Brave-Browser/stable/appcast.xml" | xpath '//rss/channel/item[1]/enclosure/@url' 2>/dev/null | cut -d '"' -f 2)
|
||||||
expectedTeamID="9BNSXJN65R"
|
expectedTeamID="KL8N8XSYF4"
|
||||||
;;
|
;;
|
||||||
umbrellaroamingclient)
|
umbrellaroamingclient)
|
||||||
# credit: Tadayuki Onishi (@kenchan0130)
|
# credit: Tadayuki Onishi (@kenchan0130)
|
||||||
@@ -765,9 +1130,9 @@ r)
|
|||||||
;;
|
;;
|
||||||
8x8)
|
8x8)
|
||||||
# credit: #D-A-James from MacAdmins Slack and Isaac Ordonez, Mann consulting (@mannconsulting)
|
# credit: #D-A-James from MacAdmins Slack and Isaac Ordonez, Mann consulting (@mannconsulting)
|
||||||
name="8x8 - Virtual Office"
|
name="8x8 Work"
|
||||||
type="dmg"
|
type="dmg"
|
||||||
downloadURL=$(curl -fs https://support.8x8.com/cloud-phone-service/voice/virtual-office-desktop/download-virtual-office-desktop | grep -m 1 -o "http.*VOD.*.dmg")
|
downloadURL=$(curl -fs -L https://support.8x8.com/cloud-phone-service/voice/work-desktop/download-8x8-work-for-desktop | grep -m 1 -o "https.*dmg")
|
||||||
expectedTeamID="FC967L3QRG"
|
expectedTeamID="FC967L3QRG"
|
||||||
;;
|
;;
|
||||||
egnyte)
|
egnyte)
|
||||||
@@ -778,6 +1143,132 @@ egnyte)
|
|||||||
expectedTeamID="FELUD555VC"
|
expectedTeamID="FELUD555VC"
|
||||||
blockingProcesses=( NONE )
|
blockingProcesses=( NONE )
|
||||||
;;
|
;;
|
||||||
|
camtasia)
|
||||||
|
name="Camtasia 2020"
|
||||||
|
type="dmg"
|
||||||
|
downloadURL=https://download.techsmith.com/camtasiamac/releases/Camtasia.dmg
|
||||||
|
expectedTeamID="7TQL462TU8"
|
||||||
|
;;
|
||||||
|
snagit2020)
|
||||||
|
# credit: Isaac Ordonez, Mann consulting (@mannconsulting)
|
||||||
|
name="Snagit 2020"
|
||||||
|
type="dmg"
|
||||||
|
downloadURL="https://download.techsmith.com/snagitmac/releases/Snagit.dmg"
|
||||||
|
expectedTeamID="7TQL462TU8"
|
||||||
|
;;
|
||||||
|
virtualbox)
|
||||||
|
# credit: AP Orlebeke (@apizz)
|
||||||
|
name="VirtualBox"
|
||||||
|
type="pkgInDmg"
|
||||||
|
pkgName="VirtualBox.pkg"
|
||||||
|
downloadURL=$(curl -fs "https://www.virtualbox.org/wiki/Downloads" \
|
||||||
|
| awk -F '"' "/OSX.dmg/ { print \$4 }")
|
||||||
|
expectedTeamID="VB5E2TV963"
|
||||||
|
;;
|
||||||
|
detectxswift)
|
||||||
|
# credit: AP Orlebeke (@apizz)
|
||||||
|
name="DetectX Swift"
|
||||||
|
type="zip"
|
||||||
|
downloadURL="https://s3.amazonaws.com/sqwarq.com/PublicZips/DetectX_Swift.app.zip"
|
||||||
|
expectedTeamID="MAJ5XBJSG3"
|
||||||
|
;;
|
||||||
|
autopkgr)
|
||||||
|
# credit: AP Orlebeke (@apizz)
|
||||||
|
name="AutoPkgr"
|
||||||
|
type="dmg"
|
||||||
|
downloadURL=$(curl -fs "https://api.github.com/repos/lindegroup/autopkgr/releases/latest" \
|
||||||
|
| awk -F '"' "/browser_download_url/ && /dmg/ && ! /sig/ && ! /CLI/ && ! /sha256/ { print \$4 }")
|
||||||
|
expectedTeamID="JVY2ZR6SEF"
|
||||||
|
;;
|
||||||
|
airserver)
|
||||||
|
# credit: AP Orlebeke (@apizz)
|
||||||
|
name="AirServer"
|
||||||
|
type="dmg"
|
||||||
|
downloadURL="https://www.airserver.com/download/mac/latest"
|
||||||
|
expectedTeamID="6C755KS5W3"
|
||||||
|
;;
|
||||||
|
vscodium)
|
||||||
|
# credit: AP Orlebeke (@apizz)
|
||||||
|
name="VSCodium"
|
||||||
|
type="dmg"
|
||||||
|
downloadURL=$(curl -fs "https://api.github.com/repos/VSCodium/vscodium/releases/latest" \
|
||||||
|
| awk -F '"' "/browser_download_url/ && /dmg/ && ! /sig/ && ! /CLI/ && ! /sha256/ { print \$4 }")
|
||||||
|
expectedTeamID="C7S3ZQ2B8V"
|
||||||
|
appName="VSCodium.app"
|
||||||
|
blockingProcesses=( Electron )
|
||||||
|
;;
|
||||||
|
keepassxc)
|
||||||
|
# credit: Patrick Atoon (@raptor399)
|
||||||
|
name="KeePassXC"
|
||||||
|
type="dmg"
|
||||||
|
downloadURL="$(downloadURLFromGit keepassxreboot keepassxc)"
|
||||||
|
expectedTeamID="G2S7P7J672"
|
||||||
|
;;
|
||||||
|
alfred)
|
||||||
|
# credit: AP Orlebeke (@apizz)
|
||||||
|
name="Alfred"
|
||||||
|
type="dmg"
|
||||||
|
downloadURL=$(curl -fs https://www.alfredapp.com | awk -F '"' "/dmg/ {print \$2}" | head -1)
|
||||||
|
appName="Alfred 4.app"
|
||||||
|
expectedTeamID="XZZXE9SED4"
|
||||||
|
;;
|
||||||
|
istatmenus)
|
||||||
|
# credit: AP Orlebeke (@apizz)
|
||||||
|
name="iStat Menus"
|
||||||
|
type="zip"
|
||||||
|
downloadURL="https://download.bjango.com/istatmenus/"
|
||||||
|
expectedTeamID="Y93TK974AT"
|
||||||
|
blockingProcesses=( "iStat Menus" "iStatMenusAgent" "iStat Menus Status" )
|
||||||
|
;;
|
||||||
|
sizeup)
|
||||||
|
# credit: AP Orlebeke (@apizz)
|
||||||
|
name="SizeUp"
|
||||||
|
type="zip"
|
||||||
|
downloadURL="https://www.irradiatedsoftware.com/download/SizeUp.zip"
|
||||||
|
expectedTeamID="GVZ7RF955D"
|
||||||
|
;;
|
||||||
|
tunnelblick)
|
||||||
|
name="Tunnelblick"
|
||||||
|
type="dmg"
|
||||||
|
downloadURL=$(downloadURLFromGit TunnelBlick Tunnelblick )
|
||||||
|
expectedTeamID="Z2SG5H3HC8"
|
||||||
|
;;
|
||||||
|
yubikeymanagerqt)
|
||||||
|
# credit: Tadayuki Onishi (@kenchan0130)
|
||||||
|
name="YubiKey Manager GUI"
|
||||||
|
type="pkg"
|
||||||
|
downloadURL="https://developers.yubico.com/yubikey-manager-qt/Releases/$(curl -sfL https://api.github.com/repos/Yubico/yubikey-manager-qt/releases/latest | awk -F '"' '/"tag_name"/ { print $4 }')-mac.pkg"
|
||||||
|
expectedTeamID="LQA3CS5MM7"
|
||||||
|
;;
|
||||||
|
skitch)
|
||||||
|
# credit: Isaac Ordonez, Mann consulting (@mannconsulting)
|
||||||
|
name="Skitch"
|
||||||
|
type="zip"
|
||||||
|
downloadURL=$(curl -fs -A "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_4) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/12.1 Safari/605.1.15" https://evernote.com/products/skitch | grep -o "https://.*zip")
|
||||||
|
expectedTeamID="J8RPQ294UB"
|
||||||
|
Company="Evernote"
|
||||||
|
;;
|
||||||
|
dialpad)
|
||||||
|
# credit: @ehosaka
|
||||||
|
name="Dialpad"
|
||||||
|
type="dmg"
|
||||||
|
downloadURL="https://storage.googleapis.com/dialpad_native/osx/Dialpad.dmg"
|
||||||
|
expectedTeamID="9V29MQSZ9M"
|
||||||
|
;;
|
||||||
|
amazonworkspaces)
|
||||||
|
# credit: Isaac Ordonez, Mann consulting (@mannconsulting)
|
||||||
|
name="Workspaces"
|
||||||
|
type="pkg"
|
||||||
|
downloadURL="https://d2td7dqidlhjx7.cloudfront.net/prod/global/osx/WorkSpaces.pkg"
|
||||||
|
expectedTeamID="94KV3E626L"
|
||||||
|
;;
|
||||||
|
apparency)
|
||||||
|
name="Apparency"
|
||||||
|
type="dmg"
|
||||||
|
downloadURL="https://www.mothersruin.com/software/downloads/Apparency.dmg"
|
||||||
|
expectedTeamID="936EB786NH"
|
||||||
|
;;
|
||||||
|
|
||||||
|
|
||||||
# MARK: add new labels above here
|
# MARK: add new labels above here
|
||||||
|
|
||||||
@@ -948,6 +1439,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)
|
||||||
@@ -975,341 +1487,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=$(printlog '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
|
||||||
|
|||||||
18
Labels.txt
18
Labels.txt
@@ -3,20 +3,29 @@
|
|||||||
adobereaderdc
|
adobereaderdc
|
||||||
adobereaderdc-install
|
adobereaderdc-install
|
||||||
adobereaderdc-update
|
adobereaderdc-update
|
||||||
|
airserver
|
||||||
|
alfred
|
||||||
|
amazonworkspaces
|
||||||
|
apparency
|
||||||
appcleaner
|
appcleaner
|
||||||
aquaskk
|
aquaskk
|
||||||
atom
|
atom
|
||||||
autodmg
|
autodmg
|
||||||
|
autopkgr
|
||||||
aviatrix
|
aviatrix
|
||||||
bbedit
|
bbedit
|
||||||
bettertouchtool
|
bettertouchtool
|
||||||
boxdrive
|
boxdrive
|
||||||
brave
|
brave
|
||||||
|
camtasia
|
||||||
|
citrixworkspace
|
||||||
code42
|
code42
|
||||||
coderunner
|
coderunner
|
||||||
cyberduck
|
cyberduck
|
||||||
depnotify
|
depnotify
|
||||||
desktoppr
|
desktoppr
|
||||||
|
detectxswift
|
||||||
|
dialpad
|
||||||
discord
|
discord
|
||||||
docker
|
docker
|
||||||
dropbox
|
dropbox
|
||||||
@@ -33,11 +42,13 @@ googlejapaneseinput
|
|||||||
grandperspective
|
grandperspective
|
||||||
handbrake
|
handbrake
|
||||||
icons
|
icons
|
||||||
|
istatmenus
|
||||||
iterm2
|
iterm2
|
||||||
jamfmigrator
|
jamfmigrator
|
||||||
jamfpppcutility
|
jamfpppcutility
|
||||||
jamfreenroller
|
jamfreenroller
|
||||||
karabinerelements
|
karabinerelements
|
||||||
|
keepassxc
|
||||||
krisp
|
krisp
|
||||||
malwarebytes
|
malwarebytes
|
||||||
microsoftautoupdate
|
microsoftautoupdate
|
||||||
@@ -74,7 +85,10 @@ royaltsx
|
|||||||
santa
|
santa
|
||||||
sfsymbols
|
sfsymbols
|
||||||
signal
|
signal
|
||||||
|
sizeup
|
||||||
|
skitch
|
||||||
slack
|
slack
|
||||||
|
snagit2020
|
||||||
sonos
|
sonos
|
||||||
sonoss1
|
sonoss1
|
||||||
sonoss2
|
sonoss2
|
||||||
@@ -88,11 +102,15 @@ textmate
|
|||||||
things
|
things
|
||||||
torbrowser
|
torbrowser
|
||||||
tunnelbear
|
tunnelbear
|
||||||
|
tunnelblick
|
||||||
umbrellaroamingclient
|
umbrellaroamingclient
|
||||||
|
virtualbox
|
||||||
visualstudiocode
|
visualstudiocode
|
||||||
vlc
|
vlc
|
||||||
|
vscodium
|
||||||
webexmeetings
|
webexmeetings
|
||||||
webexteams
|
webexteams
|
||||||
whatsapp
|
whatsapp
|
||||||
wwdcformac
|
wwdcformac
|
||||||
|
yubikeymanagerqt
|
||||||
zoom
|
zoom
|
||||||
|
|||||||
21
README.md
21
README.md
@@ -305,6 +305,27 @@ Depending on the application or pkg there are a few more variables you can or ne
|
|||||||
- `updateToolRunAsCurrentUser`:
|
- `updateToolRunAsCurrentUser`:
|
||||||
When this variable is set (any value), `$updateTool` will be run as the current user. Default is unset and
|
When this variable is set (any value), `$updateTool` will be run as the current user. Default is unset and
|
||||||
|
|
||||||
|
### Configuration from Arguments
|
||||||
|
|
||||||
|
You can provide a configuration variable, such as `DEBUG` or `NOTIFY` as an argument in the form `VAR=value`. For example:
|
||||||
|
|
||||||
|
```
|
||||||
|
./Installomator.sh desktoppr DEBUG=0 NOTIFY=silent
|
||||||
|
```
|
||||||
|
|
||||||
|
Providing variables this way will override any variables set in the script.
|
||||||
|
|
||||||
|
You can even provide _all_ the variables necessary for download and installation. Of course, without a label the argument parsing will fail, so I created a special label `valuesfromarguments` which only checks if the four required values are present:
|
||||||
|
|
||||||
|
```
|
||||||
|
./Installomator.sh name=desktoppr type=pkg downloadURL=https://github.com/scriptingosx/desktoppr/releases/download/v0.3/desktoppr-0.3.pkg expectedTeamID=JME5BW3F3R valuesfromarguments
|
||||||
|
```
|
||||||
|
|
||||||
|
The order of the variables and label is not relevant. But, when you provide more than one label, all but the _last_ label will be ignored.
|
||||||
|
|
||||||
|
Providing all the variables this way might be useful for certain downloads that have a customized URL for each vendor/customer (like customized TeamView or Watchman Monitoring) or are local downloads.
|
||||||
|
|
||||||
|
|
||||||
## Frequently Asked Questions
|
## Frequently Asked Questions
|
||||||
|
|
||||||
### What if the latest version of the app is already installed?
|
### What if the latest version of the app is already installed?
|
||||||
|
|||||||
Reference in New Issue
Block a user