https://jamf.pro.server.here/api
When choosing to view the Classic API or Jamf Pro API documentation, there’s an option to log in and authenticate, so that you can run API commands interactively to see how running the commands works in real time and what results you see. This functionality is also useful when setting up API accounts with least privileged access, as it allows testing to verify that all necessary privileges have been assigned to the accounts.
Up until now, this authentication mechanism only supported using username and password authentication but as of Jamf Pro 11.2.0, the authentication mechanism now supports both of the following authentication methods:
To use your preferred authentication method, please select it from the relevant drop-down menu.
]]>“I installed this profile for macOS NewVersion onto macOS OldVersion, then upgraded from macOS OldVersion to macOS NewVersion. The setting didn’t work. Why didn’t it work?”
Why it didn’t work has to do with how management profile settings are handled. When a management profile is installed, the settings contained within that profile are applied.
This settings application occurs exclusively at the time of the profile installation. Those applied settings are never again re-read or re-applied as long as that profile is installed. The settings in a profile are applied only at the time of installation and that is the current state of things.
How is this relevant to settings you want to apply to macOS? Apple defines what OS version a setting was introduced for, which means it does not work for OS versions prior to that. For more information, please see below the jump.
An example of this is the management setting for iPhone mirroring:
This setting was introduced for macOS as of macOS 15 Sequoia. That means that the setting works on macOS Sequoia but what happens when you install a management profile like the one below which contains this setting onto a Mac running macOS 14 Sonoma?
Nothing.
<?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>PayloadDisplayName</key> | |
<string>Restrictions</string> | |
<key>PayloadIdentifier</key> | |
<string>com.apple.applicationaccess.DD8454BB-A1D6-4DD9-B1AC-C1B6ABA512E9</string> | |
<key>PayloadType</key> | |
<string>com.apple.applicationaccess</string> | |
<key>PayloadUUID</key> | |
<string>DD8454BB-A1D6-4DD9-B1AC-C1B6ABA512E9</string> | |
<key>PayloadVersion</key> | |
<integer>1</integer> | |
<key>allowiPhoneMirroring</key> | |
<false/> | |
</dict> | |
</array> | |
<key>PayloadDescription</key> | |
<string>Blocks the use of iPhone mirroring</string> | |
<key>PayloadDisplayName</key> | |
<string>Block iPhone Mirroring</string> | |
<key>PayloadIdentifier</key> | |
<string>D0B2E096-2C7F-4F2F-A1C0-FFE16919768B</string> | |
<key>PayloadOrganization</key> | |
<string>Company Name</string> | |
<key>PayloadScope</key> | |
<string>System</string> | |
<key>PayloadType</key> | |
<string>Configuration</string> | |
<key>PayloadUUID</key> | |
<string>D0B2E096-2C7F-4F2F-A1C0-FFE16919768B</string> | |
<key>PayloadVersion</key> | |
<integer>1</integer> | |
</dict> | |
</plist> |
A profile’s settings get applied at the time of installation. If the setting isn’t understood by the OS the profile is installed onto at the time of installation, the setting is ignored.
In the context of the management setting for iPhone mirroring, macOS Sonoma doesn’t have the management option for managing iPhone mirroring so Sonoma will ignore the setting. It will remain ignored if the Mac gets upgraded to Sequoia because the setting only gets applied at the time of installation and the setting never gets re-evaluated to see if it applies to Sequoia. The outcome is that the setting does not get applied on Sequoia if the profile with the setting was installed on Sonoma.
How do you fix this? Remove the profile with the iPhone mirroring setting from the Sequoia Mac and re-install the profile. Once the profile is installed again, the setting will get applied as part of the install process. Sequoia has that setting as a management option, so Sequoia will then apply the setting from the profile and manage iPhone mirroring as defined by the profile’s settings.
So what does this mean for management settings you want to apply to macOS NewVersion? You’ll need to check what the introduction version is for the setting you want to apply. If it’s a brand new setting where the introduction is on macOS NewVersion, you’ll need to wait until the Mac is running macOS NewVersion before deploying a profile to manage that setting.
For Mac admins who want the capability to install a setting on macOS OldVersion and have it apply to macOS NewVersion, I recommend filing feedback with Apple to request it .
]]>The Apple Intelligence pop-up window can be suppressed for the logged-in user by running the command shown below:
/usr/bin/defaults write com.apple.SetupAssistant DidSeeIntelligence -bool true |
It is also possible to suppress the Apple Intelligence pop up window on macOS Sequoia using a configuration profile. For more details, please see below the jump.
The relevant preference domain and key values are below:
The profile is available on GitHub via the link below:
https://github.com/rtrouton/profiles/blob/main/SkipAppleIntelligenceSetup
]]>
As of macOS 15.2, management options are available for the following Apple Intelligence functionality:
The relevant key values are below:
Restriction | Setting available in version | Description | Key | Key value | Default setting in macOS | |
---|---|---|---|---|---|---|
Allow Image Playground | macOS 15.0.0 | If key vaule is set to FALSE, prohibits the use of image generation. | allowImagePlayground | Boolean | TRUE | |
Allow Writing Tools | macOS 15.0.0 | If key vaule is set to FALSE, allows only anonymous access to external services | allowWritingTools | Boolean | TRUE | |
Allow Genmoji | macOS 15.0.0 | If key vaule is set to FALSE, disables Genmoji | allowGenmoji | Boolean | TRUE | |
Allow Mail Summary | macOS 15.1.0 | If key vaule is set to FALSE, prohibits the ability to create email summaries | allowMailSummary | Boolean | TRUE | |
Allow External Intelligence Integrations | macOS 15.2.0 | If key vaule is set to FALSE, prohibits integrations with external services including ChatGPT and Google Gemini | allowExternalIntelligenceIntegrations | Boolean | TRUE | |
Allow External Intelligence Sign-Ins | macOS 15.2.0 | If key vaule is set to FALSE, disables non-anonymous login to external services including ChatGPT and Google Gemini | allowExternalIntelligenceIntegrationsSignIn | Boolean | TRUE |
It’s important to note that while all of the settings listed above work on macOS Sequoia 15.2, not all work on earlier versions of macOS Sequoia. Here’s the compatibility list:
macOS 15.0 and later:
macOS 15.1 and later:
macOS 15.2 and later:
These settings can be managed by a configuration profile, where setting a boolean value of false will disable the Apple Intelligence feature in question. Please see below for example profiles. The example profiles are also available via the following links:
Note: If you’re planning to use the example profiles with Jamf Pro, the profiles will need to be signed before they can be uploaded to Jamf Pro. If you’re not familiar with how to sign profiles, the post linked below is a good guide to how that process works:
https://macblog.org/sign-configuration-profiles/
Genmoji:
<?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>PayloadDisplayName</key> | |
<string>Restrictions</string> | |
<key>PayloadIdentifier</key> | |
<string>com.apple.applicationaccess.1281701E-9695-4447-9028-4962C25162FF</string> | |
<key>PayloadType</key> | |
<string>com.apple.applicationaccess</string> | |
<key>PayloadUUID</key> | |
<string>1281701E-9695-4447-9028-4962C25162FF</string> | |
<key>PayloadVersion</key> | |
<integer>1</integer> | |
<key>allowGenmoji</key> | |
<false/> | |
</dict> | |
</array> | |
<key>PayloadDescription</key> | |
<string>Disables creation of new Genmoji</string> | |
<key>PayloadDisplayName</key> | |
<string>Apple Intelligence Disable Genmoji</string> | |
<key>PayloadIdentifier</key> | |
<string>B83678F5-B2CB-467C-A89F-73F2E2E1346C</string> | |
<key>PayloadOrganization</key> | |
<string>Company Name</string> | |
<key>PayloadScope</key> | |
<string>System</string> | |
<key>PayloadType</key> | |
<string>Configuration</string> | |
<key>PayloadUUID</key> | |
<string>B83678F5-B2CB-467C-A89F-73F2E2E1346C</string> | |
<key>PayloadVersion</key> | |
<integer>1</integer> | |
</dict> | |
</plist> |
Image Playground:
<?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>PayloadDisplayName</key> | |
<string>Restrictions</string> | |
<key>PayloadIdentifier</key> | |
<string>com.apple.applicationaccess.4FDE23F1-2652-4653-813C-205C9B86C0F5</string> | |
<key>PayloadType</key> | |
<string>com.apple.applicationaccess</string> | |
<key>PayloadUUID</key> | |
<string>4FDE23F1-2652-4653-813C-205C9B86C0F5</string> | |
<key>PayloadVersion</key> | |
<integer>1</integer> | |
<key>allowImagePlayground</key> | |
<false/> | |
</dict> | |
</array> | |
<key>PayloadDescription</key> | |
<string>Disables Image Playground and prohibits the use of image generation</string> | |
<key>PayloadDisplayName</key> | |
<string>Apple Intelligence Disable Image Playground</string> | |
<key>PayloadIdentifier</key> | |
<string>5596EE02-5B47-4B4C-B3F0-AA531C1E9AEB</string> | |
<key>PayloadOrganization</key> | |
<string>Company Name</string> | |
<key>PayloadScope</key> | |
<string>System</string> | |
<key>PayloadType</key> | |
<string>Configuration</string> | |
<key>PayloadUUID</key> | |
<string>5596EE02-5B47-4B4C-B3F0-AA531C1E9AEB</string> | |
<key>PayloadVersion</key> | |
<integer>1</integer> | |
</dict> | |
</plist> |
Writing Tools:
<?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>PayloadDisplayName</key> | |
<string>Restrictions</string> | |
<key>PayloadIdentifier</key> | |
<string>com.apple.applicationaccess.2C74FDD6-E3CD-4E3B-9193-CD4818452895</string> | |
<key>PayloadType</key> | |
<string>com.apple.applicationaccess</string> | |
<key>PayloadUUID</key> | |
<string>2C74FDD6-E3CD-4E3B-9193-CD4818452895</string> | |
<key>PayloadVersion</key> | |
<integer>1</integer> | |
<key>allowWritingTools</key> | |
<false/> | |
</dict> | |
</array> | |
<key>PayloadDescription</key> | |
<string>Disables Apple Intelligence writing tools</string> | |
<key>PayloadDisplayName</key> | |
<string>Apple Intelligence Disable Writing Tools</string> | |
<key>PayloadIdentifier</key> | |
<string>FDDB4857-545D-4538-9C0B-B8ED78FFCE3E</string> | |
<key>PayloadOrganization</key> | |
<string>Company Name</string> | |
<key>PayloadScope</key> | |
<string>System</string> | |
<key>PayloadType</key> | |
<string>Configuration</string> | |
<key>PayloadUUID</key> | |
<string>FDDB4857-545D-4538-9C0B-B8ED78FFCE3E</string> | |
<key>PayloadVersion</key> | |
<integer>1</integer> | |
</dict> | |
</plist> |
Summarize emails:
<?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>PayloadDisplayName</key> | |
<string>Restrictions</string> | |
<key>PayloadIdentifier</key> | |
<string>com.apple.applicationaccess.6DD01B26-8368-45FE-A4F7-35F4CD153E5D</string> | |
<key>PayloadType</key> | |
<string>com.apple.applicationaccess</string> | |
<key>PayloadUUID</key> | |
<string>6DD01B26-8368-45FE-A4F7-35F4CD153E5D</string> | |
<key>PayloadVersion</key> | |
<integer>1</integer> | |
<key>allowMailSummary</key> | |
<false/> | |
</dict> | |
</array> | |
<key>PayloadDescription</key> | |
<string>Disables Mail Summary and prohibits the ability to create email summaries</string> | |
<key>PayloadDisplayName</key> | |
<string>Apple Intelligence Disable Mail Summary</string> | |
<key>PayloadIdentifier</key> | |
<string>45B76C44-A61D-4A1B-82B9-6118B18DB129</string> | |
<key>PayloadOrganization</key> | |
<string>Company Name</string> | |
<key>PayloadScope</key> | |
<string>System</string> | |
<key>PayloadType</key> | |
<string>Configuration</string> | |
<key>PayloadUUID</key> | |
<string>45B76C44-A61D-4A1B-82B9-6118B18DB129</string> | |
<key>PayloadVersion</key> | |
<integer>1</integer> | |
</dict> | |
</plist> |
Block Siri from connecting to third party cloud-based intelligence services:
<?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>PayloadDisplayName</key> | |
<string>Restrictions</string> | |
<key>PayloadIdentifier</key> | |
<string>com.apple.applicationaccess.69140388-BF31-4C0E-A791-F8EFDCB54C49</string> | |
<key>PayloadType</key> | |
<string>com.apple.applicationaccess</string> | |
<key>PayloadUUID</key> | |
<string>69140388-BF31-4C0E-A791-F8EFDCB54C49</string> | |
<key>PayloadVersion</key> | |
<integer>1</integer> | |
<key>allowExternalIntelligenceIntegrations</key> | |
<false/> | |
</dict> | |
</array> | |
<key>PayloadDescription</key> | |
<string>Disables External Intelligence Integrations and prohibits integrations with external services including ChatGPT and Google Gemini</string> | |
<key>PayloadDisplayName</key> | |
<string>Apple Intelligence Disable External Intelligence Integrations</string> | |
<key>PayloadIdentifier</key> | |
<string>2B3EE9B6-249E-44DD-B9A6-1E71F72A7E34</string> | |
<key>PayloadOrganization</key> | |
<string>Company Name</string> | |
<key>PayloadScope</key> | |
<string>System</string> | |
<key>PayloadType</key> | |
<string>Configuration</string> | |
<key>PayloadUUID</key> | |
<string>2B3EE9B6-249E-44DD-B9A6-1E71F72A7E34</string> | |
<key>PayloadVersion</key> | |
<integer>1</integer> | |
</dict> | |
</plist> |
Disable non-anonymous login to third party cloud-based intelligence services:
<?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>PayloadDisplayName</key> | |
<string>Restrictions</string> | |
<key>PayloadIdentifier</key> | |
<string>com.apple.applicationaccess.EB34F905-0ED5-4E29-9A4A-5AE77F4D6652</string> | |
<key>PayloadType</key> | |
<string>com.apple.applicationaccess</string> | |
<key>PayloadUUID</key> | |
<string>EB34F905-0ED5-4E29-9A4A-5AE77F4D6652</string> | |
<key>PayloadVersion</key> | |
<integer>1</integer> | |
<key>allowExternalIntelligenceIntegrationsSignIn</key> | |
<false/> | |
</dict> | |
</array> | |
<key>PayloadDescription</key> | |
<string>Disables External Intelligence Sign-in and allows only anonymous access to external services</string> | |
<key>PayloadDisplayName</key> | |
<string>Apple Intelligence Disable External Intelligence Logins</string> | |
<key>PayloadIdentifier</key> | |
<string>995CBF19-0AE8-4098-93A3-A87812366961</string> | |
<key>PayloadOrganization</key> | |
<string>Company Name</string> | |
<key>PayloadScope</key> | |
<string>System</string> | |
<key>PayloadType</key> | |
<string>Configuration</string> | |
<key>PayloadUUID</key> | |
<string>995CBF19-0AE8-4098-93A3-A87812366961</string> | |
<key>PayloadVersion</key> | |
<integer>1</integer> | |
</dict> | |
</plist> |
For shops which want to disable the MAC address randomization for their own Wi-Fi networks, Apple has provided a DisableAssociationMACRandomization management setting which is available for use in iOS 14 and later, macOS 15 and later, and watchOS 7 and later. However, for shops which don’t want to disable this privacy protection but still want to be able to find out what the actual MAC address of the Wi-Fi network interface on Macs running macOS Sequoia and later, it’s possible to use the networksetup tool to do so. (Hat tip to everyone in the Mac Admins Slack who helped with figuring this out.) For more information, please see below the jump.
Assuming the Wi-Fi network interface on your Mac has been assigned the display name of Wi-Fi, you can get the actual MAC address using the following command:
/usr/sbin/networksetup -getmacaddress Wi-Fi |
You should see output similar to what’s shown below:
username@computername ~ % /usr/sbin/networksetup -getmacaddress Wi-Fi | |
Ethernet Address: 6c:ce:2e:d3:6b:bd (Hardware Port: Wi-Fi) | |
username@computername ~ % |
If you want only the MAC address returned, you can use the following command:
/usr/sbin/networksetup -getmacaddress $(/usr/sbin/networksetup -listallhardwareports | awk '/Hardware Port: Wi-Fi/{getline; print $2}') | awk '{print $3}' |
You should see output similar to what’s shown below:
username@computername ~ % /usr/sbin/networksetup -getmacaddress $(/usr/sbin/networksetup -listallhardwareports | awk '/Hardware Port: Wi-Fi/{getline; print $2}') | awk '{print $3}' | |
6c:ce:2e:d3:6b:bd | |
username@computername ~ % |
If you want only the MAC address returned with all the colons ( : ) removed, you can use the following command:
/usr/sbin/networksetup -getmacaddress $(/usr/sbin/networksetup -listallhardwareports | awk '/Hardware Port: Wi-Fi/{getline; print $2}') | awk '{print $3}' | tr -d ':' |
You should see output similar to what’s shown below:
username@computername ~ % /usr/sbin/networksetup -getmacaddress $(/usr/sbin/networksetup -listallhardwareports | awk '/Hardware Port: Wi-Fi/{getline; print $2}') | awk '{print $3}' | tr -d ':' | |
6cce2ed36bbd | |
username@computername ~ % |
This action can be launching an app or running a script and is set by the Run after privilege change setting.
This action can be further customized by choosing to only run the action once admin rights have been granted. This can be set by the Run only if administrator privileges have been granted setting.
Something to be aware of is that when using an action is that the script or application in question will be run within the context of the logged-in user. This means it will have the same level of access rights that the logged-in user currently has (standard versus admin.) This may be important if running the script or launching the application includes functionality which works for a user with admin rights but not for a user with standard rights. An example of this is running the following command using the log command line tool:
log show –style syslog –predicate 'process BEGINSWITH "Privileges"' –last 1m |
If the logged-in user has admin rights, the log command shown above runs without issues and without requesting authentication.
If the logged-in user has standard rights, you get an error that the log command operation is not permitted.
Privileges 2.x includes management options for setting post-actions, so that their operation and configuration can be set using configuration profiles. For more details, please see below the jump.
The relevant preference domain and key values are listed below:
Here’s how the settings would appear in the following example:
<?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>PostChangeActionOnGrantOnly</key> | |
<false/> | |
<key>PostChangeExecutablePath</key> | |
<string>/System/Applications/App Store.app</string> | |
</dict> | |
</plist> |
Here’s how the settings would appear in the following example:
<?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>PostChangeActionOnGrantOnly</key> | |
<true/> | |
<key>PostChangeExecutablePath</key> | |
<string>/usr/local/bin/privileges_teams_report.sh</string> | |
</dict> | |
</plist> |
One use case for a post action script would be sending a report to a Slack or Teams channel via webhook. While Privileges natively supports sending JSON output to a web hook, both Slack and Teams need to have the JSON being sent to it formatted in specific ways, or else the receiving end won’t be able to work with it. They’re also different formats, so sending to Slack using JSON formatted for Teams doesn’t work and vice-versa.
I’ve written a couple of example scripts which can be used with Privileges as a post action, which are designed to be run as follows:
Note: The reason why the reporting script should be run only when admin rights have been granted is that the log command line tool is used in the scripts. As discussed previously, these scripts will run in the context of the logged-in user and if the logged-in user has admin rights, the log command runs without issues and without requesting authentication. If the logged-in user has standard rights though, the log command will error.
privileges_slack_report.sh
When configured with a Slack webhook URL, the following script should send a report similar to the one below to the relevant Slack channel.
#!/bin/bash | |
# This script will send a report to a Slack channel with information about the user who has been granted admin rights. | |
# You'll need to set up a Slack webhook to receive the information being sent by the script. | |
# If you need help with configuring a Slack webhook, please see the links below: | |
# | |
# https://api.slack.com/incoming-webhooks | |
# https://get.slack.help/hc/en-us/articles/115005265063-Incoming-WebHooks-for-Slack | |
# | |
# Once a Slack webhook is available, the slack_webhook variable should look similar | |
# to this: | |
# slack_webhook="https://hooks.slack.com/services/XXXXXXXXX/YYYYYYYYY/ZZZZZZZZZZ" | |
slack_webhook="" | |
# That should be it for the necessary configuration part. | |
# Nothing else should need to be edited below this line. | |
name=$(hostname) | |
logs=$(mktemp) | |
logged_in_user=$(id -un) | |
# Set script exit status | |
exit_error=0 | |
# Function for sending multi-line output to a Slack webhook. Original script from here: | |
# | |
# http://blog.getpostman.com/2015/12/23/stream-any-log-file-to-slack-using-curl/ | |
SendToSlack(){ | |
cat "$1" | while read LINE; do | |
(echo "$LINE" | grep -e "$3") && curl -X POST –silent –data-urlencode "payload={\"text\": \"$(echo $LINE | sed "s/\"/'/g")\"}" "$2"; | |
done | |
} | |
touch "$logs" | |
echo "Administrator rights have been granted to $logged_in_user using Privileges.app on $name:" >> "$logs" | |
/usr/bin/log show –style syslog –predicate 'process == "PrivilegesDaemon" && eventMessage BEGINSWITH "SAPCorp: U"' –last 1m | tail -1 >> "$logs" | |
SendToSlack ${logs} ${slack_webhook} | |
exit "$exit_error" |
privileges_teams_report.sh
When configured with a Teams webhook URL, the following script should send a report similar to the one below to the relevant Teams channel.
#!/bin/bash | |
# This script will send a report to a Teams channel with information about the user who has been granted admin rights. | |
# You'll need to set up a Teams webhook to receive the information being sent by the script. | |
# If you need help with configuring a Teams webhook, please see the links below: | |
# | |
# https://learn.microsoft.com/en-us/microsoftteams/platform/webhooks-and-connectors/how-to/add-incoming-webhook | |
# | |
# | |
# Once a Teams webhook is available, the teams_webhook variable should look similar | |
# to this: | |
# teams_webhook="https://companyname.webhook.office.com/webhookb2/7ce853bd-a9e1-462f-ae32-d3d35ed5295d@7c155bae-5207-4bb5-8b58-c43228bc1bb7/IncomingWebhook/8155d8581864479287b68b93f89556ae/651e63f8-2d96-42ab-bb51-65cb05fc62aa" | |
teams_webhook="" | |
# That should be it for the necessary configuration part. | |
# Nothing else should need to be edited below this line. | |
name=$(hostname) | |
logs=$(mktemp) | |
logged_in_user=$(id -un) | |
# Set script exit status | |
exit_error=0 | |
# Function for sending multi-line output to a Teams webhook. We add an extra Return to | |
# each line of the log file ($1) to prevent Teams from showing the log on a single line. | |
# The Teams Card format requires JSON to be sent to the Teams webhook ($2). | |
# You can add a title to the Card by specifying it as a third argument. | |
SendToTeams(){ | |
LOG_TEXT=$( cat "$1" | sed "s/\"/'/g" | sed "s/$/\r\r/g" ) | |
TEAMS_JSON='{ | |
"type": "message", | |
"attachments": [{ | |
"contentType": "application/vnd.microsoft.card.adaptive", | |
"contentUrl": null, | |
"content": { | |
"$schema": "http://adaptivecards.io/schemas/adaptive-card.json", | |
"type": "AdaptiveCard", | |
"version": "1.4", | |
"msteams": {"width": "Full"}, | |
"body": [ | |
{"type": "TextBlock", "text": "'$3'", "weight": "bolder", "size": "large", "wrap": true}, | |
{"type": "TextBlock", "text": "'$LOG_TEXT'", "wrap": true}, | |
] | |
} | |
}]}' | |
/usr/bin/curl -H "Content-Type: application/json" -d "${TEAMS_JSON}" "$2" | |
} | |
touch "$logs" | |
echo "Administrator rights have been granted to $logged_in_user using Privileges.app on $name:" >> "$logs" | |
/usr/bin/log show –style syslog –predicate 'process == "PrivilegesDaemon" && eventMessage BEGINSWITH "SAPCorp: U"' –last 1m | tail -1 >> "$logs" | |
SendToTeams ${logs} ${teams_webhook} "Privileges.app Report" | |
exit "$exit_error" |
Example configuration profiles containing the PostChangeExecutablePath and PostChangeActionOnGrantOnly settings are available below:
ConfigurePrivilegesPostActionAppStore.mobileconfig
Settings:
<?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"> | |
<dict> | |
<key>PayloadUUID</key> | |
<string>2857BC2F-FC70-4F9E-B5AE-F1DC56ECC79B</string> | |
<key>PayloadType</key> | |
<string>Configuration</string> | |
<key>PayloadOrganization</key> | |
<string>Company Name</string> | |
<key>PayloadIdentifier</key> | |
<string>2857BC2F-FC70-4F9E-B5AE-F1DC56ECC79B</string> | |
<key>PayloadDisplayName</key> | |
<string>Configure Privileges Post Action App Store</string> | |
<key>PayloadDescription</key> | |
<string>Configure Privileges to launch the Mac App Store as a post action.</string> | |
<key>PayloadVersion</key> | |
<integer>1</integer> | |
<key>PayloadEnabled</key> | |
<true/> | |
<key>PayloadRemovalDisallowed</key> | |
<true/> | |
<key>PayloadScope</key> | |
<string>System</string> | |
<key>PayloadContent</key> | |
<array> | |
<dict> | |
<key>PayloadDisplayName</key> | |
<string>Custom Settings</string> | |
<key>PayloadIdentifier</key> | |
<string>C667AE87-34F2-4CC4-B87E-70242EFD6E50</string> | |
<key>PayloadOrganization</key> | |
<string>Company Name</string> | |
<key>PayloadType</key> | |
<string>com.apple.ManagedClient.preferences</string> | |
<key>PayloadUUID</key> | |
<string>C667AE87-34F2-4CC4-B87E-70242EFD6E50</string> | |
<key>PayloadVersion</key> | |
<integer>1</integer> | |
<key>PayloadContent</key> | |
<dict> | |
<key>corp.sap.privileges</key> | |
<dict> | |
<key>Forced</key> | |
<array> | |
<dict> | |
<key>mcx_preference_settings</key> | |
<dict> | |
<key>PostChangeActionOnGrantOnly</key> | |
<false/> | |
<key>PostChangeExecutablePath</key> | |
<string>/System/Applications/App Store.app</string> | |
</dict> | |
</dict> | |
</array> | |
</dict> | |
</dict> | |
</dict> | |
</array> | |
</dict> | |
</plist> |
ConfigurePrivilegesPostActionReportScript.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"> | |
<dict> | |
<key>PayloadUUID</key> | |
<string>3DD0FB5F-F238-455D-AF43-843BB4111126</string> | |
<key>PayloadType</key> | |
<string>Configuration</string> | |
<key>PayloadOrganization</key> | |
<string>Company Name</string> | |
<key>PayloadIdentifier</key> | |
<string>3DD0FB5F-F238-455D-AF43-843BB4111126</string> | |
<key>PayloadDisplayName</key> | |
<string>Configure Privileges Post Action Report Script</string> | |
<key>PayloadDescription</key> | |
<string>Configure Privileges to launch a reporting script as a post action only when admin rights are granted.</string> | |
<key>PayloadVersion</key> | |
<integer>1</integer> | |
<key>PayloadEnabled</key> | |
<true/> | |
<key>PayloadRemovalDisallowed</key> | |
<true/> | |
<key>PayloadScope</key> | |
<string>System</string> | |
<key>PayloadContent</key> | |
<array> | |
<dict> | |
<key>PayloadDisplayName</key> | |
<string>Custom Settings</string> | |
<key>PayloadIdentifier</key> | |
<string>B4D8564A-217C-42E3-AD69-23967AF22B84</string> | |
<key>PayloadOrganization</key> | |
<string>Company Name</string> | |
<key>PayloadType</key> | |
<string>com.apple.ManagedClient.preferences</string> | |
<key>PayloadUUID</key> | |
<string>B4D8564A-217C-42E3-AD69-23967AF22B84</string> | |
<key>PayloadVersion</key> | |
<integer>1</integer> | |
<key>PayloadContent</key> | |
<dict> | |
<key>corp.sap.privileges</key> | |
<dict> | |
<key>Forced</key> | |
<array> | |
<dict> | |
<key>mcx_preference_settings</key> | |
<dict> | |
<key>PostChangeActionOnGrantOnly</key> | |
<true/> | |
<key>PostChangeExecutablePath</key> | |
<string>/path/to/reporting_script.sh</string> | |
</dict> | |
</dict> | |
</array> | |
</dict> | |
</dict> | |
</dict> | |
</array> | |
</dict> | |
</plist> |
By default, Privileges 2.x will grant administrator rights for 20 minutes if not configured otherwise.
But what if you want to configure it otherwise? There are management options available for this. For more details, please see below the jump.
The relevant preference domain and key values are listed below:
<?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>ExpirationInterval</key> | |
<integer>15</integer> | |
</dict> | |
</plist> |
<?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>ExpirationIntervalMax</key> | |
<integer>20</integer> | |
</dict> | |
</plist> |
Note: In both cases, the positive integer values are defining time in minutes.
ExpirationInterval:
The ExpirationInterval key defines a set time in minutes after which administrator rights expire and the logged-in user reverts to using standard user rights. For example, setting ExpirationInterval to a value of 15 would set Privileges to allow admin rights for fifteen minutes. Once the fifteen minutes are up, the logged-in user reverts to using standard user rights.
In this example, the Administrator privileges expire setting in the Privileges settings would be set to the defined value and grayed out.
Note: Setting a value of 0 disables the timeout and allows the user to request administrator privileges which do not expire.
ExpirationIntervalMax:
The ExpirationIntervalMax key defines a set time in minutes after which administrator rights expire and the logged-in user reverts to using standard user rights. In general, this works like the ExpirationInterval key but it allows the logged-in user to choose a timeout value which is different as long it does not exceed the defined value.
For example, setting ExpirationIntervalMax to a value of 20 would set Privileges to allow admin rights for twenty minutes. However, the logged-in user can go into the Privileges settings and set a different time interval for the Administrator privileges expire setting as long as that time interval does not exceed the defined value of twenty minutes.
Note: In the event that both the ExpirationInterval and ExpirationIntervalMax settings are set, as of Privileges 2.0 the ExpirationInterval behavior will be applied. The Administrator privileges expire setting in the Privileges settings would be set to the defined value for ExpirationInterval and be grayed out.
The ExpirationInterval and ExpirationIntervalMax settings can be managed by configuration profiles. Please see below for example profiles.
ExpirationInterval:
<?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"> | |
<dict> | |
<key>PayloadUUID</key> | |
<string>B3D51AB8-3307-4CBA-B5B7-0CB590D62797</string> | |
<key>PayloadType</key> | |
<string>Configuration</string> | |
<key>PayloadOrganization</key> | |
<string>Company Name</string> | |
<key>PayloadIdentifier</key> | |
<string>B3D51AB8-3307-4CBA-B5B7-0CB590D62797</string> | |
<key>PayloadDisplayName</key> | |
<string>Configure Privileges Admin Rights Removal Time</string> | |
<key>PayloadDescription</key> | |
<string>Configure Privileges to remove admin rights after the defined time.</string> | |
<key>PayloadVersion</key> | |
<integer>1</integer> | |
<key>PayloadEnabled</key> | |
<true/> | |
<key>PayloadRemovalDisallowed</key> | |
<true/> | |
<key>PayloadScope</key> | |
<string>System</string> | |
<key>PayloadContent</key> | |
<array> | |
<dict> | |
<key>PayloadDisplayName</key> | |
<string>Custom Settings</string> | |
<key>PayloadIdentifier</key> | |
<string>FF229F24-BF06-4CA6-AD95-500A649893FE</string> | |
<key>PayloadOrganization</key> | |
<string>Company Name</string> | |
<key>PayloadType</key> | |
<string>com.apple.ManagedClient.preferences</string> | |
<key>PayloadUUID</key> | |
<string>FF229F24-BF06-4CA6-AD95-500A649893FE</string> | |
<key>PayloadVersion</key> | |
<integer>1</integer> | |
<key>PayloadContent</key> | |
<dict> | |
<key>corp.sap.privileges</key> | |
<dict> | |
<key>Forced</key> | |
<array> | |
<dict> | |
<key>mcx_preference_settings</key> | |
<dict> | |
<key>ExpirationInterval</key> | |
<integer>15</integer> | |
</dict> | |
</dict> | |
</array> | |
</dict> | |
</dict> | |
</dict> | |
</array> | |
</dict> | |
</plist> |
ExpirationIntervalMax:
<?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"> | |
<dict> | |
<key>PayloadUUID</key> | |
<string>71512933-DEB5-4628-BFD9-2BFFF90674E9</string> | |
<key>PayloadType</key> | |
<string>Configuration</string> | |
<key>PayloadOrganization</key> | |
<string>Company Name</string> | |
<key>PayloadIdentifier</key> | |
<string>71512933-DEB5-4628-BFD9-2BFFF90674E9</string> | |
<key>PayloadDisplayName</key> | |
<string>Configure User Adjustable Privileges Admin Rights Removal Time</string> | |
<key>PayloadDescription</key> | |
<string>Configure Privileges to remove admin rights after the defined time with an option for the user to choose a shorter time.</string> | |
<key>PayloadVersion</key> | |
<integer>1</integer> | |
<key>PayloadEnabled</key> | |
<true/> | |
<key>PayloadRemovalDisallowed</key> | |
<true/> | |
<key>PayloadScope</key> | |
<string>System</string> | |
<key>PayloadContent</key> | |
<array> | |
<dict> | |
<key>PayloadDisplayName</key> | |
<string>Custom Settings</string> | |
<key>PayloadIdentifier</key> | |
<string>AD2F05BF-B01C-430F-A395-BEE34A6689C2</string> | |
<key>PayloadOrganization</key> | |
<string>Company Name</string> | |
<key>PayloadType</key> | |
<string>com.apple.ManagedClient.preferences</string> | |
<key>PayloadUUID</key> | |
<string>AD2F05BF-B01C-430F-A395-BEE34A6689C2</string> | |
<key>PayloadVersion</key> | |
<integer>1</integer> | |
<key>PayloadContent</key> | |
<dict> | |
<key>corp.sap.privileges</key> | |
<dict> | |
<key>Forced</key> | |
<array> | |
<dict> | |
<key>mcx_preference_settings</key> | |
<dict> | |
<key>ExpirationIntervalMax</key> | |
<integer>20</integer> | |
</dict> | |
</dict> | |
</array> | |
</dict> | |
</dict> | |
</dict> | |
</array> | |
</dict> | |
</plist> |
For more details, please see below the jump.
Time-limited admin
Privileges 1.x featured a mechanism for setting a time limit, but it was tied specifically to using the Toggle Privileges function. This was discussed in the previous version of the Privileges FAQ:
By default, is there a time limit on the admin rights granted by Privileges?
No. Admin rights are granted until some process (like running Privileges again) takes them away.
Can I set Privileges to give me administrator rights for a defined amount of time?
Yes. You can use the Toggle Privileges option on the dock icon to get admin rights for a set amount of time (the default amount is 20 minutes.)
With Privileges 2.x, time-limited admin is no longer tied exclusively to the Toggle Privileges function. For those who want to set a time limit for granting admin rights, you can now set this and Privileges 2.x will remove admin rights after the set time regardless of if you used the Privileges application, the dock tile or the command line tool to request admin rights.
By default, Privileges 2.x will grant administrator privileges for 20 minutes if not configured otherwise.
This is discussed in the updated Privileges FAQ:
By default, is there a time limit on the admin rights granted by Privileges?
Yes. By default, administrator privileges are granted for 20 minutes (if not configured otherwise). However, if necessary, you can configure Privileges not to remove administrator privileges by setting the expiration interval to “Never” in the app’s settings.
Installer package deployment
Privileges 1.x had an odd issue, where some folks who tried packaging it into an installer package consistently ran into problems. This was partially addressed by using AutoPkg to build the installer package, as AutoPkg-driven workflows consistently produced working installers. SAP has addressed this issue by providing a signed and notarized installer package for Privileges 2.x, which solves the problem by making it unnecessary for Mac admins to create their own installer packages for deployment.
For those using Privileges in your own shops, I recommend taking a look at Privileges 2.x as it includes more features and fixes in addition to what I’ve discussed above. It is available via the following link:
https://github.com/SAP/macOS-enterprise-privileges
For those who want to manage Privileges, please see here for the Managing Privileges documentation:
https://github.com/SAP/macOS-enterprise-privileges/wiki/Managing-Privileges
]]>You can use the FileVault recovery key to authenticate changing your local account to use a new password. Apple has documentation on how to do this available here:
https://support.apple.com/102633 (please see the Reset it using your recovery key instructions)
However, it looks like Apple made a change at the login window for macOS Sequoia. Apple’s instructions reference clicking on a ( ? ) symbol, which doesn’t appear in my testing on Apple Silicon Macs. Without that, how do you access the recovery key entry blank to enter the recovery key?
In the absence of the ( ? ) symbol appearing at the login window, you should be able to use the following keyboard shortcut to get the recovery key entry blank:
Shift+Option+Return
Clicking that combination of keyboard keys on an Apple Silicon Mac should cause the recovery key entry blank to appear at the login screen.
Note: I was not able to verify that this also works on Intel Macs, so please let me know in the comments if Intel Macs have different behavior.
Here’s how the login window should appear when you enter the keyboard shortcut in this scenario:
]]>
/usr/bin/curl -sf –header "Authorization: Bearer bearer_token_goes_here" "https://jamf.pro.server.goes.here/JSSResource/commandflush/mobiledevicegroups/id/group_Jamf_Pro_ID_number_goes_here/status/Failed" -X DELETE |
If you wanted to clear all failed MDM commands for members of a computer group, you could use a command like the one shown below:
/usr/bin/curl -sf –header "Authorization: Bearer bearer_token_goes_here" "https://jamf.pro.server.goes.here/JSSResource/commandflush/computergroups/id/group_Jamf_Pro_ID_number_goes_here/status/Failed" -X DELETE |
In both cases, the following API permission would be required:
Flush MDM Commands
If using a user account to authenticate to the API, this permission would be set in Jamf Pro Server Actions:
If using an API client to authenticate to the API, this permission would be set in an API role:
For folks who want to use this method to clear failed API commands, I’ve written a couple of scripts to assist with this. For more details, please see below the jump.
I’ve posted both scripts to the following location:
Both scripts are designed to use API client authentication, with the following permissions assigned:
clear_failed_Jamf_Pro_mdm_commands_from_computer_group.sh
clear_failed_Jamf_Pro_mdm_commands_from_mobile_device_group.sh
Both scripts are designed to use the Jamf Pro ID number for a specified Jamf Pro smart or static group to do the following:
The scripts will produce errors in the following cases:
Successful output should look like this for the following scripts:
clear_failed_Jamf_Pro_mdm_commands_from_computer_group.sh
username@computername ~ % /path/to/clear_failed_Jamf_Pro_mdm_commands_from_computer_group.sh | |
Please enter your Jamf Pro server URL : https://jamf.pro.server.goes.here | |
Please enter your Jamf Pro API client ID : 7eda98e3-12ea-469c-8c45-4e070b5003cb | |
Please enter the API client secret for the 7eda98e3-12ea-469c-8c45-4e070b5003cb API ID client: | |
The smart or static computer group you want to clear failed MDM commands from has not been specified. | |
Please enter the Jamf Pro ID of the smart or static computer group : 1 | |
Clearing failed MDM commmands from members of the following group: All Managed Clients | |
<?xml version="1.0" encoding="UTF-8"?><commandflush><status>+failed</status><computer_groups>[1]</computer_groups></commandflush> | |
Failed MDM commands successfully cleared from members of the following group: All Managed Clients | |
username@computername ~ % |
clear_failed_Jamf_Pro_mdm_commands_from_mobile_device_group.sh
username@computername ~ % /path/to/clear_failed_Jamf_Pro_mdm_commands_from_mobile_device_group.sh | |
Please enter your Jamf Pro server URL : https://jamf.pro.server.goes.here | |
Please enter your Jamf Pro API client ID : 7eda98e3-12ea-469c-8c45-4e070b5003cb | |
Please enter the API client secret for the 7eda98e3-12ea-469c-8c45-4e070b5003cb API ID client: | |
The smart or static mobile device group you want to clear failed MDM commands from has not been specified. | |
Please enter the Jamf Pro ID of the smart or static mobile device group : 1 | |
Clearing failed MDM commmands from members of the following group: All Managed Apple TVs | |
<?xml version="1.0" encoding="UTF-8"?><commandflush><status>+failed</status><mobile_device_groups>[1]</mobile_device_groups></commandflush> | |
Failed MDM commands successfully cleared from members of the following group: All Managed Apple TVs | |
username@computername ~ % |