Feature Request - App Installers Support
We have started using Jamf App Installers in more tenants to aid with ongoing patch management. It would be great to be able to copy the settings for App Installers and the Apps themselves to save us time when we create new tenants.
Waiting for a published API endpoint to work with this.
Thanks. Fingers crossed - if anyone else sees this, I created a FR in Jamf Ideas for this last year which you could upvote - https://ideas.jamf.com/ideas/PCAP-I-144
Was about to make the same feature request. 😊 Upvoted PCAP-I-144.
For what it's worth I've taken a look at https://github.com/tyler-tee/JNUC-2023 and wrote this very small script to list existing app installers, maybe its something you can work with? I'm terrible with scripts so don't think I'll be much more of assistance:
#!/usr/bin/env bash
set -e
# === Jamf Pro Settings ===
jamf_url="JAMFPROURL"
jamf_user="JAMFPROUSERNAME"
jamf_pass="JAMFPROPASSWORD"
# === Get Bearer Token ===
echo "Requesting bearer token..."
auth_response=$(curl -s -u "${jamf_user}:${jamf_pass}" \
-X POST "${jamf_url}/api/v1/auth/token")
bearer_token=$(echo "$auth_response" | jq -r .token)
if [[ -z "$bearer_token" || "$bearer_token" == "null" ]]; then
echo "Failed to get bearer token"
echo "$auth_response"
exit 1
fi
echo "Got token"
# === Get all App Installer deployments ===
echo "Fetching App Installer deployments..."
response=$(curl -s -w "\nHTTP_STATUS:%{http_code}\n" \
-X GET "${jamf_url}/api/v1/app-installers/deployments" \
-H "Authorization: Bearer ${bearer_token}" \
-H "Accept: application/json")
http_status=$(echo "$response" | tr -d '\r' | awk -F'HTTP_STATUS:' '{print $2}')
if [[ "$http_status" -eq 200 ]]; then
echo "App Installer deployments:"
echo "$response" | sed '/HTTP_STATUS:/d' | jq .
else
echo "Failed to fetch deployments (HTTP $http_status). Response:"
echo "$response" | sed '/HTTP_STATUS:/d'
exit 1
fi
I also have this small example to create the app installers (in this example hardcoded for Word, Powerpoint and Excel):
#!/usr/bin/env bash
set -e
# === Target Jamf Pro Tenant Settings ===
jamf_url="JAMFPROURL"
jamf_user="JAMFPROUSERNAME"
jamf_pass="JAMFPROPASSWORD"
# === Get Bearer Token ===
echo "Requesting bearer token..."
auth_response=$(curl -s -u "${jamf_user}:${jamf_pass}" \
-X POST "${jamf_url}/api/v1/auth/token")
bearer_token=$(echo "$auth_response" | jq -r .token)
if [[ -z "$bearer_token" || "$bearer_token" == "null" ]]; then
echo "Failed to get bearer token"
echo "$auth_response"
exit 1
fi
echo "Got token"
# === Function to create an App Installer ===
create_installer () {
local name="$1"
local appTitleId="$2"
local categoryId="$3"
local smartGroupId="$4"
local siteId="$5"
local deploymentType="$6"
local updateBehavior="$7"
local enabled="$8"
echo "Creating installer: $name"
payload=$(jq -n \
--arg name "$name" \
--arg appTitleId "$appTitleId" \
--arg categoryId "$categoryId" \
--arg smartGroupId "$smartGroupId" \
--arg siteId "$siteId" \
--arg deploymentType "$deploymentType" \
--arg updateBehavior "$updateBehavior" \
--argjson enabled "$enabled" \
'{
name: $name,
enabled: $enabled,
appTitleId: $appTitleId,
siteId: $siteId,
categoryId: $categoryId,
smartGroupId: $smartGroupId,
deploymentType: $deploymentType,
updateBehavior: $updateBehavior,
installPredefinedConfigProfiles: true
}'
)
response=$(curl -s -w "\nHTTP_STATUS:%{http_code}\n" \
-X POST "${jamf_url}/api/v1/app-installers/deployments" \
-H "Authorization: Bearer ${bearer_token}" \
-H "Content-Type: application/json" \
-d "$payload")
http_status=$(echo "$response" | tr -d '\r' | awk -F'HTTP_STATUS:' '{print $2}')
if [[ "$http_status" -eq 200 || "$http_status" -eq 201 ]]; then
echo "Created $name successfully"
else
echo "Failed to create $name (HTTP $http_status)"
echo "$response" | sed '/HTTP_STATUS:/d'
fi
}
# === Create the three installers ===
create_installer "Microsoft Word 365" "0A6" "3" "1" "-1" "SELF_SERVICE" "AUTOMATIC" true
create_installer "Microsoft PowerPoint 365" "0A3" "3" "1" "-1" "SELF_SERVICE" "AUTOMATIC" true
create_installer "Microsoft Excel 365" "09C" "3" "1" "-1" "SELF_SERVICE" "AUTOMATIC" true
This all seems to work in our environment.
I asked our friend ChatGPT to create a migration script based on the code above (but I haven't tested that one yet!)
#!/usr/bin/env bash
set -e
# === Source and Destination Jamf Pro Settings ===
SRC_JAMF_URL="https://source-tenant.jamfcloud.com"
SRC_JAMF_USER="source_user"
SRC_JAMF_PASS="source_password"
DEST_JAMF_URL="https://destination-tenant.jamfcloud.com"
DEST_JAMF_USER="dest_user"
DEST_JAMF_PASS="dest_password"
# === Function to get bearer token ===
get_token() {
local url="$1"
local user="$2"
local pass="$3"
token=$(curl -s -u "${user}:${pass}" \
-X POST "${url}/api/v1/auth/token" | jq -r .token)
if [[ -z "$token" || "$token" == "null" ]]; then
echo "Failed to get bearer token for $url"
exit 1
fi
echo "$token"
}
# === Get tokens ===
echo "Requesting token for source tenant..."
SRC_TOKEN=$(get_token "$SRC_JAMF_URL" "$SRC_JAMF_USER" "$SRC_JAMF_PASS")
echo "Got source token"
echo "Requesting token for destination tenant..."
DEST_TOKEN=$(get_token "$DEST_JAMF_URL" "$DEST_JAMF_USER" "$DEST_JAMF_PASS")
echo "Got destination token"
# === Fetch App Installers from source tenant ===
echo "Fetching App Installers from source tenant..."
SRC_RESPONSE=$(curl -s -H "Authorization: Bearer ${SRC_TOKEN}" \
-H "Accept: application/json" \
"${SRC_JAMF_URL}/api/v1/app-installers/deployments")
DEPLOYMENTS=$(echo "$SRC_RESPONSE" | jq -c '.results[]')
# === Loop through each deployment and create in destination tenant ===
echo "Migrating deployments to destination tenant..."
for d in $DEPLOYMENTS; do
name=$(echo "$d" | jq -r .name)
appTitleId=$(echo "$d" | jq -r .app.id)
categoryId=$(echo "$d" | jq -r .category.id)
smartGroupId=$(echo "$d" | jq -r .smartGroup.id)
siteId=$(echo "$d" | jq -r .site.id)
deploymentType=$(echo "$d" | jq -r .deploymentType)
updateBehavior=$(echo "$d" | jq -r .updateBehavior)
enabled=$(echo "$d" | jq -r .enabled)
selfServiceEnabled=$(echo "$d" | jq -r '.selfServiceSettings.enabled // true')
selfServiceCategoryId=$(echo "$d" | jq -r '.selfServiceSettings.categoryId // .category.id')
selfServicePriority=$(echo "$d" | jq -r '.selfServiceSettings.priority // "DEFAULT"')
echo "Creating installer: $name"
payload=$(jq -n \
--arg name "$name" \
--arg appTitleId "$appTitleId" \
--arg categoryId "$categoryId" \
--arg smartGroupId "$smartGroupId" \
--arg siteId "$siteId" \
--arg deploymentType "$deploymentType" \
--arg updateBehavior "$updateBehavior" \
--argjson enabled "$enabled" \
--arg selfServiceCategoryId "$selfServiceCategoryId" \
--arg selfServicePriority "$selfServicePriority" \
'{
name: $name,
enabled: $enabled,
appTitleId: $appTitleId,
siteId: $siteId,
categoryId: $categoryId,
smartGroupId: $smartGroupId,
deploymentType: $deploymentType,
updateBehavior: $updateBehavior,
installPredefinedConfigProfiles: true,
selfServiceSettings: {
enabled: true,
categoryId: $selfServiceCategoryId,
priority: $selfServicePriority
}
}'
)
RESPONSE=$(curl -s -w "\nHTTP_STATUS:%{http_code}\n" \
-X POST "${DEST_JAMF_URL}/api/v1/app-installers/deployments" \
-H "Authorization: Bearer ${DEST_TOKEN}" \
-H "Content-Type: application/json" \
-d "$payload")
HTTP_STATUS=$(echo "$RESPONSE" | tr -d '\r' | awk -F'HTTP_STATUS:' '{print $2}')
if [[ "$HTTP_STATUS" -eq 200 || "$HTTP_STATUS" -eq 201 ]]; then
echo "Created $name successfully"
else
echo "Failed to create $name (HTTP $HTTP_STATUS)"
echo "$RESPONSE" | sed '/HTTP_STATUS:/d'
fi
done
Nice! I've been waiting for those API endpoints to become part of the published Jamf Pro (https://