Install Experience
The scripts behind the prompt
Inspect the pre- and post-install scripts IntuneBrew generates for macOS PKG apps. These are zsh shell scripts that call swiftDialog for the interface.
View & download the scriptsView & download the scripts
Anyone can inspect and download these examples; no sign-in is needed. They use the same generator as app deployments, with public example values rather than any team's settings.
The example uses Example App, bundle ID com.example.app, version 2.0.0 and the Soft notification preset: three deferrals, a five-minute timer that defers when it expires, and a completion notification. Replace the example app details before using the scripts with your own PKG.
Pre-install script
Download .shView pre-install script
#!/bin/zsh
# Intune script content must remain below 15360 characters.
DIALOG_BIN='/usr/local/bin/dialog'
if [[ ! -x "$DIALOG_BIN" ]]; then
exit 0
fi
CONSOLE_USER=$(/usr/bin/stat -f "%Su" /dev/console 2>/dev/null || true)
if [[ -z "$CONSOLE_USER" || "$CONSOLE_USER" == "root" || "$CONSOLE_USER" == "loginwindow" ]]; then
exit 0
fi
CONSOLE_UID=$(/usr/bin/id -u "$CONSOLE_USER" 2>/dev/null || true)
if [[ -z "$CONSOLE_UID" ]]; then
exit 0
fi
CONFIG_TITLE='Update available for Example App'
CONFIG_BODY='Version **2.0.0** is ready. Save your work, then install when convenient.'
CONFIG_BUTTON1='Install now'
BUNDLE_ID='com.example.app'
ALLOW_DEFERRALS=true
MAX_DEFERRALS=3
FORCE_AT_MAX=true
TIMER_SECONDS=300
TIMER_EXPIRY='defer'
DEFERRAL_DIR="/Library/Application Support/IntuneBrew/deferrals"
DEFERRAL_FILE="${DEFERRAL_DIR}/${BUNDLE_ID}.plist"
DEFER_COUNT=$(/usr/bin/defaults read "$DEFERRAL_FILE" count 2>/dev/null || /bin/echo 0)
[[ "$DEFER_COUNT" == <-> ]] || DEFER_COUNT=0
CAN_DEFER=false
if [[ "$ALLOW_DEFERRALS" == "true" ]]; then
if [[ "$FORCE_AT_MAX" != "true" || "$DEFER_COUNT" -lt "$MAX_DEFERRALS" ]]; then
CAN_DEFER=true
fi
fi
DIALOG_MESSAGE="$CONFIG_BODY"
SUPPORT_NAME=''
SUPPORT_EMAIL=''
SUPPORT_PHONE=''
SUPPORT_TEXT=""
if [[ -n "$SUPPORT_NAME" ]]; then
SUPPORT_TEXT="Name: ${SUPPORT_NAME}"
fi
if [[ -n "$SUPPORT_EMAIL" ]]; then
[[ -n "$SUPPORT_TEXT" ]] && SUPPORT_TEXT+=$'\n'
SUPPORT_TEXT+="Email: ${SUPPORT_EMAIL}"
fi
if [[ -n "$SUPPORT_PHONE" ]]; then
[[ -n "$SUPPORT_TEXT" ]] && SUPPORT_TEXT+=$'\n'
SUPPORT_TEXT+="Phone: ${SUPPORT_PHONE}"
fi
if [[ -n "$SUPPORT_TEXT" ]]; then
DIALOG_MESSAGE+=$'\n\n**Support**\n'"$SUPPORT_TEXT"
fi
json_escape() {
local value="$1"
local escaped=""
local char=""
local index
for (( index = 1; index <= ${#value}; index++ )); do
char="${value[index]}"
case "$char" in
\\) escaped+="\\\\" ;;
\") escaped+="\\\"" ;;
$'\n') escaped+="\\n" ;;
$'\r') escaped+="\\r" ;;
$'\t') escaped+="\\t" ;;
*) escaped+="$char" ;;
esac
done
/usr/bin/printf "%s" "$escaped"
}
DIALOG_JSON=$(/usr/bin/printf '{"title":"%s","message":"%s","button1text":"%s","timer":%s' "$(json_escape "$CONFIG_TITLE")" "$(json_escape "$DIALOG_MESSAGE")" "$(json_escape "$CONFIG_BUTTON1")" "$TIMER_SECONDS")
if [[ "$CAN_DEFER" == "true" ]]; then
DIALOG_JSON+=',"button2text":"Defer"'
fi
DIALOG_JSON+='}'
DIALOG_STYLE_ARGS=(--style centered --position topright)
/bin/launchctl asuser "$CONSOLE_UID" /usr/bin/sudo -u "$CONSOLE_USER" "$DIALOG_BIN" "${DIALOG_STYLE_ARGS[@]}" --jsonstring "$DIALOG_JSON"
DIALOG_EXIT=$?
reset_deferrals() {
/bin/rm -f "$DEFERRAL_FILE" >/dev/null 2>&1 || true
}
record_deferral() {
/bin/mkdir -p "$DEFERRAL_DIR"
local next_count=$(( DEFER_COUNT + 1 ))
/usr/bin/defaults write "$DEFERRAL_FILE" count -int "$next_count" >/dev/null 2>&1 || true
exit 1
}
case "$DIALOG_EXIT" in
0)
reset_deferrals
exit 0
;;
2)
if [[ "$CAN_DEFER" == "true" ]]; then
record_deferral
fi
reset_deferrals
exit 0
;;
4)
if [[ "$TIMER_EXPIRY" == "defer" && "$CAN_DEFER" == "true" ]]; then
record_deferral
fi
reset_deferrals
exit 0
;;
*)
exit 0
;;
esac
Post-install script
Download .shView post-install script
#!/bin/zsh
# Intune script content must remain below 15360 characters.
DIALOG_BIN='/usr/local/bin/dialog'
if [[ ! -x "$DIALOG_BIN" ]]; then
exit 0
fi
CONSOLE_USER=$(/usr/bin/stat -f "%Su" /dev/console 2>/dev/null || true)
if [[ -z "$CONSOLE_USER" || "$CONSOLE_USER" == "root" || "$CONSOLE_USER" == "loginwindow" ]]; then
exit 0
fi
CONSOLE_UID=$(/usr/bin/id -u "$CONSOLE_USER" 2>/dev/null || true)
if [[ -z "$CONSOLE_UID" ]]; then
exit 0
fi
CONFIG_TITLE='Example App is ready'
CONFIG_BODY='**Example App** version 2.0.0 was installed successfully.'
AUTO_DISMISS_SECONDS=15
DIALOG_MESSAGE="$CONFIG_BODY"
SUPPORT_NAME=''
SUPPORT_EMAIL=''
SUPPORT_PHONE=''
SUPPORT_TEXT=""
if [[ -n "$SUPPORT_NAME" ]]; then
SUPPORT_TEXT="Name: ${SUPPORT_NAME}"
fi
if [[ -n "$SUPPORT_EMAIL" ]]; then
[[ -n "$SUPPORT_TEXT" ]] && SUPPORT_TEXT+=$'\n'
SUPPORT_TEXT+="Email: ${SUPPORT_EMAIL}"
fi
if [[ -n "$SUPPORT_PHONE" ]]; then
[[ -n "$SUPPORT_TEXT" ]] && SUPPORT_TEXT+=$'\n'
SUPPORT_TEXT+="Phone: ${SUPPORT_PHONE}"
fi
if [[ -n "$SUPPORT_TEXT" ]]; then
DIALOG_MESSAGE+=$'\n\n**Support**\n'"$SUPPORT_TEXT"
fi
json_escape() {
local value="$1"
local escaped=""
local char=""
local index
for (( index = 1; index <= ${#value}; index++ )); do
char="${value[index]}"
case "$char" in
\\) escaped+="\\\\" ;;
\") escaped+="\\\"" ;;
$'\n') escaped+="\\n" ;;
$'\r') escaped+="\\r" ;;
$'\t') escaped+="\\t" ;;
*) escaped+="$char" ;;
esac
done
/usr/bin/printf "%s" "$escaped"
}
DIALOG_JSON=$(/usr/bin/printf '{"title":"%s","message":"%s","timer":%s}' "$(json_escape "$CONFIG_TITLE")" "$(json_escape "$DIALOG_MESSAGE")" "$AUTO_DISMISS_SECONDS")
(/bin/launchctl asuser "$CONSOLE_UID" /usr/bin/sudo -u "$CONSOLE_USER" "$DIALOG_BIN" --style centered --position topright --jsonstring "$DIALOG_JSON" >/dev/null 2>&1 &) || true
exit 0
Download scripts for your app
Open an app's Install Experience settings in Deploy apps or Updates, then expand Generated scripts. Those downloads use the app's details, the settings currently shown in the editor, including unsaved edits, and your support defaults when enabled. Downloading does not save settings or change the app in Intune.
Save the experience and deploy or update the app to apply it to Macs. Intune runs the pre-install script before the PKG installer and the post-install script afterwards. These scripts do not download or install the package themselves.
Before you use the scripts
- Deploy swiftDialog as a required app before deploying an app with an install experience.
- Use a macOS PKG app. Intune does not attach these scripts to DMG apps.
- Test the scripts with your app and settings on a pilot Mac before a wider rollout.