Skip to content

Instantly share code, notes, and snippets.

@karthikeyan-mac
Created May 30, 2025 09:27
Show Gist options
  • Select an option

  • Save karthikeyan-mac/b7088bcef3b58f9ca88bac0085429a96 to your computer and use it in GitHub Desktop.

Select an option

Save karthikeyan-mac/b7088bcef3b58f9ca88bac0085429a96 to your computer and use it in GitHub Desktop.
This script deletes computers or mobile devices from a Jamf Pro instance using their serial numbers. The serial numbers should be listed in a plain text file (one per line).
#!/bin/bash
#
# Script to delete computers or mobile devices in Jamf Pro by serial number list
# Author: Karthikeyan Marappan
# API Role Privileges: Delete Computers and/or Mobile Devices
#
# *** Note: Please TEST the script with Non Prod Environment*** ##
#
###################### CONFIGURABLE VARIABLES ################################
serialNumberList="$HOME/Desktop/sourceList.txt" # Path to text file with serial numbers
Jamf_URL="https://karthikeyan.jamfcloud.com" # Your Jamf Pro URL
Jamf_URL="${Jamf_URL%/}" # Remove trailing slash if present
client_id="z1bb0a9b-888e-4ae4-88zX-9t402M0402" # Jamf API Client ID
client_secret="AAAxcz6PSynqyyuPfNdY4280i5cgQ3Mq" # Jamf API Client Secret
logFile="/tmp/jamf_delete_devices.log" # Log file location
deviceType="mobile" # Set to "computer" or "mobile"
#############################################################################
countSuccess=0
countFailure=0
successSerial=()
failureSerial=()
touch "$logFile"
log() {
echo "$(date +"%Y-%m-%d %H:%M:%S") - $1" | tee -a "$logFile"
}
# Validate input
if [[ ! -f "$serialNumberList" ]]; then
log "Error: Source file does not exist."
exit 1
elif [[ ! -s "$serialNumberList" ]]; then
log "Error: Source file is empty."
exit 1
elif [[ "$deviceType" != "computer" && "$deviceType" != "mobile" ]]; then
log "Error: deviceType must be either 'computer' or 'mobile'"
exit 1
fi
getAccessToken() {
log "Fetching Jamf API token..."
response=$(curl --silent --fail-with-body --location --request POST "${Jamf_URL}/api/oauth/token" \
--header "Content-Type: application/x-www-form-urlencoded" \
--data-urlencode "client_id=${client_id}" \
--data-urlencode "grant_type=client_credentials" \
--data-urlencode "client_secret=${client_secret}")
access_token=$(echo "$response" | jq -r '.access_token')
if [[ "$access_token" == "null" || -z "$access_token" ]]; then
log "Error: Failed to get valid access token."
exit 1
fi
log "Successfully obtained token."
}
invalidateToken() {
log "Invalidating token..."
responseCode=$(curl -w "%{http_code}" -H "Authorization: Bearer ${access_token}" \
"${Jamf_URL}/api/v1/auth/invalidate-token" -X POST -s -o /dev/null)
case "$responseCode" in
204) log "Token successfully invalidated." ;;
401) log "Token already invalid." ;;
*) log "Unexpected response code during token invalidation: $responseCode" ;;
esac
}
deleteDeviceBySerial() {
local serialNumber="$1"
if [[ "$deviceType" == "computer" ]]; then
deleteURL="${Jamf_URL}/JSSResource/computers/serialnumber/${serialNumber}"
echo $deleteURL
else
deleteURL="${Jamf_URL}/JSSResource/mobiledevices/serialnumber/${serialNumber}"
fi
responseCode=$(curl -s -o /dev/null -w "%{http_code}" \
--request DELETE "$deleteURL" \
--header "Authorization: Bearer ${access_token}" \
--header "Accept: application/xml")
if [[ "$responseCode" == 200 || "$responseCode" == 204 ]]; then
((countSuccess++))
successSerial+=("$serialNumber")
log "Deleted $deviceType with serial: $serialNumber"
elif [[ "$responseCode" == 404 ]]; then
((countFailure++))
failureSerial+=("$serialNumber")
log "Not found: No $deviceType with serial: $serialNumber"
elif [[ "$responseCode" == 401 ]]; then
((countFailure++))
failureSerial+=("$serialNumber")
log "Unauthorized to delete $deviceType with serial: $serialNumber. Check API role."
exit 1
else
((countFailure++))
failureSerial+=("$serialNumber")
log "Failed to delete $deviceType with serial: $serialNumber. HTTP code: $responseCode"
fi
}
processSerialNumbers() {
log "Deleting $deviceType records by serial number..."
while IFS= read -r serialNumber || [[ -n "$serialNumber" ]]; do
[[ -z "$serialNumber" ]] && continue
deleteDeviceBySerial "$serialNumber"
done < "$serialNumberList"
log "---------------------------------------"
log "Successfully deleted: $countSuccess"
printf "%s\n" "${successSerial[@]}" | tee -a "$logFile"
log "---------------------------------------"
log "Failed deletions: $countFailure"
printf "%s\n" "${failureSerial[@]}" | tee -a "$logFile"
}
main() {
getAccessToken
processSerialNumbers
invalidateToken
}
main
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment