diff --git a/MDMInstallAndDeploy.sh b/MDMInstallAndDeploy.sh new file mode 100644 index 0000000..0eacea4 --- /dev/null +++ b/MDMInstallAndDeploy.sh @@ -0,0 +1,192 @@ +#!/bin/bash + +# +# Complete script meant for running via MDM on device enrollment. This will download +# and install Dialog on the fly before opening Dialog. Tested with Mosyle MDM. +# +# The logging to /var/tmp/deploy.log is useful when getting started but +# arguably is not needed. +# +# Display a Dialog with a list of applications and indicate when they've been installed +# Useful when apps are deployed at random, perhaps without local logging. +# Applies to Mosyle App Catalog installs, VPP app installs, etc. +# +# Requires Dialog v1.9.1 or later https://github.com/bartreardon/swiftDialog/ +# + +# *** definable variables + +# List of apps/installs to process +# Provide the display name as you prefer and the path to the app/file. ex: "Google Chrome,/Applications/Google Chrome.app" +# A comma separates the display name from the path. Do not use commas in your display name text. +# Tip: Check for something like print drivers using the pkg receipt, like "Konica-Minolta drivers,/var/db/receipts/jp.konicaminolta.print.package.C759.plist" +apps=( + "Google Chrome,/Applications/Google Chrome.app" + "Google Drive,/Applications/Google Drive.app" + "VLC,/Applications/VLC.app" + "zoom.us,/Applications/zoom.us.app" +) + +dialogURL=$(curl --silent --fail "https://api.github.com/repos/bartreardon/swiftDialog/releases/latest" | awk -F '"' "/browser_download_url/ && /pkg\"/ { print \$4; exit }") +# Expected Team ID of the downloaded PKG +dialogExpectedTeamID="PWA5E9TQ59" + +# Dialog display settings, change as desired +title="Installing Apps" +message="Please wait while we download and install apps" + +# location of dialog and dialog command file +dialogApp="/usr/local/bin/dialog" +dialog_command_file="/var/tmp/dialog.log" + +# *** end definable variables + +# *** functions + +function dialog_command(){ + echo "$1" + echo "$1" >> $dialog_command_file +} + +function finalise(){ + dialog_command "progresstext: Install of apps complete" + dialog_command "progress: complete" + dialog_command "button1text: Done" + dialog_command "button1: enable" + exit 0 +} + +function appCheck(){ +dialog_command "listitem: '$(echo "$app" | cut -d ',' -f1)': wait" +while [ ! -e "$(echo "$app" | cut -d ',' -f2)" ] +do + sleep 2 +done +dialog_command "progresstext: Install of \"$(echo "$app" | cut -d ',' -f1)\" complete" +dialog_command "listitem: $(echo "$app" | cut -d ',' -f1): ✅" +progress_index=$(( progress_index + 1 )) +echo "at item number $progress_index" +} + +function dialogCheck(){ +if [ ! -e "/Library/Application Support/Dialog/Dialog.app" ]; then + echo "$(date "+%a %h %d %H:%M:%S"): Dialog not found. Installing." 2>&1 | tee -a /var/tmp/deploy.log + # Create temporary working directory + workDirectory=$( /usr/bin/basename "$0" ) + tempDirectory=$( /usr/bin/mktemp -d "/private/tmp/$workDirectory.XXXXXX" ) + echo "$(date "+%a %h %d %H:%M:%S"): Created working directory '$tempDirectory'" 2>&1 | tee -a /var/tmp/deploy.log + # Download the installer package + echo "$(date "+%a %h %d %H:%M:%S"): Downloading Dialog package" 2>&1 | tee -a /var/tmp/deploy.log + /usr/bin/curl --location --silent "$dialogURL" -o "$tempDirectory/Dialog.pkg" + # Verify the download + teamID=$(/usr/sbin/spctl -a -vv -t install "$tempDirectory/Dialog.pkg" 2>&1 | awk '/origin=/ {print $NF }' | tr -d '()') + echo "$(date "+%a %h %d %H:%M:%S"): Team ID for downloaded package: $teamID" 2>&1 | tee -a /var/tmp/deploy.log + # Install the package if Team ID validates + if [ "$dialogExpectedTeamID" = "$teamID" ] || [ "$dialogExpectedTeamID" = "" ]; then + echo "$(date "+%a %h %d %H:%M:%S"): Package verified. Installing package Dialog.pkg" 2>&1 | tee -a /var/tmp/deploy.log + /usr/sbin/installer -pkg "$tempDirectory/Dialog.pkg" -target / + exitCode=0 + else + echo "$(date "+%a %h %d %H:%M:%S"): Package verification failed before package installation could start. Download link may be invalid. Aborting." 2>&1 | tee -a /var/tmp/deploy.log + displayDialog + exitCode=1 + exit $exitCode + fi + # Remove the temporary working directory when done + echo "$(date "+%a %h %d %H:%M:%S"): Deleting working directory '$tempDirectory' and its contents" 2>&1 | tee -a /var/tmp/deploy.log + /bin/rm -Rf "$tempDirectory" +else echo "$(date "+%a %h %d %H:%M:%S"): Dialog already found. Proceeding..." 2>&1 | tee -a /var/tmp/deploy.log +fi +} + +# If something goes wrong and Dialog isn't installed we want to notify the user using AppleScript and exit the script +function displayDialog(){ + message="A problem was encountered setting up this Mac. Please contact IT." + currentUser=$(scutil <<< "show State:/Users/ConsoleUser" | awk '/Name :/ { print $3 }') + if [[ "$currentUser" != "" ]]; then + currentUserID=$(id -u "$currentUser") + launchctl asuser "$currentUserID" /usr/bin/osascript <<-EndOfScript + button returned of ¬ + (display dialog "$message" ¬ + buttons {"OK"} ¬ + default button "OK") + EndOfScript + fi +} + +# *** end functions + +# start + +setupAssistantProcess=$(pgrep -l "Setup Assistant") +until [ "$setupAssistantProcess" = "" ]; do + echo "$(date "+%a %h %d %H:%M:%S"): Setup Assistant Still Running. PID $setupAssistantProcess." 2>&1 | tee -a /var/tmp/deploy.log + sleep 1 + setupAssistantProcess=$(pgrep -l "Setup Assistant") +done +echo "$(date "+%a %h %d %H:%M:%S"): Out of Setup Assistant" 2>&1 | tee -a /var/tmp/deploy.log +echo "$(date "+%a %h %d %H:%M:%S"): Logged in user is $(scutil <<< "show State:/Users/ConsoleUser" | awk '/Name :/ { print $3 }')" 2>&1 | tee -a /var/tmp/deploy.log + +finderProcess=$(pgrep -l "Finder") +until [ "$finderProcess" != "" ]; do + echo "$(date "+%a %h %d %H:%M:%S"): Finder process not found. Assuming device is at login screen. PID $finderProcess" 2>&1 | tee -a /var/tmp/deploy.log + sleep 1 + finderProcess=$(pgrep -l "Finder") +done +echo "$(date "+%a %h %d %H:%M:%S"): Finder is running" 2>&1 | tee -a /var/tmp/deploy.log +echo "$(date "+%a %h %d %H:%M:%S"): Logged in user is $(scutil <<< "show State:/Users/ConsoleUser" | awk '/Name :/ { print $3 }')" 2>&1 | tee -a /var/tmp/deploy.log + +dialogCheck + +# set progress total to the number of apps in the list +progress_total=${#apps[@]} + +# set icon based on whether computer is a desktop or laptop +hwType=$(/usr/sbin/system_profiler SPHardwareDataType | grep "Model Identifier" | grep "Book") +if [ "$hwType" != "" ]; then + icon="SF=laptopcomputer.and.arrow.down,weight=thin,colour1=#51a3ef,colour2=#5154ef" + else + icon="SF=desktopcomputer.and.arrow.down,weight=thin,colour1=#51a3ef,colour2=#5154ef" +fi + +echo "$(date "+%a %h %d %H:%M:%S"): Logged in user is $(scutil <<< "show State:/Users/ConsoleUser" | awk '/Name :/ { print $3 }')" 2>&1 | tee -a /var/tmp/deploy.log + +dialogCMD="$dialogApp -p --title \"$title\" \ +--message \"$message\" \ +--icon \"$icon\" \ +--progress $progress_total \ +--button1text \"Please Wait\" \ +--button1disabled" + +# create the list of apps +listitems="" +for app in "${apps[@]}"; do + listitems="$listitems --listitem '$(echo "$app" | cut -d ',' -f1)'" +done + +# final command to execute +dialogCMD="$dialogCMD $listitems" + +echo "$dialogCMD" + +# Launch dialog and run it in the background sleep for a second to let thing initialise +echo "$(date "+%a %h %d %H:%M:%S"): About to launch Dialog." 2>&1 | tee -a /var/tmp/deploy.log +eval "$dialogCMD" & +sleep 2 + +progress_index=0 + + +(for app in "${apps[@]}"; do + step_progress=$(( 1 + progress_index )) + dialog_command "progress: $step_progress" + appCheck & +done + +wait) + +# all done. close off processing and enable the "Done" button + +echo "$(date "+%a %h %d %H:%M:%S"): Finalizing." 2>&1 | tee -a /var/tmp/deploy.log +finalise +echo "$(date "+%a %h %d %H:%M:%S"): Done." 2>&1 | tee -a /var/tmp/deploy.log