Created
May 27, 2025 10:40
-
-
Save vbnin/f8b3bd9335d86fd4bb9ca465be699006 to your computer and use it in GitHub Desktop.
Delete offline Mac endpoints from Jamf Protect
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 | |
| # This example Bash script below does the following: | |
| # - Obtains an access token. | |
| # - Completes a listComputers query request that returns a list of computers offline since a date defined in input parameters | |
| # - Asks for confirmation | |
| # - Delete offline computers | |
| # Keep the following in mind when using this script: | |
| # - You must define the PROTECT_INSTANCE_PREFIX, CLIENT_ID, and PASSWORD variables to match your Jamf Protect environment. The PROTECT_INSTANCE_PREFIX variable is your tenant name (e.g., your-tenant), which is included in your tenant URL (e.g., https://your-tenant.protect.jamfcloud.com). | |
| # - Only including simple GraphQL API requests in a Bash script is recommended. | |
| # - This example script leverages the jq command-line tool to parse the JSON returned from the API request. | |
| # WARNING !! USE THIS SCRIPT WITH CAUTION !! | |
| # User-editable variables | |
| PROTECT_INSTANCE_PREFIX='' | |
| CLIENT_ID='' | |
| PASSWORD='' | |
| ASK_FOR_CONFIRMATION='Yes' # Must be 'Yes' or 'No' | |
| THRESHOLD_DATE='2025-01-01T00:00:00.000000Z' #Computers that didn't check after this date are considered offline | |
| # Do not edit below this line | |
| ############################# | |
| # Generate access token | |
| access_token=$(\ | |
| curl \ | |
| --silent \ | |
| --request POST \ | |
| --header 'content-type: application/json' \ | |
| --url "https://${PROTECT_INSTANCE_PREFIX}.protect.jamfcloud.com/token" \ | |
| --data "{\"client_id\": \"$CLIENT_ID\", | |
| \"password\": \"${PASSWORD}\"}" \ | |
| | jq -r '.access_token' \ | |
| ) | |
| # List offline computers | |
| read -r -d '' LIST_COMPUTERS_QUERY << ENDQUERY | |
| query listComputers(\$next: String) { | |
| listComputers( | |
| input: { | |
| filter: { | |
| checkin: { | |
| lessThan: "${THRESHOLD_DATE}" | |
| } | |
| }, | |
| next: \$next, | |
| pageSize: 100 | |
| } | |
| ) { | |
| items { | |
| created | |
| hostName | |
| serial | |
| updated | |
| uuid | |
| checkin | |
| } | |
| pageInfo { | |
| next | |
| } | |
| } | |
| } | |
| ENDQUERY | |
| echo "Retrieving paginated results:" | |
| next_token='null' | |
| page_count=1 | |
| offline_computers=() | |
| while true; do | |
| echo " Retrieving page $((page_count++)) of results..." | |
| request_json=$(jq -n \ | |
| --arg q "$LIST_COMPUTERS_QUERY" \ | |
| --argjson next_token $next_token \ | |
| '{"query": $q, "variables": {"next": $next_token}}' | |
| ) | |
| list_computers_resp=$(\ | |
| curl \ | |
| --silent \ | |
| --request POST \ | |
| --header "Authorization: ${access_token}" \ | |
| --url "https://${PROTECT_INSTANCE_PREFIX}.protect.jamfcloud.com/graphql" \ | |
| --data "$request_json" | |
| ) | |
| # Use jq to extract the desired data and append it to the array | |
| while IFS= read -r line; do | |
| if [[ -n "$line" ]]; then | |
| offline_computers+=("$line") | |
| fi | |
| done < <(jq -r '.data.listComputers.items[]?.uuid' <<< "$list_computers_resp") | |
| next_token=$(jq '.data.listComputers.pageInfo.next' <<< "$list_computers_resp") | |
| [[ $next_token == "null" ]] && break | |
| done | |
| echo "Found ${#offline_computers[@]} computers not checkin in since ${THRESHOLD_DATE}" | |
| printf "%s\n" "${offline_computers[@]}" | |
| # Exit script if no computer is found | |
| if [[ ${#offline_computers[@]} == 0 ]]; then | |
| echo "No computers to delete, exiting now..." | |
| exit 0 | |
| fi | |
| # Ask user to confirm or not based on script parameters | |
| if [[ "$ASK_FOR_CONFIRMATION" == "Yes" ]]; then | |
| # Ask the user to confirm | |
| read -p "Do you want to delete all listed computers? (Y/N): " confirm | |
| # Check the user's input | |
| if [[ "$confirm" == [Yy] ]]; then | |
| echo "Proceeding..." | |
| # Your commands to proceed here | |
| else | |
| echo "User cancelled. Aborting..." | |
| exit 2 | |
| fi | |
| else | |
| #No confirmation required | |
| echo "No confirmation required, proceeding..." | |
| fi | |
| for uuid in "${offline_computers[@]}"; do | |
| echo "Deleting computer ${uuid}..." | |
| # Create mutation to delete a computer | |
| read -r -d '' DELETE_COMPUTER_MUTATION << ENDQUERY | |
| mutation { | |
| deleteComputer(uuid: "$uuid") { | |
| uuid | |
| } | |
| } | |
| ENDQUERY | |
| request_json=$(jq -n \ | |
| --arg query "$DELETE_COMPUTER_MUTATION" \ | |
| '{"query": $query, "variables": {}}' | |
| ) | |
| delete_computer_resp=$(\ | |
| curl \ | |
| --silent \ | |
| --request POST \ | |
| --header "Authorization: ${access_token}" \ | |
| --url "https://${PROTECT_INSTANCE_PREFIX}.protect.jamfcloud.com/graphql" \ | |
| --data "$request_json" | |
| ) | |
| # Check if the deletion was successful | |
| if [[ "$delete_computer_resp" == *"\"uuid\":\"$uuid\""* ]]; then | |
| echo "Successfully deleted computer with UUID: $uuid" | |
| else | |
| echo "Failed to delete computer with UUID: $uuid" | |
| fi | |
| done | |
| echo "Done." | |
| exit 0 |
Author
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This script can list and delete all computers that didn't check after a specified date in Jamf Protect (macOS Security portal).
It'll ask for confirmation before proceeding.