Skip to content

Instantly share code, notes, and snippets.

@lazymacadmin
Created February 22, 2024 18:48
Show Gist options
  • Save lazymacadmin/d4be46c2a782f34e1443e7714bfd22b4 to your computer and use it in GitHub Desktop.
Save lazymacadmin/d4be46c2a782f34e1443e7714bfd22b4 to your computer and use it in GitHub Desktop.
A script to sync an on-premise distribution from your JCDS
#!/bin/zsh
## Bits shamelessly borrowed from Graham Pugh - https://gist.github.com/grahampugh/836547859c18fefe1dba6ba8c093accc
## Then reversed to only pull down files which either do not exist in the DP or whose md5 doesn't match
##
## This script relies on a Jamf API role/client and a local identity file of the following format:
## {"client_name":"test_for_screenshot","client_id":"a7682e67-a276-448b-83af-9c83be5e02f4","client_secret":"ubPrXqRRyc0jRLFOY9iJYGpCjHiJc1M-tRLlCFb9aWZhtqf7iC9UpQG_dO1ZkvNF","grant_type":"client_credentials"}
##
## This is most easily obtained by creating an api client, enabling it and copying the data from the popup, then pasting it into a file
##
##
usage() {
echo "Usage: sync_jcds_local_dp.zsh --id /path/to/identity_file --jss your.jamf.server --localpath /path/to/dp/share --log /path/to/log/file"
echo "(don't include https:// but do include the port if needed)"
}
logStatement(){
# Function to log informational output for review
echo "$(date) - $1" >> "$logFile"
}
## Borrowed from https://gist.github.com/lucasad/6474224
urlencode() {
setopt localoptions extendedglob
input=( ${(s::)1} )
print ${(j::)input/(#b)([^A-Za-z0-9_.\!~*\'\(\)-])/%${(l:2::0:)$(([##16]#match))}}
}
getToken() {
client_id=$(plutil -extract client_id raw "$identity_file")
client_secret=$(plutil -extract client_secret raw "$identity_file")
cred_type=$(plutil -extract grant_type raw "$identity_file")
token=$(curl --silent --location --request POST "${jss_url}/api/oauth/token" \
--header "Content-Type: application/x-www-form-urlencoded" \
--data-urlencode "client_id=${client_id}" \
--data-urlencode "grant_type=${cred_type}" \
--data-urlencode "client_secret=${client_secret}" \
| plutil -extract access_token raw -)
# echo "$token"
}
getPackageList(){
# list all the packages
echo "Getting a list of packages from JCDS"
logStatement "Getting a list of packages from JCDS"
getToken
http_response=$(
curl --request GET \
--silent \
--header "authorization: Bearer $token" \
--header 'Accept: application/json' \
"$jss_url/api/v1/jcds/files" \
--write-out "%{http_code}" \
--output "$output_file_list"
)
logStatement "Package List response code: $http_response"
# echo "HTTP response: $http_response"
}
syncPackages(){
if [[ $http_response -eq 200 ]]; then
# convert the list to a plist so we can actually work with it in bash
plutil -convert xml1 "$output_file_list"
# count the number of items in the list
pkg_count=$(grep -c fileName "$output_file_list")
# loop through each item in the JSON response
jcds_pkg=""
jcds_pkg_md5="" # assign empty value to avoid errors
local_pkg=""
local_pkg_md5=""
echo "Looping through $pkg_count files"
for ((i=1; i<=pkg_count; i++)); do
jcds_pkg=$(/usr/libexec/PlistBuddy -c "Print :$i:fileName" "$output_file_list")
jcds_pkg_md5=$(/usr/libexec/PlistBuddy -c "Print :$i:md5" "$output_file_list")
local_pkg="${rsync_path}/${jcds_pkg}"
if [ -f "${local_pkg}" ]; then
local_pkg_md5=$(md5 -q "${local_pkg}")
fi
if [[ "$local_pkg_md5" == "$jcds_pkg_md5" ]]; then
echo "$jcds_pkg is the same"
logStatement "$jcds_pkg is the same"
else
getToken
# urlencode package names for paces
download_pkg=$(urlencode "$jcds_pkg")
# retrieve the download URL from the API endpoint
get_download_url=$(curl --request GET \
--silent \
--location \
--header "authorization: Bearer $token" \
--header 'Accept: application/json' \
"$jss_url/api/v1/jcds/files/${download_pkg}" )
download_url=$(echo "$get_download_url" | plutil -extract uri raw -)
# Get the file, please
echo "Downloading $jcds_pkg ..."
logStatement "Downloading $jcds_pkg ..."
curl "${download_url}" -o "${rsync_path}/${jcds_pkg}"
fi
done
fi
}
while test $# -gt 0 ; do
case "$1" in
-i|--id)
shift
identity_file="$1"
;;
--localpath)
shift
rsync_path="$1"
;;
--log)
shift
logFile="$1"
;;
--jss)
shift
jss="$1"
;;
*)
usage
exit
;;
esac
shift
done
if [[ ! "$identity_file" || ! "$rsync_path" ]]; then
usage
exit
fi
jss_url="https://${jss}"
output_file_list="/tmp/jcds.txt"
getPackageList
syncPackages
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment