Skip to content

Instantly share code, notes, and snippets.

@vbnin
Created May 27, 2025 10:40
Show Gist options
  • Select an option

  • Save vbnin/f8b3bd9335d86fd4bb9ca465be699006 to your computer and use it in GitHub Desktop.

Select an option

Save vbnin/f8b3bd9335d86fd4bb9ca465be699006 to your computer and use it in GitHub Desktop.
Delete offline Mac endpoints from Jamf Protect
#!/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
@vbnin
Copy link
Author

vbnin commented May 27, 2025

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment