Backing up smart and static groups from Jamf Pro
When working with smart and static groups on Jamf Pro, especially more complex smart groups, I prefer to download then and back them up to GitHub or a similar internal source control tool. The reasons I do this are the following:
- I have an off-server backup for the groups
- I can track changes to the groups
- If needed, I can make a change to a smart group and upload via the API instead of having to edit in the web console.
Up until recently, I didn’t have a good process for handling this but I was able to develop a way as part of working with an engineer from Jamf. After some work, I was able to build two scripts which do the following:
- Use the Jamf Pro API to identify the Jamf Pro ID numbers of the smart and static groups.
- Download each group as an XML file using its Jamf Pro ID number.
- Format the downloaded XML.
- Identify the display name of the group.
- Identify if it was a smart or static group.
- Save the downloaded XML as Group Name Here.xml to a specified download directory, based on whether it was a smart or static group.
For more details, please see below the jump.
I’ve written two scripts for this purpose:
- Jamf_Pro_Computer_Group_Download.sh – This script is designed to download and handle macOS smart and static groups
- Jamf_Pro_Mobile_Device_Group_Download.sh – This script is designed to download and handle iOS and tvOS smart and static groups.
For authentication, the scripts can accept hard-coded values in the script, manual input or values stored in a ~/Library/Preferences/com.github.jamfpro-info.plist file. The plist file can be created by running the following commands and substituting your own values where appropriate:
To store the Jamf Pro URL in the plist file:
defaults write com.github.jamfpro-info jamfpro_url https://jamf.pro.server.goes.here:port_number_goes_here
To store the account username in the plist file:
defaults write com.github.jamfpro-info jamfpro_user account_username_goes_here
To store the account password in the plist file:
defaults write com.github.jamfpro-info jamfpro_password account_password_goes_here
Both scripts run in similar ways, with the main difference being which kind of profiles are being downloaded.
To download macOS smart and static groups:
/path/to/Jamf_Pro_Computer_Group_Download.sh
To download iOS and tvOS smart and static groups:
/path/to/Jamf_Pro_Mobile_Device_Group_Download.sh
When run, you should see output similar to that shown below.
computername:~ username$ /path/to/Jamf_Pro_Computer_Group_Download.sh | |
A location to store downloaded groups has not been specified. | |
Downloaded groups will be stored in /var/folders/q6/z5m752w547sbrcjqwd0783340000kt/T/tmp.70KOogoR. | |
Please enter your Jamf Pro server URL : https://jamfpro.server.here:8443 | |
Please enter your Jamf Pro user account : jamfproadmin | |
Please enter the password for the jamfproadmin account: | |
Downloading computer group from https://jamfpro.server.here:8443… | |
Downloaded computer group is named: 10.11.x Macs | |
10.11.x Macs is a Smart group. | |
Saving 10.11.x Macs.xml file to /var/folders/q6/z5m752w547sbrcjqwd0783340000kt/T/tmp.70KOogoR/Smart Groups. | |
Downloading computer group from https://jamfpro.server.here:8443… | |
Downloaded computer group is named: 10.12.x Macs | |
10.12.x Macs is a Smart group. | |
Saving 10.12.x Macs.xml file to /var/folders/q6/z5m752w547sbrcjqwd0783340000kt/T/tmp.70KOogoR/Smart Groups. | |
Downloading computer group from https://jamfpro.server.here:8443… | |
Downloaded computer group is named: 10.13.x Macs | |
10.13.x Macs is a Smart group. | |
Saving 10.13.x Macs.xml file to /var/folders/q6/z5m752w547sbrcjqwd0783340000kt/T/tmp.70KOogoR/Smart Groups. | |
Downloading computer group from https://jamfpro.server.here:8443… | |
Downloaded computer group is named: 10.14.x Macs | |
10.14.x Macs is a Smart group. | |
Saving 10.14.x Macs.xml file to /var/folders/q6/z5m752w547sbrcjqwd0783340000kt/T/tmp.70KOogoR/Smart Groups. | |
Downloading computer group from https://jamfpro.server.here:8443… | |
Downloaded computer group is named: All Managed Clients | |
All Managed Clients is a Smart group. | |
Saving All Managed Clients.xml file to /var/folders/q6/z5m752w547sbrcjqwd0783340000kt/T/tmp.70KOogoR/Smart Groups. | |
Downloading computer group from https://jamfpro.server.here:8443… | |
Downloaded computer group is named: All Managed Servers | |
All Managed Servers is a Smart group. | |
Saving All Managed Servers.xml file to /var/folders/q6/z5m752w547sbrcjqwd0783340000kt/T/tmp.70KOogoR/Smart Groups. | |
Downloading computer group from https://jamfpro.server.here:8443… | |
Downloaded computer group is named: Computers w\o Secure Token | |
Computers w\o Secure Token is a Smart group. | |
Saving Encrypted VMWare.xml file to /var/folders/q6/z5m752w547sbrcjqwd0783340000kt/T/tmp.70KOogoR/Smart Groups. | |
Downloading computer group from https://jamfpro.server.here:8443… | |
Downloaded computer group is named: FileVault 2 Encryption Status | |
FileVault 2 Encryption Status is a Smart group. | |
Saving FileVault 2 Encryption Status.xml file to /var/folders/q6/z5m752w547sbrcjqwd0783340000kt/T/tmp.70KOogoR/Smart Groups. | |
Downloading computer group from https://jamfpro.server.here:8443… | |
Downloaded computer group is named: LessThanMostRecent_VLC | |
LessThanMostRecent_VLC is a Static group. | |
Saving LessThanMostRecent_VLC.xml file to /var/folders/q6/z5m752w547sbrcjqwd0783340000kt/T/tmp.70KOogoR/Static Groups. | |
computername:~ username$ |
The groups themselves will be stored in either a user-specified directory or, if no directory is specified, a directory created by the script. They will be sorted by whether the individual group is a smart or static group.
The scripts are available below, and at the following addresses on GitHub:
Jamf_Pro_Computer_Group_Download.sh:
#!/bin/bash | |
# This script is designed to use the Jamf Pro API to identify the individual IDs of | |
# the computer groups stored on a Jamf Pro server then do the following: | |
# | |
# 1. Download the group information as XML | |
# 2. Remove the group membership from the downloaded XML | |
# 3. Identify the group name | |
# 4. Categorize the downloaded group as either a smart or static computer group | |
# 4. Save the XML to a specified directory | |
# If setting up a specific user account with limited rights, here are the required API privileges | |
# for the account on the Jamf Pro server: | |
# | |
# Jamf Pro Server Objects: | |
# | |
# Smart Computer Groups: Read | |
# Static Computer Groups: Read | |
# If you choose to specify a directory to save the downloaded groups into, | |
# please enter the complete directory path into the ComputerGroupDownloadDirectory | |
# variable below. | |
ComputerGroupDownloadDirectory="" | |
# If the ComputerGroupDownloadDirectory isn't specified above, a directory will be | |
# created and the complete directory path displayed by the script. | |
if [[ -z "$ComputerGroupDownloadDirectory" ]]; then | |
ComputerGroupDownloadDirectory=$(mktemp -d) | |
echo "A location to store downloaded groups has not been specified." | |
echo "Downloaded groups will be stored in $ComputerGroupDownloadDirectory." | |
fi | |
# If you choose to hardcode API information into the script, set one or more of the following values: | |
# | |
# The username for an account on the Jamf Pro server with sufficient API privileges | |
# The password for the account | |
# The Jamf Pro URL | |
# Set the Jamf Pro URL here if you want it hardcoded. | |
jamfpro_url="" | |
# Set the username here if you want it hardcoded. | |
jamfpro_user="" | |
# Set the password here if you want it hardcoded. | |
jamfpro_password="" | |
# If you do not want to hardcode API information into the script, you can also store | |
# these values in a ~/Library/Preferences/com.github.jamfpro-info.plist file. | |
# | |
# To create the file and set the values, run the following commands and substitute | |
# your own values where appropriate: | |
# | |
# To store the Jamf Pro URL in the plist file: | |
# defaults write com.github.jamfpro-info jamfpro_url https://jamf.pro.server.goes.here:port_number_goes_here | |
# | |
# To store the account username in the plist file: | |
# defaults write com.github.jamfpro-info jamfpro_user account_username_goes_here | |
# | |
# To store the account password in the plist file: | |
# defaults write com.github.jamfpro-info jamfpro_password account_password_goes_here | |
# | |
# If the com.github.jamfpro-info.plist file is available, the script will read in the | |
# relevant information from the plist file. | |
if [[ -f "$HOME/Library/Preferences/com.github.jamfpro-info.plist" ]]; then | |
if [[ -z "$jamfpro_url" ]]; then | |
jamfpro_url=$(defaults read $HOME/Library/Preferences/com.github.jamfpro-info jamfpro_url) | |
fi | |
if [[ -z "$jamfpro_user" ]]; then | |
jamfpro_user=$(defaults read $HOME/Library/Preferences/com.github.jamfpro-info jamfpro_user) | |
fi | |
if [[ -z "$jamfpro_password" ]]; then | |
jamfpro_password=$(defaults read $HOME/Library/Preferences/com.github.jamfpro-info jamfpro_password) | |
fi | |
fi | |
# If the Jamf Pro URL, the account username or the account password aren't available | |
# otherwise, you will be prompted to enter the requested URL or account credentials. | |
if [[ -z "$jamfpro_url" ]]; then | |
read -p "Please enter your Jamf Pro server URL : " jamfpro_url | |
fi | |
if [[ -z "$jamfpro_user" ]]; then | |
read -p "Please enter your Jamf Pro user account : " jamfpro_user | |
fi | |
if [[ -z "$jamfpro_password" ]]; then | |
read -p "Please enter the password for the $jamfpro_user account: " -s jamfpro_password | |
fi | |
echo "" | |
# Remove the trailing slash from the Jamf Pro URL if needed. | |
jamfpro_url=${jamfpro_url%%/} | |
# Remove the trailing slash from the ComputerGroupDownloadDirectory variable if needed. | |
ComputerGroupDownloadDirectory=${ComputerGroupDownloadDirectory%%/} | |
DownloadComputerGroup(){ | |
# Download the group information as XML, then strip out | |
# the group membership and format it. | |
echo "Downloading computer group from $jamfpro_url…" | |
FormattedComputerGroup=$(curl -su "${jamfpro_user}:${jamfpro_password}" -H "Accept: application/xml" "${jamfpro_url}/JSSResource/computergroups/id/${ID}" -X GET | tr $'\n' $'\t' | sed -E 's|<computers>.*</computers>||' | tr $'\t' $'\n' | xmllint –format – ) | |
# Identify and display the group's name. | |
DisplayName=$(echo "$FormattedComputerGroup" | xpath "/computer_group/name/text()" 2>/dev/null | sed -e 's|:|(colon)|g' -e 's/\//\\/g') | |
echo "Downloaded computer group is named: $DisplayName" | |
# Identify if it's a smart or static group. | |
if [[ $(echo "$FormattedComputerGroup" | xpath "/computer_group/is_smart/text()" 2>/dev/null) == "true" ]]; then | |
GroupType="Smart" | |
else | |
GroupType="Static" | |
fi | |
# Save the downloaded computer group. | |
echo "$DisplayName is a $GroupType group." | |
echo "Saving ${DisplayName}.xml file to $ComputerGroupDownloadDirectory/$GroupType Groups." | |
if [[ "$GroupType" = "Smart" ]]; then | |
if [[ -d "$ComputerGroupDownloadDirectory/$GroupType Groups" ]]; then | |
echo "$FormattedComputerGroup" > "$ComputerGroupDownloadDirectory/$GroupType Groups/${DisplayName}.xml" | |
else | |
mkdir -p "$ComputerGroupDownloadDirectory/$GroupType Groups" | |
echo "$FormattedComputerGroup" > "$ComputerGroupDownloadDirectory/$GroupType Groups/${DisplayName}.xml" | |
fi | |
elif [[ "$GroupType" = "Static" ]]; then | |
if [[ -d "$ComputerGroupDownloadDirectory/$GroupType Groups" ]]; then | |
echo "$FormattedComputerGroup" > "$ComputerGroupDownloadDirectory/$GroupType Groups/${DisplayName}.xml" | |
else | |
mkdir -p "$ComputerGroupDownloadDirectory/$GroupType Groups" | |
echo "$FormattedComputerGroup" > "$ComputerGroupDownloadDirectory/$GroupType Groups/${DisplayName}.xml" | |
fi | |
fi | |
} | |
ComputerGroup_id_list=$(curl -su "${jamfpro_user}:${jamfpro_password}" -H "Accept: application/xml" "${jamfpro_url}/JSSResource/computergroups" | xpath "//id" 2>/dev/null) | |
ComputerGroup_id=$(echo "$ComputerGroup_id_list" | grep -Eo "[0-9]+") | |
for ID in ${ComputerGroup_id}; do | |
DownloadComputerGroup | |
done |
Jamf_Pro_Mobile_Device_Group_Download.sh:
#!/bin/bash | |
# This script is designed to use the Jamf Pro API to identify the individual IDs of | |
# the mobile device groups stored on a Jamf Pro server then do the following: | |
# | |
# 1. Download the group information as XML | |
# 2. Remove the group membership from the downloaded XML | |
# 3. Identify the group name | |
# 4. Categorize the downloaded group as either a smart or static mobile device group | |
# 4. Save the XML to a specified directory | |
# If setting up a specific user account with limited rights, here are the required API privileges | |
# for the account on the Jamf Pro server: | |
# | |
# Jamf Pro Server Objects: | |
# | |
# Smart Mobile Device Groups: Read | |
# Static Mobile Device Groups: Read | |
# If you choose to specify a directory to save the downloaded groups into, | |
# please enter the complete directory path into the MobileDeviceGroupDownloadDirectory | |
# variable below. | |
MobileDeviceGroupDownloadDirectory="" | |
# If the MobileDeviceGroupDownloadDirectory isn't specified above, a directory will be | |
# created and the complete directory path displayed by the script. | |
if [[ -z "$MobileDeviceGroupDownloadDirectory" ]]; then | |
MobileDeviceGroupDownloadDirectory=$(mktemp -d) | |
echo "A location to store downloaded groups has not been specified." | |
echo "Downloaded groups will be stored in $MobileDeviceGroupDownloadDirectory." | |
fi | |
# If you choose to hardcode API information into the script, set one or more of the following values: | |
# | |
# The username for an account on the Jamf Pro server with sufficient API privileges | |
# The password for the account | |
# The Jamf Pro URL | |
# Set the Jamf Pro URL here if you want it hardcoded. | |
jamfpro_url="" | |
# Set the username here if you want it hardcoded. | |
jamfpro_user="" | |
# Set the password here if you want it hardcoded. | |
jamfpro_password="" | |
# If you do not want to hardcode API information into the script, you can also store | |
# these values in a ~/Library/Preferences/com.github.jamfpro-info.plist file. | |
# | |
# To create the file and set the values, run the following commands and substitute | |
# your own values where appropriate: | |
# | |
# To store the Jamf Pro URL in the plist file: | |
# defaults write com.github.jamfpro-info jamfpro_url https://jamf.pro.server.goes.here:port_number_goes_here | |
# | |
# To store the account username in the plist file: | |
# defaults write com.github.jamfpro-info jamfpro_user account_username_goes_here | |
# | |
# To store the account password in the plist file: | |
# defaults write com.github.jamfpro-info jamfpro_password account_password_goes_here | |
# | |
# If the com.github.jamfpro-info.plist file is available, the script will read in the | |
# relevant information from the plist file. | |
if [[ -f "$HOME/Library/Preferences/com.github.jamfpro-info.plist" ]]; then | |
if [[ -z "$jamfpro_url" ]]; then | |
jamfpro_url=$(defaults read $HOME/Library/Preferences/com.github.jamfpro-info jamfpro_url) | |
fi | |
if [[ -z "$jamfpro_user" ]]; then | |
jamfpro_user=$(defaults read $HOME/Library/Preferences/com.github.jamfpro-info jamfpro_user) | |
fi | |
if [[ -z "$jamfpro_password" ]]; then | |
jamfpro_password=$(defaults read $HOME/Library/Preferences/com.github.jamfpro-info jamfpro_password) | |
fi | |
fi | |
# If the Jamf Pro URL, the account username or the account password aren't available | |
# otherwise, you will be prompted to enter the requested URL or account credentials. | |
if [[ -z "$jamfpro_url" ]]; then | |
read -p "Please enter your Jamf Pro server URL : " jamfpro_url | |
fi | |
if [[ -z "$jamfpro_user" ]]; then | |
read -p "Please enter your Jamf Pro user account : " jamfpro_user | |
fi | |
if [[ -z "$jamfpro_password" ]]; then | |
read -p "Please enter the password for the $jamfpro_user account: " -s jamfpro_password | |
fi | |
echo "" | |
# Remove the trailing slash from the Jamf Pro URL if needed. | |
jamfpro_url=${jamfpro_url%%/} | |
# Remove the trailing slash from the MobileDeviceGroupDownloadDirectory variable if needed. | |
MobileDeviceGroupDownloadDirectory=${MobileDeviceGroupDownloadDirectory%%/} | |
DownloadMobileDeviceGroup(){ | |
# Download the group information as XML, then strip out | |
# the group membership and format it. | |
echo "Downloading mobile device group from $jamfpro_url…" | |
FormattedMobileDeviceGroup=$(curl -su "${jamfpro_user}:${jamfpro_password}" -H "Accept: application/xml" "${jamfpro_url}/JSSResource/mobiledevicegroups/id/${ID}" -X GET | tr $'\n' $'\t' | sed -E 's|<mobile_devices>.*</mobile_devices>||' | tr $'\t' $'\n' | xmllint –format – ) | |
# Identify and display the group's name. | |
DisplayName=$(echo "$FormattedMobileDeviceGroup" | xpath "/mobile_device_group/name/text()" 2>/dev/null | sed -e 's|:|(colon)|g' -e 's/\//\\/g') | |
echo "Downloaded mobile device group is named: $DisplayName" | |
# Identify if it's a smart or static group. | |
if [[ $(echo "$FormattedMobileDeviceGroup" | xpath "/mobile_device_group/is_smart/text()" 2>/dev/null) == "true" ]]; then | |
GroupType="Smart" | |
else | |
GroupType="Static" | |
fi | |
# Save the downloaded mobile device group. | |
echo "$DisplayName is a $GroupType group." | |
echo "Saving ${DisplayName}.xml file to $MobileDeviceGroupDownloadDirectory/$GroupType Groups." | |
if [[ "$GroupType" = "Smart" ]]; then | |
if [[ -d "$MobileDeviceGroupDownloadDirectory/$GroupType Groups" ]]; then | |
echo "$FormattedMobileDeviceGroup" > "$MobileDeviceGroupDownloadDirectory/$GroupType Groups/${DisplayName}.xml" | |
else | |
mkdir -p "$MobileDeviceGroupDownloadDirectory/$GroupType Groups" | |
echo "$FormattedMobileDeviceGroup" > "$MobileDeviceGroupDownloadDirectory/$GroupType Groups/${DisplayName}.xml" | |
fi | |
elif [[ "$GroupType" = "Static" ]]; then | |
if [[ -d "$MobileDeviceGroupDownloadDirectory/$GroupType Groups" ]]; then | |
echo "$FormattedMobileDeviceGroup" > "$MobileDeviceGroupDownloadDirectory/$GroupType Groups/${DisplayName}.xml" | |
else | |
mkdir -p "$MobileDeviceGroupDownloadDirectory/$GroupType Groups" | |
echo "$FormattedMobileDeviceGroup" > "$MobileDeviceGroupDownloadDirectory/$GroupType Groups/${DisplayName}.xml" | |
fi | |
fi | |
} | |
MobileDeviceGroup_id_list=$(curl -su "${jamfpro_user}:${jamfpro_password}" -H "Accept: application/xml" "${jamfpro_url}/JSSResource/mobiledevicegroups" | xpath "//id" 2>/dev/null) | |
MobileDeviceGroup_id=$(echo "$MobileDeviceGroup_id_list" | grep -Eo "[0-9]+") | |
for ID in ${MobileDeviceGroup_id}; do | |
DownloadMobileDeviceGroup | |
done |
Recent Comments