Skip to content

Instantly share code, notes, and snippets.

@karthikeyan-mac
Created March 20, 2025 14:29
Show Gist options
  • Save karthikeyan-mac/4c46121ddd95b43465bd1b5e53ce571c to your computer and use it in GitHub Desktop.
Save karthikeyan-mac/4c46121ddd95b43465bd1b5e53ce571c to your computer and use it in GitHub Desktop.
#!/bin/bash
#
# This script retrieves the Mac Hardware UUID, fetches the corresponding Computer ID from Jamf Pro,
# checks for any failed MDM commands, and clears them if found.
#
# Uses JAMF API Client and Roles.
# Add Parameter 4 & 5 with API Client ID & Client Secret when running in JAMF Policy.
# API Role Privileges Required: Read Computers, Flush MDM Commands.
#
# Karthikeyan Marappan
#
#
# Path to Jamf preferences file
jamfPrefFile="/Library/Preferences/com.jamfsoftware.jamf.plist"
# Path to Jamf binary
jamfPath="/usr/local/bin/jamf"
# Client ID and secret (passed as script parameters)
#
client_id="$4"
client_secret="$5"
# Function to get the hardware UUID of the Mac
getHardwareUUID() {
system_profiler SPHardwareDataType | awk -F": " '/Hardware UUID/ {print $2}' | tr -d ' '
}
# Function to retrieve the Jamf Pro (JSS) URL from preferences
jssURL() {
if [[ -f "$jamfPrefFile" ]]; then
jss_url=$(defaults read "$jamfPrefFile" jss_url | sed 's:/*$::')
echo "$jss_url"
else
echo "Error: $jamfPrefFile not found." >&2
exit 1
fi
}
# Function to check connectivity to the Jamf Pro server
checkJSSConnection() {
#echo "Checking JSS connection..."
if ! "$jamfPath" -checkjssconnection -retry 10; then
echo "Error: JSS connection not active." >&2
exit 1
fi
echo "JSS connection active!"
}
# Function to obtain an OAuth bearer token for API authentication
getAccessToken() {
local Jamf_URL="$1"
echo $Jamf_URL
response=$(curl --silent --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}")
if [[ -z "$response" ]]; then
echo "Check Jamf URL"
exit 1
elif [[ "$response" == '{"error":"invalid_client"}' ]]; then
echo "Check the API Client credentials and permissions"
exit 1
fi
access_token=$(echo "$response" | plutil -extract access_token raw -)
token_expires_in=$(echo "$response" | plutil -extract expires_in raw -)
token_expiration_epoch=$((current_epoch + token_expires_in - 1))
}
# Function to check if the computer UUID exists in Jamf Pro
check_Mac_UUID() {
local jss_url="$1"
local Mac_UUID="$2"
local url="$jss_url/JSSResource/computers/udid/$Mac_UUID"
jssID=$(curl -s -X GET "$url" -H "Authorization: Bearer $access_token" | xmllint --xpath '/computer/general/id/text()' -)
if [[ -z "$jssID" ]]; then
echo "Error: Computer not found in Jamf." >&2
exit 1
fi
}
# Function to get the number of failed MDM commands for the computer
get_failed_commands() {
local jss_url="$1"
local jssID="$2"
local url="$jss_url/JSSResource/computerhistory/id/$jssID/subset/commands"
local failed_commands=$(curl -s -X GET "$url" -H "Authorization: Bearer $access_token" | grep -c "<failed>")
if [[ "$failed_commands" -gt 0 ]]; then
echo "Failed commands detected. Clearing..."
clear_failed_mdm_commands "$jss_url" "$jssID"
else
echo "No failed commands."
fi
}
# Function to clear failed MDM commands for the computer in Jamf Pro
clear_failed_mdm_commands() {
local jss_url="$1"
local jssID="$2"
local url="$jss_url/JSSResource/commandflush/computers/id/$jssID/status/Failed"
response=$(curl -s -X DELETE "$url" -H "Authorization: Bearer $access_token")
echo "Clear MDM Commands Response: $response"
}
# Function to invalidate Token
invalidateToken() {
local jss_url="$1"
responseCode=$(curl -w "%{http_code}" -H "Authorization: Bearer ${access_token}" \
"${jss_url}/api/v1/auth/invalidate-token" -X POST -s -o /dev/null)
if [[ $responseCode == 204 ]]; then
echo "Token successfully invalidated"
elif [[ $responseCode == 401 ]]; then
echo "Token already invalid"
else
echo "Unexpected response code: $responseCode"
exit 1 # Or handle it in a different way (e.g., retry or log the error)
fi
}
# Main execution function
main() {
checkJSSConnection
jss_url=$(jssURL)
getAccessToken "$jss_url"
Mac_UUID=$(getHardwareUUID)
if [[ -z "$Mac_UUID" ]]; then
echo "Error: Unable to retrieve Hardware UUID." >&2
exit 1
fi
check_Mac_UUID "$jss_url" "$Mac_UUID"
get_failed_commands "$jss_url" "$jssID"
invalidateToken "$jss_url"
}
# Execute the main function
main
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment