Merge branch 'dev' for v0.3

This commit is contained in:
Armin Briegel
2020-07-23 13:45:12 +02:00
4 changed files with 907 additions and 739 deletions

19
CHANGELOG.md Normal file
View File

@@ -0,0 +1,19 @@
## v0.3 - 2020-07-
- added several new labels for total of 98
- removed the powershell labels, since the installer is not notarized
- when run without any arguments, the script now lists all labels
- changed how zips are expanded because this was broken on Mojave
- improved logging in some statements
- several more minor improvements
## v0.2 - 2020-06-09
- many fixes for broken URLs and other bugs
- the `pkgInDmg` and `pkgInZip` now search for a pkg file in the archive in case the file name varies with the version
- notification on successful installation can be suppressed with the `NOTIFY` variable
- Apple signed installers and apps that dont have a Team ID are verified correctly now
improved logging
- several new applications: count increased from 62 in 0.1 to 87 in 0.2
## v0.1 - 2020-05-12

View File

@@ -8,12 +8,12 @@
# inspired by the download scripts from William Smith and Sander Schram
# with additional ideas and contribution from Isaac Ordonez, Mann consulting
VERSION='0.2'
VERSIONDATE='20200529'
VERSION='0.3'
VERSIONDATE='20200609'
export PATH=/usr/bin:/bin:/usr/sbin:/sbin
# adjust these variables:
# NOTE: adjust these variables:
# set to 0 for production, 1 for debugging
# while debugging, items will be downloaded to the parent directory of this script
@@ -38,6 +38,8 @@ BLOCKING_PROCESS_ACTION=prompt_user
# - kill kill process without prompting or giving the user a chance to save
# NOTE: How labels work
# Each workflow label needs to be listed in the case statement below.
# for each label these variables can be set:
#
@@ -110,16 +112,8 @@ BLOCKING_PROCESS_ACTION=prompt_user
# When this variable is set (any value), $updateTool will be run as the current user.
#
# todos:
# TODO: better logging (or, really, any logging other than echo)
# TODO: generic function Sparkle to get latest download
# TODO: ?notify user of errors
# TODO: ?generic function to initiate a Sparkle Update
# TODO: better version retrieval and reporting, before and after install
# functions to help with getting info
# MARK: functions to help with getting data
# Logging
log_location="/private/var/log/Installomator.log"
@@ -156,7 +150,7 @@ downloadURLFromGit() { # $1 git user name, $2 git repo name
| awk -F '"' "/browser_download_url/ && /$filetype/ { print \$4 }")
fi
if [ -z "$downloadURL" ]; then
echo "could not retrieve download URL for $gitusername/$gitreponame"
printlog "could not retrieve download URL for $gitusername/$gitreponame"
exit 9
else
echo "$downloadURL"
@@ -164,12 +158,19 @@ downloadURLFromGit() { # $1 git user name, $2 git repo name
fi
}
printlog "################## Start Installomator"
# get the label
# MARK: check minimal macOS requirement
autoload is-at-least
if ! is-at-least 10.14 $(sw_vers -productVersion); then
printlog "Installomator requires at least macOS 10.14 Mojave."
exit 98
fi
# MARK: get the label
if [[ $# -eq 0 ]]; then
printlog "no label provided"
exit 1
grep -E '^[a-z0-9\-]*(\)|\|\\)$' "$0" | tr -d ')|\' | grep -v -E '^broken' | grep -v -E '^(longversion|version)$' | sort
exit 0
elif [[ $# -gt 3 ]]; then
# jamf uses $4 for the first custom parameter
printlog "shifting arguments for Jamf"
@@ -178,6 +179,7 @@ fi
label=${1:?"no label provided"}
printlog "################## Start Installomator"
printlog "################## $label"
# lowercase the label
@@ -187,7 +189,7 @@ label=${label:l}
currentUser=$(scutil <<< "show State:/Users/ConsoleUser" | awk '/Name :/ { print $3 }')
# labels in case statement
# MARK: labels in case statement
case $label in
version)
# print the script VERSION
@@ -217,7 +219,11 @@ case $label in
googlechromepkg)
name="Google Chrome"
type="pkg"
downloadURL="https://dl.google.com/chrome/mac/stable/gcem/GoogleChrome.pkg"
#
# Note: this url acknowledges that you accept the terms of service
# https://support.google.com/chrome/a/answer/9915669
#
downloadURL="https://dl.google.com/chrome/mac/stable/accept_tos%3Dhttps%253A%252F%252Fwww.google.com%252Fintl%252Fen_ph%252Fchrome%252Fterms%252F%26_and_accept_tos%3Dhttps%253A%252F%252Fpolicies.google.com%252Fterms/googlechrome.pkg"
expectedTeamID="EQHXZ8M8AV"
updateTool="/Library/Google/GoogleSoftwareUpdate/GoogleSoftwareUpdate.bundle/Contents/Resources/GoogleSoftwareUpdateAgent.app/Contents/MacOS/GoogleSoftwareUpdateAgent"
updateToolArguments=( -runMode oneshot -userInitiated YES )
@@ -380,13 +386,20 @@ case $label in
expectedTeamID="BJ4HAAB9B3"
blockingProcesses=( zoom.us )
;;
sonos)
sonos|\
sonoss1)
# credit: Erik Stam (@erikstam)
name="Sonos"
name="Sonos S1 Controller"
type="dmg"
downloadURL="https://www.sonos.com/redir/controller_software_mac"
expectedTeamID="2G4LW83Q3E"
;;
sonoss2)
name="Sonos"
type="dmg"
downloadURL="https://www.sonos.com/redir/controller_software_mac2"
expectedTeamID="2G4LW83Q3E"
;;
coderunner)
# credit: Erik Stam (@erikstam)
name="CodeRunner"
@@ -428,15 +441,13 @@ case $label in
downloadURL="https://binaries.webex.com/WebexTeamsDesktop-MACOS-Gold/WebexTeams.dmg"
expectedTeamID="DE8Y96K9QP"
;;
citrixworkspace)
# credit: Erik Stam (@erikstam) updated by Phinehas Bynum (@phinbox)
name="Citrix Workspace"
type="pkgInDmg"
downloadURL=$(curl -s https://www.citrix.com/downloads/workspace-app/mac/workspace-app-for-mac-latest.html \
| grep -m1 -o --regexp="downloads.citrix.com/[0-9]\{5\}\/CitrixWorkspaceApp.dmg?__gda__=[0-9a-f_]*" \
| sed 's/^/https:\/\//')
expectedTeamID="S272Y5R93J"
;;
#citrixworkspace)
# credit: Erik Stam (@erikstam)
#name="Citrix Workspace"
#type="pkgInDmg"
#downloadURL="https://downloads.citrix.com/17596/CitrixWorkspaceApp.dmg?__gda__=1588183500_fc68033aef7d6d163d8b8309b964f1de"
#expectedTeamID="S272Y5R93J"
#;;
privileges)
# credit: Erik Stam (@erikstam)
name="Privileges"
@@ -546,6 +557,7 @@ case $label in
type="zip"
downloadURL="https://iterm2.com/downloads/stable/latest"
expectedTeamID="H7V7XYVQ7D"
blockingProcesses=( iTerm2 )
;;
royaltsx)
name="Royal TSX"
@@ -595,10 +607,18 @@ case $label in
downloadURL=$(downloadURLFromGit jamf ReEnroller)
expectedTeamID="PS2F6S478M"
;;
adobereaderdc)
adobereaderdc|\
adobereaderdc-install)
name="Adobe Acrobat Reader DC"
type="pkgInDmg"
downloadURL=$(adobecurrent=`curl -s https://armmf.adobe.com/arm-manifests/mac/AcrobatDC/reader/current_version.txt | tr -d '.'` && echo http://ardownload.adobe.com/pub/adobe/reader/mac/AcrobatDC/"$adobecurrent"/AcroRdrDC_"$adobecurrent"_MUI.dmg)
downloadURL=$(curl --silent --fail -H "Sec-Fetch-Site: same-origin" -H "Accept-Encoding: gzip, deflate, br" -H "Accept-Language: en-US;q=0.9,en;q=0.8" -H "DNT: 1" -H "Sec-Fetch-Mode: cors" -H "X-Requested-With: XMLHttpRequest" -H "Referer: https://get.adobe.com/reader/enterprise/" -H "Accept: */*" "https://get.adobe.com/reader/webservices/json/standalone/?platform_type=Macintosh&platform_dist=OSX&platform_arch=x86-32&language=English&eventname=readerotherversions" | grep -Eo '"download_url":.*?[^\\]",' | head -n 1 | cut -d \" -f 4)
expectedTeamID="JQ525L2MZD"
blockingProcesses=( "AdobeReader" )
;;
adobereaderdc-update)
name="Adobe Acrobat Reader DC"
type="pkgInDmg"
downloadURL=$(adobecurrent=`curl --fail --silent https://armmf.adobe.com/arm-manifests/mac/AcrobatDC/reader/current_version.txt | tr -d '.'` && echo http://ardownload.adobe.com/pub/adobe/reader/mac/AcrobatDC/"$adobecurrent"/AcroRdrDCUpd"$adobecurrent"_MUI.dmg)
expectedTeamID="JQ525L2MZD"
blockingProcesses=( "AdobeReader" )
;;
@@ -630,22 +650,33 @@ case $label in
downloadURL=https://disthost.umbrella.com/roaming/upgrade/mac/production/$( curl -fsL https://disthost.umbrella.com/roaming/upgrade/mac/production/manifest.json | awk -F '"' '/"downloadFilename"/ { print $4 }' )
expectedTeamID="7P7HQ8H646"
;;
powershell)
# credit: Tadayuki Onishi (@kenchan0130)
name="PowerShell"
type="pkg"
downloadURL=$(curl -fs "https://api.github.com/repos/Powershell/Powershell/releases/latest" \
| awk -F '"' '/browser_download_url/ && /pkg/ { print $4 }' | grep -v lts )
expectedTeamID="UBF8T346G9"
;;
powershell-lts)
# credit: Tadayuki Onishi (@kenchan0130)
name="PowerShell"
type="pkg"
downloadURL=$(curl -fs "https://api.github.com/repos/Powershell/Powershell/releases/latest" \
| awk -F '"' '/browser_download_url/ && /pkg/ { print $4 }' | grep lts)
expectedTeamID="UBF8T346G9"
;;
# TODO: vmwarefusion installation process needs testing
# vmwarefusion)
# # credit: Erik Stam (@erikstam)
# name="VMware Fusion"
# type="dmg"
# downloadURL="https://www.vmware.com/go/getfusion"
# expectedTeamID="EG7KH642X6"
# ;;
# NOTE: powershell installers are not notarized
# powershell)
# # credit: Tadayuki Onishi (@kenchan0130)
# name="PowerShell"
# type="pkg"
# downloadURL=$(curl -fs "https://api.github.com/repos/Powershell/Powershell/releases/latest" \
# | awk -F '"' '/browser_download_url/ && /pkg/ { print $4 }' | grep -v lts )
# expectedTeamID="UBF8T346G9"
# ;;
# powershell-lts)
# # credit: Tadayuki Onishi (@kenchan0130)
# name="PowerShell"
# type="pkg"
# downloadURL=$(curl -fs "https://api.github.com/repos/Powershell/Powershell/releases/latest" \
# | awk -F '"' '/browser_download_url/ && /pkg/ { print $4 }' | grep lts)
# expectedTeamID="UBF8T346G9"
# ;;
wwdcformac)
name="WWDC"
type="zip"
@@ -681,9 +712,76 @@ case $label in
downloadURL="https://updates.cdn-apple.com/2019/cert/061-41823-20191025-5efc5a59-d7dc-46d3-9096-396bb8cb4a73/SwiftRuntimeForCommandLineTools.dmg"
expectedTeamID="Software Update"
;;
aquaskk)
# credit: Tadayuki Onishi (@kenchan0130)
name="aquaskk"
type="pkg"
downloadURL="$(downloadURLFromGit codefirst aquaskk)"
expectedTeamID="FPZK4WRGW7"
;;
krisp)
# credit: Tadayuki Onishi (@kenchan0130)
name="Krisp"
type="pkg"
downloadURL="https://download.krisp.ai/mac"
expectedTeamID="U5R26XM5Z2"
;;
torbrowser)
# credit: Søren Theilgaard (@theilgaard)
name="Tor Browser"
type="dmg"
downloadURL=https://www.torproject.org$(curl -fs https://www.torproject.org/download/ | grep "downloadLink" | grep dmg | cut -d '"' -f 4)
appNewVersion=$(curl -fs https://www.torproject.org/download/ | grep "downloadLink" | grep dmg | cut -d '"' -f 4 | cut -d / -f 4)
expectedTeamID="MADPSAYN6T"
;;
code42)
# credit: Isaac Ordonez, Mann consulting (@mannconsulting)
name="Code42"
type="pkgInDmg"
downloadURL=https://download.code42.com/installs/agent/latest-mac.dmg
expectedTeamID="9YV9435DHD"
blockingProcesses=( NONE )
;;
nomad)
# credit: Tadayuki Onishi (@kenchan0130)
name="NoMAD"
type="pkg"
downloadURL="https://files.nomad.menu/NoMAD.pkg"
expectedTeamID="AAPZK3CB24"
;;
bettertouchtool)
# credit: Tadayuki Onishi (@kenchan0130)
name="BetterTouchTool"
type="zip"
downloadURL="https://folivora.ai/releases/BetterTouchTool.zip"
expectedTeamID="DAFVSXZ82P"
;;
r)
# credit: Tadayuki Onishi (@kenchan0130)
name="R"
type="pkg"
downloadURL=$( curl -fsL https://formulae.brew.sh/api/cask/r.json | sed -n 's/^.*"url":"\([^"]*\)".*$/\1/p' )
expectedTeamID="VZLD955F6P"
;;
8x8)
# credit: #D-A-James from MacAdmins Slack and Isaac Ordonez, Mann consulting (@mannconsulting)
name="8x8 - Virtual Office"
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")
expectedTeamID="FC967L3QRG"
;;
egnyte)
# credit: #MoeMunyoki from MacAdmins Slack
name="Egnyte Connect"
type="pkg"
downloadURL="https://egnyte-cdn.egnyte.com/egnytedrive/mac/en-us/latest/EgnyteConnectMac.pkg"
expectedTeamID="FELUD555VC"
blockingProcesses=( NONE )
;;
# MARK: add new labels above here
# Note: Packages is signed but _not_ notarized, so spctl will reject it
# NOTE: Packages is signed but _not_ notarized, so spctl will reject it
# packages)
# name="Packages"
# type="pkgInDmg"
@@ -877,7 +975,8 @@ case $label in
;;
esac
# functions
# MARK: Functions
cleanupAndExit() { # $1 = exit code, $2 message
if [[ -n $2 && $1 -ne 0 ]]; then
printlog "ERROR: $2"
@@ -904,9 +1003,10 @@ runAsUser() {
fi
}
displaydialog() { # $1: message
displaydialog() { # $1: message $2: title
message=${1:-"Message"}
runAsUser /usr/bin/osascript -e "button returned of (display dialog \"$message\" buttons {\"Not Now\", \"Quit and Update\"} default button \"Quit and Update\")"
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
@@ -924,7 +1024,14 @@ displaynotification() { # $1: message $2: title
getAppVersion() {
# get all apps matching name
applist=$(mdfind "kMDItemFSName == '$appName' && kMDItemKind == 'Application'" -0 )
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
@@ -953,7 +1060,7 @@ checkRunningProcesses() {
countedProcesses=0
for x in ${blockingProcesses}; do
if pgrep -xq "$x"; then
echo "found blocking process $x"
printlog "found blocking process $x"
case $BLOCKING_PROCESS_ACTION in
kill)
@@ -961,7 +1068,7 @@ checkRunningProcesses() {
pkill $x
;;
prompt_user)
button=$(displaydialog "The application $x needs to be updated. Quit $x to continue updating?")
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
@@ -1021,7 +1128,7 @@ installAppWithPath() { # $1: path to app to install in $targetDir
cleanupAndExit 6 "not running as root, exiting"
fi
echo "DEBUG enabled, skipping copy and chown steps"
printlog "DEBUG enabled, skipping copy and chown steps"
return 0
fi
@@ -1040,7 +1147,7 @@ installAppWithPath() { # $1: path to app to install in $targetDir
# set ownership to current user
if [ "$currentUser" != "loginwindow" ]; then
echo "Changing owner to $currentUser"
printlog "Changing owner to $currentUser"
chown -R "$currentUser" "$targetDir/$appName"
else
printlog "No user logged in, not changing user"
@@ -1061,7 +1168,7 @@ mountDMG() {
cleanupAndExit 3
fi
echo "Mounted: $dmgmount"
printlog "Mounted: $dmgmount"
}
installFromDMG() {
@@ -1080,7 +1187,7 @@ installFromPKG() {
fi
teamID=$(echo $spctlout | awk -F '(' '/origin=/ {print $2 }' | tr -d '()' )
echo $teamID
# Apple signed software has no teamID, grab entire origin instead
if [[ -z $teamID ]]; then
teamID=$(echo $spctlout | awk -F '=' '/origin=/ {print $NF }')
@@ -1103,7 +1210,7 @@ installFromPKG() {
# check for root
if [ "$(whoami)" != "root" ]; then
# not running as root
echo "not running as root, exiting"
printlog "not running as root, exiting"
cleanupAndExit 6
fi
@@ -1118,8 +1225,20 @@ installFromPKG() {
installFromZIP() {
# unzip the archive
printlog "Unzipping $archiveName"
tar -xf "$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"
}
@@ -1189,11 +1308,11 @@ runUpdateTool() {
### main code starts here
# MARK: main code starts here
# extract info from data
# MARK: extract info from data
if [ -z "$archiveName" ]; then
case $type in
dmg|pkg|zip|tbz)
@@ -1237,7 +1356,7 @@ if [[ -z $blockingProcesses ]]; then
blockingProcesses=( $name )
fi
# determine tmp dir
# MARK: determine tmp dir
if [ "$DEBUG" -ne 0 ]; then
# for debugging use script dir as working directory
tmpDir=$(dirname "$0")
@@ -1246,7 +1365,7 @@ else
tmpDir=$(mktemp -d )
fi
# change directory to temporary working directory
# MARK: change directory to temporary working directory
printlog "Changing directory to $tmpDir"
if ! cd "$tmpDir"; then
printlog "error changing directory $tmpDir"
@@ -1254,7 +1373,7 @@ if ! cd "$tmpDir"; then
cleanupAndExit 1
fi
# check if this is an Update
# MARK: check if this is an Update
getAppVersion
if [[ -n $appVersion ]]; then
if [[ $DEBUG -eq 0 ]]; then
@@ -1266,7 +1385,7 @@ if [[ -n $appVersion ]]; then
fi
fi
# when user is logged in, and app is running, prompt user to quit app
# MARK: when user is logged in, and app is running, prompt user to quit app
if [[ $BLOCKING_PROCESS_ACTION == "ignore" ]]; then
printlog "ignoring blocking processes"
@@ -1280,7 +1399,7 @@ else
fi
fi
# download the archive
# MARK: download the archive
if [ -f "$archiveName" ] && [ "$DEBUG" -ne 0 ]; then
printlog "$archiveName exists and DEBUG enabled, skipping download"
@@ -1293,6 +1412,8 @@ else
fi
fi
# MARK: install the download
case $type in
dmg)
installFromDMG
@@ -1300,9 +1421,12 @@ case $type in
pkg)
installFromPKG
;;
zip|tbz)
zip)
installFromZIP
;;
tbz)
installFromTBZ
;;
pkgInDmg)
installPkgInDmg
;;
@@ -1315,7 +1439,7 @@ case $type in
;;
esac
# print installed application location and version
# MARK: print installed application location and version
sleep 10 # wait a moment to let spotlight catch up
getAppVersion
@@ -1329,7 +1453,7 @@ printlog "$message"
if [[ $currentUser != "loginwindow" && $NOTIFY == "success" ]]; then
printlog "notifying"
displaynotification "$message" "Installation complete!"
displaynotification "$message" "$name update/installation complete!"
fi
# all done!

View File

@@ -1,12 +1,18 @@
1password7
8x8
adobereaderdc
adobereaderdc-install
adobereaderdc-update
appcleaner
aquaskk
atom
autodmg
aviatrix
bbedit
bettertouchtool
boxdrive
brave
code42
coderunner
cyberduck
depnotify
@@ -14,6 +20,7 @@ desktoppr
discord
docker
dropbox
egnyte
eraseinstall
firefox
firefoxesrpkg
@@ -31,6 +38,7 @@ jamfmigrator
jamfpppcutility
jamfreenroller
karabinerelements
krisp
malwarebytes
microsoftautoupdate
microsoftcompanyportal
@@ -50,15 +58,15 @@ microsoftskypeforbusiness
microsoftteams
microsoftword
netnewswire
nomad
omnifocus3
omnigraffle7
openvpnconnect
pacifist
plisteditpro
postman
powershell
powershell-lts
privileges
r
resiliosynchome
ringcentralapp
ringcentralmeetings
@@ -68,6 +76,8 @@ sfsymbols
signal
slack
sonos
sonoss1
sonoss2
sourcetree
spotify
sublimetext
@@ -76,6 +86,7 @@ swiftruntimeforcommandlinetools
teamviewer
textmate
things
torbrowser
tunnelbear
umbrellaroamingclient
visualstudiocode

View File

@@ -10,6 +10,20 @@ Your production and deployment environment will be different, please test thorou
I have put a lot of work into making it stable and safe, but I cannot - of course - make _any_ promises that it won't break in some not yet encountered edge case.
## Support and Contributing
Discussion, support and advice around Installomator happens in the `#installomator` channel in the [MacAdmins Slack](https:/macadmins.org). Go there for support questions.
Do not create an issue just when you have a questions, but do file an issue or pull request for bugs or wrong behavior. When in doubt, ask in the above Slack channel.
If you have added a new label, then please file a pull request. (and Thank you!)
## More reading
There are a few interesting post on Installomator on my weblog:
- [Introducing Installomator](https://scriptingosx.com/2020/05/introducing-installomator/)
- [Using Installomator with Jamf Pro](https://scriptingosx.com/2020/06/using-installomator-with-jamf-pro/) by Mischa van der Bent
## Background
@@ -244,7 +258,7 @@ The 10-character Developer Team ID with which the application or pkg is signed a
- Applications (in dmgs or zips)
`spctl -a -vv /Applications/BBEdit.app`
- Pkgs
- Installation Packages (pkg)
`spctl -a -vv -t install ~/Downloads/desktoppr-0.2.pkg`
@@ -337,5 +351,5 @@ But it is not suited as a client install automation tool.
### Why don't you just use brew?
Read the explanation for `autopkg`, pretty much the same applies for `brew`, i.e. While it is useful on a single Mac, it is a un-manageable mess when you think about deploying and managing on a fleet of computers.
Read the explanation for `autopkg`, pretty much the same applies for `brew`, i.e. while it is useful on a single Mac, it is a un-manageable mess when you think about deploying and managing on a fleet of computers.