Home > Jamf Pro, Jamf Pro API, Mac administration, macOS, Scripting > Backing up macOS scripts from Jamf Pro

Backing up macOS scripts from Jamf Pro

When working with scripts for managing Macs on Jamf Pro, I prefer to download then and back them up to GitHub or a similar internal source control tool. The reason I do this is the following:

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

While I’ve usually had copies of the scripts stored elsewhere, sometimes I would make changes to the scripts on Jamf Pro and then not update the offline copy of the scripts with my changes. Being able to download them from my Jamf Pro server would mean that I could always have a copy of the latest version of the script in production.

To help me with this, I’ve written a script to do the following:

  1. Use the Jamf Pro API to identify the Jamf Pro ID numbers of the scripts.
  2. Download each script using its Jamf Pro ID number as raw XML.
  3. Format the downloaded XML
  4. Identify the display name of the script
  5. Extract the script from the downloaded XML
  6. Save the script as Display Name Goes Here to a specified download directory.

For more details, please see below the jump.

For authentication, the download script 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

To run the download script:

/path/to/Jamf_Pro_Computer_Script_Download.sh

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


computername:~ username$ /path/to/Jamf_Pro_Computer_Script_Download.sh
A location to store downloaded groups has not been specified.
Downloaded groups will be stored in /var/folders/q6/z5m752w547sbrcjqwd0783340000kt/T/tmp.d1B9dIG9.
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 scripts from https://jamfpro.server.here:8443…
Downloaded script is named: Selectable_SoftwareUpdate.sh
Saving Selectable_SoftwareUpdate.sh file to /var/folders/q6/z5m752w547sbrcjqwd0783340000kt/T/tmp.d1B9dIG9.
Downloading scripts from https://jamfpro.server.here:8443…
Downloaded script is named: iscasperonline.sh
Saving iscasperonline.sh file to /var/folders/q6/z5m752w547sbrcjqwd0783340000kt/T/tmp.d1B9dIG9.
Downloading scripts from https://jamfpro.server.here:8443…
Downloaded script is named: xcode_post_install.sh
Saving xcode_post_install.sh file to /var/folders/q6/z5m752w547sbrcjqwd0783340000kt/T/tmp.d1B9dIG9.
Downloading scripts from https://jamfpro.server.here:8443…
Downloaded script is named: xcode_uninstall.sh
Saving xcode_uninstall.sh file to /var/folders/q6/z5m752w547sbrcjqwd0783340000kt/T/tmp.d1B9dIG9.
Downloading scripts from https://jamfpro.server.here:8443…
Downloaded script is named: disable_apple_icloud_and_diagnostic_pop_ups.sh
Saving disable_apple_icloud_and_diagnostic_pop_ups.sh file to /var/folders/q6/z5m752w547sbrcjqwd0783340000kt/T/tmp.d1B9dIG9.
Downloading scripts from https://jamfpro.server.here:8443…
Downloaded script is named: TextMate2Preinstall.sh
Saving TextMate2Preinstall.sh file to /var/folders/q6/z5m752w547sbrcjqwd0783340000kt/T/tmp.d1B9dIG9.
Downloading scripts from https://jamfpro.server.here:8443…
Downloaded script is named: manual_trigger.sh
Saving manual_trigger.sh file to /var/folders/q6/z5m752w547sbrcjqwd0783340000kt/T/tmp.d1B9dIG9.
Downloading scripts from https://jamfpro.server.here:8443…
Downloaded script is named: open_website_via_self_service.sh
Saving open_website_via_self_service.sh file to /var/folders/q6/z5m752w547sbrcjqwd0783340000kt/T/tmp.d1B9dIG9.
Downloading scripts from https://jamfpro.server.here:8443…
Downloaded script is named: open_macappstore_address_via_self_service.sh
Saving open_macappstore_address_via_self_service.sh file to /var/folders/q6/z5m752w547sbrcjqwd0783340000kt/T/tmp.d1B9dIG9.
computername:~ username$

view raw

gistfile1.txt

hosted with ❤ by GitHub

Screen Shot 2018 12 07 at 10 17 02 PM

The downloaded scripts 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 12 07 at 10 17 09 PM

The download script is available below, and at the following address on GitHub:

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

Jamf_Pro_Computer_Script_Download.sh:


#!/bin/bash
# This script is designed to use the Jamf Pro API to identify the individual IDs of
# the scripts stored on a Jamf Pro server then do the following:
#
# 1. Download the script as XML
# 2. Identify the script name
# 3. Extract the script contents from the downloaded XML
# 4. Save the script 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:
#
# Scripts: Read
# If you choose to specify a directory to save the downloaded scripts into,
# please enter the complete directory path into the ScriptDownloadDirectory
# variable below.
ScriptDownloadDirectory=""
# If the ScriptDownloadDirectory isn't specified above, a directory will be
# created and the complete directory path displayed by the script.
if [[ -z "$ScriptDownloadDirectory" ]]; then
ScriptDownloadDirectory=$(mktemp -d)
echo "A location to store downloaded scripts has not been specified."
echo "Downloaded scripts will be stored in $ScriptDownloadDirectory."
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 ScriptDownloadDirectory variable if needed.
ScriptDownloadDirectory=${ScriptDownloadDirectory%%/}
DownloadScript(){
# Download the script information as raw XML,
# then format it to be readable.
echo "Downloading scripts from $jamfpro_url…"
FormattedScript=$(curl -su "${jamfpro_user}:${jamfpro_password}" -H "Accept: application/xml" "${jamfpro_url}/JSSResource/scripts/id/${ID}" -X GET | xmllint –format – )
# Identify and display the script's name.
DisplayName=$(echo "$FormattedScript" | xpath "/script/name/text()" 2>/dev/null | sed -e 's|:|(colon)|g' -e 's/\//\\/g')
echo "Downloaded script is named: $DisplayName"
## Save the downloaded script
echo "Saving ${DisplayName} file to $ScriptDownloadDirectory."
echo "$FormattedScript" | xpath '/script/script_contents/text()' 2>/dev/null | sed -e 's/&lt;/</g' -e 's/&gt;/>/g' -e 's/&quot;/"/g' -e 's/&amp;/\&/g' > "$ScriptDownloadDirectory/${DisplayName}"
}
Script_id_list=$(curl -su "${jamfpro_user}:${jamfpro_password}" -H "Accept: application/xml" "${jamfpro_url}/JSSResource/scripts" | xpath "//id" 2>/dev/null)
Script_id=$(echo "$Script_id_list" | grep -Eo "[0-9]+")
for ID in ${Script_id}; do
DownloadScript
done

  1. joelifer
    January 25, 2019 at 4:17 pm

    Well you’ve gone and done it again. Can’t thank you enough for this. Burned half a day yesterday trying to get git2jss working when all I wanted was to download my scripts and put them in a repo for backup. This took all of 5 minutes.

  2. Fabien EDU-CONUSF
    November 3, 2020 at 8:57 am

    Thanks a lot for this !

    I get an error when running the script though :

    sed: RE error: illegal byte sequence

    I apparently doesn’t prevent the script from downloading my scripts and they do seem ok… but an error like this doesn’t feel good…

  3. Fabien EDU-CONUSF
    November 3, 2020 at 10:01 am

    I’m replying to myself, as I’ve figured it out. The problem is that xpath does not handle accented characters very well (I’m french-speaking) and passes content to sed that sed cannot handle.

    I’ve modified your script on line 128 to use the encoded script instead and then decode it using base64 :

    echo “$FormattedScript” | xpath ‘/script/script_contents_encoded/text()’ 2>/dev/null | base64 –decode | sed -e ‘s/<//g’ -e ‘s/"/”/g’ -e ‘s/&/\&/g’ > “$ScriptDownloadDirectory/${DisplayName}”

    Now it works like a charm !

  4. John Bowman
    September 30, 2021 at 2:27 pm

    I ran into an issue with this script on my computer running Big Sur 11.6.

    The solution for me was to change line 122 to add a -e flag to the xpath command:

    Script_id_list=$(curl -su “${jamfpro_user}:${jamfpro_password}” -H “Accept: application/xml” “${jamfpro_url}/JSSResource/scripts” | xpath -e “//id” 2>/dev/null)

  5. January 31, 2022 at 1:41 pm

    I also ran into issues and added Johns fix but found Fabiens didnt work. Also had to make some other changes so pasted into a Gist here: https://gist.github.com/monodata/d49cfff26b1cf98790dbb77b2660e544

  6. February 17, 2023 at 8:12 pm

    I am running into issues with the script as of Feb/2023. The script runs, but doesnt post any results. Running it off M2-Pro, with Ventura 13.2.1

  1. No trackbacks yet.

Leave a reply to chris mono Cancel reply