5 Commits
v0.4 ... v0.3

Author SHA1 Message Date
Armin Briegel
d40b324a91 Merge branch 'dev' for v0.3 2020-07-23 13:45:12 +02:00
Armin Briegel
cb05dfd52a Merge pull request #49 from phinbox/citrix-workspace-bugfix
Citrix Workspace downloadURL update
2020-07-22 11:45:16 +02:00
Phinehas Bynum
37262f12e7 Update Installomator.sh
Updated citrixworkspace downloadURL to pull the latest version from the HTML of the download page along with the "__gda__" portion at the end and prepend "https://" to the relative link.
2020-07-08 19:40:24 -05:00
Phinehas Bynum
697a38b7b6 Revert "Update Installomator.sh"
This reverts commit a59f965acd.
2020-07-08 19:37:26 -05:00
Phinehas Bynum
a59f965acd Update Installomator.sh
Updated citrixworkspace URL parsing to pull the latest version from the HTML of the download along with the "__gda__" portion at the end and prepend "https://" to the relative link.
2020-07-08 19:34:49 -05:00
4 changed files with 357 additions and 584 deletions

View File

@@ -1,13 +1,4 @@
## v0.4 - 2020-10-19 ## v0.3 - 2020-07-
- 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
@@ -25,4 +16,4 @@
improved logging improved logging
- several new applications: count increased from 62 in 0.1 to 87 in 0.2 - 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 # 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.4' VERSION='0.3'
VERSIONDATE='20201019' VERSIONDATE='20200609'
export PATH=/usr/bin:/bin:/usr/sbin:/sbin export PATH=/usr/bin:/bin:/usr/sbin:/sbin
@@ -35,9 +35,6 @@ 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
@@ -116,54 +113,9 @@ BLOCKING_PROCESS_ACTION=prompt_user
# #
# MARK: Functions # MARK: functions to help with getting data
cleanupAndExit() { # $1 = exit code, $2 message # Logging
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(){
@@ -195,7 +147,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"
@@ -207,312 +159,6 @@ 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
@@ -521,28 +167,17 @@ if ! is-at-least 10.14 $(sw_vers -productVersion); then
exit 98 exit 98
fi fi
# MARK: argument parsing # MARK: get the label
if [[ $# -eq 0 ]]; then if [[ $# -eq 0 ]]; then
grep -E '^[a-z0-9\-]*(\)|\|\\)$' "$0" | tr -d ')|\' | grep -v -E '^(broken.*|longversion|version|valuesfromarguments)$' | sort grep -E '^[a-z0-9\-]*(\)|\|\\)$' "$0" | tr -d ')|\' | grep -v -E '^broken' | grep -v -E '^(longversion|version)$' | sort
exit 0 exit 0
elif [[ $1 == "/" ]]; then elif [[ $# -gt 3 ]]; then
# jamf uses sends '/' as the first argument # jamf uses $4 for the first custom parameter
printlog "shifting arguments for Jamf" printlog "shifting arguments for Jamf"
shift 3 shift 3
fi fi
while [[ -n $1 ]]; do label=${1:?"no label provided"}
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"
@@ -806,13 +441,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) and #Philipp on MacAdmins Slack # credit: Erik Stam (@erikstam)
name="Citrix Workspace" #name="Citrix Workspace"
type="pkgInDmg" #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/") #downloadURL="https://downloads.citrix.com/17596/CitrixWorkspaceApp.dmg?__gda__=1588183500_fc68033aef7d6d163d8b8309b964f1de"
expectedTeamID="S272Y5R93J" #expectedTeamID="S272Y5R93J"
;; #;;
privileges) privileges)
# credit: Erik Stam (@erikstam) # credit: Erik Stam (@erikstam)
name="Privileges" name="Privileges"
@@ -1005,8 +640,8 @@ brave)
# credit: @securitygeneration # credit: @securitygeneration
name="Brave Browser" name="Brave Browser"
type="dmg" type="dmg"
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) downloadURL="https://laptop-updates.brave.com/latest/osx"
expectedTeamID="KL8N8XSYF4" expectedTeamID="9BNSXJN65R"
;; ;;
umbrellaroamingclient) umbrellaroamingclient)
# credit: Tadayuki Onishi (@kenchan0130) # credit: Tadayuki Onishi (@kenchan0130)
@@ -1130,9 +765,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 Work" name="8x8 - Virtual Office"
type="dmg" type="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") 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")
expectedTeamID="FC967L3QRG" expectedTeamID="FC967L3QRG"
;; ;;
egnyte) egnyte)
@@ -1143,132 +778,6 @@ 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
@@ -1439,27 +948,6 @@ 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)
@@ -1487,8 +975,341 @@ 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,29 +3,20 @@
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
@@ -42,13 +33,11 @@ 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
@@ -85,10 +74,7 @@ royaltsx
santa santa
sfsymbols sfsymbols
signal signal
sizeup
skitch
slack slack
snagit2020
sonos sonos
sonoss1 sonoss1
sonoss2 sonoss2
@@ -102,15 +88,11 @@ 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,27 +305,6 @@ 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?