Jamf Pro API – Get Jamf Notifications

For this post, I wanted to share how to get important notifications that may be on your Jamf Pro server without having to actually open a web browser, navigating to your Jamf Pro server, logging in, and viewing the notifications.

This task can be done utilizing the Jamf Pro API. The endpoint we will be focusing on is /api/v1/notifications

Why is this important? Jamf Pro will notify if there are issues that need to be addressed. These notifications can include things like the ADE token expiring soon, the APNS certificate is expired, or errors with the connected Jamf Infrastructure Manager. There is a need to get alerted on these notifications so the issues can be addressed before they become part of a much larger issue.

Let’s dig in…

When using the Jamf Pro API, a valid Jamf Pro account is needed. When creating Jamf Pro User Accounts for the purpose of using with the API, refer to the following link on what permissions are needed for each specific task:
https://developer.jamf.com/jamf-pro/docs/privileges-and-deprecations

For the endpoint /v1/notifications with the get operation, there are no privileges needed. This service can be created with no privileges and it will still work for this purpose.

Now that the account is created in Jamf Pro, we can start building the script that we will use.

When using the Jamf Pro API, we need to use an account to authenticate, we will use the account created in the previous step and we will look at how to generate a bearer token with the API. Supply the correct username, password, and Jamf Pro URL and our script will use those variables to generate a bearer token that will be used to authorize our API calls.

#!/bin/bash

# API Credentials
jamfUser="api_Notifications"
jamfPass="jamf1234"
jssURL="https://techitout.jamfcloud.com"

# Encode Credentials
encodedCredentials=$( printf "${jamfUser}:${jamfPass}" | /usr/bin/iconv -t ISO-8859-1 | /usr/bin/base64 -i - )

# Generate an auth token
authToken=$( /usr/bin/curl "${jssURL}/uapi/auth/token" \
--silent \
--request POST \
--header "Authorization: Basic ${encodedCredentials}"
)

# Parse authToken for token, omit expiration
token=$( /usr/bin/awk -F \" '{ print $4 }' <<< "${authToken}" | /usr/bin/xargs )

If we then do an echo $token we can see our Bearer Token value:

username@computername ~ % echo $token
eyJhbGciOiJIUzI1NiJ9.eyJhdXRoZW50aWNhdGVkLWFwcCI6IkdFTkVSSUMiLCJhdXRoZW50aWNhdGlvbi10eXBlIjoiSlNTIiwiZ3JvdXBzIjpbXSwic3ViamVjdC10eXBlIjoiSlNTX1VTRVJfSUQiLCJ0b2tlbi11dWlkIjoiY2JhMDU5ZDYtZGNiNC00ZDg2LTg5MjYtMTc0NGZkOGY4YzI0IiwibGRhcC1zZXJ2ZXItaWQiOi0xLCJzdWIiOiIxMyIsImV4cCI6MTY0ODY4MjkzN30.FF5s6LcNJue-tkCcMSf7zlOWRTf-Kv30K-eGwVVddF0

Now that we have the authentication portion of our script taken care of, we can now build the rest of our script. There are several possible notifications that Jamf Pro can give us, we can take these values and store them in an array of possibilities like this:

# Build an array of possible important notifications from Jamf Pro
noticationsArr=(
	APNS_CERT_REVOKED
	APNS_CONNECTION_FAILURE
	APPLE_SCHOOL_MANAGER_T_C_NOT_SIGNED
	BUILT_IN_CA_EXPIRED
	BUILT_IN_CA_EXPIRING
	BUILT_IN_CA_RENEWAL_FAILED
	BUILT_IN_CA_RENEWAL_SUCCESS
	CLOUD_LDAP_CERT_EXPIRED
	CLOUD_LDAP_CERT_WILL_EXPIRE
	COMPUTER_SECURITY_SSL_DISABLED
	DEP_INSTANCE_EXPIRED
	DEP_INSTANCE_WILL_EXPIRE
	DEVICE_ENROLLMENT_PROGRAM_T_C_NOT_SIGNED
	EXCEEDED_LICENSE_COUNT
	FREQUENT_INVENTORY_COLLECTION_POLICY
	GSX_CERT_EXPIRED
	GSX_CERT_WILL_EXPIRE
	HCL_BIND_ERROR
	HCL_ERROR
	INSECURE_LDAP
	INVALID_REFERENCES_EXT_ATTR
	INVALID_REFERENCES_POLICIES
	INVALID_REFERENCES_SCRIPTS
	JAMF_CONNECT_UPDATE
	JAMF_PROTECT_UPDATE
	JIM_ERROR
	LDAP_CONNECTION_CHECK_THROUGH_JIM_FAILED
	LDAP_CONNECTION_CHECK_THROUGH_JIM_SUCCESSFUL
	MDM_EXTERNAL_SIGNING_CERTIFICATE_EXPIRED
	MDM_EXTERNAL_SIGNING_CERTIFICATE_EXPIRING
	MDM_EXTERNAL_SIGNING_CERTIFICATE_EXPIRING_TODAY
	MII_HEARTBEAT_FAILED_NOTIFICATION
	MII_INVENTORY_UPLOAD_FAILED_NOTIFICATION
	MII_UNATHORIZED_RESPONSE_NOTIFICATION
	PATCH_EXTENTION_ATTRIBUTE
	PATCH_UPDATE
	POLICY_MANAGEMENT_ACCOUNT_PAYLOAD_SECURITY_MULTIPLE
	POLICY_MANAGEMENT_ACCOUNT_PAYLOAD_SECURITY_SINGLE
	PUSH_CERT_EXPIRED
	PUSH_CERT_WILL_EXPIRE
	PUSH_PROXY_CERT_EXPIRED
	SSO_CERT_EXPIRED
	SSO_CERT_WILL_EXPIRE
	TOMCAT_SSL_CERT_EXPIRED
	TOMCAT_SSL_CERT_WILL_EXPIRE
	USER_INITIATED_ENROLLMENT_MANAGEMENT_ACCOUNT_SECURITY_ISSUE
	USER_MAID_DUPLICATE_ERROR
	USER_MAID_MISMATCH_ERROR
	USER_MAID_ROSTER_DUPLICATE_ERROR
	VPP_ACCOUNT_EXPIRED
	VPP_ACCOUNT_WILL_EXPIRE
	VPP_TOKEN_REVOKED
	DEVICE_COMPLIANCE_CONNECTION_ERROR
	CONDITIONAL_ACCESS_CONNECTION_ERROR
	AZURE_AD_MIGRATION_REPORT_GENERATED
)

We now know what the possible notifications are, so let’s get the notifications from our Jamf Pro server. Notice this is where we use our Bearer token that was generated earlier:

# Returns important notifications from Jamf Pro in JSON
data=$( curl --request GET \
--url "${jssURL}/api/v1/notifications" \
--header "Accept: application/json" \
--header "Authorization: Bearer ${token}" \
)

The next step we need to do is set up a loop to find our notifications match a notification in the array that we set earlier. The logic for this loop will look like:

for str in ${notificationsArr[@]}; do
   if [[ " ${data} " =~ ${str} ]]; then
      # Notification in list matches notification from $data
   fi
done

Now, I’m sure that we want to do more with this data than just compare to a list. The next step is to populate our loop with useful steps that will give us the information that we want to know in a readable form.

# Loop each notification possibility and if it exists in the results, grab information on the notification using jq and notify
for str in ${noticationsArr[@]}; do
	if [[ " ${data} " =~ ${str} ]]; then
		# Create a clean string for read ability
		cleanString=$( echo $str | sed 's/_/ /g' )
		name=$( echo ${data} | jq --arg v "${str}" '.[]|select(.type==$v).params.name')
		# Create a clean name for read ability
		cleanname=$( echo $name | sed 's/"//g')
		days=$( echo ${data} | jq --arg v "${str}" '.[]|select(.type==$v).params.days')
		id=$( echo ${data} | jq --arg v "${str}" '.[]|select(.type==$v).params.id')
		if [[ ${name} != "null" ]]; then
			if [[ ${days} != "null" ]]; then
				if [[ ${id} != "null" ]]; then
					message=$( echo "$JPInstance Notification: $cleanString for $cleanname in $days days" )
				else
					message=$( echo "$JPInstance Notification: $cleanString for $cleanname in $days days" )
				fi
			else
				message=$( echo "$JPInstance Notification: $cleanString for $name" )
			fi
		else
			message=$( echo "$JPInstance Notification: $cleanString" )
		fi
		# Echo the message for each alert
        echo ${message}
	fi
done

Putting it all together:

#!/bin/bash

# API Credentials
jamfUser="api_Notifications"
jamfPass="jamf1234"
jssURL="https://techitout.jamfcloud.com"

# Encode Credentials
encodedCredentials=$( printf "${jamfUser}:${jamfPass}" | /usr/bin/iconv -t ISO-8859-1 | /usr/bin/base64 -i - )

# Generate an auth token
authToken=$( /usr/bin/curl "${jssURL}/uapi/auth/token" \
--silent \
--request POST \
--header "Authorization: Basic ${encodedCredentials}"
)

# Parse authToken for token, omit expiration
token=$( /usr/bin/awk -F \" '{ print $4 }' <<< "${authToken}" | /usr/bin/xargs )

# Build an array of possible important notifications from Jamf Pro
noticationsArr=(
	APNS_CERT_REVOKED
	APNS_CONNECTION_FAILURE
	APPLE_SCHOOL_MANAGER_T_C_NOT_SIGNED
	BUILT_IN_CA_EXPIRED
	BUILT_IN_CA_EXPIRING
	BUILT_IN_CA_RENEWAL_FAILED
	BUILT_IN_CA_RENEWAL_SUCCESS
	CLOUD_LDAP_CERT_EXPIRED
	CLOUD_LDAP_CERT_WILL_EXPIRE
	COMPUTER_SECURITY_SSL_DISABLED
	DEP_INSTANCE_EXPIRED
	DEP_INSTANCE_WILL_EXPIRE
	DEVICE_ENROLLMENT_PROGRAM_T_C_NOT_SIGNED
	EXCEEDED_LICENSE_COUNT
	FREQUENT_INVENTORY_COLLECTION_POLICY
	GSX_CERT_EXPIRED
	GSX_CERT_WILL_EXPIRE
	HCL_BIND_ERROR
	HCL_ERROR
	INSECURE_LDAP
	INVALID_REFERENCES_EXT_ATTR
	INVALID_REFERENCES_POLICIES
	INVALID_REFERENCES_SCRIPTS
	JAMF_CONNECT_UPDATE
	JAMF_PROTECT_UPDATE
	JIM_ERROR
	LDAP_CONNECTION_CHECK_THROUGH_JIM_FAILED
	LDAP_CONNECTION_CHECK_THROUGH_JIM_SUCCESSFUL
	MDM_EXTERNAL_SIGNING_CERTIFICATE_EXPIRED
	MDM_EXTERNAL_SIGNING_CERTIFICATE_EXPIRING
	MDM_EXTERNAL_SIGNING_CERTIFICATE_EXPIRING_TODAY
	MII_HEARTBEAT_FAILED_NOTIFICATION
	MII_INVENTORY_UPLOAD_FAILED_NOTIFICATION
	MII_UNATHORIZED_RESPONSE_NOTIFICATION
	PATCH_EXTENTION_ATTRIBUTE
	PATCH_UPDATE
	POLICY_MANAGEMENT_ACCOUNT_PAYLOAD_SECURITY_MULTIPLE
	POLICY_MANAGEMENT_ACCOUNT_PAYLOAD_SECURITY_SINGLE
	PUSH_CERT_EXPIRED
	PUSH_CERT_WILL_EXPIRE
	PUSH_PROXY_CERT_EXPIRED
	SSO_CERT_EXPIRED
	SSO_CERT_WILL_EXPIRE
	TOMCAT_SSL_CERT_EXPIRED
	TOMCAT_SSL_CERT_WILL_EXPIRE
	USER_INITIATED_ENROLLMENT_MANAGEMENT_ACCOUNT_SECURITY_ISSUE
	USER_MAID_DUPLICATE_ERROR
	USER_MAID_MISMATCH_ERROR
	USER_MAID_ROSTER_DUPLICATE_ERROR
	VPP_ACCOUNT_EXPIRED
	VPP_ACCOUNT_WILL_EXPIRE
	VPP_TOKEN_REVOKED
	DEVICE_COMPLIANCE_CONNECTION_ERROR
	CONDITIONAL_ACCESS_CONNECTION_ERROR
	AZURE_AD_MIGRATION_REPORT_GENERATED
)

# Returns important notifications from Jamf Pro in JSON
data=$( curl --request GET \
--url "${jssURL}/api/v1/notifications" \
--header "Accept: application/json" \
--header "Authorization: Bearer ${token}" \
)

# Loop each notification possibility and if it
# exists in the results, grab information on the
# notification using jq and notify
for str in ${noticationsArr[@]}; do
	if [[ " ${data} " =~ ${str} ]]; then
		cleanString=$( echo $str | sed 's/_/ /g' )
		name=$( echo ${data} | jq --arg v "${str}" '.[]|select(.type==$v).params.name')
		cleanname=$( echo $name | sed 's/"//g')
		days=$( echo ${data} | jq --arg v "${str}" '.[]|select(.type==$v).params.days')
		id=$( echo ${data} | jq --arg v "${str}" '.[]|select(.type==$v).params.id')
		if [[ ${name} != "null" ]]; then
			if [[ ${days} != "null" ]]; then
				if [[ ${id} != "null" ]]; then
					message=$( echo "$JPInstance Notification: $cleanString for $cleanname in $days days" )
				else
					message=$( echo "$JPInstance Notification: $cleanString for $cleanname in $days days" )
				fi
			else
				message=$( echo "$JPInstance Notification: $cleanString for $name" )
			fi
		else
			message=$( echo "$JPInstance Notification: $cleanString" )
		fi
		echo $message
		
	fi
done
	
exit 0

This will yield results similar to:

TECHITOUT Notification: DEP INSTANCE WILL EXPIRE for TIO ABM in 17 days
TECHITOUT Notification: USER INITIATED ENROLLMENT MANAGEMENT ACCOUNT SECURITY ISSUE

And thats it. I’ve also put it up on my GitHub: https://github.com/robjschroeder/Jamf-API-Scripts/blob/main/api-GetJPNotifications.sh

Thanks for checking it out!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: