Home > iOS, Jamf Pro, Mac administration, macOS, Management Profiles, Scripting > Backing up configuration profiles from Jamf Pro

Backing up configuration profiles from Jamf Pro

When working with configuration profiles on Jamf Pro, I prefer to download and back them up to GitHub or a similar internal source control tool. The reasons I do this are the following:

  1. I have an off-server backup for the profiles
  2. I can track changes to the profiles

Up until recently, this had been a manual process for me where I would download the profiles in question from the server and then upload them to my source control tool.

My process looked like this:

1. Download the profiles from the Jamf Pro server using the Download button.

Screen Shot 2018 11 15 at 3 47 35 PM

2. Remove the code-signing and formatting the profile using a process similar to the one described in the link below:

https://macmule.com/2015/11/16/making-downloaded-jss-configuration-profiles-readable/

3. Move the profile to the correct directory in my source control repo.
4. Review changes and commit to the repo.

However, as I’ve started using profiles more, this process got cumbersome and I wanted to automate at least the download part of the process. After some work, I was able to build two scripts which do the following:

  1. Use the Jamf Pro API to identify the Jamf Pro ID numbers of the configuration profiles.
  2. Download each profile using its Jamf Pro ID number
  3. Decode and format the profile
  4. Identify the display name of the profile
  5. Save the profile as Display Name Here.mobileconfig to a specified download directory.

For more details, please see below the jump.

I’ve written two scripts for this purpose:

  • Jamf_Pro_Mac_Configuration_Profile_Download.sh – This script is designed to download and handle macOS configuration profiles
  • Jamf_Pro_Mobile_Device_Configuration_Profile_Download.sh – This script is designed to download and handle iOS and tvOS configuration profiles

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 profiles:

/path/to/Jamf_Pro_Mac_Configuration_Profile_Download.sh

To download iOS and tvOS profiles:

/path/to/Jamf_Pro_Mobile_Device_Configuration_Profile_Download.sh

When run, you should see output similar to that shown below.

computername:~ username$ /path/to/Jamf_Pro_Mac_Configuration_Profile_Download.sh
A location to store downloaded profiles has not been specified.
Downloaded profiles will be stored in /var/folders/q6/z5m752w547sbrcjqwd0783340000kt/T/tmp.tgGWC4Te.
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 Configuration Profile…
Downloaded profile is named: Remove Shutdown menu from Apple menu
Saving Remove Shutdown menu from Apple menu.mobileconfig file to /var/folders/q6/z5m752w547sbrcjqwd0783340000kt/T/tmp.tgGWC4Te.
Downloading Configuration Profile…
Downloaded profile is named: Redirect FileVault 2 keys to JSS for Sierra
Saving Redirect FileVault 2 keys to JSS for Sierra.mobileconfig file to /var/folders/q6/z5m752w547sbrcjqwd0783340000kt/T/tmp.tgGWC4Te.
Downloading Configuration Profile…
Downloaded profile is named: Restrict iCloud Document Syncing
Saving Restrict iCloud Document Syncing.mobileconfig file to /var/folders/q6/z5m752w547sbrcjqwd0783340000kt/T/tmp.tgGWC4Te.
Downloading Configuration Profile…
Downloaded profile is named: FileVault recovery key redirection
Saving FileVault recovery key redirection.mobileconfig file to /var/folders/q6/z5m752w547sbrcjqwd0783340000kt/T/tmp.tgGWC4Te.
Downloading Configuration Profile…
Downloaded profile is named: Approved Kernel Extensions
Saving Approved Kernel Extensions.mobileconfig file to /var/folders/q6/z5m752w547sbrcjqwd0783340000kt/T/tmp.tgGWC4Te.
computername:~ username$

view raw
gistfile1.txt
hosted with ❤ by GitHub

Screen Shot 2018 11 15 at 3 11 38 PM

The profiles themselves will be stored in either a user-specified directory or, if no directory is specified, a directory created by the script.

Screen Shot 2018 11 15 at 3 13 02 PM

The scripts are available below, and at the following addresses on GitHub:

https://github.com/rtrouton/rtrouton_scripts/tree/master/rtrouton_scripts/Casper_Scripts/Jamf_Pro_Mac_Configuration_Profile_Download

https://github.com/rtrouton/rtrouton_scripts/tree/master/rtrouton_scripts/Casper_Scripts/Jamf_Pro_Mobile_Device_Configuration_Profile_Download

Jamf_Pro_Mac_Configuration_Profile_Download.sh:

#!/bin/bash
# This script is designed to use the Jamf Pro API to identify the individual IDs of
# the macOS configuration profiles stored on a Jamf Pro server then download, decode
# and properly format the profiles as .mobileconfig files.
# 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:
#
# macOS Configuration Profiles: Read
# If you choose to specify a directory to save the downloaded profiles into,
# please enter the complete directory path into the ProfileDownloadDirectory
# variable below.
ProfileDownloadDirectory=""
# If the ProfileDownloadDirectory isn't specified above, a directory will be
# created and the complete directory path displayed by the script.
if [[ -z "$ProfileDownloadDirectory" ]]; then
ProfileDownloadDirectory=$(mktemp -d)
echo "A location to store downloaded profiles has not been specified."
echo "Downloaded profiles will be stored in $ProfileDownloadDirectory."
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 ProfileDownloadDirectory variable if needed.
ProfileDownloadDirectory=${ProfileDownloadDirectory%%/}
DownloadProfile(){
# Download the profile as encoded XML, then decode and format it
echo "Downloading Configuration Profile…"
FormattedProfile=$(curl -su "${jamfpro_user}:${jamfpro_password}" -H "Accept: application/xml" "${jamfpro_url}/JSSResource/osxconfigurationprofiles/id/${ID}" -X GET | xpath '/os_x_configuration_profile/general/payloads/text()' 2>/dev/null | perl -MHTML::Entities -pe 'decode_entities($_);' | xmllint –format –)
# Identify and display the profile's name
DisplayName=$(echo "$FormattedProfile" | awk -F'>|<' '/PayloadDisplayName/{getline; print $3; exit}')
echo "Downloaded profile is named: $DisplayName"
# Save the downloaded profile
echo "Saving ${DisplayName}.mobileconfig file to $ProfileDownloadDirectory."
echo "$FormattedProfile" > "$ProfileDownloadDirectory/${DisplayName}.mobileconfig"
}
profiles_id_list=$(curl -su "${jamfpro_user}:${jamfpro_password}" -H "Accept: application/xml" "${jamfpro_url}/JSSResource/osxconfigurationprofiles" | xpath //os_x_configuration_profile/id 2>/dev/null)
profiles_id=$(echo "$profiles_id_list" | grep -Eo "[0-9]+")
for ID in ${profiles_id}; do
DownloadProfile
done

Jamf_Pro_Mobile_Device_Configuration_Profile_Download.sh:

#!/bin/bash
# This script is designed to use the Jamf Pro API to identify the individual IDs of
# the iOS and tvOS configuration profiles stored on a Jamf Pro server then download,
# decode and properly format the profiles as .mobileconfig files.
# 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:
#
# Mobile Device Configuration Profiles: Read
# If you choose to specify a directory to save the downloaded profiles into,
# please enter the complete directory path into the ProfileDownloadDirectory
# variable below.
ProfileDownloadDirectory=""
# If the ProfileDownloadDirectory isn't specified above, a directory will be
# created and the complete directory path displayed by the script.
if [[ -z "$ProfileDownloadDirectory" ]]; then
ProfileDownloadDirectory=$(mktemp -d)
echo "A location to store downloaded profiles has not been specified."
echo "Downloaded profiles will be stored in $ProfileDownloadDirectory."
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 ProfileDownloadDirectory variable if needed.
ProfileDownloadDirectory=${ProfileDownloadDirectory%%/}
DownloadProfile(){
# Download the profile as encoded XML, then decode and format it
echo "Downloading Configuration Profile…"
FormattedProfile=$(curl -su "${jamfpro_user}:${jamfpro_password}" -H "Accept: application/xml" "${jamfpro_url}/JSSResource/mobiledeviceconfigurationprofiles/id/${ID}" -X GET | xpath '/configuration_profile/general/payloads/text()' 2>/dev/null | perl -MHTML::Entities -pe 'decode_entities($_);' | xmllint –format –)
# Identify and display the profile's name
DisplayName=$(echo "$FormattedProfile" | awk -F'>|<' '/PayloadDisplayName/{getline; print $3; exit}')
echo "Downloaded profile is named: $DisplayName"
# Save the downloaded profile
echo "Saving ${DisplayName}.mobileconfig file to $ProfileDownloadDirectory."
echo "$FormattedProfile" > "$ProfileDownloadDirectory/${DisplayName}.mobileconfig"
}
profiles_id_list=$(curl -su "${jamfpro_user}:${jamfpro_password}" -H "Accept: application/xml" "${jamfpro_url}/JSSResource/mobiledeviceconfigurationprofiles" | xpath //configuration_profile/id 2>/dev/null)
profiles_id=$(echo "$profiles_id_list" | grep -Eo "[0-9]+")
for ID in ${profiles_id}; do
DownloadProfile
done

  1. Art Rathke
    December 20, 2018 at 4:12 pm

    Rich – these four backup scripts are great, Thanks. Are you working on one for policies, too? I could use that right now. Art

  2. Art Rathke
    December 20, 2018 at 4:29 pm

    Found it in GitHub – Thanks.

  3. Art Rathke
    December 20, 2018 at 7:22 pm

    I found where the scripts are in GitHub, I’m hoping you’ll do a script for policies. It would be nice to have the scope info and payloads.

    The other thing that would be nice in Jamf would be to have a where-used for groups and packages and scripts.

  4. March 18, 2019 at 2:39 pm

    Hey Rich. . .just to let you know, the script as it’s presented on GitHub has the ProfileDownloadDirectory variable populated with your(?) GitHub path. However, as presented here in your blog it appears to be fine.

    • March 18, 2019 at 2:44 pm

      Fixed. Thanks for the heads-up!

  1. No trackbacks yet.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: