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 - 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

View File

@@ -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

View File

@@ -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

View File

@@ -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?