68 Commits
v0.3 ... v0.4

Author SHA1 Message Date
Armin Briegel
4d4e22379e Update CHANGELOG.md 2020-10-19 10:21:45 +02:00
Armin Briegel
fc01e2f8de Merge branch 'dev' of https://github.com/scriptingosx/Installomator into dev 2020-10-19 10:06:33 +02:00
Armin Briegel
4283329b25 Merge pull request #78 from Raptor399/prompt-then-kill
Add option to prompt user and finally kill
2020-10-19 10:05:43 +02:00
Armin Briegel
2e207f6982 Update Labels.txt 2020-10-19 09:56:54 +02:00
Armin Briegel
b99d3b50f4 added apparency 2020-10-19 09:42:43 +02:00
Armin Briegel
c669250d8c added amazonworkspaces 2020-10-19 09:41:57 +02:00
Armin Briegel
76a38cdffc fixed 8x8 download 2020-10-19 09:36:48 +02:00
Armin Briegel
c53e49d406 Merge branch 'dialpad' into dev 2020-10-19 09:16:06 +02:00
Armin Briegel
125fadd4f4 added credit 2020-10-19 09:15:52 +02:00
Armin Briegel
53f043ede5 updated CHANGELOG 2020-10-19 09:12:17 +02:00
Armin Briegel
3530130b48 added function to deal with new xpath tool in Big Sur 2020-10-19 09:00:08 +02:00
Eiichi Hosaka
71fe13b311 added dialpad 2020-10-15 09:30:29 +09:00
Patrick Atoon
2c613803b5 Add option to prompt user and finally kill
The `prompt_user` option uses osascript to attempt to quit an app three times,
which can sometimes fail. Added an option `prompt_user_then_kill` to attempt
to quit twice, but kill the process if earlier quit attempts failed.
2020-10-11 11:26:04 +02:00
Armin Briegel
edff222adc updated README 2020-09-22 16:26:59 +02:00
Armin Briegel
4a124f2151 updated Brave downloadURL 2020-09-22 16:26:46 +02:00
Armin Briegel
977e46d33f changed zip de-compression from unzip to ditto 2020-09-21 15:02:45 +02:00
Armin Briegel
5bfeddbecf updated Labels.txt 2020-09-21 14:13:30 +02:00
Armin Briegel
0dd63eae75 added skitch 2020-09-21 14:11:06 +02:00
Armin Briegel
dff5b8c61a changed brave team ID, closes #74 and #76 2020-09-21 14:00:34 +02:00
Armin Briegel
57da0331bf added yubikeymanagerqt, closes #75 2020-09-21 13:27:53 +02:00
Armin Briegel
96c998413f Merge branch 'argument-refactor' into dev 2020-09-21 13:16:39 +02:00
Armin Briegel
933c51e00f added Tunnelblick 2020-09-17 14:41:18 +02:00
Armin Briegel
cd9247360a order of arguments now not relevant 2020-09-17 14:31:36 +02:00
Armin Briegel
a0d93f1799 added valuesfromarguments label so download info can be provided entirely from arguments 2020-08-26 20:05:39 +02:00
Armin Briegel
138301f61e now uses arguments in the form VAR=value to set value 2020-08-26 17:16:44 +02:00
Armin Briegel
901f99459a added credits 2020-08-26 14:01:10 +02:00
Armin Briegel
f653833dc2 Merge pull request #68 from apizz/alfred-add
Add Alfred
2020-08-26 08:17:20 +02:00
Armin Briegel
eb802b9a95 Merge branch 'dev' into alfred-add 2020-08-26 08:17:10 +02:00
Armin Briegel
04a2c74dd8 Merge pull request #67 from apizz/istatmenus-add
Add iStat Menus
2020-08-26 08:16:24 +02:00
Armin Briegel
4d49e51789 Merge branch 'dev' into istatmenus-add 2020-08-26 08:16:13 +02:00
Armin Briegel
2e07291c60 Merge pull request #66 from apizz/sizeup-add
Add SizeUp
2020-08-26 08:14:55 +02:00
AP Orlebeke
5c5dadfe9b Add Alfred and label 2020-08-25 20:18:14 -04:00
AP Orlebeke
bd49d7ca97 Add blocking processes 2020-08-25 20:07:46 -04:00
AP Orlebeke
3d4c1b45c9 Add iStat Menus and label 2020-08-25 20:04:40 -04:00
AP Orlebeke
961816236f Add SizeUp and label 2020-08-25 19:58:58 -04:00
Armin Briegel
be0f0a9cd0 updated Labels.txt. and added credits for new labels 2020-08-25 14:31:24 +02:00
Armin Briegel
22bd79af0e Merge pull request #64 from apizz/virtualbox-add
Add VirtualBox label
2020-08-25 14:11:58 +02:00
Armin Briegel
912a0e0046 Merge branch 'dev' into virtualbox-add 2020-08-25 14:11:44 +02:00
Armin Briegel
5059673fc7 Merge pull request #63 from apizz/detectxswift-add
Add DetectX Swift label
2020-08-25 14:11:05 +02:00
Armin Briegel
8a56d05a8a Merge branch 'dev' into detectxswift-add 2020-08-25 14:10:47 +02:00
Armin Briegel
65d8996118 Merge pull request #62 from apizz/autopkgr-add
Add AutoPkgr label
2020-08-25 14:10:05 +02:00
Armin Briegel
ef27dfde6d Merge branch 'dev' into autopkgr-add 2020-08-25 14:09:56 +02:00
Armin Briegel
e81c8114b4 Merge pull request #61 from apizz/airserver-add
Add AirServer label
2020-08-25 14:09:13 +02:00
Armin Briegel
d84ce01eb5 Merge branch 'dev' into autopkgr-add 2020-08-25 14:08:54 +02:00
Armin Briegel
09d0230256 Merge branch 'dev' into airserver-add 2020-08-25 14:08:14 +02:00
Armin Briegel
c65df61524 Merge pull request #60 from apizz/vscodium-add
Add VSCodium label
2020-08-25 14:07:29 +02:00
Armin Briegel
5dff7ee718 Merge branch 'dev' into vscodium-add 2020-08-25 14:07:18 +02:00
Armin Briegel
555a7631b9 Merge pull request #59 from Raptor399/add-keepassxc
Add label keepassxc
2020-08-25 14:06:31 +02:00
Armin Briegel
9c96b5a764 Merge pull request #58 from Raptor399/end-of-string-matching
Only match GitHub files that end in the filetype
2020-08-25 14:05:46 +02:00
AP Orlebeke
2ddbd2ab1e Add label 2020-08-24 01:08:40 -04:00
AP Orlebeke
ec7e479372 Add label 2020-08-24 01:07:52 -04:00
AP Orlebeke
a32b5fc0a2 Add label 2020-08-24 01:06:42 -04:00
AP Orlebeke
2d1777ca6e Add label 2020-08-24 01:06:11 -04:00
AP Orlebeke
37b36c8c13 Add label 2020-08-24 01:05:28 -04:00
AP Orlebeke
9508357243 Add VirtualBox 2020-08-24 00:47:35 -04:00
AP Orlebeke
c99aabccbb Add DetectX Swift 2020-08-24 00:30:01 -04:00
AP Orlebeke
a4df3399b4 Add AutoPkgr 2020-08-24 00:15:40 -04:00
AP Orlebeke
7438aa403c Fix URL 2020-08-23 23:57:58 -04:00
AP Orlebeke
965cf310e4 Add AirServer 2020-08-23 23:54:53 -04:00
AP Orlebeke
da5f99639a Add VSCodium 2020-08-23 23:39:51 -04:00
Raptor399
65f5c57772 Add label for KeePassXC 2020-08-23 12:17:53 +02:00
Raptor399
42ec528870 Some GitHub repos return multiple files matching the filetype, e.g. "filename.dmg", "filename.dmg.DIGEST", etc. Only return the file that ends in the filetype. 2020-08-23 12:03:36 +02:00
Armin Briegel
7f264733a7 added snagit2020 2020-08-09 16:53:51 +02:00
Armin Briegel
0a96de8449 fixed one printlog to many 2020-07-27 16:16:49 +02:00
Armin Briegel
7d6f4db736 added camtasia 2020-07-27 16:13:56 +02:00
Armin Briegel
adf34cb6f3 updated credit for citrixworkspace 2020-07-24 12:36:16 +02:00
Armin Briegel
8544796b75 re-added citrixworkspace 2020-07-23 14:18:38 +02:00
Armin Briegel
315398b3fc updated version 2020-07-23 13:54:49 +02:00
4 changed files with 584 additions and 357 deletions

View File

@@ -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
- removed the powershell labels, since the installer is not notarized
@@ -16,4 +25,4 @@
improved logging
- several new applications: count increased from 62 in 0.1 to 87 in 0.2
## v0.1 - 2020-05-12
## v0.1 - 2020-05-12

View File

@@ -8,8 +8,8 @@
# inspired by the download scripts from William Smith and Sander Schram
# with additional ideas and contribution from Isaac Ordonez, Mann consulting
VERSION='0.3'
VERSIONDATE='20200609'
VERSION='0.4'
VERSIONDATE='20201019'
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
# - prompt_user show a user dialog for each blocking process found
# 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
@@ -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"
printlog(){
@@ -147,7 +195,7 @@ downloadURLFromGit() { # $1 git user name, $2 git repo name
| awk -F '"' "/browser_download_url/ && /$archiveName/ { print \$4 }")
else
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
if [ -z "$downloadURL" ]; then
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
autoload is-at-least
@@ -167,17 +521,28 @@ if ! is-at-least 10.14 $(sw_vers -productVersion); then
exit 98
fi
# MARK: get the label
# MARK: argument parsing
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
elif [[ $# -gt 3 ]]; then
# jamf uses $4 for the first custom parameter
elif [[ $1 == "/" ]]; then
# jamf uses sends '/' as the first argument
printlog "shifting arguments for Jamf"
shift 3
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 "################## $label"
@@ -441,13 +806,13 @@ webexteams)
downloadURL="https://binaries.webex.com/WebexTeamsDesktop-MACOS-Gold/WebexTeams.dmg"
expectedTeamID="DE8Y96K9QP"
;;
#citrixworkspace)
# credit: Erik Stam (@erikstam)
#name="Citrix Workspace"
#type="pkgInDmg"
#downloadURL="https://downloads.citrix.com/17596/CitrixWorkspaceApp.dmg?__gda__=1588183500_fc68033aef7d6d163d8b8309b964f1de"
#expectedTeamID="S272Y5R93J"
#;;
citrixworkspace)
#credit: Erik Stam (@erikstam) and #Philipp on MacAdmins Slack
name="Citrix Workspace"
type="pkgInDmg"
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"
;;
privileges)
# credit: Erik Stam (@erikstam)
name="Privileges"
@@ -640,8 +1005,8 @@ brave)
# credit: @securitygeneration
name="Brave Browser"
type="dmg"
downloadURL="https://laptop-updates.brave.com/latest/osx"
expectedTeamID="9BNSXJN65R"
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="KL8N8XSYF4"
;;
umbrellaroamingclient)
# credit: Tadayuki Onishi (@kenchan0130)
@@ -765,9 +1130,9 @@ r)
;;
8x8)
# credit: #D-A-James from MacAdmins Slack and Isaac Ordonez, Mann consulting (@mannconsulting)
name="8x8 - Virtual Office"
name="8x8 Work"
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"
;;
egnyte)
@@ -778,6 +1143,132 @@ egnyte)
expectedTeamID="FELUD555VC"
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
@@ -948,6 +1439,27 @@ microsoftdefenderatp)
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
brokendownloadurl)
@@ -975,341 +1487,8 @@ brokenteamid)
;;
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

View File

@@ -3,20 +3,29 @@
adobereaderdc
adobereaderdc-install
adobereaderdc-update
airserver
alfred
amazonworkspaces
apparency
appcleaner
aquaskk
atom
autodmg
autopkgr
aviatrix
bbedit
bettertouchtool
boxdrive
brave
camtasia
citrixworkspace
code42
coderunner
cyberduck
depnotify
desktoppr
detectxswift
dialpad
discord
docker
dropbox
@@ -33,11 +42,13 @@ googlejapaneseinput
grandperspective
handbrake
icons
istatmenus
iterm2
jamfmigrator
jamfpppcutility
jamfreenroller
karabinerelements
keepassxc
krisp
malwarebytes
microsoftautoupdate
@@ -74,7 +85,10 @@ royaltsx
santa
sfsymbols
signal
sizeup
skitch
slack
snagit2020
sonos
sonoss1
sonoss2
@@ -88,11 +102,15 @@ textmate
things
torbrowser
tunnelbear
tunnelblick
umbrellaroamingclient
virtualbox
visualstudiocode
vlc
vscodium
webexmeetings
webexteams
whatsapp
wwdcformac
yubikeymanagerqt
zoom

View File

@@ -305,6 +305,27 @@ Depending on the application or pkg there are a few more variables you can or ne
- `updateToolRunAsCurrentUser`:
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
### What if the latest version of the app is already installed?