Created
May 30, 2025 09:27
-
-
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).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/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