-
-
Save talkingmoose/9faf50deaaefafa9a147e48ba39bb4b0 to your computer and use it in GitHub Desktop.
| #!/bin/bash | |
| <<ABOUT_THIS_SCRIPT | |
| ----------------------------------------------------------------------- | |
| Written by:William Smith | |
| Professional Services Engineer | |
| Jamf | |
| [email protected] | |
| https://gist.github.com/talkingmoose/9faf50deaaefafa9a147e48ba39bb4b0 | |
| Reference: https://developer.apple.com/documentation/devicemanagement/notifications/notificationsettingsitem | |
| Originally posted: October 5, 2019 | |
| Last updated: October 16, 2019 | |
| Purpose: Create configuration profiles to manage app notifications. | |
| Upload the configuration profile to Jamf Pro or save to your desktop. | |
| Instructions: Run the script with help, -h or --usage for help. | |
| Except where otherwise noted, this work is licensed under | |
| http://creativecommons.org/licenses/by/4.0/ | |
| "Fortune makes promises to many, keeps them to none. | |
| Live for each day, live for the hours, since nothing is forever yours." | |
| ----------------------------------------------------------------------- | |
| ABOUT_THIS_SCRIPT | |
| # Jamf Pro URL and credentials | |
| URL="https://jamfproserver.talkingmoose.net:8443" | |
| userName="API-Editor" | |
| password="P@55w0rd" | |
| organizationName="Talking Moose Industries" | |
| # -- set some variables for the rest of the script ---------------------------- | |
| # regular expression for "help" and "usage" | |
| regHelp="^-?-?[Hh]([Ee][Ll][Pp])?|[Uu]([Ss][Aa][Gg][Ee])?$" | |
| # regular expressions for "true" and "false" | |
| regTrue="^[Tt]([Rr][Uu][Ee])?|[Yy]([Ee][Ss])?$" | |
| regFalse="^[Ff]([Aa][Ll][Ss][Ee])?|[Nn]([Oo])?$" | |
| # regular expressions for "upload" and "save" | |
| regUpload="^[Uu]([Pp][Ll][Oo][Aa][Dd])?$" | |
| regSave="^[Ss]([Aa][Vv][Ee])?$" | |
| regBoth="^[Bb]([Oo][Tt][Hh])?$" | |
| # regular expressions for "none", "banners" and "alerts" | |
| regNone="^[Nn]([Oo][Nn][Ee])?$" | |
| regBanners="^[Bb]([Aa][Nn][Nn][Ee][Rr][Ss])?$" | |
| regAlerts="^[Aa]([Ll][Ee][Rr][Tt][Ss])?$" | |
| # generate two UUIDs for configuration profile payload identifiers | |
| PayloadUUID1=$( /usr/bin/uuidgen ) | |
| PayloadUUID2=$( /usr/bin/uuidgen ) | |
| appDicts="" | |
| # -- display usage information or parse app path for information -------------- | |
| appPath="$1" | |
| if [[ "$appPath" =~ ${regHelp} ]]; then | |
| echo | |
| echo "Manage App Notifications | |
| Purpose: Create configuration profiles to manage app notifications | |
| Upload the configuration profile to Jamf Pro or save to your desktop | |
| Configuration: To upload to your Jamf Pro server, edit these lines before running the script. | |
| The API-Editor account needs the Create privilege for macOS Configuration Profiles in Jamf Pro | |
| URL=\"https://jamfproserver.talkingmoose.net:8443\" | |
| userName=\"API-Editor\" | |
| password=\"P@55w0rd\" | |
| organizationName=\"Talking Moose Industries\" | |
| Usage: \"$0\" [/path/to/application] | |
| Questions are followed by allowed responses with [default] responses in brackets. | |
| Responses are case insensitive and accept the first letter or entire word. | |
| Press return to accept the default response. | |
| Example: $ \"$0\" | |
| Path to managed app (drag app into this Terminal window): /Applications/FaceTime.app | |
| ... | |
| or | |
| $ \"$0\" /Applications/FaceTime.app | |
| Allow Notifications from FaceTime ( [Yes] No ): Yes | |
| FaceTime alert style ( None [Banners] Alerts ): A | |
| Show notifications on lock screen ( [Yes] No ): n | |
| Show in Notification Center ( [Yes] No ): true | |
| Badge app icon ( [Yes] No ): | |
| Play sound for notifications ( [Yes] No ): NO | |
| Critical Alerts Enabled ( Yes [No] ): FALSE | |
| Add another app ( [Yes] No ): n | |
| Upload to Jamf Pro or Save to Desktop? ( Both [Upload] Save ): U | |
| Your new Notifications configuration profile for FaceTime was uploaded to Jamf Pro and is ready for scoping. | |
| Would you like to view the profile now? ( [Yes] No ): yes" | |
| echo | |
| exit 0 | |
| else | |
| appBundleID=$( /usr/bin/defaults read "$appPath/Contents/Info.plist" CFBundleIdentifier 2>/dev/null ) | |
| appExecutable=$( /usr/bin/defaults read "$appPath/Contents/Info.plist" CFBundleExecutable 2>/dev/null ) | |
| appExecutableString=$( /usr/bin/sed -e 's/ /./g' <<< "$appExecutable" ) | |
| fi | |
| function getApp { | |
| # -- request path to managed app if no app path provided ---------------------- | |
| while [[ "$appExecutable" = "" ]]; | |
| do | |
| echo | |
| read -p "Path to managed app (drag app into this Terminal window): " appPath | |
| appBundleID=$( /usr/bin/defaults read "$appPath/Contents/Info.plist" CFBundleIdentifier 2>/dev/null ) | |
| appExecutable=$( /usr/bin/defaults read "$appPath/Contents/Info.plist" CFBundleExecutable 2>/dev/null ) | |
| appExecutableString=$( /usr/bin/sed -e 's/ /./g' <<< "$appExecutable" ) | |
| done | |
| } | |
| function getNotificationsEnabled { | |
| # -- choose notificationsEnabled ---------------------------------------------- | |
| while [[ ! "$notificationsEnabled" =~ ${regTrue} && ! "$notificationsEnabled" =~ ${regFalse} ]]; | |
| do | |
| echo | |
| read -p "Allow Notifications from $appExecutable ( [Yes] No ): " notificationsEnabled # true, false, yes or no; case insensitive, first letter accepted, return to accept default | |
| notificationsEnabled=${notificationsEnabled:-true} | |
| done | |
| if [[ "$notificationsEnabled" =~ ${regTrue} ]]; then | |
| notificationsEnabled="true" | |
| else | |
| notificationsEnabled="false" | |
| fi | |
| } | |
| function getAlertType { | |
| # -- choose alertType --------------------------------------------------------- | |
| while [[ ! "$alertType" =~ ${regNone} && ! "$alertType" =~ ${regBanners} && ! "$alertType" =~ ${regAlerts} && "$notificationsEnabled" = "true" ]]; | |
| do | |
| echo | |
| read -p "$appExecutable alert style ( None [Banners] Alerts ): " alertType # none, banners or alerts, case insensitive, first letter accepted, return to accept default | |
| alertType=${alertType:-Banners} | |
| done | |
| if [[ "$alertType" =~ ${regNone} ]]; then | |
| alertType="0" | |
| elif [[ "$alertType" =~ ${regBanners} ]]; then | |
| alertType="1" | |
| else | |
| alertType="2" | |
| fi | |
| } | |
| function getShowInLockScreen { | |
| # -- choose showInLockScreen -------------------------------------------------- | |
| while [[ ! "$showInLockScreen" =~ ${regTrue} && ! "$showInLockScreen" =~ ${regFalse} && "$notificationsEnabled" = "true" ]]; | |
| do | |
| read -p "Show notifications on lock screen ( [Yes] No ): " showInLockScreen # true, false, yes or no; case insensitive, first letter accepted, return to accept default | |
| showInLockScreen=${showInLockScreen:-true} | |
| done | |
| if [[ "$showInLockScreen" =~ ${regTrue} ]]; then | |
| showInLockScreen="true" | |
| else | |
| showInLockScreen="false" | |
| fi | |
| } | |
| function getShowInNotificationCenter { | |
| # -- choose showInNotificationCenter ------------------------------------------ | |
| while [[ ! "$showInNotificationCenter" =~ ${regTrue} && ! "$showInNotificationCenter" =~ ${regFalse} && "$notificationsEnabled" = "true" ]]; | |
| do | |
| read -p "Show in Notification Center ( [Yes] No ): " showInNotificationCenter # true, false, yes or no; case insensitive, first letter accepted, return to accept default | |
| showInNotificationCenter=${showInNotificationCenter:-true} | |
| done | |
| if [[ "$showInNotificationCenter" =~ ${regTrue} ]]; then | |
| showInNotificationCenter="true" | |
| else | |
| showInNotificationCenter="false" | |
| fi | |
| } | |
| function getBadgesEnabled { | |
| # -- choose badgesEnabled ----------------------------------------------------- | |
| while [[ ! "$badgesEnabled" =~ ${regTrue} && ! "$badgesEnabled" =~ ${regFalse} && "$notificationsEnabled" = "true" ]]; | |
| do | |
| read -p "Badge app icon ( [Yes] No ): " badgesEnabled # true, false, yes or no; case insensitive, first letter accepted, return to accept default | |
| badgesEnabled=${badgesEnabled:-true} | |
| done | |
| if [[ "$badgesEnabled" =~ ${regTrue} ]]; then | |
| badgesEnabled="true" | |
| else | |
| badgesEnabled="false" | |
| fi | |
| } | |
| function getSoundsEnabled { | |
| # -- choose soundsEnabled ----------------------------------------------------- | |
| while [[ ! "$soundsEnabled" =~ ${regTrue} && ! "$soundsEnabled" =~ ${regFalse} && "$notificationsEnabled" = "true" ]]; | |
| do | |
| read -p "Play sound for notifications ( [Yes] No ): " soundsEnabled # true, false, yes or no; case insensitive, first letter accepted, return to accept default | |
| soundsEnabled=${soundsEnabled:-true} | |
| done | |
| if [[ "$soundsEnabled" =~ ${regTrue} ]]; then | |
| soundsEnabled="true" | |
| else | |
| soundsEnabled="false" | |
| fi | |
| } | |
| function getCriticalAlertsEnabled { | |
| # -- choose criticalAlertsEnabled (does not appear in GUI) -------------------- | |
| while [[ ! "$criticalAlertsEnabled" =~ ${regTrue} && ! "$criticalAlertsEnabled" =~ ${regFalse} && "$notificationsEnabled" = "true" ]]; | |
| do | |
| read -p "Critical Alerts Enabled ( Yes [No] ): " criticalAlertsEnabled # true, false, yes or no; case insensitive, first letter accepted, return to accept default | |
| criticalAlertsEnabled=${criticalAlertsEnabled:-false} | |
| done | |
| if [[ "$criticalAlertsEnabled" =~ ${regTrue} ]]; then | |
| criticalAlertsEnabled="true" | |
| else | |
| criticalAlertsEnabled="false" | |
| fi | |
| } | |
| function uploadProfile { | |
| # upload to Jamf Pro | |
| profilePayload=$( /usr/bin/xmllint --noblanks - <<< "$mobileconfig" | /usr/bin/sed -e 's/</\</g' -e 's/>/\>/g' ) | |
| profileXML="<os_x_configuration_profile> | |
| <general> | |
| <name>Managed Notifications</name> | |
| <description> | |
| <string>Manage Notifications settings.</string> | |
| </description> | |
| <site/> | |
| <category/> | |
| <distribution_method>Install Automatically</distribution_method> | |
| <user_removable>false</user_removable> | |
| <level>computer</level> | |
| <uuid>$PayloadUUID2</uuid> | |
| <payloads>$profilePayload</payloads> | |
| </general> | |
| </os_x_configuration_profile>" | |
| # flatten the XML for the configuration profile to upload to Jamf Pro | |
| flatXML=$( /usr/bin/xmllint --noblanks - <<< "$profileXML" ) | |
| # upload and create configuration profile | |
| result=$( /usr/bin/curl "$URL/JSSResource/osxconfigurationprofiles/id/0" \ | |
| --silent \ | |
| --insecure \ | |
| --write-out "%{http_code}" \ | |
| --user "$userName":"$password" \ | |
| --header "Content-Type: text/xml" \ | |
| --request POST \ | |
| --data "$flatXML" 2>&1 ) | |
| # evaluate HTTP status code | |
| resultStatus=${result: -3} | |
| if [[ $resultStatus = 201 ]]; then # 201 is successful | |
| echo | |
| echo "Your new Notifications configuration profile for $appExecutable was uploaded to Jamf Pro and is ready for scoping." | |
| # -- offer to open configuration profile in Jamf Pro ------------------ | |
| while [[ ! "$openProfile" =~ ${regTrue} && ! "$openProfile" =~ ${regFalse} ]]; | |
| do | |
| echo | |
| read -p "Would you like to view the profile now? ( [Yes] No ): " openProfile # true, false, yes or no; case insensitive, first letter accepted, return to accept default | |
| openProfile=${openProfile:-true} | |
| done | |
| if [[ "$openProfile" =~ ${regTrue} ]]; then | |
| resultXML=${result%???} | |
| profileID=$( /usr/bin/xpath '/os_x_configuration_profile/id/text()' <<< "$resultXML" 2>/dev/null ) | |
| /usr/bin/open "$URL/OSXConfigurationProfiles.html?id=$profileID&o=r" | |
| fi | |
| else | |
| echo | |
| echo "Unable to upload your new Notifications configuration profile for $appExecutable [Response code: $resultStatus]." | |
| echo | |
| echo "CODE DESCRIPTION | |
| 000 Check server URL in script | |
| 200 Request successful | |
| 201 Request to create or update object successful | |
| 400 Bad request. Verify the syntax of the request specifically the XML body. | |
| 401 Authentication failed. Verify the credentials being used for the request. | |
| 403 Invalid permissions. Verify the account being used has the proper permissions for the object/resource you are trying to access. | |
| 404 Object/resource not found. Verify the URL path is correct. | |
| 409 Conflict. Delete existing profile \"Set $appExecutable notifications\" first. | |
| 500 Internal server error. Retry the request or contact Jamf support if the error is persistent." | |
| fi | |
| } | |
| function saveProfile { | |
| echo | |
| echo "$mobileconfig" > "$HOME/Desktop/Managed Notifications.mobileconfig" | |
| echo "Your new Notifications configuration profile was saved to your desktop." | |
| } | |
| # -- ask for another app -------------------------------------------------- | |
| while [[ ! "$addApp" =~ ${regFalse} ]]; | |
| do | |
| getApp | |
| if [[ $appList = *"$appBundleID"* ]]; then | |
| echo | |
| echo "This app is already added to the list." | |
| else | |
| getNotificationsEnabled | |
| getAlertType | |
| getShowInLockScreen | |
| getNotificationsEnabled | |
| getShowInNotificationCenter | |
| getBadgesEnabled | |
| getSoundsEnabled | |
| getCriticalAlertsEnabled | |
| appDicts="$appDicts | |
| <dict> | |
| <key>AlertType</key> | |
| <integer>$alertType</integer> | |
| <key>BadgesEnabled</key> | |
| <$badgesEnabled/> | |
| <key>BundleIdentifier</key> | |
| <string>$appBundleID</string> | |
| <key>CriticalAlertEnabled</key> | |
| <$criticalAlertsEnabled/> | |
| <key>NotificationsEnabled</key> | |
| <$notificationsEnabled/> | |
| <key>ShowInLockScreen</key> | |
| <$showInLockScreen/> | |
| <key>ShowInNotificationCenter</key> | |
| <$showInNotificationCenter/> | |
| <key>SoundsEnabled</key> | |
| <$soundsEnabled/> | |
| </dict>" | |
| appList="$appList $appBundleID" | |
| fi | |
| addApp="" | |
| while [[ ! "$addApp" =~ ${regTrue} && ! "$addApp" =~ ${regFalse} ]]; | |
| do | |
| echo | |
| read -p "Add another app ( [Yes] No ): " addApp # true, false, yes or no; case insensitive, first letter accepted, return to accept default | |
| addApp=${addApp:-true} | |
| done | |
| if [[ "$addApp" =~ ${regTrue} ]]; then | |
| addApp="true" | |
| appExecutable="" | |
| notificationsEnabled="" | |
| alertType="" | |
| showInLockScreen="" | |
| notificationsEnabled="" | |
| showInNotificationCenter="" | |
| badgesEnabled="" | |
| soundsEnabled="" | |
| criticalAlertsEnabled="" | |
| else | |
| addApp="false" | |
| fi | |
| done | |
| # -- use this template XML to create a .mobileconfig file -------------------------- | |
| mobileconfig="<?xml version=\"1.0\" encoding=\"UTF-8\"?> | |
| <!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\"> | |
| <plist version=\"1.0\"> | |
| <dict> | |
| <key>PayloadContent</key> | |
| <array> | |
| <dict> | |
| <key>NotificationSettings</key> | |
| <array>$appDicts | |
| </array> | |
| <key>PayloadDescription</key> | |
| <string>Managed Notifications</string> | |
| <key>PayloadDisplayName</key> | |
| <string>Managed Notifications</string> | |
| <key>PayloadEnabled</key> | |
| <true/> | |
| <key>PayloadIdentifier</key> | |
| <string>$PayloadUUID1</string> | |
| <key>PayloadOrganization</key> | |
| <string>$organizationName</string> | |
| <key>PayloadType</key> | |
| <string>com.apple.notificationsettings</string> | |
| <key>PayloadUUID</key> | |
| <string>$PayloadUUID1</string> | |
| <key>PayloadVersion</key> | |
| <integer>1</integer> | |
| </dict> | |
| </array> | |
| <key>PayloadDescription</key> | |
| <string>Managed Notifications</string> | |
| <key>PayloadDisplayName</key> | |
| <string>Managed Notifications</string> | |
| <key>PayloadEnabled</key> | |
| <true/> | |
| <key>PayloadIdentifier</key> | |
| <string>$PayloadUUID2</string> | |
| <key>PayloadOrganization</key> | |
| <string>$organizationName</string> | |
| <key>PayloadRemovalDisallowed</key> | |
| <false/> | |
| <key>PayloadScope</key> | |
| <string>System</string> | |
| <key>PayloadType</key> | |
| <string>Configuration</string> | |
| <key>PayloadUUID</key> | |
| <string>$PayloadUUID2</string> | |
| <key>PayloadVersion</key> | |
| <integer>1</integer> | |
| </dict> | |
| </plist>" | |
| # -- choose to upload to Jamf Pro or save to Desktop -------------------------- | |
| while [[ ! "$chooseOutput" =~ ${regUpload} && ! "$chooseOutput" =~ ${regSave} && ! "$chooseOutput" =~ ${regBoth} ]]; | |
| do | |
| echo | |
| read -p "Upload to Jamf Pro or Save to Desktop? ( Both [Upload] Save ): " chooseOutput # upload, save or both; case insensitive, first letter accepted, return to accept default | |
| chooseOutput=${chooseOutput:-upload} | |
| done | |
| if [[ "$chooseOutput" =~ ${regUpload} ]]; then | |
| uploadProfile | |
| elif [[ "$chooseOutput" =~ ${regSave} ]]; then | |
| saveProfile | |
| else | |
| uploadProfile | |
| saveProfile | |
| fi | |
| exit 0 |
Old reply but desperately looking for a solution to this issue and I am not having any success using this on Big Sur. The profile isn't getting picked up by Jamf and even when installed manually it has inconsistent success with different apps.
@curdZ Jamf has since added Notifications as a payload to Configuration Profiles. You should use that instead.
Old reply but desperately looking for a solution to this issue and I am not having any success using this on Big Sur. The profile isn't getting picked up by Jamf and even when installed manually it has inconsistent success with different apps.
@curdZ Jamf has since added Notifications as a payload to Configuration Profiles. You should use that instead.
Wow I'm blind, I'll definitely use that. Thanks for your reply!
Old reply but desperately looking for a solution to this issue and I am not having any success using this on Big Sur. The profile isn't getting picked up by Jamf and even when installed manually it has inconsistent success with different apps.