Created
March 20, 2025 14:29
-
-
Save karthikeyan-mac/4c46121ddd95b43465bd1b5e53ce571c to your computer and use it in GitHub Desktop.
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 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