SwiftDialog custom notifications via system scripts
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Posted on 02-04-2025 05:46 AM
Hello all,
Been busy lately...this time I created a system script to display nicely formatted Swift Dialog notifications that you can deploy to scoped users., includes timers, and images if you want.
#!/bin/zsh
#
# Written by: Scott E. Kendall
#
# Created Date: 01/227/2025
# Last modified: 01/27/2025
#
# v1.0 - Inital script
#
# Expected Paramaters:
# #4 - Title
# #5 - Full formatted message to display
# #6 - Button1 Text
# #7 - Image to display
# #8 - JAMF policy to load image if it doeesn't exist
# #9 - Notification icon name
# #10 - Timer (in seconds) to wait until dismissal
######################################################################################################
#
# Gobal "Common" variables (do not change these!)
#
######################################################################################################
export PATH=/usr/bin:/bin:/usr/sbin:/sbin
LOGGED_IN_USER=$( scutil <<< "show State:/Users/ConsoleUser" | awk '/Name :/ && ! /loginwindow/ { print $3 }' )
USER_DIR=$( dscl . -read /Users/${LOGGED_IN_USER} NFSHomeDirectory | awk '{ print $2 }' )
SUPPORT_DIR="/Library/Application Support/GiantEagle"
OVERLAY_ICON="${SUPPORT_DIR}/SupportFiles/DiskSpace.png"
SD_BANNER_IMAGE="${SUPPORT_DIR}/SupportFiles/GE_SD_BannerImage.png"
LOG_DIR="${SUPPORT_DIR}/logs"
LOG_FILE="${LOG_DIR}/DialogNotify.log"
LOG_STAMP=$(echo $(/bin/date +%Y%m%d))
# Swift Dialog version requirements
SW_DIALOG="/usr/local/bin/dialog"
[[ -e "${SW_DIALOG}" ]] && SD_VERSION=$( ${SW_DIALOG} --version) || SD_VERSION="0.0.0"
MIN_SD_REQUIRED_VERSION="2.3.3"
DIALOG_INSTALL_POLICY="install_SwiftDialog"
SUPPORT_FILE_INSTALL_POLICY="install_SymFiles"
ICON_FILES="/System/Library/CoreServices/CoreTypes.bundle/Contents/Resources/"
JSONOptions=$(mktemp /var/tmp/ClearBrowserCache.XXXXX)
BANNER_TEXT_PADDING=" "
SD_INFO_BOX_MSG=""
SD_DIALOG_GREETING=$((){print Good ${argv[2+($1>11)+($1>18)]}} ${(%):-%D{%H}} morning afternoon evening)
##################################################
#
# Passed in variables
#
#################################################
JAMF_LOGGED_IN_USER=$3 # Passed in by JAMF automatically
SD_FIRST_NAME="${(C)JAMF_LOGGED_IN_USER%%.*}"
SD_WINDOW_TITLE="${BANNER_TEXT_PADDING}$4"
SD_WELCOME_MSG="${5:-"Information Message"}"
SD_BUTTON1_PROMPT="${6:-"OK"}"
SD_IMAGE_TO_DISPLAY="${7:-""}"
SD_IMAGE_POLCIY="${8:-""}"
SD_ICON_PRIMARY="${9:-"AlertNoteIcon.icns"}"
SD_TIMER="${10-120}"
SD_ICON_PRIMARY="${ICON_FILES}${SD_ICON_PRIMARY}"
####################################################################################################
#
# Functions
#
####################################################################################################
function create_log_directory ()
{
# Ensure that the log directory and the log files exist. If they
# do not then create them and set the permissions.
#
# RETURN: None
# If the log directory doesnt exist - create it and set the permissions
[[ ! -d "${LOG_DIR}" ]] && /bin/mkdir -p "${LOG_DIR}"
/bin/chmod 755 "${LOG_DIR}"
# If the log file does not exist - create it and set the permissions
[[ ! -f "${LOG_FILE}" ]] && /usr/bin/touch "${LOG_FILE}"
/bin/chmod 644 "${LOG_FILE}"
}
function logMe ()
{
# Basic two pronged logging function that will log like this:
#
# 20231204 12:00:00: Some message here
#
# This function logs both to STDOUT/STDERR and a file
# The log file is set by the $LOG_FILE variable.
#
# RETURN: None
echo "${1}" 1>&2
echo "$(/bin/date '+%Y-%m-%d %H:%M:%S'): ${1}" | tee -a "${LOG_FILE}"
}
function check_swift_dialog_install ()
{
# Check to make sure that Swift Dialog is installed and functioning correctly
# Will install process if missing or corrupted
#
# RETURN: None
logMe "Ensuring that swiftDialog version is installed..."
if [[ ! -x "${SW_DIALOG}" ]]; then
logMe "Swift Dialog is missing or corrupted - Installing from JAMF"
install_swift_dialog
SD_VERSION=$( ${SW_DIALOG} --version)
fi
if ! is-at-least "${MIN_SD_REQUIRED_VERSION}" "${SD_VERSION}"; then
logMe "Swift Dialog is outdated - Installing version '${MIN_SD_REQUIRED_VERSION}' from JAMF..."
install_swift_dialog
else
logMe "Swift Dialog is currently running: ${SD_VERSION}"
fi
}
function install_swift_dialog ()
{
# Install Swift dialog From JAMF
# PARMS Expected: DIALOG_INSTALL_POLICY - policy trigger from JAMF
#
# RETURN: None
/usr/local/bin/jamf policy -trigger ${DIALOG_INSTALL_POLICY}
}
function check_support_files ()
{
[[ ! -e "${SD_BANNER_IMAGE}" ]] && /usr/local/bin/jamf policy -trigger ${SUPPORT_FILE_INSTALL_POLICY}
if [[ ! -z "${SD_IMAGE_TO_DISPLAY}" ]]; then
[[ ! -e "${SD_IMAGE_TO_DISPLAY}" ]] && /usr/local/bin/jamf policy -trigger ${SD_IMAGE_POLCIY}
fi
# Make sure it is readable by everyone
chmod +r "${SD_IMAGE_TO_DISPLAY}"
}
function display_msg ()
{
MainDialogBody=(
--message "${SD_DIALOG_GREETING} ${SD_FIRST_NAME}. ${SD_WELCOME_MSG}"
--ontop
--icon "${SD_ICON_PRIMARY}"
--overlayicon computer
--bannerimage "${SD_BANNER_IMAGE}"
--bannertitle "${SD_WINDOW_TITLE}"
--quitkey 0
--timer "${SD_TIMER}"
--button1text "${SD_BUTTON1_PROMPT}"
)
[[ ! -z "${SD_IMAGE_TO_DISPLAY}" ]] && MainDialogBody+=(--height 520 --image "${SD_IMAGE_TO_DISPLAY}")
# Show the dialog screen and allow the user to choose
"${SW_DIALOG}" "${MainDialogBody[@]}" 2>/dev/null
returnCode=$?
}
function create_infobox_message()
{
################################
#
# Swift Dialog InfoBox message construct
#
################################
SD_INFO_BOX_MSG="## System Info ##\n"
SD_INFO_BOX_MSG+="${MAC_CPU}<br>"
SD_INFO_BOX_MSG+="${MAC_SERIAL_NUMBER}<br>"
SD_INFO_BOX_MSG+="${MAC_RAM} RAM<br>"
SD_INFO_BOX_MSG+="${FREE_DISK_SPACE}GB Available<br>"
SD_INFO_BOX_MSG+="macOS ${MACOS_VERSION}<br>"
}
autoload 'is-at-least'
check_swift_dialog_install
check_support_files
create_infobox_message
display_msg
exit 0
This is what the script parameters look like:
You can optionally include images with the dialog, but you will need to provide the exact location of where the image is that is to be deployed, and if the script cannot find it, you will need to provide a policy -trigger event to install the image file. This is a sample notification that I have created for my users:
and this is the parameters that I used to create the dialog:
The screenshot that I have shown is what I have setup with SUPERMAN for the installation of Sequoia. The possibilities are endless of what you can do with it...have fun and let me know if you have ay questions...
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Posted on 02-04-2025 09:39 AM
Hi Scott
Nice. and it works perfectly, although I wonder what is the function "create_infobox_message()" used for? it doesn't seem the variable in it is used anywhere.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Posted on 02-04-2025 09:44 AM
I forgot to take that out of the script…I don’t use it for the notification system…
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Posted on 02-05-2025 06:25 AM
this is what it would look like if you put '--infobox "${SD_INFO_BOX_MSG}" ' into the dialog parameters (ignore the icon...that is from a different app)

- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Posted on 02-11-2025 11:17 AM
I'm suddenly obsessed with that icon 😉.
How do you probe for whether they're presenting in a meeting before displaying said notification
I like to get everyone's opinion on that topic
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Posted on 02-11-2025 11:23 AM
As far as I know, there is no option to detect that thru the script. Any ideas on how to check/implement functionality for that would be appreciated... I didn't see any docs about it in the wiki

- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Posted on 02-04-2025 02:42 PM
Great work! I always like to see how others are using Swift Dialog. I have been working on a macOS update prompt for the last few weeks. I know there are solutions already created by other people, but I wanted to work on one of my own. Once I have it completed, I will be sharing it. We currently use Nudge to alert users to do their macOS updates, but I want something I can have more granular control over.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Posted on 04-25-2025 12:02 PM
Hey @howie_isaacks - did you ever get this one done?
Thanks!
@ScottEKendall - amazingly useful bunch of SD scripts you've created! Finding many of them useful already.

- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Posted on 04-28-2025 10:18 AM
It's done... mostly. I'm trying to tweak it and hammer out the bugs.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Friday
Just nagging...any luck? Have a great weekend!

- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Friday - last edited Friday
It's completed. To share it I will need to remove any company specific data from it. Currently the icon used in the script is my company's logo. I also need to go through the script and remove anything that is not needed and I need to make sure that all of my comments are easy to understand. I deployed this script to a pilot group this morning. It appears to be working as intended. The script installs a launch daemon and a script that are responsible for checking if the deferral time that the user selected has elapsed. Right now, I have the launch daemon triggering the script to run every 10 minutes, but this can easily be adjusted. It does not appear that it causes any issues. Since I used epoch time in the PLIST that stores the deferral data, it's easy for the script to do the math and figure out if the deferral time has ended. If the deferral time has ended, the script will then trigger the Jamf Policy that prompts the user again to run the macOS update. I added a JSS check to the script so that if the Jamf Pro server is not reachable, it will not try to trigger the policy to run. A follow up policy runs after the Mac has been updated to remove the launch daemon and the script that triggers the update policy to run. It also removes the PLIST that stored the deferral data.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Friday
Sounds cool - totally understand on the data aspect. Just curious as this is a constant problem, and I don't love Nudge as much as I should...thanks for the update.

- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Monday
Here's a public version of the script. https://github.com/howieisaacks/shell-scripts/blob/main/macOS_Update_Prompt_with_Swift_Dialog-Public... I am always open to suggestions on how to make my scripts better. This script creates a launch daemon that reads the deferral PLIST file every 10 minutes to check if the defferal time the user selected has elapsed. There is a function in the script for a 5-minute deferral. This was created for testing. To use it you would need to add it in the "--selectvalues" lines in the displayDialog function. You can adjust when the launch daemon runs the check.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Monday - last edited Monday
I like your script...here is one thing that I noticed that you are doing (and I did as well)...
updateLog() {
if [ ! -f "$logFile" ]; then
touch "$logFile"
fi
echo -e "$(date +'%Y-%m-%d %H:%M:%S') - $1" >> "$logFile"
echo "$1" # To Jamf policy log
}
updateLog() {
[ ! -f "$logFile" ] && touch "$logFile"
echo -e "$(date +'%Y-%m-%d %H:%M:%S') - $1" | tee -a "$logFile"

- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Monday
Thanks! The updateLog function is one that I drop into most scripts so I can make this change easily. I appreciate the feedback. I originally wanted to use launch daemons in a way that would make them trigger the policy to run again at the end of a deferral but then I ran into the fact that you can't unload and then delete a launch daemon to install a new version if that launch daemon was the parent process of the policy launching. So, I now just have the launch daemon run every 10 minutes to run a script that does the work of checking the deferral. The launch daemon gets deleted by a policy that runs at startup which checks if macOS has been updated. If it has, the policy deletes the launch daemon, the script, the PLIST, and the file that gets created to catch people who decide not to update after initially clicking to update now.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Monday - last edited Monday
Looks pretty cool! If I can figure out how to make it all work, I might nix my Nudge setup...it will be great to configure with Jamf variables. I'm a dork when it comes to scripting - I'm at best a user who can make other's work work. I like the simplicity of this and Scott's swift alternatives...thanks much for sharing!

- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Tuesday
I love the challenge of figuring out how to script things. There are several people here who have helped me so they have been mentioned in several of my scripts. I'm usually the only person who ever sees the scripts but I feel that these super smart and generous people deseve to be credited. If you decide to put this script into use, feel free to reach out to me for help or for suggestions on making it better. I'm in the Mac Admins Slack. This script goes into full production at the end of this week. I recently created a process for enforcing macOS updates after enrollment if the Mac is below macOS 14.4 which is the minimum OS required for enforcing updates during PreStage. I have been testing that one a lot recently and it's working exactly as intended. It uses Swift Dialog to alert the user that they need to update. I also add these Macs to a smart group that gets a lot of apps blocked in restricted software to help get these users to update. Later, I will add in a more aggressive Swift Dialog alert to further make the point that they need to update NOW!
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Posted on 02-05-2025 04:23 AM
Yep..I know that there are multiple solutions out there..I just wanted to do my own as well. Ever since learning about Swift Dialog, I have been "all in" on trying to adopt it for all of my Mac users. The only thing that I cannot convert to SD is SUPERMAN as the IBM notification system doesn't allow for banner images like SD can. I am not moving away from SUPERMAN though...it is a very well designed system..
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Monday
I for one really appreciate your work, Scott!
