Menu Close

Custom Branded macOS Notifications with swiftDialog 2.0

A pair of scripts to help Jamf Pro admins easily display custom branded macOS Notifications

swiftDialog Pre-install (0.0.3) & swiftDialog Notifications (0.0.3)

Jamf Pro built-in Notifications compared to custom branded swiftDialog Notifications
Jamf Pro built-in Notifications compared to custom branded swiftDialog Notifications

Introduction

One of the more welcome features of swiftDialog 2.0 are macOS Notifications. When leveraged with Script Parameters, Jamf Pro administrators can easily display custom branded macOS Notifications to their users.

Configuration

After reviewing Bart’s Notifications documentation — including deploying the necessary Configuration Profile — complete the following steps to create custom branded macOS Notifications via swiftDialog 2.

A. Add the swiftDialog Pre-install script to your Jamf Pro server

The swiftDialog Pre-install script automates the creation of Dialog.png, based on your customized Self Service icon (thanks, @meschwartz).

/Library/Application Support/Dialog/Dialog.png
  1. Add the swiftDialog Pre-install script to your Jamf Pro server
  2. Specify the following for Options > Parameter Labels
    • Parameter 4: Script Log Location
  3. Click Save

Latest version available on GitHub.

#!/bin/bash
####################################################################################################
#
# ABOUT
#
#   swiftDialog Pre-install
#   Pre-install Company Logo for swiftDialog v2 Notifications
#
#   See: https://snelson.us/2023/03/swiftdialog-notifications/
#
####################################################################################################
#
# HISTORY
#
#   Version 0.0.1, 14-Nov-2022, Dan K. Snelson (@dan-snelson)
#       - Original proof-of-concept version
#
#   Version 0.0.2, 16-Nov-2022, Dan K. Snelson (@dan-snelson)
#       - Added "last logged-in user" logic
#       - Added check for Dialog.png (with graceful exit)
#
#   Version 0.0.3, 16-Mar-2023, Dan K. Snelson (@dan-snelson)
#       - Create 'Dialog.png' from Self Service's custom icon (thanks, @meschwartz!)
#       - Remove no longer required 'loggedInUser'-related code
#
####################################################################################################



####################################################################################################
#
# Variables
#
####################################################################################################

# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Global Variables
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

scriptVersion="0.0.3"
export PATH=/usr/bin:/bin:/usr/sbin:/sbin
scriptLog="${4:-"/var/tmp/org.churchofjesuschrist.log"}"



####################################################################################################
#
# Pre-flight Checks
#
####################################################################################################

# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Pre-flight Check: Client-side Logging
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

if [[ ! -f "${scriptLog}" ]]; then
    touch "${scriptLog}"
fi



# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Pre-flight Check: Client-side Script Logging Function
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

function updateScriptLog() {
    echo -e "$( date +%Y-%m-%d\ %H:%M:%S ) - ${1}" | tee -a "${scriptLog}"
}



# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Pre-flight Check: Logging Preamble
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

updateScriptLog "\n\n###\n# swiftDialog Pre-install (${scriptVersion})\n# https://snelson.us\n###\n"
updateScriptLog "PRE-FLIGHT CHECK: Initiating …"



# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Pre-flight Check: Confirm script is running as root
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

if [[ $(id -u) -ne 0 ]]; then
    updateScriptLog "PRE-FLIGHT CHECK: This script must be run as root; exiting."
    exit 1
fi



# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Pre-flight Check: Complete
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

updateScriptLog "PRE-FLIGHT CHECK: Complete"



####################################################################################################
#
# Program
#
####################################################################################################

# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Validate Dialog Branding Image
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

updateScriptLog "Validate 'Dialog.png' …"
if [[ -f "/Library/Application Support/Dialog/Dialog.png" ]]; then
    updateScriptLog "The file '/Library/Application Support/Dialog/Dialog.png' already exists; exiting."
    exit 0
else
    updateScriptLog "The file '/Library/Application Support/Dialog/Dialog.png' does NOT exist; proceeding …"
fi



# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Create Dialog directory
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

if [[ ! -d "/Library/Application Support/Dialog/" ]]; then
    updateScriptLog "Creating '/Library/Application Support/Dialog/' …"
    mkdir -p "/Library/Application Support/Dialog/"
else
    updateScriptLog "The directory '/Library/Application Support/Dialog/' exists …"
fi



# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Create Dialog.png from Self Service's custom icon (thanks, @meschwartz!)
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

updateScriptLog "Create 'Dialog.png' …"
xxd -p -s 260 "$(defaults read /Library/Preferences/com.jamfsoftware.jamf self_service_app_path)"/Icon$'\r'/..namedfork/rsrc | xxd -r -p > "/Library/Application Support/Dialog/Dialog.png"



# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Validate Dialog Branding Image
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

updateScriptLog "Validate 'Dialog.png' …"
if [[ ! -f "/Library/Application Support/Dialog/Dialog.png" ]]; then
    updateScriptLog "Error: The file '/Library/Application Support/Dialog/Dialog.png' was NOT found."
    exit 1
else
    updateScriptLog "The file '/Library/Application Support/Dialog/Dialog.png' was created sucessfully."
    find "/Library/Application Support/Dialog/Dialog.png" | tee -a "${scriptLog}"
fi



# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Exit
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

updateScriptLog "End-of-line."

exit 0
B. Modify your swiftDialog installation policy
  1. Modify your swiftDialog installation policy, by selecting the Scripts payload and adding the swiftDialog Pre-install script, specifying the following Parameter Value
    • Script Log Location: /var/log/com.company.log
  2. Add the Files and Processes payload and specify the following experimental one-liner for the Execute Command
/usr/bin/su - "$(/usr/bin/stat -f%Su /dev/console)" -c "/usr/bin/open '/Library/Application Support/Dialog/Dialog.app'" ; /usr/local/bin/dialog --notification --title "Greetings from IT" --message "You may safely dismiss this test Notification"
  1. Click Save
C. Add the swiftDialog Notifications script to your Jamf Pro server
  1. Add the swiftDialog Notifications script to your Jamf Pro server
  2. Specify the following for Options > Parameter Labels
    • Parameter 4: Script Log Location
    • Parameter 5: Title
    • Parameter 6: Subtitle
    • Parameter 7: Message
  3. Click Save

Latest version available on GitHub.

#!/bin/bash
####################################################################################################
#
# ABOUT
#
#   swiftDialog Notifications
#
#   See: https://snelson.us/2023/03/swiftdialog-notifications/
#
####################################################################################################
#
# HISTORY
#
#   Version 0.0.1, 14-Nov-2022, Dan K. Snelson (@dan-snelson)
#       - Original proof-of-concept version
#   
#   Version 0.0.3, 16-Mar-2023, Dan K. Snelson (@dan-snelson)
#       - Updates from 'swiftDialog Pre-install.bash'
#       - Matched version number of 'swiftDialog Pre-install.bash'
#
####################################################################################################



####################################################################################################
#
# Variables
#
####################################################################################################

# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Global Variables
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

scriptVersion="0.0.3"
export PATH=/usr/bin:/bin:/usr/sbin:/sbin
loggedInUser=$( echo "show State:/Users/ConsoleUser" | scutil | awk '/Name :/ { print $3 }' )
dialogApp="/usr/local/bin/dialog"
dialogNotificationLog=$( mktemp /var/tmp/dialogNotificationLog.XXX )
scriptLog="${4:-"/var/tmp/org.churchofjesuschrist.log"}"

if [[ -n ${5} ]]; then titleoption="--title"; title="${5}"; fi
if [[ -n ${6} ]]; then subtitleoption="--subtitle"; subtitle="${6}"; fi
if [[ -n ${7} ]]; then messageoption="--message"; message="${7}"; fi



####################################################################################################
#
# Pre-flight Checks
#
####################################################################################################

# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Pre-flight Check: Client-side Logging
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

if [[ ! -f "${scriptLog}" ]]; then
    touch "${scriptLog}"
fi



# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Pre-flight Check: Client-side Script Logging Function
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

function updateScriptLog() {
    echo -e "$( date +%Y-%m-%d\ %H:%M:%S ) - ${1}" | tee -a "${scriptLog}"
}



# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Pre-flight Check: Current Logged-in User Function
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

function currentLoggedInUser() {
    loggedInUser=$( echo "show State:/Users/ConsoleUser" | scutil | awk '/Name :/ { print $3 }' )
    updateScriptLog "PRE-FLIGHT CHECK: Current Logged-in User: ${loggedInUser}"
}



# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Pre-flight Check: Logging Preamble
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

updateScriptLog "\n\n###\n# swiftDialog Notifications (${scriptVersion})\n# https://snelson.us\n###\n"
updateScriptLog "PRE-FLIGHT CHECK: Initiating …"



# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Pre-flight Check: Confirm script is running as root
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

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 logged-in user
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

currentLoggedInUser
if [[ -z "${loggedInUser}" || "${loggedInUser}" == "loginwindow" ]]; then
    updateScriptLog "PRE-FLIGHT CHECK: No user logged-in; exiting"
    exit 1
fi



# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Pre-flight Check: Complete
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

updateScriptLog "PRE-FLIGHT CHECK: Complete"



####################################################################################################
#
# Functions
#
####################################################################################################

# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Quit Script (thanks, @bartreadon!)
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

function quitScript() {

    updateScriptLog "Quitting …"

    # Remove dialogNotificationLog
    if [[ -e ${dialogNotificationLog} ]]; then
        updateScriptLog "Removing ${dialogNotificationLog} …"
        rm "${dialogNotificationLog}"
    fi

    updateScriptLog "Goodbye!"
    exit "${1}"

}



# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Validate Script Parameters
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

if [[ -z "${title}" ]] ; then

    updateScriptLog "Parameter 5 is NOT populated; displaying instructions …"

    titleoption="--title"
    title="Title [Parameter 5] goes here"

    subtitleoption="--subtitle"
    subtitle="Subtitle [Parameter 6] goes here"

    messageoption="--message"
    message="Message [Parameter 7] goes here"

else

    updateScriptLog "Parameters 5, \"title,\" is populated; proceeding ..."

fi



# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Display Notification
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

updateScriptLog "Title: ${title}"
updateScriptLog "Subtitle: ${subtitle}"
updateScriptLog "Message: ${message}"

${dialogApp} \
    --notification \
    "${titleoption}" "${title}" \
    "${subtitleoption}" "${subtitle}" \
    "${messageoption}" "${message}" \
    --commandfile "$dialogNotificationLog}"



# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Exit
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

quitScript "0"
D. Create a test Jamf Pro policy to display the notification
  1. Create a new Jamf Pro policy, using the following as a guide for Options > General:
    • Set Display Name to swfitDialog Notification Test (0.0.3)
    • Set Execution Frequency to Ongoing
  2. Select the Scripts payload and add the swiftDialog Notifications script, specifying the following Parameter Values
    • Script Log Location: /var/log/com.company.log
    • Title: Custom Branded macOS Notifications
    • Subtitle (blank)
    • Message: with swiftDialog 2
  1. Adjust Scope to your liking; we limited testing policies to our opt-in Beta Testers
  2. Use the following for Self Service
    • Self Service Display Name: swfitDialog Notification Test (0.0.3)
    • Button Name Before Initiation: Execute
    • Button Name After Initiation: Execute
    • Description: Tests macOS Notifications with swiftDialog
  1. Click Save
Testing Notes

Through trial-and-error, we discovered that even with our preferred settings for au.bartreardon.dialog Notifications …

swiftDialog (Bundle ID: au.bartreardon.dialog)

… the logged-in user had to first launch Dialog at least once before a Notification would display.

Now, we include the following Files and Processes payload, Execute Command, as one of our last steps in Setup Your Mac (after which the computer is restarted):

/usr/bin/su - "$(/usr/bin/stat -f%Su /dev/console)" -c "/usr/bin/open '/Library/Application Support/Dialog/Dialog.app'" ; /usr/local/bin/dialog --notification --title "Setup Your Mac" --message "Finalizing configuration …"
Posted in Jamf Pro, macOS, Scripts, swiftDialog, Tips & Tricks

Related Posts