diff --git a/README.md b/README.md
index 0714ec5..fbb53ed 100644
--- a/README.md
+++ b/README.md
@@ -1,11 +1,11 @@
[
](https://snelson.us/sym)
-# Setup Your Mac (1.14.0) with SYM-Helper (1.1.1) via swiftDialog (2.4.0)
+# Setup Your Mac (1.15.0) with SYM-Helper (1.1.1) via swiftDialog (2.4.0)
    
-> Optimized to leverage SYM-Helper (1.1.1), Setup Your Mac (1.14.0) leverages new features of swiftDialog (2.4.0)
+> Optimized to leverage SYM-Helper (1.1.1), Setup Your Mac (1.15.0) leverages new features of swiftDialog (2.4.0)
[
](https://snelson.us/sym)
diff --git a/Setup-Your-Mac-via-Dialog.bash b/Setup-Your-Mac-via-Dialog.bash
index f78efe9..5848225 100755
--- a/Setup-Your-Mac-via-Dialog.bash
+++ b/Setup-Your-Mac-via-Dialog.bash
@@ -10,18 +10,8 @@
#
# HISTORY
#
-# Version 1.14.0, 05-Feb-2024
-# - Updated Vimeo ID
-# - Corrected omission of [SYM-Helper] for `moveableInProduction`
-# - Updated "Microsoft Office 365" to "Microsoft 365"
-# - Added OS Build number to webhook output [Pull Request No. 124](https://github.com/dan-snelson/Setup-Your-Mac/pull/124); thanks, @drtaru!
-# - Changed filepath validation test from `-f` (i.e., "True if file exists and is a regular file") to `-e` (i.e., "True if file exists (regardless of type)."); thanks for the inspiration, @mrmte! [Issue 19](https://github.com/BIG-RAT/SYM-Helper/issues/19); thanks for the code suggestion, @bartreardon!
-# - Updates to `README.md`, `CONTRIBUTORS.md` and `CONTRIBUTING.md` [Pull Request No. 128](https://github.com/setup-your-mac/Setup-Your-Mac/pull/128); thanks, @robjschroeder!
-# - Refactored the way `brandingBanner` variable is checked [Pull Request No. 131](https://github.com/setup-your-mac/Setup-Your-Mac/pull/131); thanks, @drtaru!
-# - Increased minimum required version of swiftDialog to 2.4.0.4750
-# - Leveraged the new `listitem: subtitle` option with a dedicated `subtitle` field in `policyJSON`
-# - Corrected misspelling of "policies" in log entries [Issue No. 134](https://github.com/setup-your-mac/Setup-Your-Mac/issues/134); thanks, @Honestpuck!
-# - Updated `brandingBanner` to [image by benzoix on Freepik](https://www.freepik.com/author/benzoix)
+# Version 1.15.0, 06-Feb-2024
+# - Added logging functions
#
####################################################################################################
@@ -37,7 +27,7 @@
# Script Version and Jamf Pro Script Parameters
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
-scriptVersion="1.14.0"
+scriptVersion="1.15.0"
export PATH=/usr/bin:/bin:/usr/sbin:/sbin
scriptLog="${4:-"/var/log/org.churchofjesuschrist.log"}" # Parameter 4: Script Log Location [ /var/log/org.churchofjesuschrist.log ] (i.e., Your organization's default location for client-side logs)
debugMode="${5:-"verbose"}" # Parameter 5: Debug Mode [ verbose (default) | true | false ]
@@ -55,6 +45,8 @@ swiftDialogMinimumRequiredVersion="2.4.0.4750"
# Various Feature Variables
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+humanReadableScriptName="Setup Your Mac" # Script Human-readable Name
+organizationScriptName="sym" # Organization's Script Name
debugModeSleepAmount="3" # Delay for various actions when running in Debug Mode
failureDialog="true" # Display the so-called "Failure" dialog (after the main SYM dialog) [ true | false ]
@@ -162,2597 +154,2646 @@ configurationThreeDescription="Recommended apps, Adobe Acrobat Reader and Google
configurationThreeSize="106" # Configuration Three in Gibibits (i.e., Total File Size in Gigabytes * 7.451)
configurationThreeInstallBuffer="0" # Buffer time added to estimates to include installation time of packages, in seconds. Set to 0 to disable.
-
-
####################################################################################################
#
-# Pre-flight Checks
+# Functions
#
####################################################################################################
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
-# Pre-flight Check: Client-side Logging
+# Client-side Logging
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
-if [[ ! -f "${scriptLog}" ]]; then
- touch "${scriptLog}"
-fi
+function updateScriptLog() {
+ echo -e "${organizationScriptName} ($scriptVersion): $( date +%Y-%m-%d\ %H:%M:%S ) - ${1}" | tee -a "${scriptLog}"
+}
+function preFlight() {
+ updateScriptLog "[PRE-FLIGHT] ${1}"
+}
+function welcomeDialog() {
+ updateScriptLog "[WELCOME DIALOG] ${1}"
+}
-# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
-# Pre-flight Check: Client-side Script Logging Function
-# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+function error() {
+ updateScriptLog "[ERROR] ${1}"
+}
-function updateScriptLog() {
- echo -e "$( date +%Y-%m-%d\ %H:%M:%S ) - ${1}" | tee -a "${scriptLog}"
+function fatal() {
+ updateScriptLog "[FATAL ERROR] ${1}"
+ exit 1
}
+function info() {
+ updateScriptLog "[INFO] ${1}"
+}
+function updateSetupYourMacDialog() {
+ updateScriptLog "[SETUP YOUR MAC DIALOG] ${1}"
+}
-# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
-# Pre-flight Check: Current Logged-in User Function
-# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+function updateFailureDialog() {
+ updateScriptLog "[FAILURE DIALOG] ${1}"
+}
-function currentLoggedInUser() {
- loggedInUser=$( echo "show State:/Users/ConsoleUser" | scutil | awk '/Name :/ { print $3 }' )
- updateScriptLog "PRE-FLIGHT CHECK: Current Logged-in User: ${loggedInUser}"
+function updateSuccessDialog() {
+ updateScriptLog "[SUCCESS] ${1}"
+}
+
+function finaliseUserExperience() {
+ updateScriptLog "[FINALISE USER EXPERIENCE] ${1}"
}
+function completionActionOut() {
+ updateScriptLog "[COMPLETION ACTION] ${1}"
+}
+function quitOut() {
+ updateScriptLog "[QUIT SCRIPT] ${1}"
+}
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
-# Pre-flight Check: Logging Preamble
+# Output Line Number in `verbose` Debug Mode (thanks, @bartreardon!)
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
-updateScriptLog "\n\n###\n# Setup Your Mac (${scriptVersion})\n# https://snelson.us/sym\n###\n"
-updateScriptLog "PRE-FLIGHT CHECK: Initiating …"
+function outputLineNumberInVerboseDebugMode() {
+ if [[ "${debugMode}" == "verbose" ]]; then updateScriptLog "# # # SETUP YOUR MAC VERBOSE DEBUG MODE: Line No. ${BASH_LINENO[0]} # # #" ; fi
+}
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
-# Pre-flight Check: Confirm script is running under bash
+# Run command as logged-in user (thanks, @scriptingosx!)
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
-if [[ "$BASH" != "/bin/bash" ]] ; then
- updateScriptLog "PRE-FLIGHT CHECK: This script must be run under 'bash', please do not run it using 'sh', 'zsh', etc.; exiting."
- exit 1
-fi
-
-
+function runAsUser() {
-# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
-# Pre-flight Check: Confirm script is running as root
-# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+ info "Run \"$@\" as \"$loggedInUserID\" … "
+ launchctl asuser "$loggedInUserID" sudo -u "$loggedInUser" "$@"
-if [[ $(id -u) -ne 0 ]]; then
- updateScriptLog "PRE-FLIGHT CHECK: This script must be run as root; exiting."
- exit 1
-fi
+}
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
-# Pre-flight Check: Validate Setup Assistant has completed
+# Calculate Free Disk Space
+# Disk Usage with swiftDialog (https://snelson.us/2022/11/disk-usage-with-swiftdialog-0-0-2/)
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
-while pgrep -q -x "Setup Assistant"; do
- updateScriptLog "PRE-FLIGHT CHECK: Setup Assistant is still running; pausing for 2 seconds"
- sleep 2
-done
+function calculateFreeDiskSpace() {
+
+ freeSpace=$( diskutil info / | grep -E 'Free Space|Available Space|Container Free Space' | awk -F ":\s*" '{ print $2 }' | awk -F "(" '{ print $1 }' | xargs )
+ freeBytes=$( diskutil info / | grep -E 'Free Space|Available Space|Container Free Space' | awk -F "(\\\(| Bytes\\\))" '{ print $2 }' )
+ diskBytes=$( diskutil info / | grep -E 'Total Space' | awk -F "(\\\(| Bytes\\\))" '{ print $2 }' )
+ freePercentage=$( echo "scale=2; ( $freeBytes * 100 ) / $diskBytes" | bc )
+ diskSpace="$freeSpace free (${freePercentage}% available)"
+
+ diskMessage=$(echo "Disk Space: ${diskSpace}")
-updateScriptLog "PRE-FLIGHT CHECK: Setup Assistant is no longer running; proceeding …"
+}
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
-# Pre-flight Check: Confirm Dock is running / user is at Desktop
+# Update the "Welcome" dialog
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
-until pgrep -q -x "Finder" && pgrep -q -x "Dock"; do
- updateScriptLog "PRE-FLIGHT CHECK: Finder & Dock are NOT running; pausing for 1 second"
- sleep 1
-done
-
-updateScriptLog "PRE-FLIGHT CHECK: Finder & Dock are running; proceeding …"
+function dialogUpdateWelcome(){
+ # welcomeDialog "$1"
+ echo "$1" >> "$welcomeCommandFile"
+}
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
-# Pre-flight Check: Validate Logged-in System Accounts
+# Update the "Setup Your Mac" dialog
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
-updateScriptLog "PRE-FLIGHT CHECK: Check for Logged-in System Accounts …"
-currentLoggedInUser
-
-counter="1"
+function dialogUpdateSetupYourMac() {
+ updateSetupYourMacDialog "$1"
+ echo "$1" >> "$setupYourMacCommandFile"
+}
-until { [[ "${loggedInUser}" != "_mbsetupuser" ]] || [[ "${counter}" -gt "180" ]]; } && { [[ "${loggedInUser}" != "loginwindow" ]] || [[ "${counter}" -gt "30" ]]; } ; do
- updateScriptLog "PRE-FLIGHT CHECK: Logged-in User Counter: ${counter}"
- currentLoggedInUser
- sleep 2
- ((counter++))
-done
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+# Update the "Failure" dialog
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
-loggedInUserFullname=$( id -F "${loggedInUser}" )
-loggedInUserFirstname=$( echo "$loggedInUserFullname" | sed -E 's/^.*, // ; s/([^ ]*).*/\1/' | sed 's/\(.\{25\}\).*/\1…/' | awk '{print ( $0 == toupper($0) ? toupper(substr($0,1,1))substr(tolower($0),2) : toupper(substr($0,1,1))substr($0,2) )}' )
-loggedInUserID=$( id -u "${loggedInUser}" )
-updateScriptLog "PRE-FLIGHT CHECK: Current Logged-in User First Name: ${loggedInUserFirstname}"
-updateScriptLog "PRE-FLIGHT CHECK: Current Logged-in User ID: ${loggedInUserID}"
+function dialogUpdateFailure(){
+ updateFailureDialog "$1"
+ echo "$1" >> "$failureCommandFile"
+}
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
-# Pre-flight Check: Validate Operating System Version and Build
+# Finalise User Experience
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
-if [[ "${requiredMinimumBuild}" == "disabled" ]]; then
-
- updateScriptLog "PRE-FLIGHT CHECK: 'requiredMinimumBuild' has been set to ${requiredMinimumBuild}; skipping OS validation."
- updateScriptLog "PRE-FLIGHT CHECK: macOS ${osVersion} (${osBuild}) installed"
-
-else
+function finalise(){
- # Since swiftDialog requires at least macOS 12 Monterey, first confirm the major OS version
- if [[ "${osMajorVersion}" -ge 12 ]] ; then
+ outputLineNumberInVerboseDebugMode
- updateScriptLog "PRE-FLIGHT CHECK: macOS ${osMajorVersion} installed; checking build version ..."
+ if [[ "${configurationDownloadEstimation}" == "true" ]]; then
- # Confirm the Mac is running `requiredMinimumBuild` (or later)
- if [[ "${osBuild}" > "${requiredMinimumBuild}" ]]; then
+ outputLineNumberInVerboseDebugMode
+ calculateFreeDiskSpace
+ finaliseUserExperience "${diskMessage}"
- updateScriptLog "PRE-FLIGHT CHECK: macOS ${osVersion} (${osBuild}) installed; proceeding ..."
+ fi
- # When the current `osBuild` is older than `requiredMinimumBuild`; exit with error
- else
- updateScriptLog "PRE-FLIGHT CHECK: The installed operating system, macOS ${osVersion} (${osBuild}), needs to be updated to Build ${requiredMinimumBuild}; exiting with error."
- osascript -e 'display dialog "Please advise your Support Representative of the following error:\r\rExpected macOS Build '${requiredMinimumBuild}' (or newer), but found macOS '${osVersion}' ('${osBuild}').\r\r" with title "Setup Your Mac: Detected Outdated Operating System" buttons {"Open Software Update"} with icon caution'
- updateScriptLog "PRE-FLIGHT CHECK: Executing /usr/bin/open '${outdatedOsAction}' …"
- su - "${loggedInUser}" -c "/usr/bin/open \"${outdatedOsAction}\""
- exit 1
+ if [[ "${jamfProPolicyTriggerFailure}" == "failed" ]]; then
+ outputLineNumberInVerboseDebugMode
+ updateFailureDialog "Failed policies detected …"
+ if [[ -n "${webhookURL}" ]]; then
+ updateFailureDialog "Display Failure dialog: Sending webhook message"
+ webhookStatus="Failures detected"
+ webHookMessage
fi
- # The Mac is running an operating system older than macOS 12 Monterey; exit with error
- else
-
- updateScriptLog "PRE-FLIGHT CHECK: swiftDialog requires at least macOS 12 Monterey and this Mac is running ${osVersion} (${osBuild}), exiting with error."
- osascript -e 'display dialog "Please advise your Support Representative of the following error:\r\rExpected macOS Build '${requiredMinimumBuild}' (or newer), but found macOS '${osVersion}' ('${osBuild}').\r\r" with title "Setup Your Mac: Detected Outdated Operating System" buttons {"Open Software Update"} with icon caution'
- updateScriptLog "PRE-FLIGHT CHECK: Executing /usr/bin/open '${outdatedOsAction}' …"
- su - "${loggedInUser}" -c "/usr/bin/open \"${outdatedOsAction}\""
- exit 1
-
- fi
+ if [[ "${failureDialog}" == "true" ]]; then
-fi
+ outputLineNumberInVerboseDebugMode
+ updateFailureDialog "Display Failure dialog: ${failureDialog}"
+ killProcess "caffeinate"
+ if [[ "${brandingBannerDisplayText}" == "true" ]] ; then dialogUpdateSetupYourMac "title: Sorry ${loggedInUserFirstname}, something went sideways"; fi
+ dialogUpdateSetupYourMac "icon: SF=xmark.circle.fill,weight=bold,colour1=#BB1717,colour2=#F31F1F"
+ dialogUpdateSetupYourMac "progresstext: Failures detected. Please click Continue for troubleshooting information."
+ dialogUpdateSetupYourMac "button1text: Continue …"
+ dialogUpdateSetupYourMac "button1: enable"
+ dialogUpdateSetupYourMac "progress: reset"
+
+ # Wait for user-acknowledgment due to detected failure
+ wait
+ dialogUpdateSetupYourMac "quit:"
+ eval "${dialogFailureCMD}" & sleep 0.3
-# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
-# Pre-flight Check: Ensure computer does not go to sleep during SYM (thanks, @grahampugh!)
-# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+ updateFailureDialog "\n\n# # #\n# FAILURE DIALOG\n# # #\n"
+ updateFailureDialog "Jamf Pro Policy Name Failures:"
+ updateFailureDialog "${jamfProPolicyNameFailures}"
-symPID="$$"
-updateScriptLog "PRE-FLIGHT CHECK: Caffeinating this script (PID: $symPID)"
-caffeinate -dimsu -w $symPID &
+ failureMessage="A failure has been detected, ${loggedInUserFirstname}. \n\nPlease complete the following steps:\n1. Reboot and login to your ${modelName} \n2. Login to Self Service \n3. Re-run any failed policy listed below \n\nThe following failed: \n${jamfProPolicyNameFailures}"
+
+ if [[ -n "${supportTeamName}" ]]; then
+ supportContactMessage+="If you need assistance, please contact the **${supportTeamName}**: \n"
+ if [[ -n "${supportTeamPhone}" ]]; then
+ supportContactMessage+="- **Telephone:** ${supportTeamPhone}\n"
+ fi
-# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
-# Pre-flight Check: Toggle `jamf` binary check-in (thanks, @robjschroeder!)
-# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+ if [[ -n "${supportTeamEmail}" ]]; then
+ supportContactMessage+="- **Email:** $supportTeamEmail\n"
+ fi
-function toggleJamfLaunchDaemon() {
-
- jamflaunchDaemon="/Library/LaunchDaemons/com.jamfsoftware.task.1.plist"
+ if [[ -n "${supportTeamWebsite}" ]]; then
+ supportContactMessage+="- **Web**: ${supportTeamHyperlink}\n"
+ fi
- if [[ "${debugMode}" == "true" ]] || [[ "${debugMode}" == "verbose" ]] ; then
+ if [[ -n "${supportKB}" ]]; then
+ supportContactMessage+="- **Knowledge Base Article:** $supportTeamErrorKB\n"
+ fi
+
+ fi
- if [[ $(/bin/launchctl list | grep com.jamfsoftware.task.E) ]]; then
- updateScriptLog "PRE-FLIGHT CHECK: DEBUG MODE: Normally, 'jamf' binary check-in would be temporarily disabled"
- else
- updateScriptLog "QUIT SCRIPT: DEBUG MODE: Normally, 'jamf' binary check-in would be re-enabled"
- fi
+ failureMessage+="\n\n${supportContactMessage}"
- else
+ dialogUpdateFailure "message: ${failureMessage}"
- while [[ ! -f "${jamflaunchDaemon}" ]] ; do
- updateScriptLog "PRE-FLIGHT CHECK: Waiting for installation of ${jamflaunchDaemon}"
- sleep 0.1
- done
+ dialogUpdateFailure "icon: SF=xmark.circle.fill,weight=bold,colour1=#BB1717,colour2=#F31F1F"
+ dialogUpdateFailure "button1text: ${button1textCompletionActionOption}"
- if [[ $(/bin/launchctl list | grep com.jamfsoftware.task.E) ]]; then
+ # Wait for user-acknowledgment due to detected failure
+ wait
- updateScriptLog "PRE-FLIGHT CHECK: Temporarily disable 'jamf' binary check-in"
- /bin/launchctl bootout system "${jamflaunchDaemon}"
+ dialogUpdateFailure "quit:"
+ quitScript "1"
else
- updateScriptLog "QUIT SCRIPT: Re-enabling 'jamf' binary check-in"
- updateScriptLog "QUIT SCRIPT: 'jamf' binary check-in daemon not loaded, attempting to bootstrap and start"
- result="0"
+ outputLineNumberInVerboseDebugMode
+ dialogUpdateFailure "Display Failure dialog: ${failureDialog}"
- until [ $result -eq 3 ]; do
+ killProcess "caffeinate"
+ if [[ "${brandingBannerDisplayText}" == "true" ]] ; then dialogUpdateSetupYourMac "title: Sorry ${loggedInUserFirstname}, something went sideways"; fi
+ dialogUpdateSetupYourMac "icon: SF=xmark.circle.fill,weight=bold,colour1=#BB1717,colour2=#F31F1F"
+ dialogUpdateSetupYourMac "progresstext: Failures detected."
+ dialogUpdateSetupYourMac "button1text: ${button1textCompletionActionOption}"
+ dialogUpdateSetupYourMac "button1: enable"
+ dialogUpdateSetupYourMac "progress: reset"
+ dialogUpdateSetupYourMac "progresstext: Errors detected; please ${progressTextCompletionAction// and } your ${modelName}, ${loggedInUserFirstname}."
- /bin/launchctl bootstrap system "${jamflaunchDaemon}" && /bin/launchctl start "${jamflaunchDaemon}"
- result="$?"
+ quitScript "1"
- if [ $result = 3 ]; then
- updateScriptLog "QUIT SCRIPT: Staring 'jamf' binary check-in daemon"
- else
- updateScriptLog "QUIT SCRIPT: Failed to start 'jamf' binary check-in daemon"
- fi
+ fi
- done
+ else
+ outputLineNumberInVerboseDebugMode
+ updateSuccessDialog "All policies executed successfully"
+ if [[ -n "${webhookURL}" ]]; then
+ webhookStatus="Successful"
+ updateSuccessDialog "Sending success webhook message"
+ webHookMessage
fi
+ if [[ "${brandingBannerDisplayText}" == "true" ]] ; then dialogUpdateSetupYourMac "title: ${loggedInUserFirstname}‘s ${modelName} is ready!"; fi
+ dialogUpdateSetupYourMac "icon: SF=checkmark.circle.fill,weight=bold,colour1=#00ff44,colour2=#075c1e"
+ dialogUpdateSetupYourMac "progresstext: Complete! Please ${progressTextCompletionAction}enjoy your new ${modelName}, ${loggedInUserFirstname}!"
+ dialogUpdateSetupYourMac "progress: complete"
+ dialogUpdateSetupYourMac "button1text: ${button1textCompletionActionOption}"
+ dialogUpdateSetupYourMac "button1: enable"
+
+ quitScript "0"
+
fi
}
-toggleJamfLaunchDaemon
-
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
-# Pre-flight Check: Validate / install swiftDialog (Thanks big bunches, @acodega!)
+# Parse JSON via osascript and JavaScript
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
-function dialogInstall() {
+function get_json_value() {
+ # set -x
+ JSON="$1" osascript -l 'JavaScript' \
+ -e 'const env = $.NSProcessInfo.processInfo.environment.objectForKey("JSON").js' \
+ -e "JSON.parse(env).$2"
+ # set +x
+}
- # Get the URL of the latest PKG From the Dialog GitHub repo
- dialogURL=$(curl -L --silent --fail "https://api.github.com/repos/swiftDialog/swiftDialog/releases/latest" | awk -F '"' "/browser_download_url/ && /pkg\"/ { print \$4; exit }")
- # Expected Team ID of the downloaded PKG
- expectedDialogTeamID="PWA5E9TQ59"
- updateScriptLog "PRE-FLIGHT CHECK: Installing swiftDialog..."
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+# Parse JSON via osascript and JavaScript for the Welcome dialog (thanks, @bartreardon!)
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
- # Create temporary working directory
- workDirectory=$( /usr/bin/basename "$0" )
- tempDirectory=$( /usr/bin/mktemp -d "/private/tmp/$workDirectory.XXXXXX" )
+function get_json_value_welcomeDialog() {
+ # set -x
+ for var in "${@:2}"; do jsonkey="${jsonkey}['${var}']"; done
+ JSON="$1" osascript -l 'JavaScript' \
+ -e 'const env = $.NSProcessInfo.processInfo.environment.objectForKey("JSON").js' \
+ -e "JSON.parse(env)$jsonkey"
+ # set +x
+}
- # Download the installer package
- /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 '()')
-
- # Install the package if Team ID validates
- if [[ "$expectedDialogTeamID" == "$teamID" ]]; then
-
- /usr/sbin/installer -pkg "$tempDirectory/Dialog.pkg" -target /
- sleep 2
- dialogVersion=$( /usr/local/bin/dialog --version )
- updateScriptLog "PRE-FLIGHT CHECK: swiftDialog version ${dialogVersion} installed; proceeding..."
-
- else
-
- # Display a so-called "simple" dialog if Team ID fails to validate
- osascript -e 'display dialog "Please advise your Support Representative of the following error:\r\r• Dialog Team ID verification failed\r\r" with title "Setup Your Mac: Error" buttons {"Close"} with icon caution'
- completionActionOption="Quit"
- exitCode="1"
- quitScript
-
- fi
-
- # Remove the temporary working directory when done
- /bin/rm -Rf "$tempDirectory"
-
-}
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+# Execute Jamf Pro Policy Custom Events (thanks, @smithjw)
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+function run_jamf_trigger() {
-function dialogCheck() {
+ outputLineNumberInVerboseDebugMode
- # Output Line Number in `verbose` Debug Mode
- if [[ "${debugMode}" == "verbose" ]]; then updateScriptLog "PRE-FLIGHT CHECK: # # # SETUP YOUR MAC VERBOSE DEBUG MODE: Line No. ${LINENO} # # #" ; fi
+ trigger="$1"
- # Check for Dialog and install if not found
- if [ ! -e "/Library/Application Support/Dialog/Dialog.app" ]; then
+ if [[ "${debugMode}" == "true" ]] || [[ "${debugMode}" == "verbose" ]] ; then
- updateScriptLog "PRE-FLIGHT CHECK: swiftDialog not found. Installing..."
- dialogInstall
+ updateSetupYourMacDialog "DEBUG MODE: TRIGGER: $jamfBinary policy -event $trigger ${suppressRecon}"
+ sleep "${debugModeSleepAmount}"
else
- dialogVersion=$(/usr/local/bin/dialog --version)
- if [[ "${dialogVersion}" < "${swiftDialogMinimumRequiredVersion}" ]]; then
-
- updateScriptLog "PRE-FLIGHT CHECK: swiftDialog version ${dialogVersion} found but swiftDialog ${swiftDialogMinimumRequiredVersion} or newer is required; updating..."
- dialogInstall
-
- else
-
- updateScriptLog "PRE-FLIGHT CHECK: swiftDialog version ${dialogVersion} found; proceeding..."
+ updateSetupYourMacDialog "RUNNING: $jamfBinary policy -event $trigger"
+ eval "${jamfBinary} policy -event ${trigger} ${suppressRecon}" # Add comment for policy testing
+ # eval "${jamfBinary} policy -event ${trigger} ${suppressRecon} -verbose | tee -a ${scriptLog}" # Remove comment for policy testing
- fi
-
fi
}
-dialogCheck
-
-
-
-# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
-# Pre-flight Check: Validate `supportTeam` variables are populated
-# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
-
-if [[ -z $supportTeamName ]]; then
- updateScriptLog "PRE-FLIGHT CHECK: 'supportTeamName' must be populated to proceed; exiting"
- exit 1
-fi
-
-if [[ -z $supportTeamPhone && -z $supportTeamEmail && -z $supportKB ]]; then
- updateScriptLog "PRE-FLIGHT CHECK: At least ONE 'supportTeam' variable must be populated to proceed; exiting"
- exit 1
-fi
-
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
-# Pre-flight Check: Complete
+# Confirm Policy Execution
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
-updateScriptLog "PRE-FLIGHT CHECK: Complete"
-
+function confirmPolicyExecution() {
+ outputLineNumberInVerboseDebugMode
-####################################################################################################
-#
-# Dialog Variables
-#
-####################################################################################################
+ trigger="${1}"
+ validation="${2}"
+ updateSetupYourMacDialog "Confirm Policy Execution: '${trigger}' '${validation}'"
+ if [ "${suppressReconOnPolicy}" == "true" ]; then suppressRecon="-forceNoRecon"; fi
-# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
-# infobox-related variables
-# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+ case ${validation} in
-macOSproductVersion="$( sw_vers -productVersion )"
-macOSbuildVersion="$( sw_vers -buildVersion )"
-serialNumber=$( ioreg -rd1 -c IOPlatformExpertDevice | awk -F'"' '/IOPlatformSerialNumber/{print $4}' )
-timestamp="$( date '+%Y-%m-%d-%H%M%S' )"
-dialogVersion=$( /usr/local/bin/dialog --version )
+ */* ) # If the validation variable contains a forward slash (i.e., "/"), presume it's a path and check if that path exists on disk
+ outputLineNumberInVerboseDebugMode
+ if [[ "${debugMode}" == "true" ]] || [[ "${debugMode}" == "verbose" ]] ; then
+ updateSetupYourMacDialog "Confirm Policy Execution: DEBUG MODE: Skipping 'run_jamf_trigger ${trigger}'"
+ sleep "${debugModeSleepAmount}"
+ elif [[ -e "${validation}" ]]; then
+ updateSetupYourMacDialog "Confirm Policy Execution: ${validation} exists; skipping 'run_jamf_trigger ${trigger}'"
+ previouslyInstalled="true"
+ else
+ updateSetupYourMacDialog "Confirm Policy Execution: ${validation} does NOT exist; executing 'run_jamf_trigger ${trigger}'"
+ previouslyInstalled="false"
+ run_jamf_trigger "${trigger}"
+ fi
+ ;;
+ "None" | "none" )
-# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
-# Reflect Debug Mode in `infotext` (i.e., bottom, left-hand corner of each dialog)
-# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+ outputLineNumberInVerboseDebugMode
+ updateSetupYourMacDialog "Confirm Policy Execution: ${validation}"
+ if [[ "${debugMode}" == "true" ]] || [[ "${debugMode}" == "verbose" ]] ; then
+ sleep "${debugModeSleepAmount}"
+ else
+ run_jamf_trigger "${trigger}"
+ fi
+ ;;
-case ${debugMode} in
- "true" ) scriptVersion="DEBUG MODE | Dialog: v${dialogVersion} • Setup Your Mac: v${scriptVersion}" ;;
- "verbose" ) scriptVersion="VERBOSE DEBUG MODE | Dialog: v${dialogVersion} • Setup Your Mac: v${scriptVersion}" ;;
-esac
+ "Recon" | "recon" )
+ outputLineNumberInVerboseDebugMode
+ updateSetupYourMacDialog "Confirm Policy Execution: ${validation}"
+ if [[ "${debugMode}" == "true" ]] || [[ "${debugMode}" == "verbose" ]] ; then
+ updateSetupYourMacDialog "DEBUG MODE: Set 'debugMode' to false to update computer inventory with the following 'reconOptions': \"${reconOptions}\" …"
+ sleep "${debugModeSleepAmount}"
+ else
+ updateSetupYourMacDialog "Updating computer inventory with the following 'reconOptions': \"${reconOptions}\" …"
+ dialogUpdateSetupYourMac "listitem: index: $i, status: wait, statustext: Updating …, "
+ reconRaw=$( eval "${jamfBinary} recon ${reconOptions} -verbose | tee -a ${scriptLog}" )
+ computerID=$( echo "${reconRaw}" | grep '' | xmllint --xpath xmllint --xpath '/computer_id/text()' - )
+ fi
+ ;;
+ * )
-# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
-# Set JAMF binary, Dialog path and Command Files
-# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+ outputLineNumberInVerboseDebugMode
+ updateSetupYourMacDialog "Confirm Policy Execution Catch-all: ${validation}"
+ if [[ "${debugMode}" == "true" ]] || [[ "${debugMode}" == "verbose" ]] ; then
+ sleep "${debugModeSleepAmount}"
+ else
+ run_jamf_trigger "${trigger}"
+ fi
+ ;;
-jamfBinary="/usr/local/bin/jamf"
-dialogBinary="/usr/local/bin/dialog"
-welcomeJSONFile=$( mktemp -u /var/tmp/welcomeJSONFile.XXX )
-welcomeCommandFile=$( mktemp -u /var/tmp/dialogCommandFileWelcome.XXX )
-setupYourMacCommandFile=$( mktemp -u /var/tmp/dialogCommandFileSetupYourMac.XXX )
-failureCommandFile=$( mktemp -u /var/tmp/dialogCommandFileFailure.XXX )
+ esac
+}
-####################################################################################################
-#
-# Welcome dialog
-#
-####################################################################################################
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
-# "Welcome" dialog Title, Message and Icon
+# Validate Policy Result
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
-welcomeTitle="Happy $( date +'%A' ), ${loggedInUserFirstname}! \nWelcome to your new ${modelName}"
-
-welcomeMessage="Please enter the **required** information for your ${modelName}, select your preferred **Configuration** then click **Continue** to start applying settings to your new Mac. \n\nOnce completed, the **Wait** button will be enabled and you‘ll be able to review the results before restarting your ${modelName}."
-
-if [[ -n "${supportTeamName}" ]]; then
-
- welcomeMessage+="\n\nIf you need assistance, please contact the **${supportTeamName}**: \n"
-
- if [[ -n "${supportTeamPhone}" ]]; then
- welcomeMessage+="- **Telephone**: ${supportTeamPhone}\n"
- fi
-
- if [[ -n "${supportTeamEmail}" ]]; then
- welcomeMessage+="- **Email**: ${supportTeamEmail}\n"
- fi
-
- if [[ -n "${supportTeamWebsite}" ]]; then
- welcomeMessage+="- **Web**: ${supportTeamHyperlink}\n"
- fi
-
- if [[ -n "${supportKB}" ]]; then
- welcomeMessage+="- **Knowledge Base Article:** ${supportTeamErrorKB}\n"
- fi
-
-fi
-
-welcomeMessage+="\n\n---"
-
-if { [[ "${promptForConfiguration}" == "true" ]] && [[ "${welcomeDialog}" != "messageOnly" ]]; } then
- welcomeMessage+=" \n\n#### Configurations \n- **${configurationOneName}:** ${configurationOneDescription} \n- **${configurationTwoName}:** ${configurationTwoDescription} \n- **${configurationThreeName}:** ${configurationThreeDescription}"
-else
- welcomeMessage=${welcomeMessage//", select your preferred **Configuration**"/}
-fi
-
-
-if [[ "${brandingBannerDisplayText}" == "true" ]]; then welcomeBannerText="Happy $( date +'%A' ), ${loggedInUserFirstname}! \nWelcome to your new ${modelName}";
-else welcomeBannerText=""; fi
-welcomeCaption="Please review the above video, then click Continue."
-welcomeVideoID="vimeoid=909473114"
-
-
-# Check brandingBanner and cache if necessary
-case ${brandingBanner} in
-
- *"https"* )
- welcomeBannerImage="${brandingBanner}"
- bannerImage="${brandingBanner}"
- if curl -L --output /dev/null --silent --head --fail "$welcomeBannerImage" || [ -f "$welcomeBannerImage" ]; then
- updateScriptLog "WELCOME DIALOG: brandingBanner is available, using it"
- else
- updateScriptLog "WELCOME DIALOG: brandingBanner is not available, using a default image"
- welcomeBannerImage="https://img.freepik.com/free-vector/green-abstract-geometric-wallpaper_52683-29623.jpg" # Image by pikisuperstar on Freepik
- bannerImage="https://img.freepik.com/free-vector/green-abstract-geometric-wallpaper_52683-29623.jpg" # Image by pikisuperstar on Freepik
- fi
-
- welcomeBannerImageFileName=$( echo ${welcomeBannerImage} | awk -F '/' '{print $NF}' )
- updateScriptLog "WELCOME DIALOG: Auto-caching hosted '$welcomeBannerImageFileName' …"
- curl -L --location --silent "$welcomeBannerImage" -o "/var/tmp/${welcomeBannerImageFileName}"
- welcomeBannerImage="/var/tmp/${welcomeBannerImageFileName}"
- bannerImage="/var/tmp/${welcomeBannerImageFileName}"
- ;;
-
- */* )
- updateScriptLog "WELCOME DIALOG: brandingBanner is local file, using it"
- welcomeBannerImage="${brandingBanner}"
- bannerImage="${brandingBanner}"
- ;;
-
- "None" | "none" | "" )
- updateScriptLog "WELCOME DIALOG: brandingBanner set to \"None\", or empty"
- welcomeBannerImage="${brandingBanner}"
- bannerImage="${brandingBanner}"
- ;;
+function validatePolicyResult() {
- * )
- updateScriptLog "WELCOME DIALOG: brandingBanner set to \"None\""
- ;;
+ outputLineNumberInVerboseDebugMode
-esac
+ trigger="${1}"
+ validation="${2}"
+ updateSetupYourMacDialog "Validate Policy Result: '${trigger}' '${validation}'"
+ case ${validation} in
+ ###
+ # Absolute Path
+ # Simulates pre-v1.6.0 behavior, for example: "/Applications/Microsoft Teams classic.app/Contents/Info.plist"
+ ###
-# Welcome icon set to either light or dark, based on user's Apperance setting (thanks, @mm2270!)
-appleInterfaceStyle=$( /usr/bin/defaults read /Users/"${loggedInUser}"/Library/Preferences/.GlobalPreferences.plist AppleInterfaceStyle 2>&1 )
-if [[ "${appleInterfaceStyle}" == "Dark" ]]; then
- if [[ -n "$brandingIconDark" ]]; then welcomeIcon="$brandingIconDark";
- else welcomeIcon="https://cdn-icons-png.flaticon.com/512/740/740878.png"; fi
-else
- if [[ -n "$brandingIconLight" ]]; then welcomeIcon="$brandingIconLight";
- else welcomeIcon="https://cdn-icons-png.flaticon.com/512/979/979585.png"; fi
-fi
+ */* )
+ updateSetupYourMacDialog "Validate Policy Result: Testing for \"$validation\" …"
+ if [[ "${previouslyInstalled}" == "true" ]]; then
+ dialogUpdateSetupYourMac "listitem: index: $i, status: success, statustext: Previously Installed"
+ elif [[ -e "${validation}" ]]; then
+ dialogUpdateSetupYourMac "listitem: index: $i, status: success, statustext: Installed"
+ else
+ dialogUpdateSetupYourMac "listitem: index: $i, status: fail, statustext: Failed"
+ jamfProPolicyTriggerFailure="failed"
+ exitCode="1"
+ jamfProPolicyNameFailures+="• $listitem \n"
+ fi
+ ;;
-# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
-# "Welcome" Video Settings and Features
-# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+ ###
+ # Local
+ # Validation within this script, for example: "rosetta" or "filevault"
+ ###
-welcomeVideo="--title \"$welcomeTitle\" \
---videocaption \"$welcomeCaption\" \
---video \"$welcomeVideoID\" \
---infotext \"$scriptVersion\" \
---button1text \"Continue …\" \
---autoplay \
---moveable \
---ontop \
---width '800' \
---height '600' \
---commandfile \"$welcomeCommandFile\" "
+ "Local" )
+ case ${trigger} in
+ rosetta )
+ updateSetupYourMacDialog "Locally Validate Policy Result: Rosetta 2 … " # Thanks, @smithjw!
+ dialogUpdateSetupYourMac "listitem: index: $i, status: wait, statustext: Checking …"
+ arch=$( /usr/bin/arch )
+ if [[ "${arch}" == "arm64" ]]; then
+ # Mac with Apple silicon; check for Rosetta
+ rosettaTest=$( arch -x86_64 /usr/bin/true 2> /dev/null ; echo $? )
+ if [[ "${rosettaTest}" -eq 0 ]]; then
+ # Installed
+ updateSetupYourMacDialog "Locally Validate Policy Result: Rosetta 2 is installed"
+ dialogUpdateSetupYourMac "listitem: index: $i, status: success, statustext: Running"
+ else
+ # Not Installed
+ updateSetupYourMacDialog "Locally Validate Policy Result: Rosetta 2 is NOT installed"
+ dialogUpdateSetupYourMac "listitem: index: $i, status: fail, statustext: Failed"
+ jamfProPolicyTriggerFailure="failed"
+ exitCode="1"
+ jamfProPolicyNameFailures+="• $listitem \n"
+ fi
+ else
+ # Ineligible
+ updateSetupYourMacDialog "Locally Validate Policy Result: Rosetta 2 is not applicable"
+ dialogUpdateSetupYourMac "listitem: index: $i, status: error, statustext: Ineligible"
+ fi
+ ;;
+ filevault )
+ updateSetupYourMacDialog "Locally Validate Policy Result: Validate FileVault … "
+ dialogUpdateSetupYourMac "listitem: index: $i, status: wait, statustext: Checking …"
+ updateSetupYourMacDialog "Validate Policy Result: Pausing for 5 seconds for FileVault … "
+ sleep 5 # Arbitrary value; tuning needed
+ fileVaultCheck=$( fdesetup isactive )
+ if [[ -f /Library/Preferences/com.apple.fdesetup.plist ]] || [[ "$fileVaultCheck" == "true" ]]; then
+ fileVaultStatus=$( fdesetup status -extended -verbose 2>&1 )
+ case ${fileVaultStatus} in
+ *"FileVault is On."* )
+ updateSetupYourMacDialog "Locally Validate Policy Result: FileVault: FileVault is On."
+ dialogUpdateSetupYourMac "listitem: index: $i, status: success, statustext: Enabled"
+ ;;
+ *"Deferred enablement appears to be active for user"* )
+ updateSetupYourMacDialog "Locally Validate Policy Result: FileVault: Enabled"
+ dialogUpdateSetupYourMac "listitem: index: $i, status: success, statustext: Enabled (next login)"
+ ;;
+ * )
+ dialogUpdateSetupYourMac "listitem: index: $i, status: error, statustext: Unknown"
+ jamfProPolicyTriggerFailure="failed"
+ exitCode="1"
+ jamfProPolicyNameFailures+="• $listitem \n"
+ ;;
+ esac
+ else
+ updateSetupYourMacDialog "Locally Validate Policy Result: '/Library/Preferences/com.apple.fdesetup.plist' NOT Found"
+ dialogUpdateSetupYourMac "listitem: index: $i, status: fail, statustext: Failed"
+ jamfProPolicyTriggerFailure="failed"
+ exitCode="1"
+ jamfProPolicyNameFailures+="• $listitem \n"
+ fi
+ ;;
+ sophosEndpointServices )
+ updateSetupYourMacDialog "Locally Validate Policy Result: Sophos Endpoint RTS Status … "
+ dialogUpdateSetupYourMac "listitem: index: $i, status: wait, statustext: Checking …"
+ if [[ -d /Applications/Sophos/Sophos\ Endpoint.app ]]; then
+ if [[ -f /Library/Preferences/com.sophos.sav.plist ]]; then
+ sophosOnAccessRunning=$( /usr/bin/defaults read /Library/Preferences/com.sophos.sav.plist OnAccessRunning )
+ case ${sophosOnAccessRunning} in
+ "0" )
+ updateSetupYourMacDialog "Locally Validate Policy Result: Sophos Endpoint RTS Status: Disabled"
+ dialogUpdateSetupYourMac "listitem: index: $i, status: fail, statustext: Failed"
+ jamfProPolicyTriggerFailure="failed"
+ exitCode="1"
+ jamfProPolicyNameFailures+="• $listitem \n"
+ ;;
+ "1" )
+ updateSetupYourMacDialog "Locally Validate Policy Result: Sophos Endpoint RTS Status: Enabled"
+ dialogUpdateSetupYourMac "listitem: index: $i, status: success, statustext: Running"
+ ;;
+ * )
+ updateSetupYourMacDialog "Locally Validate Policy Result: Sophos Endpoint RTS Status: Unknown"
+ dialogUpdateSetupYourMac "listitem: index: $i, status: fail, statustext: Unknown"
+ jamfProPolicyTriggerFailure="failed"
+ exitCode="1"
+ jamfProPolicyNameFailures+="• $listitem \n"
+ ;;
+ esac
+ else
+ updateSetupYourMacDialog "Locally Validate Policy Result: Sophos Endpoint Not Found"
+ dialogUpdateSetupYourMac "listitem: index: $i, status: fail, statustext: Failed"
+ jamfProPolicyTriggerFailure="failed"
+ exitCode="1"
+ jamfProPolicyNameFailures+="• $listitem \n"
+ fi
+ else
+ dialogUpdateSetupYourMac "listitem: index: $i, status: fail, statustext: Failed"
+ jamfProPolicyTriggerFailure="failed"
+ exitCode="1"
+ jamfProPolicyNameFailures+="• $listitem \n"
+ fi
+ ;;
+ globalProtect )
+ updateSetupYourMacDialog "Locally Validate Policy Result: Palo Alto Networks GlobalProtect Status … "
+ dialogUpdateSetupYourMac "listitem: index: $i, status: wait, statustext: Checking …"
+ if [[ -d /Applications/GlobalProtect.app ]]; then
+ updateSetupYourMacDialog "Locally Validate Policy Result: Pausing for 10 seconds to allow Palo Alto Networks GlobalProtect Services … "
+ sleep 10 # Arbitrary value; tuning needed
+ if [[ -f /Library/Preferences/com.paloaltonetworks.GlobalProtect.settings.plist ]]; then
+ globalProtectStatus=$( /usr/libexec/PlistBuddy -c "print :Palo\ Alto\ Networks:GlobalProtect:PanGPS:disable-globalprotect" /Library/Preferences/com.paloaltonetworks.GlobalProtect.settings.plist )
+ case "${globalProtectStatus}" in
+ "0" )
+ updateSetupYourMacDialog "Locally Validate Policy Result: Palo Alto Networks GlobalProtect Status: Enabled"
+ dialogUpdateSetupYourMac "listitem: index: $i, status: success, statustext: Running"
+ ;;
+ "1" )
+ updateSetupYourMacDialog "Locally Validate Policy Result: Palo Alto Networks GlobalProtect Status: Disabled"
+ dialogUpdateSetupYourMac "listitem: index: $i, status: fail, statustext: Failed"
+ jamfProPolicyTriggerFailure="failed"
+ exitCode="1"
+ jamfProPolicyNameFailures+="• $listitem \n"
+ ;;
+ * )
+ updateSetupYourMacDialog "Locally Validate Policy Result: Palo Alto Networks GlobalProtect Status: Unknown"
+ dialogUpdateSetupYourMac "listitem: index: $i, status: fail, statustext: Unknown"
+ jamfProPolicyTriggerFailure="failed"
+ exitCode="1"
+ jamfProPolicyNameFailures+="• $listitem \n"
+ ;;
+ esac
+ else
+ updateSetupYourMacDialog "Locally Validate Policy Result: Palo Alto Networks GlobalProtect Not Found"
+ dialogUpdateSetupYourMac "listitem: index: $i, status: fail, statustext: Failed"
+ jamfProPolicyTriggerFailure="failed"
+ exitCode="1"
+ jamfProPolicyNameFailures+="• $listitem \n"
+ fi
+ else
+ dialogUpdateSetupYourMac "listitem: index: $i, status: fail, statustext: Failed"
+ jamfProPolicyTriggerFailure="failed"
+ exitCode="1"
+ jamfProPolicyNameFailures+="• $listitem \n"
+ fi
+ ;;
+ * )
+ updateSetupYourMacDialog "Locally Validate Policy Result: Local Validation “${validation}” Missing"
+ dialogUpdateSetupYourMac "listitem: index: $i, status: fail, statustext: Missing Local “${validation}” Validation"
+ jamfProPolicyTriggerFailure="failed"
+ exitCode="1"
+ jamfProPolicyNameFailures+="• $listitem \n"
+ ;;
+ esac
+ ;;
-# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
-# "Welcome" JSON Conditionals (thanks, @rougegoat!)
-# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+ ###
+ # Remote
+ # Validation via a Jamf Pro policy which has a single-script payload, for example: "symvGlobalProtect"
+ # See: https://vimeo.com/782561166
+ ###
-# Text Fields
-if [ "$prefillUsername" == "true" ]; then usernamePrefil=',"value" : "'${loggedInUser}'"'; fi
-if [ "$prefillRealname" == "true" ]; then realnamePrefil=',"value" : "'${loggedInUserFullname}'"'; fi
-if [ "$promptForUsername" == "true" ]; then usernameJSON='{ "title" : "User Name","required" : false,"prompt" : "User Name"'${usernamePrefil}'},'; fi
-if [ "$promptForRealName" == "true" ]; then realNameJSON='{ "title" : "Full Name","required" : false,"prompt" : "Full Name"'${realnamePrefil}'},'; fi
-if [ "$promptForEmail" == "true" ]; then
- emailJSON='{ "title" : "E-mail",
- "required" : true,
- "prompt" : "E-mail Address",
- "regex" : "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$",
- "regexerror" : "Please enter a valid email address."
- },'
-fi
-if [ "$promptForComputerName" == "true" ]; then compNameJSON='{ "title" : "Computer Name","required" : false,"prompt" : "Computer Name" },'; fi
-if [ "$promptForAssetTag" == "true" ]; then
- assetTagJSON='{ "title" : "Asset Tag",
- "required" : true,
- "prompt" : "Please enter the (at least) seven-digit Asset Tag",
- "regex" : "^(AP|IP|CD)?[0-9]{7,}$",
- "regexerror" : "Please enter (at least) seven digits for the Asset Tag, optionally preceded by either AP, IP or CD."
- },'
-fi
-if [ "$promptForRoom" == "true" ]; then roomJSON='{ "title" : "Room","required" : false,"prompt" : "Optional" },'; fi
-if [[ "$promptForPosition" == "true" && -z "$positionListRaw" ]]; then positionJSON='{ "title" : "Position","required" : false,"prompt" : "Position" },'; fi
+ "Remote" )
+ if [[ "${debugMode}" == "true" ]] || [[ "${debugMode}" == "verbose" ]] ; then
+ updateSetupYourMacDialog "DEBUG MODE: Remotely Confirm Policy Execution: Skipping 'run_jamf_trigger ${trigger}'"
+ dialogUpdateSetupYourMac "listitem: index: $i, status: error, statustext: Debug Mode Enabled"
+ sleep 0.5
+ else
+ updateSetupYourMacDialog "Remotely Validate '${trigger}' '${validation}'"
+ dialogUpdateSetupYourMac "listitem: index: $i, status: wait, statustext: Checking …"
+ result=$( "${jamfBinary}" policy -event "${trigger}" | grep "Script result:" )
+ if [[ "${result}" == *"Running"* ]]; then
+ dialogUpdateSetupYourMac "listitem: index: $i, status: success, statustext: Running"
+ elif [[ "${result}" == *"Installed"* || "${result}" == *"Success"* ]]; then
+ dialogUpdateSetupYourMac "listitem: index: $i, status: success, statustext: Installed"
+ else
+ dialogUpdateSetupYourMac "listitem: index: $i, status: fail, statustext: Failed"
+ jamfProPolicyTriggerFailure="failed"
+ exitCode="1"
+ jamfProPolicyNameFailures+="• $listitem \n"
+ fi
+ fi
+ ;;
-textFieldJSON="${usernameJSON}${realNameJSON}${emailJSON}${compNameJSON}${assetTagJSON}${positionJSON}${roomJSON}"
-textFieldJSON=$( echo ${textFieldJSON} | sed 's/,$//' )
-# Dropdowns
-if [ "$promptForBuilding" == "true" ]; then
- if [ -n "$buildingsListRaw" ]; then
- buildingJSON='{
- "title" : "Building",
- "default" : "",
- "required" : true,
- "values" : [
- '${buildingsList}'
- ]
- },'
- fi
-fi
-if [ "$promptForDepartment" == "true" ]; then
- if [ -n "$departmentListRaw" ]; then
- departmentJSON='{
- "title" : "Department",
- "default" : "",
- "required" : true,
- "values" : [
- '${departmentList}'
- ]
- },'
- fi
-fi
+ ###
+ # None: For triggers which don't require validation
+ # (Always evaluates as: 'success' and 'Installed')
+ ###
-if [ "$promptForPosition" == "true" ]; then
- if [ -n "${positionListRaw}" ]; then
- positionSelectJSON='{
- "title" : "Position",
- "default" : "",
- "required" : true,
- "values" : [
- '${positionList}'
- ]
- },'
- fi
-fi
+ "None" | "none")
-if [ "$promptForConfiguration" == "true" ] && [ -z "${presetConfiguration}" ]; then
- configurationJSON='{
- "title" : "Configuration",
- "style" : "radio",
- "default" : "'"${configurationOneName}"'",
- "values" : [
- "'"${configurationOneName}"'",
- "'"${configurationTwoName}"'",
- "'"${configurationThreeName}"'"
- ]
- }'
-fi
+ outputLineNumberInVerboseDebugMode
+ updateSetupYourMacDialog "Confirm Policy Execution: ${validation}"
+ dialogUpdateSetupYourMac "listitem: index: $i, status: success, statustext: Installed"
+ ;;
-selectItemsJSON="${buildingJSON}${departmentJSON}${positionSelectJSON}${configurationJSON}"
-selectItemsJSON=$( echo $selectItemsJSON | sed 's/,$//' )
+
+
+ ###
+ # Recon: For reporting computer inventory update
+ # (Always evaluates as: 'success' and 'Updated')
+ ###
+
+ "Recon" | "recon" )
+
+ outputLineNumberInVerboseDebugMode
+ updateSetupYourMacDialog "Confirm Policy Execution: ${validation}"
+ dialogUpdateSetupYourMac "listitem: index: $i, status: success, statustext: Updated"
+ ;;
+
+
+
+ ###
+ # Catch-all
+ ###
+
+ * )
+
+ outputLineNumberInVerboseDebugMode
+ updateSetupYourMacDialog "Validate Policy Results Catch-all: ${validation}"
+ dialogUpdateSetupYourMac "listitem: index: $i, status: error, statustext: Error"
+ ;;
+
+ esac
+
+}
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
-# "Welcome" JSON for Capturing User Input (thanks, @bartreardon!)
+# Kill a specified process (thanks, @grahampugh!)
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
-welcomeJSON='
-{
- "commandfile" : "'"${welcomeCommandFile}"'",
- "bannerimage" : "'"${welcomeBannerImage}"'",
- "bannertext" : "'"${welcomeBannerText}"'",
- "title" : "'"${welcomeTitle}"'",
- "message" : "'"${welcomeMessage}"'",
- "icon" : "'"${welcomeIcon}"'",
- "infobox" : "Analyzing …",
- "iconsize" : "198.0",
- "button1text" : "Continue",
- "button2text" : "Quit",
- "infotext" : "'"${scriptVersion}"'",
- "blurscreen" : "true",
- "ontop" : "true",
- "titlefont" : "shadow=true, size=36, colour=#FFFDF4",
- "messagefont" : "size=14",
- "textfield" : [
- '${textFieldJSON}'
- ],
- "selectitems" : [
- '${selectItemsJSON}'
- ],
- "height" : "800"
+function killProcess() {
+ process="$1"
+ if process_pid=$( pgrep -a "${process}" 2>/dev/null ) ; then
+ info "Attempting to terminate the '$process' process …"
+ info "(Termination message indicates success.)"
+ kill "$process_pid" 2> /dev/null
+ if pgrep -a "$process" >/dev/null ; then
+ error "'$process' could not be terminated."
+ fi
+ else
+ info "The '$process' process isn't running."
+ fi
}
-'
-
-####################################################################################################
-#
-# Setup Your Mac dialog
-#
-####################################################################################################
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
-# "Setup Your Mac" dialog Title, Message, Icon and Overlay Icon
+# Completion Action (i.e., Wait, Sleep, Logout, Restart or Shutdown)
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
-title="Setting up ${loggedInUserFirstname}‘s ${modelName}"
-message="Please wait while the following apps are installed …"
+function completionAction() {
-if [[ "${brandingBannerDisplayText}" == "true" ]] ; then
- bannerText="Setting up ${loggedInUserFirstname}‘s ${modelName}";
-else
- bannerText=""
-fi
+ outputLineNumberInVerboseDebugMode
-if [ -n "$supportTeamName" ]; then
- helpmessage+="If you need assistance, please contact: \n\n**${supportTeamName}** \n"
-fi
+ if [[ "${debugMode}" == "true" ]] || [[ "${debugMode}" == "verbose" ]] ; then
-if [ -n "$supportTeamPhone" ]; then
- helpmessage+="- **Telephone:** ${supportTeamPhone} \n"
-fi
+ # If Debug Mode is enabled, ignore specified `completionActionOption`, display simple dialog box and exit
+ runAsUser osascript -e 'display dialog "Setup Your Mac is operating in Debug Mode.\r\r• completionActionOption == '"'${completionActionOption}'"'\r\r" with title "Setup Your Mac: Debug Mode" buttons {"Close"} with icon note'
+ exitCode="0"
-if [ -n "$supportTeamEmail" ]; then
- helpmessage+="- **Email:** ${supportTeamEmail} \n"
-fi
+ else
-if [ -n "$supportTeamWebsite" ]; then
- helpmessage+="- **Web**: ${supportTeamHyperlink} \n"
-fi
+ shopt -s nocasematch
-if [ -n "$supportKB" ]; then
- helpmessage+="- **Knowledge Base Article:** ${supportTeamErrorKB} \n"
-fi
+ case ${completionActionOption} in
-helpmessage+="\n**Computer Information:** \n"
-helpmessage+="- **Operating System:** ${macOSproductVersion} (${macOSbuildVersion}) \n"
-helpmessage+="- **Serial Number:** ${serialNumber} \n"
-helpmessage+="- **Dialog:** ${dialogVersion} \n"
-helpmessage+="- **Started:** ${timestamp}"
+ "Shut Down" )
+ completionActionOut "Shut Down sans user interaction"
+ killProcess "Self Service"
+ # runAsUser osascript -e 'tell app "System Events" to shut down'
+ # sleep 5 && runAsUser osascript -e 'tell app "System Events" to shut down' &
+ sleep 5 && shutdown -h now &
+ ;;
-infobox="Analyzing input …" # Customize at "Update Setup Your Mac's infobox"
+ "Shut Down Attended" )
+ completionActionOut "Shut Down, requiring user-interaction"
+ killProcess "Self Service"
+ wait
+ # runAsUser osascript -e 'tell app "System Events" to shut down'
+ # sleep 5 && runAsUser osascript -e 'tell app "System Events" to shut down' &
+ sleep 5 && shutdown -h now &
+ ;;
+ "Shut Down Confirm" )
+ completionActionOut "Shut down, only after macOS time-out or user confirmation"
+ runAsUser osascript -e 'tell app "loginwindow" to «event aevtrsdn»'
+ ;;
-# Create `overlayicon` from Self Service's custom icon (thanks, @meschwartz!)
-xxd -p -s 260 "$(defaults read /Library/Preferences/com.jamfsoftware.jamf self_service_app_path)"/Icon$'\r'/..namedfork/rsrc | xxd -r -p > /var/tmp/overlayicon.icns
-overlayicon="/var/tmp/overlayicon.icns"
+ "Restart" )
+ completionActionOut "Restart sans user interaction"
+ killProcess "Self Service"
+ # runAsUser osascript -e 'tell app "System Events" to restart'
+ # sleep 5 && runAsUser osascript -e 'tell app "System Events" to restart' &
+ sleep 5 && shutdown -r now &
+ ;;
-# Uncomment to use generic, Self Service icon as overlayicon
-# overlayicon="https://ics.services.jamfcloud.com/icon/hash_aa63d5813d6ed4846b623ed82acdd1562779bf3716f2d432a8ee533bba8950ee"
+ "Restart Attended" )
+ completionActionOut "Restart, requiring user-interaction"
+ killProcess "Self Service"
+ wait
+ # runAsUser osascript -e 'tell app "System Events" to restart'
+ # sleep 5 && runAsUser osascript -e 'tell app "System Events" to restart' &
+ sleep 5 && shutdown -r now &
+ ;;
-# Set initial icon based on whether the Mac is a desktop or laptop
-if system_profiler SPPowerDataType | grep -q "Battery Power"; then
- icon="SF=laptopcomputer.and.arrow.down,weight=semibold,colour1=#ef9d51,colour2=#ef7951"
-else
- icon="SF=desktopcomputer.and.arrow.down,weight=semibold,colour1=#ef9d51,colour2=#ef7951"
-fi
+ "Restart Confirm" )
+ completionActionOut "Restart, only after macOS time-out or user confirmation"
+ runAsUser osascript -e 'tell app "loginwindow" to «event aevtrrst»'
+ ;;
+ "Log Out" )
+ completionActionOut "Log out sans user interaction"
+ killProcess "Self Service"
+ # sleep 5 && runAsUser osascript -e 'tell app "loginwindow" to «event aevtrlgo»'
+ # sleep 5 && runAsUser osascript -e 'tell app "loginwindow" to «event aevtrlgo»' &
+ sleep 5 && launchctl bootout user/"${loggedInUserID}"
+ ;;
+ "Log Out Attended" )
+ completionActionOut "Log out sans user interaction"
+ killProcess "Self Service"
+ wait
+ # sleep 5 && runAsUser osascript -e 'tell app "loginwindow" to «event aevtrlgo»'
+ # sleep 5 && runAsUser osascript -e 'tell app "loginwindow" to «event aevtrlgo»' &
+ sleep 5 && launchctl bootout user/"${loggedInUserID}"
+ ;;
-# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
-# "Setup Your Mac" dialog Settings and Features
-# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+ "Log Out Confirm" )
+ completionActionOut "Log out, only after macOS time-out or user confirmation"
+ sleep 5 && runAsUser osascript -e 'tell app "System Events" to log out'
+ ;;
-dialogSetupYourMacCMD="$dialogBinary \
---bannerimage \"$bannerImage\" \
---bannertext \"$bannerText\" \
---title \"$title\" \
---message \"$message\" \
---helpmessage \"$helpmessage\" \
---icon \"$icon\" \
---infobox \"${infobox}\" \
---progress \
---progresstext \"Initializing configuration …\" \
---button1text \"Wait\" \
---button1disabled \
---infotext \"$scriptVersion\" \
---titlefont 'shadow=true, size=36, colour=#FFFDF4' \
---messagefont 'size=14' \
---height '800' \
---position 'centre' \
---blurscreen \
---ontop \
---overlayicon \"$overlayicon\" \
---quitkey k \
---commandfile \"$setupYourMacCommandFile\" "
+ "Sleep"* )
+ sleepDuration=$( awk '{print $NF}' <<< "${1}" )
+ completionActionOut "Sleeping for ${sleepDuration} seconds …"
+ sleep "${sleepDuration}"
+ killProcess "Dialog"
+ info "Goodnight!"
+ ;;
+ "Wait" )
+ completionActionOut "Waiting for user interaction …"
+ wait
+ ;;
+ "Quit" )
+ completionActionOut "Quitting script"
+ exitCode="0"
+ ;;
-# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
-#
-# [SYM-Helper] "Setup Your Mac" policies to execute (Thanks, Obi-@smithjw!)
-#
-# For each configuration step, specify:
-# - listitem: The text to be displayed in the list
-# - icon: The hash of the icon to be displayed on the left
-# - See: https://vimeo.com/772998915
-# - progresstext: The text to be displayed below the progress bar
-# - trigger: The Jamf Pro Policy Custom Event Name
-# - validation: [ {absolute path} | Local | Remote | None | Recon ]
-# See: https://snelson.us/2023/01/setup-your-mac-validation/
-# - {absolute path} (simulates pre-v1.6.0 behavior, for example: "/Applications/Microsoft Teams classic.app/Contents/Info.plist")
-# - Local (for validation within this script, for example: "filevault")
-# - Remote (for validation via a single-script Jamf Pro policy, for example: "symvGlobalProtect")
-# - None (for triggers which don't require validation; always evaluates as successful)
-# - Recon (to update the computer's inventory with your Jamf Pro server)
-#
-# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
-#
-# Thanks, @wakco: If you would prefer to get your policyJSON externally replace it with:
-# - policyJSON="$(cat /path/to/file.json)" # For getting from a file, replacing /path/to/file.json with the path to your file, or
-# - policyJSON="$(curl -sL https://server.name/jsonquery)" # For a URL, replacing https://server.name/jsonquery with the URL of your file.
-#
-# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
-#
-# Thanks, @astrugatch: I added this line to global variables:
-# jsonURL=${10} # URL Hosting JSON for policy_array
-#
-# And this line replaces the entirety of the policy_array (~ line 503):
-# policy_array=("$(curl -sL $jsonURL)")
-#
-# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+ * )
+ completionActionOut "Using the default of 'wait'"
+ wait
+ ;;
+ esac
+ shopt -u nocasematch
-# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
-# Select `policyJSON` based on Configuration selected in "Welcome" dialog (thanks, @drtaru!)
-# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+ fi
-function policyJSONConfiguration() {
+ # Remove custom welcomeBannerImageFileName
+ if [[ -e "/var/tmp/${welcomeBannerImageFileName}" ]]; then
+ completionActionOut "Removing /var/tmp/${welcomeBannerImageFileName} …"
+ rm "/var/tmp/${welcomeBannerImageFileName}"
+ fi
- outputLineNumberInVerboseDebugMode
+ # Remove overlayicon
+ if [[ -e ${overlayicon} ]]; then
+ completionActionOut "Removing ${overlayicon} …"
+ rm "${overlayicon}"
+ fi
- updateScriptLog "WELCOME DIALOG: PolicyJSON Configuration: $symConfiguration"
+ exit "${exitCode}"
- case ${symConfiguration} in
+}
- "${configurationOneName}" )
- overlayoverride=""
- policyJSON='
- {
- "steps": [
- {
- "listitem": "Rosetta",
- "subtitle": "Enables a Mac with Apple silicon to use apps built for an Intel processor",
- "icon": "https://ics.services.jamfcloud.com/icon/hash_8bac19160fabb0c8e7bac97b37b51d2ac8f38b7100b6357642d9505645d37b52",
- "progresstext": "Rosetta enables a Mac with Apple silicon to use apps built for a Mac with an Intel processor.",
- "trigger_list": [
- {
- "trigger": "rosettaInstall",
- "validation": "None"
- },
- {
- "trigger": "rosetta",
- "validation": "Local"
- }
- ]
- },
- {
- "listitem": "FileVault Disk Encryption",
- "subtitle": "FileVault provides full-disk encryption",
- "icon": "https://ics.services.jamfcloud.com/icon/hash_f9ba35bd55488783456d64ec73372f029560531ca10dfa0e8154a46d7732b913",
- "progresstext": "FileVault is built-in to macOS and provides full-disk encryption to help prevent unauthorized access to your Mac.",
- "trigger_list": [
- {
- "trigger": "filevault",
- "validation": "Local"
- }
- ]
- },
- {
- "listitem": "Sophos Endpoint",
- "subtitle": "Catches malware without relying on signatures",
- "icon": "https://ics.services.jamfcloud.com/icon/hash_c70f1acf8c96b99568fec83e165d2a534d111b0510fb561a283d32aa5b01c60c",
- "progresstext": "You’ll enjoy next-gen protection with Sophos Endpoint which doesn’t rely on signatures to catch malware.",
- "trigger_list": [
- {
- "trigger": "sophosEndpoint",
- "validation": "/Applications/Sophos/Sophos Endpoint.app/Contents/Info.plist"
- }
- ]
- },
- {
- "listitem": "Sophos Endpoint Services (Remote)",
- "subtitle": "Ensures Sophos Endpoint services are running",
- "icon": "https://ics.services.jamfcloud.com/icon/hash_0f68be689684a00a3a054d71a31e43e2362f96c16efa5a560fb61bc1bf41901c",
- "progresstext": "Remotely validating Sophos Endpoint services …",
- "trigger_list": [
- {
- "trigger": "symvSophosEndpointRTS",
- "validation": "Remote"
- }
- ]
- },
- {
- "listitem": "Palo Alto GlobalProtect",
- "subtitle": "Virtual Private Network (VPN) connection to Church headquarters",
- "icon": "https://ics.services.jamfcloud.com/icon/hash_acbf39d8904ad1a772cf71c45d93e373626d379a24f8b1283b88134880acb8ef",
- "progresstext": "Use Palo Alto GlobalProtect to establish a Virtual Private Network (VPN) connection to Church headquarters.",
- "trigger_list": [
- {
- "trigger": "globalProtect",
- "validation": "/Applications/GlobalProtect.app/Contents/Info.plist"
- }
- ]
- },
- {
- "listitem": "Palo Alto GlobalProtect Services (Remote)",
- "subtitle": "Ensures GlobalProtect services are running",
- "icon": "https://ics.services.jamfcloud.com/icon/hash_709e8bdf0019e8faf9df85ec0a68545bfdb8bfa1227ac9bed9bba40a1fa8ff42",
- "progresstext": "Remotely validating Palo Alto GlobalProtect services …",
- "trigger_list": [
- {
- "trigger": "symvGlobalProtect",
- "validation": "Remote"
- }
- ]
- },
- {
- "listitem": "Final Configuration",
- "subtitle": "Configures remaining Church settings",
- "icon": "https://ics.services.jamfcloud.com/icon/hash_4723e3e341a7e11e6881e418cf91b157fcc081bdb8948697750e5da3562df728",
- "progresstext": "Finalizing Configuration …",
- "trigger_list": [
- {
- "trigger": "finalConfiguration",
- "validation": "None"
- },
- {
- "trigger": "reconAtReboot",
- "validation": "None"
- }
- ]
- },
- {
- "listitem": "Computer Inventory",
- "subtitle": "The listing of your Mac’s apps and settings",
- "icon": "https://ics.services.jamfcloud.com/icon/hash_ff2147a6c09f5ef73d1c4406d00346811a9c64c0b6b7f36eb52fcb44943d26f9",
- "progresstext": "A listing of your Mac’s apps and settings — its inventory — is sent automatically to the Jamf Pro server daily.",
- "trigger_list": [
- {
- "trigger": "recon",
- "validation": "recon"
- }
- ]
- }
- ]
- }
- '
- ;;
- "${configurationTwoName}" )
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+# Welcome dialog 'infobox' animation (thanks, @bartreadon!)
+# To convert emojis, see: https://r12a.github.io/app-conversion/
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
- overlayoverride=""
- policyJSON='
- {
- "steps": [
- {
- "listitem": "Rosetta",
- "subtitle": "Enables a Mac with Apple silicon to use apps built for an Intel processor",
- "icon": "https://ics.services.jamfcloud.com/icon/hash_8bac19160fabb0c8e7bac97b37b51d2ac8f38b7100b6357642d9505645d37b52",
- "progresstext": "Rosetta enables a Mac with Apple silicon to use apps built for a Mac with an Intel processor.",
- "trigger_list": [
- {
- "trigger": "rosettaInstall",
- "validation": "None"
- },
- {
- "trigger": "rosetta",
- "validation": "Local"
- }
- ]
- },
- {
- "listitem": "FileVault Disk Encryption",
- "subtitle": "FileVault provides full-disk encryption",
- "icon": "https://ics.services.jamfcloud.com/icon/hash_f9ba35bd55488783456d64ec73372f029560531ca10dfa0e8154a46d7732b913",
- "progresstext": "FileVault is built-in to macOS and provides full-disk encryption to help prevent unauthorized access to your Mac.",
- "trigger_list": [
- {
- "trigger": "filevault",
- "validation": "Local"
- }
- ]
- },
- {
- "listitem": "Sophos Endpoint",
- "subtitle": "Catches malware without relying on signatures",
- "icon": "https://ics.services.jamfcloud.com/icon/hash_c70f1acf8c96b99568fec83e165d2a534d111b0510fb561a283d32aa5b01c60c",
- "progresstext": "You’ll enjoy next-gen protection with Sophos Endpoint which doesn’t rely on signatures to catch malware.",
- "trigger_list": [
- {
- "trigger": "sophosEndpoint",
- "validation": "/Applications/Sophos/Sophos Endpoint.app/Contents/Info.plist"
- }
- ]
- },
- {
- "listitem": "Sophos Endpoint Services (Local)",
- "subtitle": "Ensures Sophos Endpoint services are running",
- "icon": "https://ics.services.jamfcloud.com/icon/hash_0f68be689684a00a3a054d71a31e43e2362f96c16efa5a560fb61bc1bf41901c",
- "progresstext": "Locally validating Sophos Endpoint services …",
- "trigger_list": [
- {
- "trigger": "sophosEndpointServices",
- "validation": "Local"
- }
- ]
- },
- {
- "listitem": "Palo Alto GlobalProtect",
- "subtitle": "Virtual Private Network (VPN) connection to Church headquarters",
- "icon": "https://ics.services.jamfcloud.com/icon/hash_acbf39d8904ad1a772cf71c45d93e373626d379a24f8b1283b88134880acb8ef",
- "progresstext": "Use Palo Alto GlobalProtect to establish a Virtual Private Network (VPN) connection to Church headquarters.",
- "trigger_list": [
- {
- "trigger": "globalProtect",
- "validation": "/Applications/GlobalProtect.app/Contents/Info.plist"
- }
- ]
- },
- {
- "listitem": "Palo Alto GlobalProtect Services (Local)",
- "subtitle": "Ensures GlobalProtect services are running",
- "icon": "https://ics.services.jamfcloud.com/icon/hash_709e8bdf0019e8faf9df85ec0a68545bfdb8bfa1227ac9bed9bba40a1fa8ff42",
- "progresstext": "Locally validating Palo Alto GlobalProtect services …",
- "trigger_list": [
- {
- "trigger": "globalProtect",
- "validation": "Local"
- }
- ]
- },
- {
- "listitem": "Microsoft 365",
- "subtitle": "Microsoft Office is now Microsoft 365",
- "icon": "https://ics.services.jamfcloud.com/icon/hash_1801d1fdd81e19ce5eb0e567371377e7995bff32947adb7a94c5feea760edcb5",
- "progresstext": "Office is now Microsoft 365. Create, share, and collaborate with your favorite apps — all in one place — with Microsoft 365.",
- "trigger_list": [
- {
- "trigger": "microsoftOffice365",
- "validation": "/Applications/Microsoft Outlook.app/Contents/Info.plist"
- },
- {
- "trigger": "symvMicrosoftOffice365",
- "validation": "Remote"
- }
- ]
- },
- {
- "listitem": "Microsoft Teams",
- "subtitle": "The hub for teamwork in Microsoft 365",
- "icon": "https://ics.services.jamfcloud.com/icon/hash_dcb65709dba6cffa90a5eeaa54cb548d5ecc3b051f39feadd39e02744f37c19e",
- "progresstext": "Microsoft Teams is a hub for teamwork in Microsoft 365. Keep all your team’s chats, meetings and files together in one place.",
- "trigger_list": [
- {
- "trigger": "microsoftTeams",
- "validation": "/Applications/Microsoft Teams classic.app/Contents/Info.plist"
- }
- ]
- },
- {
- "listitem": "Final Configuration",
- "subtitle": "Configures remaining Church settings",
- "icon": "https://ics.services.jamfcloud.com/icon/hash_4723e3e341a7e11e6881e418cf91b157fcc081bdb8948697750e5da3562df728",
- "progresstext": "Finalizing Configuration …",
- "trigger_list": [
- {
- "trigger": "finalConfiguration",
- "validation": "None"
- },
- {
- "trigger": "reconAtReboot",
- "validation": "None"
- }
- ]
- },
- {
- "listitem": "Computer Inventory",
- "subtitle": "The listing of your Mac’s apps and settings",
- "icon": "https://ics.services.jamfcloud.com/icon/hash_ff2147a6c09f5ef73d1c4406d00346811a9c64c0b6b7f36eb52fcb44943d26f9",
- "progresstext": "A listing of your Mac’s apps and settings — its inventory — is sent automatically to the Jamf Pro server daily.",
- "trigger_list": [
- {
- "trigger": "recon",
- "validation": "recon"
- }
- ]
- }
- ]
- }
- '
+function welcomeDialogInfoboxAnimation() {
+ callingPID=$1
+ # clock_emojis=("🕐" "🕑" "🕒" "🕓" "🕔" "🕕" "🕖" "🕗" "🕘" "🕙" "🕚" "🕛")
+ clock_emojis=("🕐" "🕑" "🕒" "🕓" "🕔" "🕕" "🕖" "🕗" "🕘" "🕙" "🕚" "🕛")
+ while true; do
+ for emoji in "${clock_emojis[@]}"; do
+ if kill -0 "$callingPID" 2>/dev/null; then
+ dialogUpdateWelcome "infobox: Testing Connection $emoji"
+ else
+ break
+ fi
+ sleep 0.6
+ done
+ done
+}
+
+
+
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+# Setup Your Mac dialog 'infobox' animation (thanks, @bartreadon!)
+# To convert emojis, see: https://r12a.github.io/app-conversion/
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+
+function setupYourMacDialogInfoboxAnimation() {
+ callingPID=$1
+ # clock_emojis=("🕐" "🕑" "🕒" "🕓" "🕔" "🕕" "🕖" "🕗" "🕘" "🕙" "🕚" "🕛")
+ clock_emojis=("🕐" "🕑" "🕒" "🕓" "🕔" "🕕" "🕖" "🕗" "🕘" "🕙" "🕚" "🕛")
+ while true; do
+ for emoji in "${clock_emojis[@]}"; do
+ if kill -0 "$callingPID" 2>/dev/null; then
+ dialogUpdateSetupYourMac "infobox: Testing Connection $emoji"
+ else
+ break
+ fi
+ sleep 0.6
+ done
+ done
+}
+
+
+
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+# Check Network Quality for Configurations (thanks, @bartreadon!)
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+
+function checkNetworkQualityConfigurations() {
+
+ myPID="$$"
+ welcomeDialog "Display Welcome dialog 'infobox' animation …"
+ welcomeDialogInfoboxAnimation "$myPID" &
+ welcomeDialogInfoboxAnimationPID="$!"
+
+ networkQuality -s -v -c > /var/tmp/networkQualityTest
+ kill ${welcomeDialogInfoboxAnimationPID}
+ outputLineNumberInVerboseDebugMode
+
+ welcomeDialog "Completed networkQualityTest …"
+ networkQualityTest=$( < /var/tmp/networkQualityTest )
+ rm /var/tmp/networkQualityTest
+
+ case "${osVersion}" in
+
+ 11* )
+ dlThroughput="N/A; macOS ${osVersion}"
+ dlResponsiveness="N/A; macOS ${osVersion}"
+ dlStartDate="N/A; macOS ${osVersion}"
+ dlEndDate="N/A; macOS ${osVersion}"
;;
- "${configurationThreeName}" )
+ 12* | 13* | 14*)
+ dlThroughput=$( get_json_value "$networkQualityTest" "dl_throughput")
+ dlResponsiveness=$( get_json_value "$networkQualityTest" "dl_responsiveness" )
+ dlStartDate=$( get_json_value "$networkQualityTest" "start_date" )
+ dlEndDate=$( get_json_value "$networkQualityTest" "end_date" )
+ ;;
- overlayoverride=""
- policyJSON='
- {
- "steps": [
- {
- "listitem": "Rosetta",
- "subtitle": "Enables a Mac with Apple silicon to use apps built for an Intel processor",
- "icon": "https://ics.services.jamfcloud.com/icon/hash_8bac19160fabb0c8e7bac97b37b51d2ac8f38b7100b6357642d9505645d37b52",
- "progresstext": "Rosetta enables a Mac with Apple silicon to use apps built for a Mac with an Intel processor.",
- "trigger_list": [
- {
- "trigger": "rosettaInstall",
- "validation": "None"
- },
- {
- "trigger": "rosetta",
- "validation": "Local"
- }
- ]
- },
- {
- "listitem": "FileVault Disk Encryption",
- "subtitle": "FileVault provides full-disk encryption",
- "icon": "https://ics.services.jamfcloud.com/icon/hash_f9ba35bd55488783456d64ec73372f029560531ca10dfa0e8154a46d7732b913",
- "progresstext": "FileVault is built-in to macOS and provides full-disk encryption to help prevent unauthorized access to your Mac.",
- "trigger_list": [
- {
- "trigger": "filevault",
- "validation": "Local"
- }
- ]
- },
- {
- "listitem": "Sophos Endpoint",
- "subtitle": "Catches malware without relying on signatures",
- "icon": "https://ics.services.jamfcloud.com/icon/hash_c70f1acf8c96b99568fec83e165d2a534d111b0510fb561a283d32aa5b01c60c",
- "progresstext": "You’ll enjoy next-gen protection with Sophos Endpoint which doesn’t rely on signatures to catch malware.",
- "trigger_list": [
- {
- "trigger": "sophosEndpoint",
- "validation": "/Applications/Sophos/Sophos Endpoint.app/Contents/Info.plist"
- }
- ]
- },
- {
- "listitem": "Sophos Endpoint Services (Local)",
- "subtitle": "Ensures Sophos Endpoint services are running",
- "icon": "https://ics.services.jamfcloud.com/icon/hash_0f68be689684a00a3a054d71a31e43e2362f96c16efa5a560fb61bc1bf41901c",
- "progresstext": "Locally validating Sophos Endpoint services …",
- "trigger_list": [
- {
- "trigger": "sophosEndpointServices",
- "validation": "Local"
- }
- ]
- },
- {
- "listitem": "Sophos Endpoint Services (Remote)",
- "subtitle": "Ensures Sophos Endpoint services are running",
- "icon": "https://ics.services.jamfcloud.com/icon/hash_0f68be689684a00a3a054d71a31e43e2362f96c16efa5a560fb61bc1bf41901c",
- "progresstext": "Remotely validating Sophos Endpoint services …",
- "trigger_list": [
- {
- "trigger": "symvSophosEndpointRTS",
- "validation": "Remote"
- }
- ]
- },
- {
- "listitem": "Palo Alto GlobalProtect",
- "subtitle": "Virtual Private Network (VPN) connection to Church headquarters",
- "icon": "https://ics.services.jamfcloud.com/icon/hash_acbf39d8904ad1a772cf71c45d93e373626d379a24f8b1283b88134880acb8ef",
- "progresstext": "Use Palo Alto GlobalProtect to establish a Virtual Private Network (VPN) connection to Church headquarters.",
- "trigger_list": [
- {
- "trigger": "globalProtect",
- "validation": "/Applications/GlobalProtect.app/Contents/Info.plist"
- }
- ]
- },
- {
- "listitem": "Palo Alto GlobalProtect Services (Local)",
- "subtitle": "Ensures GlobalProtect services are running",
- "icon": "https://ics.services.jamfcloud.com/icon/hash_709e8bdf0019e8faf9df85ec0a68545bfdb8bfa1227ac9bed9bba40a1fa8ff42",
- "progresstext": "Locally validating Palo Alto GlobalProtect services …",
- "trigger_list": [
- {
- "trigger": "globalProtect",
- "validation": "Local"
- }
- ]
- },
- {
- "listitem": "Palo Alto GlobalProtect Services (Remote)",
- "subtitle": "Ensures GlobalProtect services are running",
- "icon": "https://ics.services.jamfcloud.com/icon/hash_709e8bdf0019e8faf9df85ec0a68545bfdb8bfa1227ac9bed9bba40a1fa8ff42",
- "progresstext": "Remotely validating Palo Alto GlobalProtect services …",
- "trigger_list": [
- {
- "trigger": "symvGlobalProtect",
- "validation": "Remote"
- }
- ]
- },
- {
- "listitem": "Microsoft 365",
- "subtitle": "Microsoft Office is now Microsoft 365",
- "icon": "https://ics.services.jamfcloud.com/icon/hash_1801d1fdd81e19ce5eb0e567371377e7995bff32947adb7a94c5feea760edcb5",
- "progresstext": "Office is now Microsoft 365. Create, share, and collaborate with your favorite apps — all in one place — with Microsoft 365.",
- "trigger_list": [
- {
- "trigger": "microsoftOffice365",
- "validation": "/Applications/Microsoft Outlook.app/Contents/Info.plist"
- },
- {
- "trigger": "symvMicrosoftOffice365",
- "validation": "Remote"
- }
- ]
- },
- {
- "listitem": "Microsoft Teams",
- "subtitle": "The hub for teamwork in Microsoft 365",
- "icon": "https://ics.services.jamfcloud.com/icon/hash_dcb65709dba6cffa90a5eeaa54cb548d5ecc3b051f39feadd39e02744f37c19e",
- "progresstext": "Microsoft Teams is a hub for teamwork in Microsoft 365. Keep all your team’s chats, meetings and files together in one place.",
- "trigger_list": [
- {
- "trigger": "microsoftTeams",
- "validation": "/Applications/Microsoft Teams classic.app/Contents/Info.plist"
- }
- ]
- },
- {
- "listitem": "Adobe Acrobat Reader",
- "subtitle": "Full-featured PDF reader",
- "icon": "https://ics.services.jamfcloud.com/icon/hash_988b669ca27eab93a9bcd53bb7e2873fb98be4eaa95ae8974c14d611bea1d95f",
- "progresstext": "Views, prints, and comments on PDF documents, and connects to Adobe Document Cloud.",
- "trigger_list": [
- {
- "trigger": "adobeAcrobatReader",
- "validation": "/Applications/Adobe Acrobat Reader.app/Contents/Info.plist"
- }
- ]
- },
- {
- "listitem": "Google Chrome",
- "subtitle": "Third-party Web browser",
- "icon": "https://ics.services.jamfcloud.com/icon/hash_12d3d198f40ab2ac237cff3b5cb05b09f7f26966d6dffba780e4d4e5325cc701",
- "progresstext": "Google Chrome is a browser that combines a minimal design with sophisticated technology to make the Web faster.",
- "trigger_list": [
- {
- "trigger": "googleChrome",
- "validation": "/Applications/Google Chrome.app/Contents/Info.plist"
- }
- ]
- },
- {
- "listitem": "Final Configuration",
- "subtitle": "Configures remaining Church settings",
- "icon": "https://ics.services.jamfcloud.com/icon/hash_4723e3e341a7e11e6881e418cf91b157fcc081bdb8948697750e5da3562df728",
- "progresstext": "Finalizing Configuration …",
- "trigger_list": [
- {
- "trigger": "finalConfiguration",
- "validation": "None"
- },
- {
- "trigger": "reconAtReboot",
- "validation": "None"
- }
- ]
- },
- {
- "listitem": "Computer Inventory",
- "subtitle": "The listing of your Mac’s apps and settings",
- "icon": "https://ics.services.jamfcloud.com/icon/hash_ff2147a6c09f5ef73d1c4406d00346811a9c64c0b6b7f36eb52fcb44943d26f9",
- "progresstext": "A listing of your Mac’s apps and settings — its inventory — is sent automatically to the Jamf Pro server daily.",
- "trigger_list": [
- {
- "trigger": "recon",
- "validation": "recon"
- }
- ]
- }
- ]
- }
- '
+ esac
+
+ mbps=$( echo "scale=2; ( $dlThroughput / 1000000 )" | bc )
+ welcomeDialog "$mbps (Mbps)"
+
+ configurationOneEstimatedSeconds=$( echo "scale=2; ((((( $configurationOneSize / $mbps ) * 60 ) * 60 ) * $correctionCoefficient ) + $configurationOneInstallBuffer)" | bc | sed 's/\.[0-9]*//' )
+ welcomeDialog "Configuration One Estimated Seconds: $configurationOneEstimatedSeconds"
+ welcomeDialog "Configuration One Estimate: $(printf '%dh:%dm:%ds\n' $((configurationOneEstimatedSeconds/3600)) $((configurationOneEstimatedSeconds%3600/60)) $((configurationOneEstimatedSeconds%60)))"
+
+ configurationTwoEstimatedSeconds=$( echo "scale=2; ((((( $configurationTwoSize / $mbps ) * 60 ) * 60 ) * $correctionCoefficient ) + $configurationTwoInstallBuffer)" | bc | sed 's/\.[0-9]*//' )
+ welcomeDialog "Configuration Two Estimated Seconds: $configurationTwoEstimatedSeconds"
+ welcomeDialog "Configuration Two Estimate: $(printf '%dh:%dm:%ds\n' $((configurationTwoEstimatedSeconds/3600)) $((configurationTwoEstimatedSeconds%3600/60)) $((configurationTwoEstimatedSeconds%60)))"
+
+ configurationThreeEstimatedSeconds=$( echo "scale=2; ((((( $configurationThreeSize / $mbps ) * 60 ) * 60 ) * $correctionCoefficient ) + $configurationThreeInstallBuffer)" | bc | sed 's/\.[0-9]*//' )
+ welcomeDialog "Configuration Three Estimated Seconds: $configurationThreeEstimatedSeconds"
+ welcomeDialog "Configuration Three Estimate: $(printf '%dh:%dm:%ds\n' $((configurationThreeEstimatedSeconds/3600)) $((configurationThreeEstimatedSeconds%3600/60)) $((configurationThreeEstimatedSeconds%60)))"
+
+ welcomeDialog "Network Quality Test: Started: $dlStartDate, Ended: $dlEndDate; Download: $mbps Mbps, Responsiveness: $dlResponsiveness"
+ dialogUpdateWelcome "infobox: **Connection:** \n- Download: \n$mbps Mbps \n\n**Estimates:** \n- ${configurationOneName}: \n$(printf '%dh:%dm:%ds\n' $((configurationOneEstimatedSeconds/3600)) $((configurationOneEstimatedSeconds%3600/60)) $((configurationOneEstimatedSeconds%60))) \n\n- ${configurationTwoName}: \n$(printf '%dh:%dm:%ds\n' $((configurationTwoEstimatedSeconds/3600)) $((configurationTwoEstimatedSeconds%3600/60)) $((configurationTwoEstimatedSeconds%60))) \n\n- ${configurationThreeName}: \n$(printf '%dh:%dm:%ds\n' $((configurationThreeEstimatedSeconds/3600)) $((configurationThreeEstimatedSeconds%3600/60)) $((configurationThreeEstimatedSeconds%60)))"
+
+ # If option to lock the continue button is set to true, enable the continue button now to let the user progress
+ if [[ "${lockContinueBeforeEstimations}" == "true" ]]; then
+ welcomeDialog "Enabling Continue Button"
+ dialogUpdateWelcome "button1: enable"
+ fi
+}
+
+
+
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+# Check Network Quality for Catch-all Configuration (thanks, @bartreadon!)
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+
+function checkNetworkQualityCatchAllConfiguration() {
+
+ myPID="$$"
+ updateSetupYourMacDialog "Display Welcome dialog 'infobox' animation …"
+ setupYourMacDialogInfoboxAnimation "$myPID" &
+ setupYourMacDialogInfoboxAnimationPID="$!"
+
+ networkQuality -s -v -c > /var/tmp/networkQualityTest
+ kill ${setupYourMacDialogInfoboxAnimationPID}
+ outputLineNumberInVerboseDebugMode
+
+ updateSetupYourMacDialog "Completed networkQualityTest …"
+ networkQualityTest=$( < /var/tmp/networkQualityTest )
+ rm /var/tmp/networkQualityTest
+
+ case "${osVersion}" in
+
+ 11* )
+ dlThroughput="N/A; macOS ${osVersion}"
+ dlResponsiveness="N/A; macOS ${osVersion}"
+ dlStartDate="N/A; macOS ${osVersion}"
+ dlEndDate="N/A; macOS ${osVersion}"
;;
- * ) # Catch-all (i.e., used when `welcomeDialog` is set to `video`, `messageOnly` or `false`)
-
- overlayoverride=""
- policyJSON='
- {
- "steps": [
- {
- "listitem": "Rosetta",
- "subtitle": "Enables a Mac with Apple silicon to use apps built for an Intel processor",
- "icon": "https://ics.services.jamfcloud.com/icon/hash_8bac19160fabb0c8e7bac97b37b51d2ac8f38b7100b6357642d9505645d37b52",
- "progresstext": "Rosetta enables a Mac with Apple silicon to use apps built for a Mac with an Intel processor.",
- "trigger_list": [
- {
- "trigger": "rosettaInstall",
- "validation": "None"
- },
- {
- "trigger": "rosetta",
- "validation": "Local"
- }
- ]
- },
- {
- "listitem": "FileVault Disk Encryption",
- "subtitle": "FileVault provides full-disk encryption",
- "icon": "https://ics.services.jamfcloud.com/icon/hash_f9ba35bd55488783456d64ec73372f029560531ca10dfa0e8154a46d7732b913",
- "progresstext": "FileVault is built-in to macOS and provides full-disk encryption to help prevent unauthorized access to your Mac.",
- "trigger_list": [
- {
- "trigger": "filevault",
- "validation": "Local"
- }
- ]
- },
- {
- "listitem": "Sophos Endpoint",
- "subtitle": "Catches malware without relying on signatures",
- "icon": "https://ics.services.jamfcloud.com/icon/hash_c70f1acf8c96b99568fec83e165d2a534d111b0510fb561a283d32aa5b01c60c",
- "progresstext": "You’ll enjoy next-gen protection with Sophos Endpoint which doesn’t rely on signatures to catch malware.",
- "trigger_list": [
- {
- "trigger": "sophosEndpoint",
- "validation": "/Applications/Sophos/Sophos Endpoint.app/Contents/Info.plist"
- },
- {
- "trigger": "symvSophosEndpointRTS",
- "validation": "Remote"
- }
- ]
- },
- {
- "listitem": "Palo Alto GlobalProtect",
- "subtitle": "Virtual Private Network (VPN) connection to Church headquarters",
- "icon": "https://ics.services.jamfcloud.com/icon/hash_acbf39d8904ad1a772cf71c45d93e373626d379a24f8b1283b88134880acb8ef",
- "progresstext": "Use Palo Alto GlobalProtect to establish a Virtual Private Network (VPN) connection to Church headquarters.",
- "trigger_list": [
- {
- "trigger": "globalProtect",
- "validation": "/Applications/GlobalProtect.app/Contents/Info.plist"
- },
- {
- "trigger": "symvGlobalProtect",
- "validation": "Remote"
- }
- ]
- },
- {
- "listitem": "Final Configuration",
- "subtitle": "Configures remaining Church settings",
- "icon": "https://ics.services.jamfcloud.com/icon/hash_4723e3e341a7e11e6881e418cf91b157fcc081bdb8948697750e5da3562df728",
- "progresstext": "Finalizing Configuration …",
- "trigger_list": [
- {
- "trigger": "finalConfiguration",
- "validation": "None"
- },
- {
- "trigger": "reconAtReboot",
- "validation": "None"
- }
- ]
- },
- {
- "listitem": "Computer Inventory",
- "subtitle": "The listing of your Mac’s apps and settings",
- "icon": "https://ics.services.jamfcloud.com/icon/hash_ff2147a6c09f5ef73d1c4406d00346811a9c64c0b6b7f36eb52fcb44943d26f9",
- "progresstext": "A listing of your Mac’s apps and settings — its inventory — is sent automatically to the Jamf Pro server daily.",
- "trigger_list": [
- {
- "trigger": "recon",
- "validation": "recon"
- }
- ]
- }
- ]
- }
- '
+ 12* | 13* | 14*)
+ dlThroughput=$( get_json_value "$networkQualityTest" "dl_throughput")
+ dlResponsiveness=$( get_json_value "$networkQualityTest" "dl_responsiveness" )
+ dlStartDate=$( get_json_value "$networkQualityTest" "start_date" )
+ dlEndDate=$( get_json_value "$networkQualityTest" "end_date" )
;;
esac
+ mbps=$( echo "scale=2; ( $dlThroughput / 1000000 )" | bc )
+ updateSetupYourMacDialog "$mbps (Mbps)"
+
+ configurationCatchAllEstimatedSeconds=$( echo "scale=2; ((((( $configurationCatchAllSize / $mbps ) * 60 ) * 60 ) * $correctionCoefficient ) + $configurationCatchAllInstallBuffer)" | bc | sed 's/\.[0-9]*//' )
+ updateSetupYourMacDialog "Catch-all Configuration Estimated Seconds: $configurationCatchAllEstimatedSeconds"
+ updateSetupYourMacDialog "Catch-all Configuration Estimate: $(printf '%dh:%dm:%ds\n' $((configurationCatchAllEstimatedSeconds/3600)) $((configurationCatchAllEstimatedSeconds%3600/60)) $((configurationCatchAllEstimatedSeconds%60)))"
+
+ updateSetupYourMacDialog "Network Quality Test: Started: $dlStartDate, Ended: $dlEndDate; Download: $mbps Mbps, Responsiveness: $dlResponsiveness"
+ dialogUpdateSetupYourMac "infobox: **Connection:** \n- Download: \n$mbps Mbps \n\n**Estimates:** \n- $(printf '%dh:%dm:%ds\n' $((configurationCatchAllEstimatedSeconds/3600)) $((configurationCatchAllEstimatedSeconds%3600/60)) $((configurationCatchAllEstimatedSeconds%60)))"
+ if [[ "${lockContinueBeforeEstimations}" == "true" ]]; then
+ welcomeDialog "Enabling Continue Button"
+ dialogUpdateWelcome "button1: enable"
+ fi
+}
+
+
+
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+# Webhook Message (Microsoft Teams or Slack) (thanks, @robjschroeder! and @iDrewbs!)
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+
+function webHookMessage() {
+
+ outputLineNumberInVerboseDebugMode
+
+ jamfProURL=$(/usr/bin/defaults read /Library/Preferences/com.jamfsoftware.jamf.plist jss_url)
+
+ # # Jamf Pro URL for on-prem, multi-node, clustered environments
+ # case ${jamfProURL} in
+ # *"beta"* ) jamfProURL="https://jamfpro-beta.internal.company.com/" ;;
+ # * ) jamfProURL="https://jamfpro-prod.internal.company.com/" ;;
+ # esac
+
+ jamfProComputerURL="${jamfProURL}computers.html?id=${computerID}&o=r"
+
+ # If there aren't any failures, use "None" for the value of `jamfProPolicyNameFailures`
+ if [[ -z "${jamfProPolicyNameFailures}" ]]; then
+ jamfProPolicyNameFailures="None"
+ fi
+
+ if [[ $webhookURL == *"slack"* ]]; then
+
+ info "Generating Slack Message …"
+
+ webHookdata=$(cat <&1
+
+ webhookResult="$?"
+ info "Slack Webhook Result: ${webhookResult}"
+
+ else
+
+ info "Generating Microsoft Teams Message …"
+
+ # URL to an image to add to your notification
+ activityImage="https://creazilla-store.fra1.digitaloceanspaces.com/cliparts/78010/old-mac-computer-clipart-md.png"
+
+ webHookdata=$(cat <> "$welcomeCommandFile"
-}
+while pgrep -q -x "Setup Assistant"; do
+ preFlight "Setup Assistant is still running; pausing for 2 seconds"
+ sleep 2
+done
+
+preFlight "Setup Assistant is no longer running; proceeding …"
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
-# Update the "Setup Your Mac" dialog
+# Pre-flight Check: Confirm Dock is running / user is at Desktop
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
-function dialogUpdateSetupYourMac() {
- updateScriptLog "SETUP YOUR MAC DIALOG: $1"
- echo "$1" >> "$setupYourMacCommandFile"
-}
+until pgrep -q -x "Finder" && pgrep -q -x "Dock"; do
+ preFlight "Finder & Dock are NOT running; pausing for 1 second"
+ sleep 1
+done
+
+preFlight "Finder & Dock are running; proceeding …"
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
-# Update the "Failure" dialog
+# Pre-flight Check: Validate Logged-in System Accounts
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
-function dialogUpdateFailure(){
- updateScriptLog "FAILURE DIALOG: $1"
- echo "$1" >> "$failureCommandFile"
-}
+preFlight "Check for Logged-in System Accounts …"
+currentLoggedInUser
+
+counter="1"
+
+until { [[ "${loggedInUser}" != "_mbsetupuser" ]] || [[ "${counter}" -gt "180" ]]; } && { [[ "${loggedInUser}" != "loginwindow" ]] || [[ "${counter}" -gt "30" ]]; } ; do
+
+ preFlight "Logged-in User Counter: ${counter}"
+ currentLoggedInUser
+ sleep 2
+ ((counter++))
+
+done
+
+loggedInUserFullname=$( id -F "${loggedInUser}" )
+loggedInUserFirstname=$( echo "$loggedInUserFullname" | sed -E 's/^.*, // ; s/([^ ]*).*/\1/' | sed 's/\(.\{25\}\).*/\1…/' | awk '{print ( $0 == toupper($0) ? toupper(substr($0,1,1))substr(tolower($0),2) : toupper(substr($0,1,1))substr($0,2) )}' )
+loggedInUserID=$( id -u "${loggedInUser}" )
+preFlight "Current Logged-in User First Name: ${loggedInUserFirstname}"
+preFlight "Current Logged-in User ID: ${loggedInUserID}"
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
-# Finalise User Experience
+# Pre-flight Check: Validate Operating System Version and Build
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
-function finalise(){
+if [[ "${requiredMinimumBuild}" == "disabled" ]]; then
- outputLineNumberInVerboseDebugMode
+ preFlight "'requiredMinimumBuild' has been set to ${requiredMinimumBuild}; skipping OS validation."
+ preFlight "macOS ${osVersion} (${osBuild}) installed"
- if [[ "${configurationDownloadEstimation}" == "true" ]]; then
+else
- outputLineNumberInVerboseDebugMode
- calculateFreeDiskSpace "FINALISE USER EXPERIENCE"
+ # Since swiftDialog requires at least macOS 12 Monterey, first confirm the major OS version
+ if [[ "${osMajorVersion}" -ge 12 ]] ; then
- fi
+ preFlight "macOS ${osMajorVersion} installed; checking build version ..."
- if [[ "${jamfProPolicyTriggerFailure}" == "failed" ]]; then
+ # Confirm the Mac is running `requiredMinimumBuild` (or later)
+ if [[ "${osBuild}" > "${requiredMinimumBuild}" ]]; then
+
+ preFlight "macOS ${osVersion} (${osBuild}) installed; proceeding ..."
+
+ # When the current `osBuild` is older than `requiredMinimumBuild`; exit with error
+ else
+ preFlight "The installed operating system, macOS ${osVersion} (${osBuild}), needs to be updated to Build ${requiredMinimumBuild}; exiting with error."
+ osascript -e 'display dialog "Please advise your Support Representative of the following error:\r\rExpected macOS Build '${requiredMinimumBuild}' (or newer), but found macOS '${osVersion}' ('${osBuild}').\r\r" with title "Setup Your Mac: Detected Outdated Operating System" buttons {"Open Software Update"} with icon caution'
+ preFlight "Executing /usr/bin/open '${outdatedOsAction}' …"
+ su - "${loggedInUser}" -c "/usr/bin/open \"${outdatedOsAction}\""
+ exit 1
- outputLineNumberInVerboseDebugMode
- updateScriptLog "Failed policies detected …"
- if [[ -n "${webhookURL}" ]]; then
- updateScriptLog "Display Failure dialog: Sending webhook message"
- webhookStatus="Failures detected"
- webHookMessage
fi
- if [[ "${failureDialog}" == "true" ]]; then
+ # The Mac is running an operating system older than macOS 12 Monterey; exit with error
+ else
+
+ preFlight "swiftDialog requires at least macOS 12 Monterey and this Mac is running ${osVersion} (${osBuild}), exiting with error."
+ osascript -e 'display dialog "Please advise your Support Representative of the following error:\r\rExpected macOS Build '${requiredMinimumBuild}' (or newer), but found macOS '${osVersion}' ('${osBuild}').\r\r" with title "Setup Your Mac: Detected Outdated Operating System" buttons {"Open Software Update"} with icon caution'
+ preFlight "Executing /usr/bin/open '${outdatedOsAction}' …"
+ su - "${loggedInUser}" -c "/usr/bin/open \"${outdatedOsAction}\""
+ exit 1
- outputLineNumberInVerboseDebugMode
- updateScriptLog "Display Failure dialog: ${failureDialog}"
+ fi
- killProcess "caffeinate"
- if [[ "${brandingBannerDisplayText}" == "true" ]] ; then dialogUpdateSetupYourMac "title: Sorry ${loggedInUserFirstname}, something went sideways"; fi
- dialogUpdateSetupYourMac "icon: SF=xmark.circle.fill,weight=bold,colour1=#BB1717,colour2=#F31F1F"
- dialogUpdateSetupYourMac "progresstext: Failures detected. Please click Continue for troubleshooting information."
- dialogUpdateSetupYourMac "button1text: Continue …"
- dialogUpdateSetupYourMac "button1: enable"
- dialogUpdateSetupYourMac "progress: reset"
-
- # Wait for user-acknowledgment due to detected failure
- wait
+fi
- dialogUpdateSetupYourMac "quit:"
- eval "${dialogFailureCMD}" & sleep 0.3
- updateScriptLog "\n\n# # #\n# FAILURE DIALOG\n# # #\n"
- updateScriptLog "Jamf Pro Policy Name Failures:"
- updateScriptLog "${jamfProPolicyNameFailures}"
- failureMessage="A failure has been detected, ${loggedInUserFirstname}. \n\nPlease complete the following steps:\n1. Reboot and login to your ${modelName} \n2. Login to Self Service \n3. Re-run any failed policy listed below \n\nThe following failed: \n${jamfProPolicyNameFailures}"
-
- if [[ -n "${supportTeamName}" ]]; then
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+# Pre-flight Check: Ensure computer does not go to sleep during SYM (thanks, @grahampugh!)
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
- supportContactMessage+="If you need assistance, please contact the **${supportTeamName}**: \n"
+symPID="$$"
+preFlight "Caffeinating this script (PID: $symPID)"
+caffeinate -dimsu -w $symPID &
- if [[ -n "${supportTeamPhone}" ]]; then
- supportContactMessage+="- **Telephone:** ${supportTeamPhone}\n"
- fi
- if [[ -n "${supportTeamEmail}" ]]; then
- supportContactMessage+="- **Email:** $supportTeamEmail\n"
- fi
- if [[ -n "${supportTeamWebsite}" ]]; then
- supportContactMessage+="- **Web**: ${supportTeamHyperlink}\n"
- fi
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+# Pre-flight Check: Toggle `jamf` binary check-in (thanks, @robjschroeder!)
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
- if [[ -n "${supportKB}" ]]; then
- supportContactMessage+="- **Knowledge Base Article:** $supportTeamErrorKB\n"
- fi
-
- fi
+function toggleJamfLaunchDaemon() {
+
+ jamflaunchDaemon="/Library/LaunchDaemons/com.jamfsoftware.task.1.plist"
- failureMessage+="\n\n${supportContactMessage}"
+ if [[ "${debugMode}" == "true" ]] || [[ "${debugMode}" == "verbose" ]] ; then
- dialogUpdateFailure "message: ${failureMessage}"
+ if [[ $(/bin/launchctl list | grep com.jamfsoftware.task.E) ]]; then
+ preFlight "DEBUG MODE: Normally, 'jamf' binary check-in would be temporarily disabled"
+ else
+ quitOut "DEBUG MODE: Normally, 'jamf' binary check-in would be re-enabled"
+ fi
- dialogUpdateFailure "icon: SF=xmark.circle.fill,weight=bold,colour1=#BB1717,colour2=#F31F1F"
- dialogUpdateFailure "button1text: ${button1textCompletionActionOption}"
+ else
- # Wait for user-acknowledgment due to detected failure
- wait
+ while [[ ! -f "${jamflaunchDaemon}" ]] ; do
+ preFlight "Waiting for installation of ${jamflaunchDaemon}"
+ sleep 0.1
+ done
- dialogUpdateFailure "quit:"
- quitScript "1"
+ if [[ $(/bin/launchctl list | grep com.jamfsoftware.task.E) ]]; then
+
+ preFlight "Temporarily disable 'jamf' binary check-in"
+ /bin/launchctl bootout system "${jamflaunchDaemon}"
else
- outputLineNumberInVerboseDebugMode
- updateScriptLog "Display Failure dialog: ${failureDialog}"
+ quitOut "Re-enabling 'jamf' binary check-in"
+ quitOut "'jamf' binary check-in daemon not loaded, attempting to bootstrap and start"
+ result="0"
- killProcess "caffeinate"
- if [[ "${brandingBannerDisplayText}" == "true" ]] ; then dialogUpdateSetupYourMac "title: Sorry ${loggedInUserFirstname}, something went sideways"; fi
- dialogUpdateSetupYourMac "icon: SF=xmark.circle.fill,weight=bold,colour1=#BB1717,colour2=#F31F1F"
- dialogUpdateSetupYourMac "progresstext: Failures detected."
- dialogUpdateSetupYourMac "button1text: ${button1textCompletionActionOption}"
- dialogUpdateSetupYourMac "button1: enable"
- dialogUpdateSetupYourMac "progress: reset"
- dialogUpdateSetupYourMac "progresstext: Errors detected; please ${progressTextCompletionAction// and } your ${modelName}, ${loggedInUserFirstname}."
+ until [ $result -eq 3 ]; do
- quitScript "1"
+ /bin/launchctl bootstrap system "${jamflaunchDaemon}" && /bin/launchctl start "${jamflaunchDaemon}"
+ result="$?"
- fi
+ if [ $result = 3 ]; then
+ quitOut "Staring 'jamf' binary check-in daemon"
+ else
+ quitOut "Failed to start 'jamf' binary check-in daemon"
+ fi
- else
+ done
- outputLineNumberInVerboseDebugMode
- updateScriptLog "All policies executed successfully"
- if [[ -n "${webhookURL}" ]]; then
- webhookStatus="Successful"
- updateScriptLog "Sending success webhook message"
- webHookMessage
fi
- if [[ "${brandingBannerDisplayText}" == "true" ]] ; then dialogUpdateSetupYourMac "title: ${loggedInUserFirstname}‘s ${modelName} is ready!"; fi
- dialogUpdateSetupYourMac "icon: SF=checkmark.circle.fill,weight=bold,colour1=#00ff44,colour2=#075c1e"
- dialogUpdateSetupYourMac "progresstext: Complete! Please ${progressTextCompletionAction}enjoy your new ${modelName}, ${loggedInUserFirstname}!"
- dialogUpdateSetupYourMac "progress: complete"
- dialogUpdateSetupYourMac "button1text: ${button1textCompletionActionOption}"
- dialogUpdateSetupYourMac "button1: enable"
-
- quitScript "0"
-
fi
}
+toggleJamfLaunchDaemon
+
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
-# Parse JSON via osascript and JavaScript
+# Pre-flight Check: Validate / install swiftDialog (Thanks big bunches, @acodega!)
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
-function get_json_value() {
- # set -x
- JSON="$1" osascript -l 'JavaScript' \
- -e 'const env = $.NSProcessInfo.processInfo.environment.objectForKey("JSON").js' \
- -e "JSON.parse(env).$2"
- # set +x
-}
+function dialogInstall() {
+ # Get the URL of the latest PKG From the Dialog GitHub repo
+ dialogURL=$(curl -L --silent --fail "https://api.github.com/repos/swiftDialog/swiftDialog/releases/latest" | awk -F '"' "/browser_download_url/ && /pkg\"/ { print \$4; exit }")
+ # Expected Team ID of the downloaded PKG
+ expectedDialogTeamID="PWA5E9TQ59"
-# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
-# Parse JSON via osascript and JavaScript for the Welcome dialog (thanks, @bartreardon!)
-# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+ preFlight "Installing swiftDialog..."
-function get_json_value_welcomeDialog() {
- # set -x
- for var in "${@:2}"; do jsonkey="${jsonkey}['${var}']"; done
- JSON="$1" osascript -l 'JavaScript' \
- -e 'const env = $.NSProcessInfo.processInfo.environment.objectForKey("JSON").js' \
- -e "JSON.parse(env)$jsonkey"
- # set +x
-}
+ # Create temporary working directory
+ workDirectory=$( /usr/bin/basename "$0" )
+ tempDirectory=$( /usr/bin/mktemp -d "/private/tmp/$workDirectory.XXXXXX" )
+ # Download the installer package
+ /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 '()')
-# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
-# Execute Jamf Pro Policy Custom Events (thanks, @smithjw)
-# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+ # Install the package if Team ID validates
+ if [[ "$expectedDialogTeamID" == "$teamID" ]]; then
-function run_jamf_trigger() {
+ /usr/sbin/installer -pkg "$tempDirectory/Dialog.pkg" -target /
+ sleep 2
+ dialogVersion=$( /usr/local/bin/dialog --version )
+ preFlight "swiftDialog version ${dialogVersion} installed; proceeding..."
- outputLineNumberInVerboseDebugMode
+ else
- trigger="$1"
+ # Display a so-called "simple" dialog if Team ID fails to validate
+ osascript -e 'display dialog "Please advise your Support Representative of the following error:\r\r• Dialog Team ID verification failed\r\r" with title "Setup Your Mac: Error" buttons {"Close"} with icon caution'
+ completionActionOption="Quit"
+ exitCode="1"
+ quitScript
- if [[ "${debugMode}" == "true" ]] || [[ "${debugMode}" == "verbose" ]] ; then
+ fi
+
+ # Remove the temporary working directory when done
+ /bin/rm -Rf "$tempDirectory"
+
+}
- updateScriptLog "SETUP YOUR MAC DIALOG: DEBUG MODE: TRIGGER: $jamfBinary policy -event $trigger ${suppressRecon}"
- sleep "${debugModeSleepAmount}"
+
+
+function dialogCheck() {
+
+ # Output Line Number in `verbose` Debug Mode
+ if [[ "${debugMode}" == "verbose" ]]; then preFlight "# # # SETUP YOUR MAC VERBOSE DEBUG MODE: Line No. ${LINENO} # # #" ; fi
+
+ # Check for Dialog and install if not found
+ if [ ! -e "/Library/Application Support/Dialog/Dialog.app" ]; then
+
+ preFlight "swiftDialog not found. Installing..."
+ dialogInstall
else
- updateScriptLog "SETUP YOUR MAC DIALOG: RUNNING: $jamfBinary policy -event $trigger"
- eval "${jamfBinary} policy -event ${trigger} ${suppressRecon}" # Add comment for policy testing
- # eval "${jamfBinary} policy -event ${trigger} ${suppressRecon} -verbose | tee -a ${scriptLog}" # Remove comment for policy testing
+ dialogVersion=$(/usr/local/bin/dialog --version)
+ if [[ "${dialogVersion}" < "${swiftDialogMinimumRequiredVersion}" ]]; then
+
+ preFlight "swiftDialog version ${dialogVersion} found but swiftDialog ${swiftDialogMinimumRequiredVersion} or newer is required; updating..."
+ dialogInstall
+
+ else
+ preFlight "swiftDialog version ${dialogVersion} found; proceeding..."
+
+ fi
+
fi
}
+dialogCheck
+
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
-# Confirm Policy Execution
+# Pre-flight Check: Validate `supportTeam` variables are populated
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
-function confirmPolicyExecution() {
+if [[ -z $supportTeamName ]]; then
+ preFlight "'supportTeamName' must be populated to proceed; exiting"
+ exit 1
+fi
- outputLineNumberInVerboseDebugMode
+if [[ -z $supportTeamPhone && -z $supportTeamEmail && -z $supportKB ]]; then
+ preFlight "At least ONE 'supportTeam' variable must be populated to proceed; exiting"
+ exit 1
+fi
- trigger="${1}"
- validation="${2}"
- updateScriptLog "SETUP YOUR MAC DIALOG: Confirm Policy Execution: '${trigger}' '${validation}'"
- if [ "${suppressReconOnPolicy}" == "true" ]; then suppressRecon="-forceNoRecon"; fi
- case ${validation} in
- */* ) # If the validation variable contains a forward slash (i.e., "/"), presume it's a path and check if that path exists on disk
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+# Pre-flight Check: Complete
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
- outputLineNumberInVerboseDebugMode
- if [[ "${debugMode}" == "true" ]] || [[ "${debugMode}" == "verbose" ]] ; then
- updateScriptLog "SETUP YOUR MAC DIALOG: Confirm Policy Execution: DEBUG MODE: Skipping 'run_jamf_trigger ${trigger}'"
- sleep "${debugModeSleepAmount}"
- elif [[ -e "${validation}" ]]; then
- updateScriptLog "SETUP YOUR MAC DIALOG: Confirm Policy Execution: ${validation} exists; skipping 'run_jamf_trigger ${trigger}'"
- previouslyInstalled="true"
- else
- updateScriptLog "SETUP YOUR MAC DIALOG: Confirm Policy Execution: ${validation} does NOT exist; executing 'run_jamf_trigger ${trigger}'"
- previouslyInstalled="false"
- run_jamf_trigger "${trigger}"
- fi
- ;;
+preFlight "Complete"
- "None" | "none" )
- outputLineNumberInVerboseDebugMode
- updateScriptLog "SETUP YOUR MAC DIALOG: Confirm Policy Execution: ${validation}"
- if [[ "${debugMode}" == "true" ]] || [[ "${debugMode}" == "verbose" ]] ; then
- sleep "${debugModeSleepAmount}"
- else
- run_jamf_trigger "${trigger}"
- fi
- ;;
- "Recon" | "recon" )
+####################################################################################################
+#
+# Dialog Variables
+#
+####################################################################################################
- outputLineNumberInVerboseDebugMode
- updateScriptLog "SETUP YOUR MAC DIALOG: Confirm Policy Execution: ${validation}"
- if [[ "${debugMode}" == "true" ]] || [[ "${debugMode}" == "verbose" ]] ; then
- updateScriptLog "SETUP YOUR MAC DIALOG: DEBUG MODE: Set 'debugMode' to false to update computer inventory with the following 'reconOptions': \"${reconOptions}\" …"
- sleep "${debugModeSleepAmount}"
- else
- updateScriptLog "SETUP YOUR MAC DIALOG: Updating computer inventory with the following 'reconOptions': \"${reconOptions}\" …"
- dialogUpdateSetupYourMac "listitem: index: $i, status: wait, statustext: Updating …, "
- reconRaw=$( eval "${jamfBinary} recon ${reconOptions} -verbose | tee -a ${scriptLog}" )
- computerID=$( echo "${reconRaw}" | grep '' | xmllint --xpath xmllint --xpath '/computer_id/text()' - )
- fi
- ;;
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+# infobox-related variables
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
- * )
+macOSproductVersion="$( sw_vers -productVersion )"
+macOSbuildVersion="$( sw_vers -buildVersion )"
+serialNumber=$( ioreg -rd1 -c IOPlatformExpertDevice | awk -F'"' '/IOPlatformSerialNumber/{print $4}' )
+timestamp="$( date '+%Y-%m-%d-%H%M%S' )"
+dialogVersion=$( /usr/local/bin/dialog --version )
- outputLineNumberInVerboseDebugMode
- updateScriptLog "SETUP YOUR MAC DIALOG: Confirm Policy Execution Catch-all: ${validation}"
- if [[ "${debugMode}" == "true" ]] || [[ "${debugMode}" == "verbose" ]] ; then
- sleep "${debugModeSleepAmount}"
- else
- run_jamf_trigger "${trigger}"
- fi
- ;;
- esac
-}
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+# Reflect Debug Mode in `infotext` (i.e., bottom, left-hand corner of each dialog)
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+
+case ${debugMode} in
+ "true" ) scriptVersion="DEBUG MODE | Dialog: v${dialogVersion} • Setup Your Mac: v${scriptVersion}" ;;
+ "verbose" ) scriptVersion="VERBOSE DEBUG MODE | Dialog: v${dialogVersion} • Setup Your Mac: v${scriptVersion}" ;;
+esac
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
-# Validate Policy Result
+# Set JAMF binary, Dialog path and Command Files
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
-function validatePolicyResult() {
-
- outputLineNumberInVerboseDebugMode
-
- trigger="${1}"
- validation="${2}"
- updateScriptLog "SETUP YOUR MAC DIALOG: Validate Policy Result: '${trigger}' '${validation}'"
+jamfBinary="/usr/local/bin/jamf"
+dialogBinary="/usr/local/bin/dialog"
+welcomeJSONFile=$( mktemp -u /var/tmp/welcomeJSONFile.XXX )
+welcomeCommandFile=$( mktemp -u /var/tmp/dialogCommandFileWelcome.XXX )
+setupYourMacCommandFile=$( mktemp -u /var/tmp/dialogCommandFileSetupYourMac.XXX )
+failureCommandFile=$( mktemp -u /var/tmp/dialogCommandFileFailure.XXX )
- case ${validation} in
- ###
- # Absolute Path
- # Simulates pre-v1.6.0 behavior, for example: "/Applications/Microsoft Teams classic.app/Contents/Info.plist"
- ###
- */* )
- updateScriptLog "SETUP YOUR MAC DIALOG: Validate Policy Result: Testing for \"$validation\" …"
- if [[ "${previouslyInstalled}" == "true" ]]; then
- dialogUpdateSetupYourMac "listitem: index: $i, status: success, statustext: Previously Installed"
- elif [[ -e "${validation}" ]]; then
- dialogUpdateSetupYourMac "listitem: index: $i, status: success, statustext: Installed"
- else
- dialogUpdateSetupYourMac "listitem: index: $i, status: fail, statustext: Failed"
- jamfProPolicyTriggerFailure="failed"
- exitCode="1"
- jamfProPolicyNameFailures+="• $listitem \n"
- fi
- ;;
+####################################################################################################
+#
+# Welcome dialog
+#
+####################################################################################################
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+# "Welcome" dialog Title, Message and Icon
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+welcomeTitle="Happy $( date +'%A' ), ${loggedInUserFirstname}! \nWelcome to your new ${modelName}"
- ###
- # Local
- # Validation within this script, for example: "rosetta" or "filevault"
- ###
+welcomeMessage="Please enter the **required** information for your ${modelName}, select your preferred **Configuration** then click **Continue** to start applying settings to your new Mac. \n\nOnce completed, the **Wait** button will be enabled and you‘ll be able to review the results before restarting your ${modelName}."
- "Local" )
- case ${trigger} in
- rosetta )
- updateScriptLog "SETUP YOUR MAC DIALOG: Locally Validate Policy Result: Rosetta 2 … " # Thanks, @smithjw!
- dialogUpdateSetupYourMac "listitem: index: $i, status: wait, statustext: Checking …"
- arch=$( /usr/bin/arch )
- if [[ "${arch}" == "arm64" ]]; then
- # Mac with Apple silicon; check for Rosetta
- rosettaTest=$( arch -x86_64 /usr/bin/true 2> /dev/null ; echo $? )
- if [[ "${rosettaTest}" -eq 0 ]]; then
- # Installed
- updateScriptLog "SETUP YOUR MAC DIALOG: Locally Validate Policy Result: Rosetta 2 is installed"
- dialogUpdateSetupYourMac "listitem: index: $i, status: success, statustext: Running"
- else
- # Not Installed
- updateScriptLog "SETUP YOUR MAC DIALOG: Locally Validate Policy Result: Rosetta 2 is NOT installed"
- dialogUpdateSetupYourMac "listitem: index: $i, status: fail, statustext: Failed"
- jamfProPolicyTriggerFailure="failed"
- exitCode="1"
- jamfProPolicyNameFailures+="• $listitem \n"
- fi
- else
- # Ineligible
- updateScriptLog "SETUP YOUR MAC DIALOG: Locally Validate Policy Result: Rosetta 2 is not applicable"
- dialogUpdateSetupYourMac "listitem: index: $i, status: error, statustext: Ineligible"
- fi
- ;;
- filevault )
- updateScriptLog "SETUP YOUR MAC DIALOG: Locally Validate Policy Result: Validate FileVault … "
- dialogUpdateSetupYourMac "listitem: index: $i, status: wait, statustext: Checking …"
- updateScriptLog "SETUP YOUR MAC DIALOG: Validate Policy Result: Pausing for 5 seconds for FileVault … "
- sleep 5 # Arbitrary value; tuning needed
- fileVaultCheck=$( fdesetup isactive )
- if [[ -f /Library/Preferences/com.apple.fdesetup.plist ]] || [[ "$fileVaultCheck" == "true" ]]; then
- fileVaultStatus=$( fdesetup status -extended -verbose 2>&1 )
- case ${fileVaultStatus} in
- *"FileVault is On."* )
- updateScriptLog "SETUP YOUR MAC DIALOG: Locally Validate Policy Result: FileVault: FileVault is On."
- dialogUpdateSetupYourMac "listitem: index: $i, status: success, statustext: Enabled"
- ;;
- *"Deferred enablement appears to be active for user"* )
- updateScriptLog "SETUP YOUR MAC DIALOG: Locally Validate Policy Result: FileVault: Enabled"
- dialogUpdateSetupYourMac "listitem: index: $i, status: success, statustext: Enabled (next login)"
- ;;
- * )
- dialogUpdateSetupYourMac "listitem: index: $i, status: error, statustext: Unknown"
- jamfProPolicyTriggerFailure="failed"
- exitCode="1"
- jamfProPolicyNameFailures+="• $listitem \n"
- ;;
- esac
- else
- updateScriptLog "SETUP YOUR MAC DIALOG: Locally Validate Policy Result: '/Library/Preferences/com.apple.fdesetup.plist' NOT Found"
- dialogUpdateSetupYourMac "listitem: index: $i, status: fail, statustext: Failed"
- jamfProPolicyTriggerFailure="failed"
- exitCode="1"
- jamfProPolicyNameFailures+="• $listitem \n"
- fi
- ;;
- sophosEndpointServices )
- updateScriptLog "SETUP YOUR MAC DIALOG: Locally Validate Policy Result: Sophos Endpoint RTS Status … "
- dialogUpdateSetupYourMac "listitem: index: $i, status: wait, statustext: Checking …"
- if [[ -d /Applications/Sophos/Sophos\ Endpoint.app ]]; then
- if [[ -f /Library/Preferences/com.sophos.sav.plist ]]; then
- sophosOnAccessRunning=$( /usr/bin/defaults read /Library/Preferences/com.sophos.sav.plist OnAccessRunning )
- case ${sophosOnAccessRunning} in
- "0" )
- updateScriptLog "SETUP YOUR MAC DIALOG: Locally Validate Policy Result: Sophos Endpoint RTS Status: Disabled"
- dialogUpdateSetupYourMac "listitem: index: $i, status: fail, statustext: Failed"
- jamfProPolicyTriggerFailure="failed"
- exitCode="1"
- jamfProPolicyNameFailures+="• $listitem \n"
- ;;
- "1" )
- updateScriptLog "SETUP YOUR MAC DIALOG: Locally Validate Policy Result: Sophos Endpoint RTS Status: Enabled"
- dialogUpdateSetupYourMac "listitem: index: $i, status: success, statustext: Running"
- ;;
- * )
- updateScriptLog "SETUP YOUR MAC DIALOG: Locally Validate Policy Result: Sophos Endpoint RTS Status: Unknown"
- dialogUpdateSetupYourMac "listitem: index: $i, status: fail, statustext: Unknown"
- jamfProPolicyTriggerFailure="failed"
- exitCode="1"
- jamfProPolicyNameFailures+="• $listitem \n"
- ;;
- esac
- else
- updateScriptLog "SETUP YOUR MAC DIALOG: Locally Validate Policy Result: Sophos Endpoint Not Found"
- dialogUpdateSetupYourMac "listitem: index: $i, status: fail, statustext: Failed"
- jamfProPolicyTriggerFailure="failed"
- exitCode="1"
- jamfProPolicyNameFailures+="• $listitem \n"
- fi
- else
- dialogUpdateSetupYourMac "listitem: index: $i, status: fail, statustext: Failed"
- jamfProPolicyTriggerFailure="failed"
- exitCode="1"
- jamfProPolicyNameFailures+="• $listitem \n"
- fi
- ;;
- globalProtect )
- updateScriptLog "SETUP YOUR MAC DIALOG: Locally Validate Policy Result: Palo Alto Networks GlobalProtect Status … "
- dialogUpdateSetupYourMac "listitem: index: $i, status: wait, statustext: Checking …"
- if [[ -d /Applications/GlobalProtect.app ]]; then
- updateScriptLog "SETUP YOUR MAC DIALOG: Locally Validate Policy Result: Pausing for 10 seconds to allow Palo Alto Networks GlobalProtect Services … "
- sleep 10 # Arbitrary value; tuning needed
- if [[ -f /Library/Preferences/com.paloaltonetworks.GlobalProtect.settings.plist ]]; then
- globalProtectStatus=$( /usr/libexec/PlistBuddy -c "print :Palo\ Alto\ Networks:GlobalProtect:PanGPS:disable-globalprotect" /Library/Preferences/com.paloaltonetworks.GlobalProtect.settings.plist )
- case "${globalProtectStatus}" in
- "0" )
- updateScriptLog "SETUP YOUR MAC DIALOG: Locally Validate Policy Result: Palo Alto Networks GlobalProtect Status: Enabled"
- dialogUpdateSetupYourMac "listitem: index: $i, status: success, statustext: Running"
- ;;
- "1" )
- updateScriptLog "SETUP YOUR MAC DIALOG: Locally Validate Policy Result: Palo Alto Networks GlobalProtect Status: Disabled"
- dialogUpdateSetupYourMac "listitem: index: $i, status: fail, statustext: Failed"
- jamfProPolicyTriggerFailure="failed"
- exitCode="1"
- jamfProPolicyNameFailures+="• $listitem \n"
- ;;
- * )
- updateScriptLog "SETUP YOUR MAC DIALOG: Locally Validate Policy Result: Palo Alto Networks GlobalProtect Status: Unknown"
- dialogUpdateSetupYourMac "listitem: index: $i, status: fail, statustext: Unknown"
- jamfProPolicyTriggerFailure="failed"
- exitCode="1"
- jamfProPolicyNameFailures+="• $listitem \n"
- ;;
- esac
- else
- updateScriptLog "SETUP YOUR MAC DIALOG: Locally Validate Policy Result: Palo Alto Networks GlobalProtect Not Found"
- dialogUpdateSetupYourMac "listitem: index: $i, status: fail, statustext: Failed"
- jamfProPolicyTriggerFailure="failed"
- exitCode="1"
- jamfProPolicyNameFailures+="• $listitem \n"
- fi
- else
- dialogUpdateSetupYourMac "listitem: index: $i, status: fail, statustext: Failed"
- jamfProPolicyTriggerFailure="failed"
- exitCode="1"
- jamfProPolicyNameFailures+="• $listitem \n"
- fi
- ;;
- * )
- updateScriptLog "SETUP YOUR MAC DIALOG: Locally Validate Policy Result: Local Validation “${validation}” Missing"
- dialogUpdateSetupYourMac "listitem: index: $i, status: fail, statustext: Missing Local “${validation}” Validation"
- jamfProPolicyTriggerFailure="failed"
- exitCode="1"
- jamfProPolicyNameFailures+="• $listitem \n"
- ;;
- esac
- ;;
+if [[ -n "${supportTeamName}" ]]; then
+ welcomeMessage+="\n\nIf you need assistance, please contact the **${supportTeamName}**: \n"
+ if [[ -n "${supportTeamPhone}" ]]; then
+ welcomeMessage+="- **Telephone**: ${supportTeamPhone}\n"
+ fi
- ###
- # Remote
- # Validation via a Jamf Pro policy which has a single-script payload, for example: "symvGlobalProtect"
- # See: https://vimeo.com/782561166
- ###
+ if [[ -n "${supportTeamEmail}" ]]; then
+ welcomeMessage+="- **Email**: ${supportTeamEmail}\n"
+ fi
- "Remote" )
- if [[ "${debugMode}" == "true" ]] || [[ "${debugMode}" == "verbose" ]] ; then
- updateScriptLog "SETUP YOUR MAC DIALOG: DEBUG MODE: Remotely Confirm Policy Execution: Skipping 'run_jamf_trigger ${trigger}'"
- dialogUpdateSetupYourMac "listitem: index: $i, status: error, statustext: Debug Mode Enabled"
- sleep 0.5
- else
- updateScriptLog "SETUP YOUR MAC DIALOG: Remotely Validate '${trigger}' '${validation}'"
- dialogUpdateSetupYourMac "listitem: index: $i, status: wait, statustext: Checking …"
- result=$( "${jamfBinary}" policy -event "${trigger}" | grep "Script result:" )
- if [[ "${result}" == *"Running"* ]]; then
- dialogUpdateSetupYourMac "listitem: index: $i, status: success, statustext: Running"
- elif [[ "${result}" == *"Installed"* || "${result}" == *"Success"* ]]; then
- dialogUpdateSetupYourMac "listitem: index: $i, status: success, statustext: Installed"
- else
- dialogUpdateSetupYourMac "listitem: index: $i, status: fail, statustext: Failed"
- jamfProPolicyTriggerFailure="failed"
- exitCode="1"
- jamfProPolicyNameFailures+="• $listitem \n"
- fi
- fi
- ;;
+ if [[ -n "${supportTeamWebsite}" ]]; then
+ welcomeMessage+="- **Web**: ${supportTeamHyperlink}\n"
+ fi
+ if [[ -n "${supportKB}" ]]; then
+ welcomeMessage+="- **Knowledge Base Article:** ${supportTeamErrorKB}\n"
+ fi
+fi
- ###
- # None: For triggers which don't require validation
- # (Always evaluates as: 'success' and 'Installed')
- ###
+welcomeMessage+="\n\n---"
- "None" | "none")
+if { [[ "${promptForConfiguration}" == "true" ]] && [[ "${welcomeDialog}" != "messageOnly" ]]; } then
+ welcomeMessage+=" \n\n#### Configurations \n- **${configurationOneName}:** ${configurationOneDescription} \n- **${configurationTwoName}:** ${configurationTwoDescription} \n- **${configurationThreeName}:** ${configurationThreeDescription}"
+else
+ welcomeMessage=${welcomeMessage//", select your preferred **Configuration**"/}
+fi
- outputLineNumberInVerboseDebugMode
- updateScriptLog "SETUP YOUR MAC DIALOG: Confirm Policy Execution: ${validation}"
- dialogUpdateSetupYourMac "listitem: index: $i, status: success, statustext: Installed"
- ;;
+if [[ "${brandingBannerDisplayText}" == "true" ]]; then welcomeBannerText="Happy $( date +'%A' ), ${loggedInUserFirstname}! \nWelcome to your new ${modelName}";
+else welcomeBannerText=""; fi
+welcomeCaption="Please review the above video, then click Continue."
+welcomeVideoID="vimeoid=909473114"
- ###
- # Recon: For reporting computer inventory update
- # (Always evaluates as: 'success' and 'Updated')
- ###
+# Check brandingBanner and cache if necessary
+case ${brandingBanner} in
- "Recon" | "recon" )
+ *"https"* )
+ welcomeBannerImage="${brandingBanner}"
+ bannerImage="${brandingBanner}"
+ if curl -L --output /dev/null --silent --head --fail "$welcomeBannerImage" || [ -f "$welcomeBannerImage" ]; then
+ welcomeDialog "brandingBanner is available, using it"
+ else
+ welcomeDialog "brandingBanner is not available, using a default image"
+ welcomeBannerImage="https://img.freepik.com/free-vector/green-abstract-geometric-wallpaper_52683-29623.jpg" # Image by pikisuperstar on Freepik
+ bannerImage="https://img.freepik.com/free-vector/green-abstract-geometric-wallpaper_52683-29623.jpg" # Image by pikisuperstar on Freepik
+ fi
- outputLineNumberInVerboseDebugMode
- updateScriptLog "SETUP YOUR MAC DIALOG: Confirm Policy Execution: ${validation}"
- dialogUpdateSetupYourMac "listitem: index: $i, status: success, statustext: Updated"
- ;;
+ welcomeBannerImageFileName=$( echo ${welcomeBannerImage} | awk -F '/' '{print $NF}' )
+ welcomeDialog "Auto-caching hosted '$welcomeBannerImageFileName' …"
+ curl -L --location --silent "$welcomeBannerImage" -o "/var/tmp/${welcomeBannerImageFileName}"
+ welcomeBannerImage="/var/tmp/${welcomeBannerImageFileName}"
+ bannerImage="/var/tmp/${welcomeBannerImageFileName}"
+ ;;
+ */* )
+ welcomeDialog "brandingBanner is local file, using it"
+ welcomeBannerImage="${brandingBanner}"
+ bannerImage="${brandingBanner}"
+ ;;
+ "None" | "none" | "" )
+ welcomeDialog "brandingBanner set to \"None\", or empty"
+ welcomeBannerImage="${brandingBanner}"
+ bannerImage="${brandingBanner}"
+ ;;
- ###
- # Catch-all
- ###
+ * )
+ welcomeDialog "brandingBanner set to \"None\""
+ ;;
- * )
+esac
- outputLineNumberInVerboseDebugMode
- updateScriptLog "SETUP YOUR MAC DIALOG: Validate Policy Results Catch-all: ${validation}"
- dialogUpdateSetupYourMac "listitem: index: $i, status: error, statustext: Error"
- ;;
- esac
-}
+# Welcome icon set to either light or dark, based on user's Apperance setting (thanks, @mm2270!)
+appleInterfaceStyle=$( /usr/bin/defaults read /Users/"${loggedInUser}"/Library/Preferences/.GlobalPreferences.plist AppleInterfaceStyle 2>&1 )
+if [[ "${appleInterfaceStyle}" == "Dark" ]]; then
+ if [[ -n "$brandingIconDark" ]]; then welcomeIcon="$brandingIconDark";
+ else welcomeIcon="https://cdn-icons-png.flaticon.com/512/740/740878.png"; fi
+else
+ if [[ -n "$brandingIconLight" ]]; then welcomeIcon="$brandingIconLight";
+ else welcomeIcon="https://cdn-icons-png.flaticon.com/512/979/979585.png"; fi
+fi
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
-# Kill a specified process (thanks, @grahampugh!)
+# "Welcome" Video Settings and Features
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
-function killProcess() {
- process="$1"
- if process_pid=$( pgrep -a "${process}" 2>/dev/null ) ; then
- updateScriptLog "Attempting to terminate the '$process' process …"
- updateScriptLog "(Termination message indicates success.)"
- kill "$process_pid" 2> /dev/null
- if pgrep -a "$process" >/dev/null ; then
- updateScriptLog "ERROR: '$process' could not be terminated."
- fi
- else
- updateScriptLog "The '$process' process isn't running."
- fi
-}
+welcomeVideo="--title \"$welcomeTitle\" \
+--videocaption \"$welcomeCaption\" \
+--video \"$welcomeVideoID\" \
+--infotext \"$scriptVersion\" \
+--button1text \"Continue …\" \
+--autoplay \
+--moveable \
+--ontop \
+--width '800' \
+--height '600' \
+--commandfile \"$welcomeCommandFile\" "
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
-# Completion Action (i.e., Wait, Sleep, Logout, Restart or Shutdown)
+# "Welcome" JSON Conditionals (thanks, @rougegoat!)
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
-function completionAction() {
+# Text Fields
+if [ "$prefillUsername" == "true" ]; then usernamePrefil=',"value" : "'${loggedInUser}'"'; fi
+if [ "$prefillRealname" == "true" ]; then realnamePrefil=',"value" : "'${loggedInUserFullname}'"'; fi
+if [ "$promptForUsername" == "true" ]; then usernameJSON='{ "title" : "User Name","required" : false,"prompt" : "User Name"'${usernamePrefil}'},'; fi
+if [ "$promptForRealName" == "true" ]; then realNameJSON='{ "title" : "Full Name","required" : false,"prompt" : "Full Name"'${realnamePrefil}'},'; fi
+if [ "$promptForEmail" == "true" ]; then
+ emailJSON='{ "title" : "E-mail",
+ "required" : true,
+ "prompt" : "E-mail Address",
+ "regex" : "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$",
+ "regexerror" : "Please enter a valid email address."
+ },'
+fi
+if [ "$promptForComputerName" == "true" ]; then compNameJSON='{ "title" : "Computer Name","required" : false,"prompt" : "Computer Name" },'; fi
+if [ "$promptForAssetTag" == "true" ]; then
+ assetTagJSON='{ "title" : "Asset Tag",
+ "required" : true,
+ "prompt" : "Please enter the (at least) seven-digit Asset Tag",
+ "regex" : "^(AP|IP|CD)?[0-9]{7,}$",
+ "regexerror" : "Please enter (at least) seven digits for the Asset Tag, optionally preceded by either AP, IP or CD."
+ },'
+fi
+if [ "$promptForRoom" == "true" ]; then roomJSON='{ "title" : "Room","required" : false,"prompt" : "Optional" },'; fi
+if [[ "$promptForPosition" == "true" && -z "$positionListRaw" ]]; then positionJSON='{ "title" : "Position","required" : false,"prompt" : "Position" },'; fi
- outputLineNumberInVerboseDebugMode
+textFieldJSON="${usernameJSON}${realNameJSON}${emailJSON}${compNameJSON}${assetTagJSON}${positionJSON}${roomJSON}"
+textFieldJSON=$( echo ${textFieldJSON} | sed 's/,$//' )
- if [[ "${debugMode}" == "true" ]] || [[ "${debugMode}" == "verbose" ]] ; then
+# Dropdowns
+if [ "$promptForBuilding" == "true" ]; then
+ if [ -n "$buildingsListRaw" ]; then
+ buildingJSON='{
+ "title" : "Building",
+ "default" : "",
+ "required" : true,
+ "values" : [
+ '${buildingsList}'
+ ]
+ },'
+ fi
+fi
- # If Debug Mode is enabled, ignore specified `completionActionOption`, display simple dialog box and exit
- runAsUser osascript -e 'display dialog "Setup Your Mac is operating in Debug Mode.\r\r• completionActionOption == '"'${completionActionOption}'"'\r\r" with title "Setup Your Mac: Debug Mode" buttons {"Close"} with icon note'
- exitCode="0"
+if [ "$promptForDepartment" == "true" ]; then
+ if [ -n "$departmentListRaw" ]; then
+ departmentJSON='{
+ "title" : "Department",
+ "default" : "",
+ "required" : true,
+ "values" : [
+ '${departmentList}'
+ ]
+ },'
+ fi
+fi
- else
+if [ "$promptForPosition" == "true" ]; then
+ if [ -n "${positionListRaw}" ]; then
+ positionSelectJSON='{
+ "title" : "Position",
+ "default" : "",
+ "required" : true,
+ "values" : [
+ '${positionList}'
+ ]
+ },'
+ fi
+fi
- shopt -s nocasematch
+if [ "$promptForConfiguration" == "true" ] && [ -z "${presetConfiguration}" ]; then
+ configurationJSON='{
+ "title" : "Configuration",
+ "style" : "radio",
+ "default" : "'"${configurationOneName}"'",
+ "values" : [
+ "'"${configurationOneName}"'",
+ "'"${configurationTwoName}"'",
+ "'"${configurationThreeName}"'"
+ ]
+ }'
+fi
- case ${completionActionOption} in
+selectItemsJSON="${buildingJSON}${departmentJSON}${positionSelectJSON}${configurationJSON}"
+selectItemsJSON=$( echo $selectItemsJSON | sed 's/,$//' )
- "Shut Down" )
- updateScriptLog "COMPLETION ACTION: Shut Down sans user interaction"
- killProcess "Self Service"
- # runAsUser osascript -e 'tell app "System Events" to shut down'
- # sleep 5 && runAsUser osascript -e 'tell app "System Events" to shut down' &
- sleep 5 && shutdown -h now &
- ;;
- "Shut Down Attended" )
- updateScriptLog "COMPLETION ACTION: Shut Down, requiring user-interaction"
- killProcess "Self Service"
- wait
- # runAsUser osascript -e 'tell app "System Events" to shut down'
- # sleep 5 && runAsUser osascript -e 'tell app "System Events" to shut down' &
- sleep 5 && shutdown -h now &
- ;;
- "Shut Down Confirm" )
- updateScriptLog "COMPLETION ACTION: Shut down, only after macOS time-out or user confirmation"
- runAsUser osascript -e 'tell app "loginwindow" to «event aevtrsdn»'
- ;;
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+# "Welcome" JSON for Capturing User Input (thanks, @bartreardon!)
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
- "Restart" )
- updateScriptLog "COMPLETION ACTION: Restart sans user interaction"
- killProcess "Self Service"
- # runAsUser osascript -e 'tell app "System Events" to restart'
- # sleep 5 && runAsUser osascript -e 'tell app "System Events" to restart' &
- sleep 5 && shutdown -r now &
- ;;
+welcomeJSON='
+{
+ "commandfile" : "'"${welcomeCommandFile}"'",
+ "bannerimage" : "'"${welcomeBannerImage}"'",
+ "bannertext" : "'"${welcomeBannerText}"'",
+ "title" : "'"${welcomeTitle}"'",
+ "message" : "'"${welcomeMessage}"'",
+ "icon" : "'"${welcomeIcon}"'",
+ "infobox" : "Analyzing …",
+ "iconsize" : "198.0",
+ "button1text" : "Continue",
+ "button2text" : "Quit",
+ "infotext" : "'"${scriptVersion}"'",
+ "blurscreen" : "true",
+ "ontop" : "true",
+ "titlefont" : "shadow=true, size=36, colour=#FFFDF4",
+ "messagefont" : "size=14",
+ "textfield" : [
+ '${textFieldJSON}'
+ ],
+ "selectitems" : [
+ '${selectItemsJSON}'
+ ],
+ "height" : "800"
+}
+'
- "Restart Attended" )
- updateScriptLog "COMPLETION ACTION: Restart, requiring user-interaction"
- killProcess "Self Service"
- wait
- # runAsUser osascript -e 'tell app "System Events" to restart'
- # sleep 5 && runAsUser osascript -e 'tell app "System Events" to restart' &
- sleep 5 && shutdown -r now &
- ;;
- "Restart Confirm" )
- updateScriptLog "COMPLETION ACTION: Restart, only after macOS time-out or user confirmation"
- runAsUser osascript -e 'tell app "loginwindow" to «event aevtrrst»'
- ;;
- "Log Out" )
- updateScriptLog "COMPLETION ACTION: Log out sans user interaction"
- killProcess "Self Service"
- # sleep 5 && runAsUser osascript -e 'tell app "loginwindow" to «event aevtrlgo»'
- # sleep 5 && runAsUser osascript -e 'tell app "loginwindow" to «event aevtrlgo»' &
- sleep 5 && launchctl bootout user/"${loggedInUserID}"
- ;;
+####################################################################################################
+#
+# Setup Your Mac dialog
+#
+####################################################################################################
- "Log Out Attended" )
- updateScriptLog "COMPLETION ACTION: Log out sans user interaction"
- killProcess "Self Service"
- wait
- # sleep 5 && runAsUser osascript -e 'tell app "loginwindow" to «event aevtrlgo»'
- # sleep 5 && runAsUser osascript -e 'tell app "loginwindow" to «event aevtrlgo»' &
- sleep 5 && launchctl bootout user/"${loggedInUserID}"
- ;;
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+# "Setup Your Mac" dialog Title, Message, Icon and Overlay Icon
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
- "Log Out Confirm" )
- updateScriptLog "COMPLETION ACTION: Log out, only after macOS time-out or user confirmation"
- sleep 5 && runAsUser osascript -e 'tell app "System Events" to log out'
- ;;
+title="Setting up ${loggedInUserFirstname}‘s ${modelName}"
+message="Please wait while the following apps are installed …"
- "Sleep"* )
- sleepDuration=$( awk '{print $NF}' <<< "${1}" )
- updateScriptLog "COMPLETION ACTION: Sleeping for ${sleepDuration} seconds …"
- sleep "${sleepDuration}"
- killProcess "Dialog"
- updateScriptLog "Goodnight!"
- ;;
+if [[ "${brandingBannerDisplayText}" == "true" ]] ; then
+ bannerText="Setting up ${loggedInUserFirstname}‘s ${modelName}";
+else
+ bannerText=""
+fi
- "Wait" )
- updateScriptLog "COMPLETION ACTION: Waiting for user interaction …"
- wait
- ;;
+if [ -n "$supportTeamName" ]; then
+ helpmessage+="If you need assistance, please contact: \n\n**${supportTeamName}** \n"
+fi
- "Quit" )
- updateScriptLog "COMPLETION ACTION: Quitting script"
- exitCode="0"
- ;;
+if [ -n "$supportTeamPhone" ]; then
+ helpmessage+="- **Telephone:** ${supportTeamPhone} \n"
+fi
- * )
- updateScriptLog "COMPLETION ACTION: Using the default of 'wait'"
- wait
- ;;
+if [ -n "$supportTeamEmail" ]; then
+ helpmessage+="- **Email:** ${supportTeamEmail} \n"
+fi
- esac
+if [ -n "$supportTeamWebsite" ]; then
+ helpmessage+="- **Web**: ${supportTeamHyperlink} \n"
+fi
- shopt -u nocasematch
+if [ -n "$supportKB" ]; then
+ helpmessage+="- **Knowledge Base Article:** ${supportTeamErrorKB} \n"
+fi
- fi
+helpmessage+="\n**Computer Information:** \n"
+helpmessage+="- **Operating System:** ${macOSproductVersion} (${macOSbuildVersion}) \n"
+helpmessage+="- **Serial Number:** ${serialNumber} \n"
+helpmessage+="- **Dialog:** ${dialogVersion} \n"
+helpmessage+="- **Started:** ${timestamp}"
- # Remove custom welcomeBannerImageFileName
- if [[ -e "/var/tmp/${welcomeBannerImageFileName}" ]]; then
- updateScriptLog "COMPLETION ACTION: Removing /var/tmp/${welcomeBannerImageFileName} …"
- rm "/var/tmp/${welcomeBannerImageFileName}"
- fi
+infobox="Analyzing input …" # Customize at "Update Setup Your Mac's infobox"
- # Remove overlayicon
- if [[ -e ${overlayicon} ]]; then
- updateScriptLog "COMPLETION ACTION: Removing ${overlayicon} …"
- rm "${overlayicon}"
- fi
- exit "${exitCode}"
+# Create `overlayicon` from Self Service's custom icon (thanks, @meschwartz!)
+xxd -p -s 260 "$(defaults read /Library/Preferences/com.jamfsoftware.jamf self_service_app_path)"/Icon$'\r'/..namedfork/rsrc | xxd -r -p > /var/tmp/overlayicon.icns
+overlayicon="/var/tmp/overlayicon.icns"
-}
+# Uncomment to use generic, Self Service icon as overlayicon
+# overlayicon="https://ics.services.jamfcloud.com/icon/hash_aa63d5813d6ed4846b623ed82acdd1562779bf3716f2d432a8ee533bba8950ee"
+
+# Set initial icon based on whether the Mac is a desktop or laptop
+if system_profiler SPPowerDataType | grep -q "Battery Power"; then
+ icon="SF=laptopcomputer.and.arrow.down,weight=semibold,colour1=#ef9d51,colour2=#ef7951"
+else
+ icon="SF=desktopcomputer.and.arrow.down,weight=semibold,colour1=#ef9d51,colour2=#ef7951"
+fi
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
-# Welcome dialog 'infobox' animation (thanks, @bartreadon!)
-# To convert emojis, see: https://r12a.github.io/app-conversion/
+# "Setup Your Mac" dialog Settings and Features
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
-function welcomeDialogInfoboxAnimation() {
- callingPID=$1
- # clock_emojis=("🕐" "🕑" "🕒" "🕓" "🕔" "🕕" "🕖" "🕗" "🕘" "🕙" "🕚" "🕛")
- clock_emojis=("🕐" "🕑" "🕒" "🕓" "🕔" "🕕" "🕖" "🕗" "🕘" "🕙" "🕚" "🕛")
- while true; do
- for emoji in "${clock_emojis[@]}"; do
- if kill -0 "$callingPID" 2>/dev/null; then
- dialogUpdateWelcome "infobox: Testing Connection $emoji"
- else
- break
- fi
- sleep 0.6
- done
- done
-}
+dialogSetupYourMacCMD="$dialogBinary \
+--bannerimage \"$bannerImage\" \
+--bannertext \"$bannerText\" \
+--title \"$title\" \
+--message \"$message\" \
+--helpmessage \"$helpmessage\" \
+--icon \"$icon\" \
+--infobox \"${infobox}\" \
+--progress \
+--progresstext \"Initializing configuration …\" \
+--button1text \"Wait\" \
+--button1disabled \
+--infotext \"$scriptVersion\" \
+--titlefont 'shadow=true, size=36, colour=#FFFDF4' \
+--messagefont 'size=14' \
+--height '800' \
+--position 'centre' \
+--blurscreen \
+--ontop \
+--overlayicon \"$overlayicon\" \
+--quitkey k \
+--commandfile \"$setupYourMacCommandFile\" "
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
-# Setup Your Mac dialog 'infobox' animation (thanks, @bartreadon!)
-# To convert emojis, see: https://r12a.github.io/app-conversion/
+#
+# [SYM-Helper] "Setup Your Mac" policies to execute (Thanks, Obi-@smithjw!)
+#
+# For each configuration step, specify:
+# - listitem: The text to be displayed in the list
+# - icon: The hash of the icon to be displayed on the left
+# - See: https://vimeo.com/772998915
+# - progresstext: The text to be displayed below the progress bar
+# - trigger: The Jamf Pro Policy Custom Event Name
+# - validation: [ {absolute path} | Local | Remote | None | Recon ]
+# See: https://snelson.us/2023/01/setup-your-mac-validation/
+# - {absolute path} (simulates pre-v1.6.0 behavior, for example: "/Applications/Microsoft Teams classic.app/Contents/Info.plist")
+# - Local (for validation within this script, for example: "filevault")
+# - Remote (for validation via a single-script Jamf Pro policy, for example: "symvGlobalProtect")
+# - None (for triggers which don't require validation; always evaluates as successful)
+# - Recon (to update the computer's inventory with your Jamf Pro server)
+#
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+#
+# Thanks, @wakco: If you would prefer to get your policyJSON externally replace it with:
+# - policyJSON="$(cat /path/to/file.json)" # For getting from a file, replacing /path/to/file.json with the path to your file, or
+# - policyJSON="$(curl -sL https://server.name/jsonquery)" # For a URL, replacing https://server.name/jsonquery with the URL of your file.
+#
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+#
+# Thanks, @astrugatch: I added this line to global variables:
+# jsonURL=${10} # URL Hosting JSON for policy_array
+#
+# And this line replaces the entirety of the policy_array (~ line 503):
+# policy_array=("$(curl -sL $jsonURL)")
+#
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
-
-function setupYourMacDialogInfoboxAnimation() {
- callingPID=$1
- # clock_emojis=("🕐" "🕑" "🕒" "🕓" "🕔" "🕕" "🕖" "🕗" "🕘" "🕙" "🕚" "🕛")
- clock_emojis=("🕐" "🕑" "🕒" "🕓" "🕔" "🕕" "🕖" "🕗" "🕘" "🕙" "🕚" "🕛")
- while true; do
- for emoji in "${clock_emojis[@]}"; do
- if kill -0 "$callingPID" 2>/dev/null; then
- dialogUpdateSetupYourMac "infobox: Testing Connection $emoji"
- else
- break
- fi
- sleep 0.6
- done
- done
-}
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
-# Check Network Quality for Configurations (thanks, @bartreadon!)
+# Select `policyJSON` based on Configuration selected in "Welcome" dialog (thanks, @drtaru!)
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
-function checkNetworkQualityConfigurations() {
-
- myPID="$$"
- updateScriptLog "WELCOME DIALOG: Display Welcome dialog 'infobox' animation …"
- welcomeDialogInfoboxAnimation "$myPID" &
- welcomeDialogInfoboxAnimationPID="$!"
+function policyJSONConfiguration() {
- networkQuality -s -v -c > /var/tmp/networkQualityTest
- kill ${welcomeDialogInfoboxAnimationPID}
outputLineNumberInVerboseDebugMode
- updateScriptLog "WELCOME DIALOG: Completed networkQualityTest …"
- networkQualityTest=$( < /var/tmp/networkQualityTest )
- rm /var/tmp/networkQualityTest
+ welcomeDialog "PolicyJSON Configuration: $symConfiguration"
- case "${osVersion}" in
+ case ${symConfiguration} in
+
+ "${configurationOneName}" )
+
+ overlayoverride=""
+ policyJSON='
+ {
+ "steps": [
+ {
+ "listitem": "Rosetta",
+ "subtitle": "Enables a Mac with Apple silicon to use apps built for an Intel processor",
+ "icon": "https://ics.services.jamfcloud.com/icon/hash_8bac19160fabb0c8e7bac97b37b51d2ac8f38b7100b6357642d9505645d37b52",
+ "progresstext": "Rosetta enables a Mac with Apple silicon to use apps built for a Mac with an Intel processor.",
+ "trigger_list": [
+ {
+ "trigger": "rosettaInstall",
+ "validation": "None"
+ },
+ {
+ "trigger": "rosetta",
+ "validation": "Local"
+ }
+ ]
+ },
+ {
+ "listitem": "FileVault Disk Encryption",
+ "subtitle": "FileVault provides full-disk encryption",
+ "icon": "https://ics.services.jamfcloud.com/icon/hash_f9ba35bd55488783456d64ec73372f029560531ca10dfa0e8154a46d7732b913",
+ "progresstext": "FileVault is built-in to macOS and provides full-disk encryption to help prevent unauthorized access to your Mac.",
+ "trigger_list": [
+ {
+ "trigger": "filevault",
+ "validation": "Local"
+ }
+ ]
+ },
+ {
+ "listitem": "Sophos Endpoint",
+ "subtitle": "Catches malware without relying on signatures",
+ "icon": "https://ics.services.jamfcloud.com/icon/hash_c70f1acf8c96b99568fec83e165d2a534d111b0510fb561a283d32aa5b01c60c",
+ "progresstext": "You’ll enjoy next-gen protection with Sophos Endpoint which doesn’t rely on signatures to catch malware.",
+ "trigger_list": [
+ {
+ "trigger": "sophosEndpoint",
+ "validation": "/Applications/Sophos/Sophos Endpoint.app/Contents/Info.plist"
+ }
+ ]
+ },
+ {
+ "listitem": "Sophos Endpoint Services (Remote)",
+ "subtitle": "Ensures Sophos Endpoint services are running",
+ "icon": "https://ics.services.jamfcloud.com/icon/hash_0f68be689684a00a3a054d71a31e43e2362f96c16efa5a560fb61bc1bf41901c",
+ "progresstext": "Remotely validating Sophos Endpoint services …",
+ "trigger_list": [
+ {
+ "trigger": "symvSophosEndpointRTS",
+ "validation": "Remote"
+ }
+ ]
+ },
+ {
+ "listitem": "Palo Alto GlobalProtect",
+ "subtitle": "Virtual Private Network (VPN) connection to Church headquarters",
+ "icon": "https://ics.services.jamfcloud.com/icon/hash_acbf39d8904ad1a772cf71c45d93e373626d379a24f8b1283b88134880acb8ef",
+ "progresstext": "Use Palo Alto GlobalProtect to establish a Virtual Private Network (VPN) connection to Church headquarters.",
+ "trigger_list": [
+ {
+ "trigger": "globalProtect",
+ "validation": "/Applications/GlobalProtect.app/Contents/Info.plist"
+ }
+ ]
+ },
+ {
+ "listitem": "Palo Alto GlobalProtect Services (Remote)",
+ "subtitle": "Ensures GlobalProtect services are running",
+ "icon": "https://ics.services.jamfcloud.com/icon/hash_709e8bdf0019e8faf9df85ec0a68545bfdb8bfa1227ac9bed9bba40a1fa8ff42",
+ "progresstext": "Remotely validating Palo Alto GlobalProtect services …",
+ "trigger_list": [
+ {
+ "trigger": "symvGlobalProtect",
+ "validation": "Remote"
+ }
+ ]
+ },
+ {
+ "listitem": "Final Configuration",
+ "subtitle": "Configures remaining Church settings",
+ "icon": "https://ics.services.jamfcloud.com/icon/hash_4723e3e341a7e11e6881e418cf91b157fcc081bdb8948697750e5da3562df728",
+ "progresstext": "Finalizing Configuration …",
+ "trigger_list": [
+ {
+ "trigger": "finalConfiguration",
+ "validation": "None"
+ },
+ {
+ "trigger": "reconAtReboot",
+ "validation": "None"
+ }
+ ]
+ },
+ {
+ "listitem": "Computer Inventory",
+ "subtitle": "The listing of your Mac’s apps and settings",
+ "icon": "https://ics.services.jamfcloud.com/icon/hash_ff2147a6c09f5ef73d1c4406d00346811a9c64c0b6b7f36eb52fcb44943d26f9",
+ "progresstext": "A listing of your Mac’s apps and settings — its inventory — is sent automatically to the Jamf Pro server daily.",
+ "trigger_list": [
+ {
+ "trigger": "recon",
+ "validation": "recon"
+ }
+ ]
+ }
+ ]
+ }
+ '
+ ;;
+
+ "${configurationTwoName}" )
- 11* )
- dlThroughput="N/A; macOS ${osVersion}"
- dlResponsiveness="N/A; macOS ${osVersion}"
- dlStartDate="N/A; macOS ${osVersion}"
- dlEndDate="N/A; macOS ${osVersion}"
+ overlayoverride=""
+ policyJSON='
+ {
+ "steps": [
+ {
+ "listitem": "Rosetta",
+ "subtitle": "Enables a Mac with Apple silicon to use apps built for an Intel processor",
+ "icon": "https://ics.services.jamfcloud.com/icon/hash_8bac19160fabb0c8e7bac97b37b51d2ac8f38b7100b6357642d9505645d37b52",
+ "progresstext": "Rosetta enables a Mac with Apple silicon to use apps built for a Mac with an Intel processor.",
+ "trigger_list": [
+ {
+ "trigger": "rosettaInstall",
+ "validation": "None"
+ },
+ {
+ "trigger": "rosetta",
+ "validation": "Local"
+ }
+ ]
+ },
+ {
+ "listitem": "FileVault Disk Encryption",
+ "subtitle": "FileVault provides full-disk encryption",
+ "icon": "https://ics.services.jamfcloud.com/icon/hash_f9ba35bd55488783456d64ec73372f029560531ca10dfa0e8154a46d7732b913",
+ "progresstext": "FileVault is built-in to macOS and provides full-disk encryption to help prevent unauthorized access to your Mac.",
+ "trigger_list": [
+ {
+ "trigger": "filevault",
+ "validation": "Local"
+ }
+ ]
+ },
+ {
+ "listitem": "Sophos Endpoint",
+ "subtitle": "Catches malware without relying on signatures",
+ "icon": "https://ics.services.jamfcloud.com/icon/hash_c70f1acf8c96b99568fec83e165d2a534d111b0510fb561a283d32aa5b01c60c",
+ "progresstext": "You’ll enjoy next-gen protection with Sophos Endpoint which doesn’t rely on signatures to catch malware.",
+ "trigger_list": [
+ {
+ "trigger": "sophosEndpoint",
+ "validation": "/Applications/Sophos/Sophos Endpoint.app/Contents/Info.plist"
+ }
+ ]
+ },
+ {
+ "listitem": "Sophos Endpoint Services (Local)",
+ "subtitle": "Ensures Sophos Endpoint services are running",
+ "icon": "https://ics.services.jamfcloud.com/icon/hash_0f68be689684a00a3a054d71a31e43e2362f96c16efa5a560fb61bc1bf41901c",
+ "progresstext": "Locally validating Sophos Endpoint services …",
+ "trigger_list": [
+ {
+ "trigger": "sophosEndpointServices",
+ "validation": "Local"
+ }
+ ]
+ },
+ {
+ "listitem": "Palo Alto GlobalProtect",
+ "subtitle": "Virtual Private Network (VPN) connection to Church headquarters",
+ "icon": "https://ics.services.jamfcloud.com/icon/hash_acbf39d8904ad1a772cf71c45d93e373626d379a24f8b1283b88134880acb8ef",
+ "progresstext": "Use Palo Alto GlobalProtect to establish a Virtual Private Network (VPN) connection to Church headquarters.",
+ "trigger_list": [
+ {
+ "trigger": "globalProtect",
+ "validation": "/Applications/GlobalProtect.app/Contents/Info.plist"
+ }
+ ]
+ },
+ {
+ "listitem": "Palo Alto GlobalProtect Services (Local)",
+ "subtitle": "Ensures GlobalProtect services are running",
+ "icon": "https://ics.services.jamfcloud.com/icon/hash_709e8bdf0019e8faf9df85ec0a68545bfdb8bfa1227ac9bed9bba40a1fa8ff42",
+ "progresstext": "Locally validating Palo Alto GlobalProtect services …",
+ "trigger_list": [
+ {
+ "trigger": "globalProtect",
+ "validation": "Local"
+ }
+ ]
+ },
+ {
+ "listitem": "Microsoft 365",
+ "subtitle": "Microsoft Office is now Microsoft 365",
+ "icon": "https://ics.services.jamfcloud.com/icon/hash_1801d1fdd81e19ce5eb0e567371377e7995bff32947adb7a94c5feea760edcb5",
+ "progresstext": "Office is now Microsoft 365. Create, share, and collaborate with your favorite apps — all in one place — with Microsoft 365.",
+ "trigger_list": [
+ {
+ "trigger": "microsoftOffice365",
+ "validation": "/Applications/Microsoft Outlook.app/Contents/Info.plist"
+ },
+ {
+ "trigger": "symvMicrosoftOffice365",
+ "validation": "Remote"
+ }
+ ]
+ },
+ {
+ "listitem": "Microsoft Teams",
+ "subtitle": "The hub for teamwork in Microsoft 365",
+ "icon": "https://ics.services.jamfcloud.com/icon/hash_dcb65709dba6cffa90a5eeaa54cb548d5ecc3b051f39feadd39e02744f37c19e",
+ "progresstext": "Microsoft Teams is a hub for teamwork in Microsoft 365. Keep all your team’s chats, meetings and files together in one place.",
+ "trigger_list": [
+ {
+ "trigger": "microsoftTeams",
+ "validation": "/Applications/Microsoft Teams classic.app/Contents/Info.plist"
+ }
+ ]
+ },
+ {
+ "listitem": "Final Configuration",
+ "subtitle": "Configures remaining Church settings",
+ "icon": "https://ics.services.jamfcloud.com/icon/hash_4723e3e341a7e11e6881e418cf91b157fcc081bdb8948697750e5da3562df728",
+ "progresstext": "Finalizing Configuration …",
+ "trigger_list": [
+ {
+ "trigger": "finalConfiguration",
+ "validation": "None"
+ },
+ {
+ "trigger": "reconAtReboot",
+ "validation": "None"
+ }
+ ]
+ },
+ {
+ "listitem": "Computer Inventory",
+ "subtitle": "The listing of your Mac’s apps and settings",
+ "icon": "https://ics.services.jamfcloud.com/icon/hash_ff2147a6c09f5ef73d1c4406d00346811a9c64c0b6b7f36eb52fcb44943d26f9",
+ "progresstext": "A listing of your Mac’s apps and settings — its inventory — is sent automatically to the Jamf Pro server daily.",
+ "trigger_list": [
+ {
+ "trigger": "recon",
+ "validation": "recon"
+ }
+ ]
+ }
+ ]
+ }
+ '
;;
- 12* | 13* | 14*)
- dlThroughput=$( get_json_value "$networkQualityTest" "dl_throughput")
- dlResponsiveness=$( get_json_value "$networkQualityTest" "dl_responsiveness" )
- dlStartDate=$( get_json_value "$networkQualityTest" "start_date" )
- dlEndDate=$( get_json_value "$networkQualityTest" "end_date" )
+ "${configurationThreeName}" )
+
+ overlayoverride=""
+ policyJSON='
+ {
+ "steps": [
+ {
+ "listitem": "Rosetta",
+ "subtitle": "Enables a Mac with Apple silicon to use apps built for an Intel processor",
+ "icon": "https://ics.services.jamfcloud.com/icon/hash_8bac19160fabb0c8e7bac97b37b51d2ac8f38b7100b6357642d9505645d37b52",
+ "progresstext": "Rosetta enables a Mac with Apple silicon to use apps built for a Mac with an Intel processor.",
+ "trigger_list": [
+ {
+ "trigger": "rosettaInstall",
+ "validation": "None"
+ },
+ {
+ "trigger": "rosetta",
+ "validation": "Local"
+ }
+ ]
+ },
+ {
+ "listitem": "FileVault Disk Encryption",
+ "subtitle": "FileVault provides full-disk encryption",
+ "icon": "https://ics.services.jamfcloud.com/icon/hash_f9ba35bd55488783456d64ec73372f029560531ca10dfa0e8154a46d7732b913",
+ "progresstext": "FileVault is built-in to macOS and provides full-disk encryption to help prevent unauthorized access to your Mac.",
+ "trigger_list": [
+ {
+ "trigger": "filevault",
+ "validation": "Local"
+ }
+ ]
+ },
+ {
+ "listitem": "Sophos Endpoint",
+ "subtitle": "Catches malware without relying on signatures",
+ "icon": "https://ics.services.jamfcloud.com/icon/hash_c70f1acf8c96b99568fec83e165d2a534d111b0510fb561a283d32aa5b01c60c",
+ "progresstext": "You’ll enjoy next-gen protection with Sophos Endpoint which doesn’t rely on signatures to catch malware.",
+ "trigger_list": [
+ {
+ "trigger": "sophosEndpoint",
+ "validation": "/Applications/Sophos/Sophos Endpoint.app/Contents/Info.plist"
+ }
+ ]
+ },
+ {
+ "listitem": "Sophos Endpoint Services (Local)",
+ "subtitle": "Ensures Sophos Endpoint services are running",
+ "icon": "https://ics.services.jamfcloud.com/icon/hash_0f68be689684a00a3a054d71a31e43e2362f96c16efa5a560fb61bc1bf41901c",
+ "progresstext": "Locally validating Sophos Endpoint services …",
+ "trigger_list": [
+ {
+ "trigger": "sophosEndpointServices",
+ "validation": "Local"
+ }
+ ]
+ },
+ {
+ "listitem": "Sophos Endpoint Services (Remote)",
+ "subtitle": "Ensures Sophos Endpoint services are running",
+ "icon": "https://ics.services.jamfcloud.com/icon/hash_0f68be689684a00a3a054d71a31e43e2362f96c16efa5a560fb61bc1bf41901c",
+ "progresstext": "Remotely validating Sophos Endpoint services …",
+ "trigger_list": [
+ {
+ "trigger": "symvSophosEndpointRTS",
+ "validation": "Remote"
+ }
+ ]
+ },
+ {
+ "listitem": "Palo Alto GlobalProtect",
+ "subtitle": "Virtual Private Network (VPN) connection to Church headquarters",
+ "icon": "https://ics.services.jamfcloud.com/icon/hash_acbf39d8904ad1a772cf71c45d93e373626d379a24f8b1283b88134880acb8ef",
+ "progresstext": "Use Palo Alto GlobalProtect to establish a Virtual Private Network (VPN) connection to Church headquarters.",
+ "trigger_list": [
+ {
+ "trigger": "globalProtect",
+ "validation": "/Applications/GlobalProtect.app/Contents/Info.plist"
+ }
+ ]
+ },
+ {
+ "listitem": "Palo Alto GlobalProtect Services (Local)",
+ "subtitle": "Ensures GlobalProtect services are running",
+ "icon": "https://ics.services.jamfcloud.com/icon/hash_709e8bdf0019e8faf9df85ec0a68545bfdb8bfa1227ac9bed9bba40a1fa8ff42",
+ "progresstext": "Locally validating Palo Alto GlobalProtect services …",
+ "trigger_list": [
+ {
+ "trigger": "globalProtect",
+ "validation": "Local"
+ }
+ ]
+ },
+ {
+ "listitem": "Palo Alto GlobalProtect Services (Remote)",
+ "subtitle": "Ensures GlobalProtect services are running",
+ "icon": "https://ics.services.jamfcloud.com/icon/hash_709e8bdf0019e8faf9df85ec0a68545bfdb8bfa1227ac9bed9bba40a1fa8ff42",
+ "progresstext": "Remotely validating Palo Alto GlobalProtect services …",
+ "trigger_list": [
+ {
+ "trigger": "symvGlobalProtect",
+ "validation": "Remote"
+ }
+ ]
+ },
+ {
+ "listitem": "Microsoft 365",
+ "subtitle": "Microsoft Office is now Microsoft 365",
+ "icon": "https://ics.services.jamfcloud.com/icon/hash_1801d1fdd81e19ce5eb0e567371377e7995bff32947adb7a94c5feea760edcb5",
+ "progresstext": "Office is now Microsoft 365. Create, share, and collaborate with your favorite apps — all in one place — with Microsoft 365.",
+ "trigger_list": [
+ {
+ "trigger": "microsoftOffice365",
+ "validation": "/Applications/Microsoft Outlook.app/Contents/Info.plist"
+ },
+ {
+ "trigger": "symvMicrosoftOffice365",
+ "validation": "Remote"
+ }
+ ]
+ },
+ {
+ "listitem": "Microsoft Teams",
+ "subtitle": "The hub for teamwork in Microsoft 365",
+ "icon": "https://ics.services.jamfcloud.com/icon/hash_dcb65709dba6cffa90a5eeaa54cb548d5ecc3b051f39feadd39e02744f37c19e",
+ "progresstext": "Microsoft Teams is a hub for teamwork in Microsoft 365. Keep all your team’s chats, meetings and files together in one place.",
+ "trigger_list": [
+ {
+ "trigger": "microsoftTeams",
+ "validation": "/Applications/Microsoft Teams classic.app/Contents/Info.plist"
+ }
+ ]
+ },
+ {
+ "listitem": "Adobe Acrobat Reader",
+ "subtitle": "Full-featured PDF reader",
+ "icon": "https://ics.services.jamfcloud.com/icon/hash_988b669ca27eab93a9bcd53bb7e2873fb98be4eaa95ae8974c14d611bea1d95f",
+ "progresstext": "Views, prints, and comments on PDF documents, and connects to Adobe Document Cloud.",
+ "trigger_list": [
+ {
+ "trigger": "adobeAcrobatReader",
+ "validation": "/Applications/Adobe Acrobat Reader.app/Contents/Info.plist"
+ }
+ ]
+ },
+ {
+ "listitem": "Google Chrome",
+ "subtitle": "Third-party Web browser",
+ "icon": "https://ics.services.jamfcloud.com/icon/hash_12d3d198f40ab2ac237cff3b5cb05b09f7f26966d6dffba780e4d4e5325cc701",
+ "progresstext": "Google Chrome is a browser that combines a minimal design with sophisticated technology to make the Web faster.",
+ "trigger_list": [
+ {
+ "trigger": "googleChrome",
+ "validation": "/Applications/Google Chrome.app/Contents/Info.plist"
+ }
+ ]
+ },
+ {
+ "listitem": "Final Configuration",
+ "subtitle": "Configures remaining Church settings",
+ "icon": "https://ics.services.jamfcloud.com/icon/hash_4723e3e341a7e11e6881e418cf91b157fcc081bdb8948697750e5da3562df728",
+ "progresstext": "Finalizing Configuration …",
+ "trigger_list": [
+ {
+ "trigger": "finalConfiguration",
+ "validation": "None"
+ },
+ {
+ "trigger": "reconAtReboot",
+ "validation": "None"
+ }
+ ]
+ },
+ {
+ "listitem": "Computer Inventory",
+ "subtitle": "The listing of your Mac’s apps and settings",
+ "icon": "https://ics.services.jamfcloud.com/icon/hash_ff2147a6c09f5ef73d1c4406d00346811a9c64c0b6b7f36eb52fcb44943d26f9",
+ "progresstext": "A listing of your Mac’s apps and settings — its inventory — is sent automatically to the Jamf Pro server daily.",
+ "trigger_list": [
+ {
+ "trigger": "recon",
+ "validation": "recon"
+ }
+ ]
+ }
+ ]
+ }
+ '
;;
- esac
-
- mbps=$( echo "scale=2; ( $dlThroughput / 1000000 )" | bc )
- updateScriptLog "WELCOME DIALOG: $mbps (Mbps)"
-
- configurationOneEstimatedSeconds=$( echo "scale=2; ((((( $configurationOneSize / $mbps ) * 60 ) * 60 ) * $correctionCoefficient ) + $configurationOneInstallBuffer)" | bc | sed 's/\.[0-9]*//' )
- updateScriptLog "WELCOME DIALOG: Configuration One Estimated Seconds: $configurationOneEstimatedSeconds"
- updateScriptLog "WELCOME DIALOG: Configuration One Estimate: $(printf '%dh:%dm:%ds\n' $((configurationOneEstimatedSeconds/3600)) $((configurationOneEstimatedSeconds%3600/60)) $((configurationOneEstimatedSeconds%60)))"
-
- configurationTwoEstimatedSeconds=$( echo "scale=2; ((((( $configurationTwoSize / $mbps ) * 60 ) * 60 ) * $correctionCoefficient ) + $configurationTwoInstallBuffer)" | bc | sed 's/\.[0-9]*//' )
- updateScriptLog "WELCOME DIALOG: Configuration Two Estimated Seconds: $configurationTwoEstimatedSeconds"
- updateScriptLog "WELCOME DIALOG: Configuration Two Estimate: $(printf '%dh:%dm:%ds\n' $((configurationTwoEstimatedSeconds/3600)) $((configurationTwoEstimatedSeconds%3600/60)) $((configurationTwoEstimatedSeconds%60)))"
-
- configurationThreeEstimatedSeconds=$( echo "scale=2; ((((( $configurationThreeSize / $mbps ) * 60 ) * 60 ) * $correctionCoefficient ) + $configurationThreeInstallBuffer)" | bc | sed 's/\.[0-9]*//' )
- updateScriptLog "WELCOME DIALOG: Configuration Three Estimated Seconds: $configurationThreeEstimatedSeconds"
- updateScriptLog "WELCOME DIALOG: Configuration Three Estimate: $(printf '%dh:%dm:%ds\n' $((configurationThreeEstimatedSeconds/3600)) $((configurationThreeEstimatedSeconds%3600/60)) $((configurationThreeEstimatedSeconds%60)))"
-
- updateScriptLog "WELCOME DIALOG: Network Quality Test: Started: $dlStartDate, Ended: $dlEndDate; Download: $mbps Mbps, Responsiveness: $dlResponsiveness"
- dialogUpdateWelcome "infobox: **Connection:** \n- Download: \n$mbps Mbps \n\n**Estimates:** \n- ${configurationOneName}: \n$(printf '%dh:%dm:%ds\n' $((configurationOneEstimatedSeconds/3600)) $((configurationOneEstimatedSeconds%3600/60)) $((configurationOneEstimatedSeconds%60))) \n\n- ${configurationTwoName}: \n$(printf '%dh:%dm:%ds\n' $((configurationTwoEstimatedSeconds/3600)) $((configurationTwoEstimatedSeconds%3600/60)) $((configurationTwoEstimatedSeconds%60))) \n\n- ${configurationThreeName}: \n$(printf '%dh:%dm:%ds\n' $((configurationThreeEstimatedSeconds/3600)) $((configurationThreeEstimatedSeconds%3600/60)) $((configurationThreeEstimatedSeconds%60)))"
-
- # If option to lock the continue button is set to true, enable the continue button now to let the user progress
- if [[ "${lockContinueBeforeEstimations}" == "true" ]]; then
- updateScriptLog "WELCOME DIALOG: Enabling Continue Button"
- dialogUpdateWelcome "button1: enable"
- fi
-}
-
-
-
-# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
-# Check Network Quality for Catch-all Configuration (thanks, @bartreadon!)
-# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
-
-function checkNetworkQualityCatchAllConfiguration() {
-
- myPID="$$"
- updateScriptLog "SETUP YOUR MAC DIALOG: Display Welcome dialog 'infobox' animation …"
- setupYourMacDialogInfoboxAnimation "$myPID" &
- setupYourMacDialogInfoboxAnimationPID="$!"
-
- networkQuality -s -v -c > /var/tmp/networkQualityTest
- kill ${setupYourMacDialogInfoboxAnimationPID}
- outputLineNumberInVerboseDebugMode
-
- updateScriptLog "SETUP YOUR MAC DIALOG: Completed networkQualityTest …"
- networkQualityTest=$( < /var/tmp/networkQualityTest )
- rm /var/tmp/networkQualityTest
-
- case "${osVersion}" in
-
- 11* )
- dlThroughput="N/A; macOS ${osVersion}"
- dlResponsiveness="N/A; macOS ${osVersion}"
- dlStartDate="N/A; macOS ${osVersion}"
- dlEndDate="N/A; macOS ${osVersion}"
- ;;
+ * ) # Catch-all (i.e., used when `welcomeDialog` is set to `video`, `messageOnly` or `false`)
- 12* | 13* | 14*)
- dlThroughput=$( get_json_value "$networkQualityTest" "dl_throughput")
- dlResponsiveness=$( get_json_value "$networkQualityTest" "dl_responsiveness" )
- dlStartDate=$( get_json_value "$networkQualityTest" "start_date" )
- dlEndDate=$( get_json_value "$networkQualityTest" "end_date" )
+ overlayoverride=""
+ policyJSON='
+ {
+ "steps": [
+ {
+ "listitem": "Rosetta",
+ "subtitle": "Enables a Mac with Apple silicon to use apps built for an Intel processor",
+ "icon": "https://ics.services.jamfcloud.com/icon/hash_8bac19160fabb0c8e7bac97b37b51d2ac8f38b7100b6357642d9505645d37b52",
+ "progresstext": "Rosetta enables a Mac with Apple silicon to use apps built for a Mac with an Intel processor.",
+ "trigger_list": [
+ {
+ "trigger": "rosettaInstall",
+ "validation": "None"
+ },
+ {
+ "trigger": "rosetta",
+ "validation": "Local"
+ }
+ ]
+ },
+ {
+ "listitem": "FileVault Disk Encryption",
+ "subtitle": "FileVault provides full-disk encryption",
+ "icon": "https://ics.services.jamfcloud.com/icon/hash_f9ba35bd55488783456d64ec73372f029560531ca10dfa0e8154a46d7732b913",
+ "progresstext": "FileVault is built-in to macOS and provides full-disk encryption to help prevent unauthorized access to your Mac.",
+ "trigger_list": [
+ {
+ "trigger": "filevault",
+ "validation": "Local"
+ }
+ ]
+ },
+ {
+ "listitem": "Sophos Endpoint",
+ "subtitle": "Catches malware without relying on signatures",
+ "icon": "https://ics.services.jamfcloud.com/icon/hash_c70f1acf8c96b99568fec83e165d2a534d111b0510fb561a283d32aa5b01c60c",
+ "progresstext": "You’ll enjoy next-gen protection with Sophos Endpoint which doesn’t rely on signatures to catch malware.",
+ "trigger_list": [
+ {
+ "trigger": "sophosEndpoint",
+ "validation": "/Applications/Sophos/Sophos Endpoint.app/Contents/Info.plist"
+ },
+ {
+ "trigger": "symvSophosEndpointRTS",
+ "validation": "Remote"
+ }
+ ]
+ },
+ {
+ "listitem": "Palo Alto GlobalProtect",
+ "subtitle": "Virtual Private Network (VPN) connection to Church headquarters",
+ "icon": "https://ics.services.jamfcloud.com/icon/hash_acbf39d8904ad1a772cf71c45d93e373626d379a24f8b1283b88134880acb8ef",
+ "progresstext": "Use Palo Alto GlobalProtect to establish a Virtual Private Network (VPN) connection to Church headquarters.",
+ "trigger_list": [
+ {
+ "trigger": "globalProtect",
+ "validation": "/Applications/GlobalProtect.app/Contents/Info.plist"
+ },
+ {
+ "trigger": "symvGlobalProtect",
+ "validation": "Remote"
+ }
+ ]
+ },
+ {
+ "listitem": "Final Configuration",
+ "subtitle": "Configures remaining Church settings",
+ "icon": "https://ics.services.jamfcloud.com/icon/hash_4723e3e341a7e11e6881e418cf91b157fcc081bdb8948697750e5da3562df728",
+ "progresstext": "Finalizing Configuration …",
+ "trigger_list": [
+ {
+ "trigger": "finalConfiguration",
+ "validation": "None"
+ },
+ {
+ "trigger": "reconAtReboot",
+ "validation": "None"
+ }
+ ]
+ },
+ {
+ "listitem": "Computer Inventory",
+ "subtitle": "The listing of your Mac’s apps and settings",
+ "icon": "https://ics.services.jamfcloud.com/icon/hash_ff2147a6c09f5ef73d1c4406d00346811a9c64c0b6b7f36eb52fcb44943d26f9",
+ "progresstext": "A listing of your Mac’s apps and settings — its inventory — is sent automatically to the Jamf Pro server daily.",
+ "trigger_list": [
+ {
+ "trigger": "recon",
+ "validation": "recon"
+ }
+ ]
+ }
+ ]
+ }
+ '
;;
esac
- mbps=$( echo "scale=2; ( $dlThroughput / 1000000 )" | bc )
- updateScriptLog "SETUP YOUR MAC DIALOG: $mbps (Mbps)"
-
- configurationCatchAllEstimatedSeconds=$( echo "scale=2; ((((( $configurationCatchAllSize / $mbps ) * 60 ) * 60 ) * $correctionCoefficient ) + $configurationCatchAllInstallBuffer)" | bc | sed 's/\.[0-9]*//' )
- updateScriptLog "SETUP YOUR MAC DIALOG: Catch-all Configuration Estimated Seconds: $configurationCatchAllEstimatedSeconds"
- updateScriptLog "SETUP YOUR MAC DIALOG: Catch-all Configuration Estimate: $(printf '%dh:%dm:%ds\n' $((configurationCatchAllEstimatedSeconds/3600)) $((configurationCatchAllEstimatedSeconds%3600/60)) $((configurationCatchAllEstimatedSeconds%60)))"
-
- updateScriptLog "SETUP YOUR MAC DIALOG: Network Quality Test: Started: $dlStartDate, Ended: $dlEndDate; Download: $mbps Mbps, Responsiveness: $dlResponsiveness"
- dialogUpdateSetupYourMac "infobox: **Connection:** \n- Download: \n$mbps Mbps \n\n**Estimates:** \n- $(printf '%dh:%dm:%ds\n' $((configurationCatchAllEstimatedSeconds/3600)) $((configurationCatchAllEstimatedSeconds%3600/60)) $((configurationCatchAllEstimatedSeconds%60)))"
- if [[ "${lockContinueBeforeEstimations}" == "true" ]]; then
- updateScriptLog "WELCOME DIALOG: Enabling Continue Button"
- dialogUpdateWelcome "button1: enable"
- fi
}
-# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
-# Webhook Message (Microsoft Teams or Slack) (thanks, @robjschroeder! and @iDrewbs!)
-# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
-
-function webHookMessage() {
-
- outputLineNumberInVerboseDebugMode
-
- jamfProURL=$(/usr/bin/defaults read /Library/Preferences/com.jamfsoftware.jamf.plist jss_url)
-
- # # Jamf Pro URL for on-prem, multi-node, clustered environments
- # case ${jamfProURL} in
- # *"beta"* ) jamfProURL="https://jamfpro-beta.internal.company.com/" ;;
- # * ) jamfProURL="https://jamfpro-prod.internal.company.com/" ;;
- # esac
+####################################################################################################
+#
+# Failure dialog
+#
+####################################################################################################
- jamfProComputerURL="${jamfProURL}computers.html?id=${computerID}&o=r"
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+# "Failure" dialog Title, Message and Icon
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
- # If there aren't any failures, use "None" for the value of `jamfProPolicyNameFailures`
- if [[ -z "${jamfProPolicyNameFailures}" ]]; then
- jamfProPolicyNameFailures="None"
- fi
+failureTitle="Failure Detected"
+failureMessage="Placeholder message; update in the 'finalise' function"
+failureIcon="SF=xmark.circle.fill,weight=bold,colour1=#BB1717,colour2=#F31F1F"
- if [[ $webhookURL == *"slack"* ]]; then
-
- updateScriptLog "Generating Slack Message …"
-
- webHookdata=$(cat <&1
-
- webhookResult="$?"
- updateScriptLog "Slack Webhook Result: ${webhookResult}"
-
- else
-
- updateScriptLog "Generating Microsoft Teams Message …"
- # URL to an image to add to your notification
- activityImage="https://creazilla-store.fra1.digitaloceanspaces.com/cliparts/78010/old-mac-computer-clipart-md.png"
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+# "Failure" dialog Settings and Features
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
- webHookdata=$(cat < "$welcomeJSONFile"
# If option to lock the continue button is set to true, open welcome dialog with button 1 disabled
if [[ "${lockContinueBeforeEstimations}" == "true" ]]; then
- updateScriptLog "WELCOME DIALOG: Display 'Welcome' dialog with disabled Continue Button …"
+ welcomeDialog "Display 'Welcome' dialog with disabled Continue Button …"
welcomeResults=$( eval "${dialogBinary} --jsonfile ${welcomeJSONFile} --json --button1disabled" )
else
- updateScriptLog "WELCOME DIALOG: Display 'Welcome' dialog …"
+ welcomeDialog "Display 'Welcome' dialog …"
welcomeResults=$( eval "${dialogBinary} --jsonfile ${welcomeJSONFile} --json" )
fi
@@ -2890,7 +2932,7 @@ elif [[ "${welcomeDialog}" == "userInput" ]]; then
else
# Display Welcome dialog, sans estimation of Configuration download times
- updateScriptLog "WELCOME DIALOG: Skipping estimation of Configuration download times"
+ welcomeDialog "Skipping estimation of Configuration download times"
# Write Welcome JSON to disk
welcomeJSON=${welcomeJSON//Analyzing …/}
@@ -2909,7 +2951,7 @@ elif [[ "${welcomeDialog}" == "userInput" ]]; then
case "${welcomeReturnCode}" in
0) # Process exit code 0 scenario here
- updateScriptLog "WELCOME DIALOG: ${loggedInUser} entered information and clicked Continue"
+ welcomeDialog "${loggedInUser} entered information and clicked Continue"
###
# Extract the various values from the welcomeResults JSON
@@ -2938,16 +2980,16 @@ elif [[ "${welcomeDialog}" == "userInput" ]]; then
# Output the various values from the welcomeResults JSON to the log file
###
- updateScriptLog "WELCOME DIALOG: • Computer Name: $computerName"
- updateScriptLog "WELCOME DIALOG: • User Name: $userName"
- updateScriptLog "WELCOME DIALOG: • Real Name: $realName"
- updateScriptLog "WELCOME DIALOG: • E-mail: $email"
- updateScriptLog "WELCOME DIALOG: • Asset Tag: $assetTag"
- updateScriptLog "WELCOME DIALOG: • Configuration: $symConfiguration"
- updateScriptLog "WELCOME DIALOG: • Department: $department"
- updateScriptLog "WELCOME DIALOG: • Building: $building"
- updateScriptLog "WELCOME DIALOG: • Room: $room"
- updateScriptLog "WELCOME DIALOG: • Position: $position"
+ welcomeDialog "• Computer Name: $computerName"
+ welcomeDialog "• User Name: $userName"
+ welcomeDialog "• Real Name: $realName"
+ welcomeDialog "• E-mail: $email"
+ welcomeDialog "• Asset Tag: $assetTag"
+ welcomeDialog "• Configuration: $symConfiguration"
+ welcomeDialog "• Department: $department"
+ welcomeDialog "• Building: $building"
+ welcomeDialog "• Room: $room"
+ welcomeDialog "• Position: $position"
###
@@ -2966,7 +3008,7 @@ elif [[ "${welcomeDialog}" == "userInput" ]]; then
if [[ -n "${computerName}" ]]; then
# UNTESTED, UNSUPPORTED "YOYO" EXAMPLE
- updateScriptLog "WELCOME DIALOG: Set Computer Name …"
+ welcomeDialog "Set Computer Name …"
currentComputerName=$( scutil --get ComputerName )
currentLocalHostName=$( scutil --get LocalHostName )
@@ -2978,8 +3020,8 @@ elif [[ "${welcomeDialog}" == "userInput" ]]; then
if [[ "${debugMode}" == "true" ]] || [[ "${debugMode}" == "verbose" ]] ; then
- updateScriptLog "WELCOME DIALOG: DEBUG MODE: Would have renamed computer from: \"${currentComputerName}\" to \"${computerName}\" "
- updateScriptLog "WELCOME DIALOG: DEBUG MODE: Would have renamed LocalHostName from: \"${currentLocalHostName}\" to \"${newLocalHostName}\" "
+ welcomeDialog "DEBUG MODE: Would have renamed computer from: \"${currentComputerName}\" to \"${computerName}\" "
+ welcomeDialog "DEBUG MODE: Would have renamed LocalHostName from: \"${currentLocalHostName}\" to \"${newLocalHostName}\" "
else
@@ -2992,16 +3034,16 @@ elif [[ "${welcomeDialog}" == "userInput" ]]; then
# Delay required to reflect change …
# … side-effect is a delay in the "Setup Your Mac" dialog appearing
sleep 5
- updateScriptLog "WELCOME DIALOG: Renamed computer from: \"${currentComputerName}\" to \"$( scutil --get ComputerName )\" "
- updateScriptLog "WELCOME DIALOG: Renamed LocalHostName from: \"${currentLocalHostName}\" to \"$( scutil --get LocalHostName )\" "
+ welcomeDialog "Renamed computer from: \"${currentComputerName}\" to \"$( scutil --get ComputerName )\" "
+ welcomeDialog "Renamed LocalHostName from: \"${currentLocalHostName}\" to \"$( scutil --get LocalHostName )\" "
fi
else
- updateScriptLog "WELCOME DIALOG: ${loggedInUser} did NOT specify a new computer name"
- updateScriptLog "WELCOME DIALOG: • Current Computer Name: \"$( scutil --get ComputerName )\" "
- updateScriptLog "WELCOME DIALOG: • Current Local Host Name: \"$( scutil --get LocalHostName )\" "
+ welcomeDialog "${loggedInUser} did NOT specify a new computer name"
+ welcomeDialog "• Current Computer Name: \"$( scutil --get ComputerName )\" "
+ welcomeDialog "• Current Local Host Name: \"$( scutil --get LocalHostName )\" "
fi
@@ -3044,7 +3086,7 @@ elif [[ "${welcomeDialog}" == "userInput" ]]; then
if [[ -n "${position}" ]]; then reconOptions+="-position \"${position}\" "; fi
# Output `recon` options to log
- updateScriptLog "WELCOME DIALOG: reconOptions: ${reconOptions}"
+ welcomeDialog "reconOptions: ${reconOptions}"
###
# Display "Setup Your Mac" dialog (and capture Process ID)
@@ -3053,10 +3095,10 @@ elif [[ "${welcomeDialog}" == "userInput" ]]; then
eval "${dialogSetupYourMacCMD[*]}" & sleep 0.3
until pgrep -q -x "Dialog"; do
outputLineNumberInVerboseDebugMode
- updateScriptLog "WELCOME DIALOG: Waiting to display 'Setup Your Mac' dialog; pausing"
+ welcomeDialog "Waiting to display 'Setup Your Mac' dialog; pausing"
sleep 0.5
done
- updateScriptLog "WELCOME DIALOG: 'Setup Your Mac' dialog displayed; ensure it's the front-most app"
+ welcomeDialog "'Setup Your Mac' dialog displayed; ensure it's the front-most app"
runAsUser osascript -e 'tell application "Dialog" to activate'
if [[ -n "${overlayoverride}" ]]; then
dialogUpdateSetupYourMac "overlayicon: ${overlayoverride}"
@@ -3064,24 +3106,24 @@ elif [[ "${welcomeDialog}" == "userInput" ]]; then
;;
2) # Process exit code 2 scenario here
- updateScriptLog "WELCOME DIALOG: ${loggedInUser} clicked Quit at Welcome dialog"
+ welcomeDialog "${loggedInUser} clicked Quit at Welcome dialog"
completionActionOption="Quit"
quitScript "1"
;;
3) # Process exit code 3 scenario here
- updateScriptLog "WELCOME DIALOG: ${loggedInUser} clicked infobutton"
+ welcomeDialog "${loggedInUser} clicked infobutton"
osascript -e "set Volume 3"
afplay /System/Library/Sounds/Glass.aiff
;;
4) # Process exit code 4 scenario here
- updateScriptLog "WELCOME DIALOG: ${loggedInUser} allowed timer to expire"
+ welcomeDialog "${loggedInUser} allowed timer to expire"
quitScript "1"
;;
*) # Catch all processing
- updateScriptLog "WELCOME DIALOG: Something else happened; Exit code: ${welcomeReturnCode}"
+ welcomeDialog "Something else happened; Exit code: ${welcomeReturnCode}"
quitScript "1"
;;
@@ -3099,7 +3141,7 @@ else
else
symConfiguration="Catch-all ('Welcome' dialog disabled)"
fi
- updateScriptLog "WELCOME DIALOG: Using ${symConfiguration} Configuration …"
+ welcomeDialog "Using ${symConfiguration} Configuration …"
policyJSONConfiguration
@@ -3111,10 +3153,10 @@ else
eval "${dialogSetupYourMacCMD[*]}" & sleep 0.3
until pgrep -q -x "Dialog"; do
outputLineNumberInVerboseDebugMode
- updateScriptLog "WELCOME DIALOG: Waiting to display 'Setup Your Mac' dialog; pausing"
+ welcomeDialog "Waiting to display 'Setup Your Mac' dialog; pausing"
sleep 0.5
done
- updateScriptLog "WELCOME DIALOG: 'Setup Your Mac' dialog displayed; ensure it's the front-most app"
+ welcomeDialog "'Setup Your Mac' dialog displayed; ensure it's the front-most app"
runAsUser osascript -e 'tell application "Dialog" to activate'
if [[ -n "${overlayoverride}" ]]; then
dialogUpdateSetupYourMac "overlayicon: ${overlayoverride}"
@@ -3150,8 +3192,8 @@ outputLineNumberInVerboseDebugMode
totalProgressSteps=$(get_json_value "${policyJSON}" "steps.length")
progressIncrementValue=$(( 100 / totalProgressSteps ))
-updateScriptLog "SETUP YOUR MAC DIALOG: Total Number of Steps: ${totalProgressSteps}"
-updateScriptLog "SETUP YOUR MAC DIALOG: Progress Increment Value: ${progressIncrementValue}"
+updateSetupYourMacDialog "Total Number of Steps: ${totalProgressSteps}"
+updateSetupYourMacDialog "Progress Increment Value: ${progressIncrementValue}"
@@ -3178,7 +3220,7 @@ dialogUpdateSetupYourMac "list: show"
outputLineNumberInVerboseDebugMode
-updateScriptLog "SETUP YOUR MAC DIALOG: Initial progress bar"
+updateSetupYourMacDialog "Initial progress bar"
dialogUpdateSetupYourMac "progress: 1"
@@ -3207,7 +3249,7 @@ if [[ "${symConfiguration}" == *"Catch-all"* ]] || [[ -z "${symConfiguration}" ]
checkNetworkQualityCatchAllConfiguration &
- updateScriptLog "SETUP YOUR MAC DIALOG: **Connection:** \n- Download: \n$mbps Mbps \n\n**Estimate:** \n- $(printf '%dh:%dm:%ds\n' $((configurationCatchAllEstimatedSeconds/3600)) $((configurationCatchAllEstimatedSeconds%3600/60)) $((configurationCatchAllEstimatedSeconds%60)))"
+ updateSetupYourMacDialog "**Connection:** \n- Download: \n$mbps Mbps \n\n**Estimate:** \n- $(printf '%dh:%dm:%ds\n' $((configurationCatchAllEstimatedSeconds/3600)) $((configurationCatchAllEstimatedSeconds%3600/60)) $((configurationCatchAllEstimatedSeconds%60)))"
infoboxConfiguration="**Connection:** \n- Download: \n$mbps Mbps \n\n**Estimate:** \n- $(printf '%dh:%dm:%ds\n' $((configurationCatchAllEstimatedSeconds/3600)) $((configurationCatchAllEstimatedSeconds%3600/60)) $((configurationCatchAllEstimatedSeconds%60)))"
@@ -3237,9 +3279,9 @@ if [[ -n ${room} ]]; then infobox+="**Room:** \n$room \n\n" ; fi
if [[ -n ${position} ]]; then infobox+="**Position:** \n$position \n\n" ; fi
if { [[ "${promptForConfiguration}" != "true" ]] && [[ "${configurationDownloadEstimation}" == "true" ]]; } || { [[ "${welcomeDialog}" == "false" ]] || [[ "${welcomeDialog}" == "messageOnly" ]]; } then
- updateScriptLog "SETUP YOUR MAC DIALOG: Purposely NOT updating 'infobox'"
+ updateSetupYourMacDialog "Purposely NOT updating 'infobox'"
else
- updateScriptLog "SETUP YOUR MAC DIALOG: Updating 'infobox'"
+ updateSetupYourMacDialog "Updating 'infobox'"
dialogUpdateSetupYourMac "infobox: ${infobox}"
fi
@@ -3279,7 +3321,7 @@ if [[ "${symConfiguration}" != *"Catch-all"* ]]; then
fi
- updateScriptLog "Update 'helpmessage' with Configuration: ${infoboxConfiguration} …"
+ updateSetupYourMacDialog "Update 'helpmessage' with Configuration: ${infoboxConfiguration} …"
helpmessage+="\n**Configuration:**\n- $infoboxConfiguration\n"
helpmessage+="\n**Computer Information:** \n"
@@ -3315,7 +3357,7 @@ for (( i=0; i listitem: ${listitem}\n# # #\n"
+ updateSetupYourMacDialog "\n\n# # #\n# policyJSON > listitem: ${listitem}\n# # #\n"
dialogUpdateSetupYourMac "listitem: index: $i, status: wait, statustext: Installing …, "
fi
if [[ -n "$icon" ]]; then dialogUpdateSetupYourMac "icon: ${icon}"; fi
@@ -3329,7 +3371,7 @@ for (( i=0; i