From 8e1c85118e0a28b33fbe5b6ba9212ff02c02bbfd Mon Sep 17 00:00:00 2001 From: Zack T Date: Tue, 11 Jun 2024 10:40:05 -0700 Subject: [PATCH] v1.0.0 = Initial Version Some MDM client health check scripts --- .../Collect-APNSMgmtTopic.sh | 154 +++++ .../Collect-APNSOpportunisticTopicStatus.sh | 142 ++++ .../Collect-APNSPersistentConnStatus.sh | 142 ++++ .../Collect-LastMDMPush.sh | 163 +++++ .../Get-APNSMDMClientHealth.sh | 638 ++++++++++++++++++ .../Extension Attributes/Get-LastMDMPush.sh | 274 ++++++++ .../Verify-APNSCertTopic.sh | 329 +++++++++ 7 files changed, 1842 insertions(+) create mode 100644 Jamf Pro/Extension Attributes/Collect-APNSMgmtTopic.sh create mode 100644 Jamf Pro/Extension Attributes/Collect-APNSOpportunisticTopicStatus.sh create mode 100644 Jamf Pro/Extension Attributes/Collect-APNSPersistentConnStatus.sh create mode 100644 Jamf Pro/Extension Attributes/Collect-LastMDMPush.sh create mode 100644 Jamf Pro/Extension Attributes/Get-APNSMDMClientHealth.sh create mode 100644 Jamf Pro/Extension Attributes/Get-LastMDMPush.sh create mode 100644 Jamf Pro/Extension Attributes/Verify-APNSCertTopic.sh diff --git a/Jamf Pro/Extension Attributes/Collect-APNSMgmtTopic.sh b/Jamf Pro/Extension Attributes/Collect-APNSMgmtTopic.sh new file mode 100644 index 0000000..37e2a66 --- /dev/null +++ b/Jamf Pro/Extension Attributes/Collect-APNSMgmtTopic.sh @@ -0,0 +1,154 @@ +#!/bin/bash + +################################################################################################### +# Script Name: Collect-APNSMgmtTopic.sh +# By: Zack Thompson / Created: 11/3/2023 +# Version: 1.0.0 / Updated: 11/20/2023 / By: ZT +# +# Description: This script collects specific results from the Get-APNSMDMClientHealth.sh script +# which reports on the APNS MDM Client and MDM Profile management Topics. +# +# Pass [--debug | -d ] as an argument to "test" the script and not write to the local EA files. +# +################################################################################################### + +################################################## +# Define Variables + +# Locally log EA value for historical reference (since Jamf Pro only ever has the last value). +# Supported actions: +# true - Do locally Log +# false - Do not log locally +locally_log="true" +local_ea_history="/opt/ManagedFrameworks/EA_History.log" +local_ea_inventory="/opt/ManagedFrameworks/Inventory.plist" +debugging_description="Collect-APNSMgmtTopic.sh: " + +#################### +# Compiled Results +local_ea_inventory_compiled_key="apns_mdm_mgmt_topics" + +# MDM Profile APNS Topic +local_ea_inventory_mdm_profile_key="mdm_apns_topic" + +# APNS Cert and Local Push Topic Comparison +local_ea_inventory_apns_topic_key="apns_topics" + +# APNS Cert and Device Push Topic Comparison +local_ea_inventory_apns_and_device_topics="apns_and_device_topics" + +# APNS Cert and User Push Topic Comparison +local_ea_inventory_apns_and_user_topics="apns_and_user_topics" + +#############################################n##### +# Functions + +arg_parse() { + # Command Line Argument Parser + + while (( "$#" )); do + # Work through the passed arguments + + case "${1}" in + -d | --debug ) + debug="true" + write_to_ea_history "DEBUGGING ENABLED" "${debugging_description}" + ;; + # * ) + # switch="${1}" + # shift + # value="${1}" + # eval "${switch}"="'${value}'" + # ;; + esac + + shift + done +} + +write_to_ea_history() { + + # Arguments + # $1 = (str) Message that will be written to a log file + # $2 = (str) Optional description that will be written ahead of message + + local message="${1}" + local description="${2}" + + time_stamp=$( /bin/date +%Y-%m-%d\ %H:%M:%S ) + + if [[ "${locally_log}" == "true" && -z "${debug}" ]]; then + + if [[ ! -e "${local_ea_history}" ]]; then + + /bin/mkdir -p "$( /usr/bin/dirname "${local_ea_history}" )" + /usr/bin/touch "${local_ea_history}" + + fi + + echo "${time_stamp} | ${description}${message}" >> "${local_ea_history}" + + else + + echo "${time_stamp} | ${description}${message}" + + fi + +} + +get_value() { + + # Arguments + # $1 = (str) Message that will be recorded to the configured locations + + local key="${1}" + + /usr/bin/defaults read "${local_ea_inventory}" "${key}" + +} + +################################################## +# Command Line Argument Parser + +parameters=( "$@" ) +arg_parse "${parameters[@]}" + +################################################## +# Bits staged, collect the information... + +if [[ ! -e $local_ea_inventory ]]; then + return_result="Missing local inventory register" +else + return_result="" + + if [[ "$( get_value "${local_ea_inventory_compiled_key}" )" == "Valid" ]]; then + return_result="Valid" + else + + if [[ "$( get_value "${local_ea_inventory_mdm_profile_key}" )" != "Valid" ]]; then + return_result+="MDM Mgmt Topic is Invalid;" + + if [[ "$( get_value "${local_ea_inventory_apns_topic_key}" )" != "Valid" ]]; then + + if [[ "$( get_value "${local_ea_inventory_apns_and_device_topics}" )" != "Valid" ]]; then + return_result+=" Device APNS Topics are Invalid;" + fi + + if [[ "$( get_value "${local_ea_inventory_apns_and_user_topics}" )" != "Valid" ]]; then + return_result+=" User APNS Topics are Invalid;" + fi + + fi + + fi + fi + + if [[ -z $return_result ]]; then + return_result="Unknown" + fi + +fi + +write_to_ea_history "APNS Mgmt Topic Collected: ${return_result}" +echo "${return_result}" +exit 0 \ No newline at end of file diff --git a/Jamf Pro/Extension Attributes/Collect-APNSOpportunisticTopicStatus.sh b/Jamf Pro/Extension Attributes/Collect-APNSOpportunisticTopicStatus.sh new file mode 100644 index 0000000..798e31c --- /dev/null +++ b/Jamf Pro/Extension Attributes/Collect-APNSOpportunisticTopicStatus.sh @@ -0,0 +1,142 @@ +#!/bin/bash + +################################################################################################### +# Script Name: Collect-APNSOpportunisticTopicStatus.sh +# By: Zack Thompson / Created: 11/3/2023 +# Version: 1.0.0 / Updated: 11/20/2023 / By: ZT +# +# Description: This script collects specific results from the Get-APNSMDMClientHealth.sh script +# which reports on the APNS MDM Client and MDM Profile management Topics. +# +# Pass [--debug | -d ] as an argument to "test" the script and not write to the local EA files. +# +################################################################################################### + +################################################## +# Define Variables + +# Locally log EA value for historical reference (since Jamf Pro only ever has the last value). +# Supported actions: +# true - Do locally Log +# false - Do not log locally +locally_log="true" +local_ea_history="/opt/ManagedFrameworks/EA_History.log" +local_ea_inventory="/opt/ManagedFrameworks/Inventory.plist" +debugging_description="Collect-APNSOpportunisticTopicStatus.sh: " + +# APNS Device Channel Opportunistic Topic Status +local_ea_inventory_apns_device_opportunistic_topic_status="apns_device_opportunistic_topic_status" + +# APNS User Channel Opportunistic Topic Status +local_ea_inventory_apns_user_opportunistic_topic_status="apns_user_opportunistic_topic_status" + +#############################################n##### +# Functions + +arg_parse() { + # Command Line Argument Parser + + while (( "$#" )); do + # Work through the passed arguments + + case "${1}" in + -d | --debug ) + debug="true" + write_to_ea_history "DEBUGGING ENABLED" "${debugging_description}" + ;; + # * ) + # switch="${1}" + # shift + # value="${1}" + # eval "${switch}"="'${value}'" + # ;; + esac + + shift + done +} + +write_to_ea_history() { + + # Arguments + # $1 = (str) Message that will be written to a log file + # $2 = (str) Optional description that will be written ahead of message + + local message="${1}" + local description="${2}" + + time_stamp=$( /bin/date +%Y-%m-%d\ %H:%M:%S ) + + if [[ "${locally_log}" == "true" && -z "${debug}" ]]; then + + if [[ ! -e "${local_ea_history}" ]]; then + + /bin/mkdir -p "$( /usr/bin/dirname "${local_ea_history}" )" + /usr/bin/touch "${local_ea_history}" + + fi + + echo "${time_stamp} | ${description}${message}" >> "${local_ea_history}" + + else + + echo "${time_stamp} | ${description}${message}" + + fi + +} + +get_value() { + + # Arguments + # $1 = (str) Message that will be recorded to the configured locations + + local key="${1}" + + /usr/bin/defaults read "${local_ea_inventory}" "${key}" + +} + +################################################## +# Command Line Argument Parser + +parameters=( "$@" ) +arg_parse "${parameters[@]}" + +################################################## +# Bits staged, collect the information... + +if [[ ! -e $local_ea_inventory ]]; then + return_result="Missing local inventory register" +else + return_result="" + + device_opportunistic_topic_status=$( get_value "${local_ea_inventory_apns_device_opportunistic_topic_status}" ) + user_opportunistic_topic_status=$( get_value "${local_ea_inventory_apns_user_opportunistic_topic_status}" ) + + if [[ "${device_opportunistic_topic_status}" == "Ok" && "${user_opportunistic_topic_status}" == "Ok" ]]; then + write_to_ea_history "Reporting on both channels" + return_result="Ok" + + elif [[ -n $device_opportunistic_topic_status && -n $user_opportunistic_topic_status ]]; then + write_to_ea_history "Reporting on both channels" + return_result="Device: ${device_opportunistic_topic_status}; User: ${user_opportunistic_topic_status}" + + elif [[ -n $device_opportunistic_topic_status ]]; then + write_to_ea_history "Reporting device channel" + return_result="Device: ${device_opportunistic_topic_status}" + + elif [[ -n $user_opportunistic_topic_status ]]; then + write_to_ea_history "Reporting user channel" + return_result="User: ${user_opportunistic_topic_status}" + fi + + if [[ -z $return_result ]]; then + return_result="Unknown" + fi + +fi + +write_to_ea_history "APNS Opportunistic Topic Status Collected: ${return_result}" +echo "${return_result}" +exit 0 \ No newline at end of file diff --git a/Jamf Pro/Extension Attributes/Collect-APNSPersistentConnStatus.sh b/Jamf Pro/Extension Attributes/Collect-APNSPersistentConnStatus.sh new file mode 100644 index 0000000..13c31e0 --- /dev/null +++ b/Jamf Pro/Extension Attributes/Collect-APNSPersistentConnStatus.sh @@ -0,0 +1,142 @@ +#!/bin/bash + +################################################################################################### +# Script Name: Collect-APNSPersistentConnStatus.sh +# By: Zack Thompson / Created: 11/3/2023 +# Version: 1.0.0 / Updated: 11/20/2023 / By: ZT +# +# Description: This script collects specific results from the Get-APNSMDMClientHealth.sh script +# which reports on the APNS MDM Client and MDM Profile management Topics. +# +# Pass [--debug | -d ] as an argument to "test" the script and not write to the local EA files. +# +################################################################################################### + +################################################## +# Define Variables + +# Locally log EA value for historical reference (since Jamf Pro only ever has the last value). +# Supported actions: +# true - Do locally Log +# false - Do not log locally +locally_log="true" +local_ea_history="/opt/ManagedFrameworks/EA_History.log" +local_ea_inventory="/opt/ManagedFrameworks/Inventory.plist" +debugging_description="Collect-APNSPersistentConnStatus.sh: " + +# APNS Device Channel Persistent Connection Status +local_ea_inventory_apns_device_persistent_conn_status="apns_device_persistent_conn_status" + +# APNS User Channel Persistent Connection Status +local_ea_inventory_apns_user_persistent_conn_status="apns_user_persistent_conn_status" + +#############################################n##### +# Functions + +arg_parse() { + # Command Line Argument Parser + + while (( "$#" )); do + # Work through the passed arguments + + case "${1}" in + -d | --debug ) + debug="true" + write_to_ea_history "DEBUGGING ENABLED" "${debugging_description}" + ;; + # * ) + # switch="${1}" + # shift + # value="${1}" + # eval "${switch}"="'${value}'" + # ;; + esac + + shift + done +} + +write_to_ea_history() { + + # Arguments + # $1 = (str) Message that will be written to a log file + # $2 = (str) Optional description that will be written ahead of message + + local message="${1}" + local description="${2}" + + time_stamp=$( /bin/date +%Y-%m-%d\ %H:%M:%S ) + + if [[ "${locally_log}" == "true" && -z "${debug}" ]]; then + + if [[ ! -e "${local_ea_history}" ]]; then + + /bin/mkdir -p "$( /usr/bin/dirname "${local_ea_history}" )" + /usr/bin/touch "${local_ea_history}" + + fi + + echo "${time_stamp} | ${description}${message}" >> "${local_ea_history}" + + else + + echo "${time_stamp} | ${description}${message}" + + fi + +} + +get_value() { + + # Arguments + # $1 = (str) Message that will be recorded to the configured locations + + local key="${1}" + + /usr/bin/defaults read "${local_ea_inventory}" "${key}" + +} + +################################################## +# Command Line Argument Parser + +parameters=( "$@" ) +arg_parse "${parameters[@]}" + +################################################## +# Bits staged, collect the information... + +if [[ ! -e $local_ea_inventory ]]; then + return_result="Missing local inventory register" +else + return_result="" + + device_persistent_conn_status=$( get_value "${local_ea_inventory_apns_device_persistent_conn_status}" ) + user_persistent_conn_status=$( get_value "${local_ea_inventory_apns_user_persistent_conn_status}" ) + + if [[ "${device_persistent_conn_status}" == "Ok" && "${user_persistent_conn_status}" == "Ok" ]]; then + write_to_ea_history "Reporting on both channels" + return_result="Ok" + + elif [[ -n $device_persistent_conn_status && -n $user_persistent_conn_status ]]; then + write_to_ea_history "Reporting on both channels" + return_result="Device: ${device_persistent_conn_status}; User: ${user_persistent_conn_status}" + + elif [[ -n $device_persistent_conn_status ]]; then + write_to_ea_history "Reporting device channel" + return_result="Device: ${device_persistent_conn_status}" + + elif [[ -n $user_persistent_conn_status ]]; then + write_to_ea_history "Reporting user channel" + return_result="User: ${user_persistent_conn_status}" + fi + + if [[ -z $return_result ]]; then + return_result="Unknown" + fi + +fi + +write_to_ea_history "APNS Persistent Connection Status Collected: ${return_result}" +echo "${return_result}" +exit 0 \ No newline at end of file diff --git a/Jamf Pro/Extension Attributes/Collect-LastMDMPush.sh b/Jamf Pro/Extension Attributes/Collect-LastMDMPush.sh new file mode 100644 index 0000000..8695a41 --- /dev/null +++ b/Jamf Pro/Extension Attributes/Collect-LastMDMPush.sh @@ -0,0 +1,163 @@ +#!/bin/bash + +################################################################################################### +# Script Name: Collect-LastMDMPush.sh +# By: Zack Thompson / Created: 11/3/2023 +# Version: 1.0.0 / Updated: 11/20/2023 / By: ZT +# +# Description: This script collects specific results from the Get-APNSMDMClientHealth.sh script +# which reports on the APNS MDM Client and MDM Profile management Topics. +# +# Pass [--debug | -d ] as an argument to "test" the script and not write to the local EA files. +# +################################################################################################### + +################################################## +# Define Variables + +# Locally log EA value for historical reference (since Jamf Pro only ever has the last value). +# Supported actions: +# true - Do locally Log +# false - Do not log locally +locally_log="true" +local_ea_history="/opt/ManagedFrameworks/EA_History.log" +local_ea_inventory="/opt/ManagedFrameworks/Inventory.plist" +debugging_description="Collect-LastMDMPush.sh: " + +# The format of the date string that will be used for reporting. +jamfpro_ea_date_format="%Y-%m-%d %H:%M:%S" + +# APNS Device Channel Last Push Date +local_ea_inventory_apns_device_last_push_date="apns_device_last_push_date" + +# APNS User Channel Last Push Date +local_ea_inventory_apns_user_last_push_date="apns_user_last_push_date" + +#############################################n##### +# Functions + +arg_parse() { + # Command Line Argument Parser + + while (( "$#" )); do + # Work through the passed arguments + + case "${1}" in + -d | --debug ) + debug="true" + write_to_ea_history "DEBUGGING ENABLED" "${debugging_description}" + ;; + # * ) + # switch="${1}" + # shift + # value="${1}" + # eval "${switch}"="'${value}'" + # ;; + esac + + shift + done +} + +write_to_ea_history() { + + # Arguments + # $1 = (str) Message that will be written to a log file + # $2 = (str) Optional description that will be written ahead of message + + local message="${1}" + local description="${2}" + + time_stamp=$( /bin/date +%Y-%m-%d\ %H:%M:%S ) + + if [[ "${locally_log}" == "true" && -z "${debug}" ]]; then + + if [[ ! -e "${local_ea_history}" ]]; then + + /bin/mkdir -p "$( /usr/bin/dirname "${local_ea_history}" )" + /usr/bin/touch "${local_ea_history}" + + fi + + echo "${time_stamp} | ${description}${message}" >> "${local_ea_history}" + + else + + echo "${time_stamp} | ${description}${message}" + + fi + +} + +get_value() { + + # Arguments + # $1 = (str) Message that will be recorded to the configured locations + + local key="${1}" + + /usr/bin/defaults read "${local_ea_inventory}" "${key}" + +} + +convert_date(){ + + # Convert a formatted date string into another format + # Arguments + # $1 = (str) a date in string format + # $2 = (str) the expected format of the date string + # $3 = (str) the desired format of the string + + /bin/date -j -f "${2}" "$( fixup_space_in_string "${1}" )" +"${3}" + +} + +################################################## +# Command Line Argument Parser + +parameters=( "$@" ) +arg_parse "${parameters[@]}" + +################################################## +# Bits staged, collect the information... + +if [[ ! -e $local_ea_inventory ]]; then + return_result="Missing local inventory register" +else + return_result="" + + device_last_push_date=$( get_value "${local_ea_inventory_apns_device_last_push_date}" ) + user_last_push_date=$( get_value "${local_ea_inventory_apns_user_last_push_date}" ) + + if [[ -n $device_last_push_date && -n $user_last_push_date ]]; then + + # Convert dates to epoch to easily compare + if [[ + $( convert_date "${device_last_push_date}" "${jamfpro_ea_date_format}" "%s" ) -gt \ + $( convert_date "${user_last_push_date}" "${jamfpro_ea_date_format}" "%s" ) + ]]; then + write_to_ea_history "Reporting device channel date" + return_result="${device_last_push_date}" + else + write_to_ea_history "Reporting user channel date" + return_result="${user_last_push_date}" + fi + + elif [[ -n $device_last_push_date ]]; then + write_to_ea_history "Reporting device channel date" + return_result="${device_last_push_date}" + + elif [[ -n $user_last_push_date ]]; then + write_to_ea_history "Reporting user channel date" + return_result="${user_last_push_date}" + fi + + if [[ -z $return_result ]]; then + return_result="Unknown" + fi + +fi + +write_to_ea_history "Last MDM Push Collected: ${return_result}" +echo "${return_result}" +exit 0 \ No newline at end of file diff --git a/Jamf Pro/Extension Attributes/Get-APNSMDMClientHealth.sh b/Jamf Pro/Extension Attributes/Get-APNSMDMClientHealth.sh new file mode 100644 index 0000000..5e2ee22 --- /dev/null +++ b/Jamf Pro/Extension Attributes/Get-APNSMDMClientHealth.sh @@ -0,0 +1,638 @@ +#!/bin/bash +# set -x + +#################################################################################################### +# Script Name: Get-APNSMDMClientHealth.sh +# By: Zack Thompson / Created: 11/3/2023 +# Version: 1.0.0 / Updated: 11/20/2023 / By: ZT +# +# Description: This script checks the health of the APNS MDM Client and local MDM Profile. +# +# Pass [--debug | -d ] as an argument to "test" the script and not write to the local EA files. +# +#################################################################################################### + +################################################## +# Set variables for your environment + +# Jamf Pro Server URL +jamf_pro_server=$( /usr/bin/defaults read /Library/Preferences/com.jamfsoftware.jamf.plist jss_url ) + +# APNS Cert Topic +# Can be obtained from https://identity.apple.com/pushcert/ +# or https://:8443/pushNotificationCertificate.html +if [[ "${jamf_pro_server}" =~ .*production.* ]]; then + apple_mgmt_cert="com.apple.mgmt.External. value: ${value}" + + fi + +} + +write_to_ea_history() { + + # Arguments + # $1 = (str) Message that will be written to a log file + # $2 = (str) Optional description that will be written ahead of message + + local message="${1}" + local description="${2}" + + time_stamp=$( /bin/date +%Y-%m-%d\ %H:%M:%S ) + + if [[ "${locally_log}" == "true" && -z "${debug}" ]]; then + + if [[ ! -e "${local_ea_history}" ]]; then + + /bin/mkdir -p "$( /usr/bin/dirname "${local_ea_history}" )" + /usr/bin/touch "${local_ea_history}" + + fi + + echo "${time_stamp} | ${description}${message}" >> "${local_ea_history}" + + else + + echo "${time_stamp} | ${description}${message}" + + fi + +} + +PlistBuddy_Helper() { + # Helper function to interact with plists. + + # Arguments + # $1 = (str) action to perform on the plist + # The "print" action expects to work with text (passed to PlistBuddy + # via stdin), which can be generated via "print_xml" + # $2 = (str) Path to plist or generated xml + # $3 = (str) Key or key path to read + # $4 = (str) Type that will be used for the value + # $5 = (str) Value to be set to the passed key + + local action="${1}" + local plist="${2}" + local key="${3}" + local type="${4}" + local value="${5}" + + if [[ "${action}" == "print_xml" ]]; then + + # Dump plist file as XML + /usr/libexec/PlistBuddy -x -c "print" "${plist}" 2> /dev/null + + elif [[ "${action}" == "print" ]]; then + + # Read plist "str" (as a heredoc) and print the passed key + /usr/libexec/PlistBuddy -c "Print :${key}" /dev/stdin <<< "${plist}" 2> /dev/null + + elif [[ "${action}" == "add" ]]; then + + # Configure values + /usr/libexec/PlistBuddy -c "Add :${key} ${type} ${value}" "${plist}" > /dev/null 2>&1 || \ + /usr/libexec/PlistBuddy -c "Set :${key} ${value}" "${plist}" > /dev/null 2>&1 + + elif [[ "${action}" == "delete" ]]; then + + # Delete a key + /usr/libexec/PlistBuddy -c "Delete :${key} ${type}" "${plist}" > /dev/null 2>&1 + + elif [[ "${action}" == "clear" ]]; then + + # Clear a key's value + /usr/libexec/PlistBuddy -c "clear ${type}" "${plist}" > /dev/null 2>&1 + + fi + +} + +check_last_connection() { + + # Check if the last connected date is older than date variance. + # Arguments + # $1 = (str) a date in string format + # $2 = (str) the expected format of the date string + # $3 = (int) date variance; in number of days + # $4 = (str) Additional message to prefix the output + + fixed_date="$( fixup_space_in_string "${1}" )" + + if [[ + $( convert_date "${fixed_date}" "${2}" "%s" ) \ + -lt $( /bin/date -j -v-"${3}"d +"%s" ) + ]]; then + + echo "${4}${fixed_date} ([WARNING] Last connection was over ${3} days)" + + else + + echo "${4}${fixed_date} (Last connection was less than ${3} days)" + + fi + +} + +convert_date(){ + + # Convert a formatted date string into another format + # Arguments + # $1 = (str) a date in string format + # $2 = (str) the expected format of the date string + # $3 = (str) the desired format of the string + + /bin/date -j -f "${2}" "$( fixup_space_in_string "${1}" )" +"${3}" + +} + +fixup_space_in_string(){ + + # Convert unicode spaces in a string into a basic space + # Arguments + # $1 = (str) a string + + /usr/bin/sed 's/[[:space:]]/ /g' <<< "${1}" + +} + +verify_array_items_match() { + + # Verify all items in a passed array match + # Each item has leading and trailing whitespace removed + # Arguments + # $@ = (array) an array + + local array=("$@") + + result="True" + + for (( i=0; i<((${#array[@]}-1)); i++ )); do + if [[ $( echo "${array[$i]}" | xargs ) != $( echo "${array[(($i+1))]}" | xargs ) ]]; then + result="False" + break + fi + done + + echo "${result}" + +} + +################################################## +# Command Line Argument Parser + +parameters=( "$@" ) +arg_parse "${parameters[@]}" + +################################################## +# Check MDM Profile APNS Topic + +# Dump installed Profiles to stdout in XML format +all_profiles=$( /usr/bin/profiles show -cached --output "stdout-xml" ) + +# Get the number of installed profiles +number_of_profiles=$( + PlistBuddy_Helper "print" "${all_profiles}" "_computerlevel" | \ + /usr/bin/grep -a -E "^ Dict {$" | /usr/bin/wc -l | /usr/bin/xargs +) + +mdm_profile_matches="Unable to validate MDM Profile" + +# Loop through the Profile, searching for the one we're looking for. +for (( count=0; count < number_of_profiles; ++count )); do + + if [[ "${break_loop}" == "true" ]]; then + break + fi + + identifier=$( + PlistBuddy_Helper "print" "${all_profiles}" "_computerlevel:${count}:ProfileIdentifier" + ) + + if [[ "${identifier}" == "${mdm_profile_identifier}" ]]; then + + number_of_profile_items=$( + PlistBuddy_Helper "print" "${all_profiles}" "_computerlevel:${count}:ProfileItems" | \ + /usr/bin/grep -a -E "^ Dict {$" | /usr/bin/wc -l | /usr/bin/xargs + ) + + for (( + profile_items_count=0; + profile_items_count < number_of_profile_items; + ++profile_items_count + )); do + + if [[ "${break_loop}" == "true" ]]; then + break + fi + + payload_type=$( + PlistBuddy_Helper "print" "${all_profiles}" \ + "_computerlevel:${count}:ProfileItems:${profile_items_count}:PayloadType" + ) + + if [[ "${payload_type}" == "com.apple.mdm" ]]; then + + payload_content_topic=$( + PlistBuddy_Helper "print" "${all_profiles}" \ + "_computerlevel:${count}:ProfileItems:${profile_items_count}:PayloadContent:Topic" + ) + + if [[ "${payload_content_topic}" == "${apple_mgmt_cert}" ]]; then + + write_to_ea_history "MDM Profile's APNS Topic is valid" "${local_ea_history_mdm_profile_description}" + write_to_ea_inventory "${local_ea_inventory_mdm_profile_key}" "Valid" + mdm_profile_matches="true" + break_loop="true" + + else + + write_to_ea_history "[ERROR] MDM Profile's APNS Topic is invalid!" "${local_ea_history_mdm_profile_description}" + write_to_ea_history "MDM Profile APNS Topic: ${payload_content_topic}" "${local_ea_history_mdm_profile_description}" + write_to_ea_inventory "${local_ea_inventory_mdm_profile_key}" "Invalid" + break_loop="true" + mdm_profile_matches="false" + + fi + + fi + + done + + fi + +done + +################################################## +# Check MDM Profile APNS Topic + +# Check APNS status for the MDM Client service +apns_stats=$( /System/Library/PrivateFrameworks/ApplePushService.framework/apsctl status ) + +if [[ -z "${apns_stats}" ]]; then + + apns_topic_matches="Unable to validate APNS Topic" + +else + + ######################################## + # Device Channel Stats +device_apns_stats=$( /usr/bin/osascript -l JavaScript << EndOfScript + + var apns_stats=\`$apns_stats\` + + apns_stats.match( + /(^\s+application port name:\s+)com.apple.aps.mdmclient.daemon.push.production(.|\n)+?(?=\1)/gm + ) + +EndOfScript +) + + ############################## + # Device Last Push Notification Date + IFS=$'\n' read -r -d '' -a device_last_push_date <<< "$( + echo "${device_apns_stats}" | \ + /usr/bin/awk -F 'last full wake incoming push:' '{print $2}' | \ + /usr/bin/awk -F ' \\(' '{print $1}' + )" + + declare -a device_last_push_date_fixup + for item in "${device_last_push_date[@]}"; do + item=$( echo "${item}" | xargs ) + device_last_push_date_fixup+=("${item}") + done + + # Check if the more recent date is older than seven days + write_to_ea_history "$( + check_last_connection "${device_last_push_date_fixup[0]}" \ + "${default_date_format}" $last_connected_variance "${local_ea_history_apns_device_last_push_date}" + )" + write_to_ea_inventory "${local_ea_inventory_apns_device_last_push_date}" "$( + convert_date "${device_last_push_date_fixup[0]}" "${default_date_format}" "${jamfpro_ea_date_format}" + )" + + if [[ $( verify_array_items_match "${device_last_push_date_fixup[@]}" ) != "True" ]]; then + # Check if the more recent date is older than seven days + write_to_ea_history "$( + check_last_connection "${device_last_push_date_fixup[1]}" \ + "${default_date_format}" $last_connected_variance "${local_ea_history_apns_device_last_push_date}" + )" + fi + + ############################## + # Device Persistent Connection Status (Should be 'Ok') + device_persistent_conn_status=$( + echo "${device_apns_stats}" | \ + /usr/bin/awk -F 'persistent connection status:' '{print $2}' | \ + /usr/bin/xargs + ) + + write_to_ea_history "${device_persistent_conn_status}" "${local_ea_history_apns_device_persistent_conn_status}" + write_to_ea_inventory "${local_ea_inventory_apns_device_persistent_conn_status}" "${device_persistent_conn_status}" + + ############################## + # Device APNS Topics + IFS=$'\n' read -r -d '' -a device_push_topics <<< "$( + echo "${device_apns_stats}" | \ + /usr/bin/awk -F 'topic:' '{print $2}' + )" + + declare -a device_push_topics_fixup + for item in "${device_push_topics[@]}"; do + item=$( echo "${item}" | xargs ) + device_push_topics_fixup+=("${item}") + done + + if [[ $( verify_array_items_match "${device_push_topics_fixup[@]}" ) == "True" ]]; then + write_to_ea_history "Match" "${local_ea_history_apns_device_push_topics}" + write_to_ea_inventory "${local_ea_inventory_apns_device_push_topics}" "Match" + else + write_to_ea_history "${device_push_topics_fixup[0]}" "${local_ea_history_apns_device_push_topics}" + write_to_ea_history "${device_push_topics_fixup[1]}" "${local_ea_history_apns_device_push_topics}" + write_to_ea_inventory "${local_ea_inventory_apns_device_push_topics}" "Mismatch" + fi + + ############################## + # Device APNS Opportunistic Topic Status (Should be 'Ok') + device_opportunistic_topic_status=$( + echo "${device_apns_stats}" | \ + /usr/bin/grep -Ezo '\s\s+status:\s+[A-Za-z]+' | \ + /usr/bin/awk -F ':' '{print $2}' | \ + /usr/bin/xargs + ) + + write_to_ea_history "${device_opportunistic_topic_status}" "${local_ea_history_apns_device_opportunistic_topic_status}" + write_to_ea_inventory "${local_ea_inventory_apns_device_opportunistic_topic_status}" "${device_opportunistic_topic_status}" + + ######################################## + # User Channel Stats + user_apns_stats=$( /usr/bin/osascript -l JavaScript << EndOfScript + + var apns_stats=\`$apns_stats\` + + apns_stats.match( + /(^\s+application port name:\s+)com.apple.aps.mdmclient.agent.push.production(.|\n)+?(?=\1)/gm + ) + +EndOfScript +) + + ############################## + # User Last Push Notification Date + IFS=$'\n' read -r -d '' -a user_last_push_date <<< "$( + echo "${user_apns_stats}" | \ + /usr/bin/awk -F 'last incoming push(:| notification:)' '{print $2}' | \ + /usr/bin/awk -F ' \\(' '{print $1}' + )" + + if [[ -z "${user_last_push_date}" ]]; then + + write_to_ea_history "Last Push Not Reported" "${local_ea_history_apns_user_last_push_date}" + write_to_ea_inventory "${local_ea_inventory_apns_user_last_push_date}" "" + + else + + declare -a user_last_push_date_fixup + for item in "${user_last_push_date[@]}"; do + item=$( echo "${item}" | xargs ) + user_last_push_date_fixup+=("${item}") + done + + # Check if the more recent date is older than seven days + write_to_ea_history "$( + check_last_connection "${user_last_push_date_fixup[0]}" \ + "${default_date_format}" $last_connected_variance "${local_ea_history_apns_user_last_push_date}" + )" + write_to_ea_inventory "${local_ea_inventory_apns_user_last_push_date}" "$( + convert_date "${user_last_push_date_fixup[0]}" "${default_date_format}" "${jamfpro_ea_date_format}" + )" + + if [[ $( verify_array_items_match "${user_last_push_date_fixup[@]}" ) != "True" ]]; then + # Check if the more recent date is older than seven days + write_to_ea_history "$( + check_last_connection "${user_last_push_date_fixup[1]}" \ + "${default_date_format}" $last_connected_variance "${local_ea_history_apns_user_last_push_date}" + )" + fi + + fi + + ############################## + # User Persistent Connection Status (Should be 'Ok') + user_persistent_conn_status=$( + echo "${user_apns_stats}" | \ + /usr/bin/awk -F 'persistent connection status:' '{print $2}' | \ + /usr/bin/xargs + ) + + write_to_ea_history "${user_persistent_conn_status}" "${local_ea_history_apns_user_persistent_conn_status}" + write_to_ea_inventory "${local_ea_inventory_apns_user_persistent_conn_status}" "${user_persistent_conn_status}" + + ############################## + # User APNS Topics + IFS=$'\n' read -r -d '' -a user_push_topics <<< "$( + echo "${user_apns_stats}" | \ + /usr/bin/awk -F 'topic:' '{print $2}' + )" + + declare -a user_push_topics_fixup + for item in "${user_push_topics[@]}"; do + item=$( echo "${item}" | xargs ) + user_push_topics_fixup+=("${item}") + done + + if [[ $( verify_array_items_match "${user_push_topics_fixup[@]}" ) == "True" ]]; then + write_to_ea_history "Match" "${local_ea_history_apns_user_push_topics}" + write_to_ea_inventory "${local_ea_inventory_apns_user_push_topics}" "Match" + else + write_to_ea_history "${user_push_topics_fixup[0]}" "${local_ea_history_apns_user_push_topics}" + write_to_ea_history "${user_push_topics_fixup[1]}" "${local_ea_history_apns_user_push_topics}" + write_to_ea_inventory "${local_ea_inventory_apns_user_push_topics}" "Mismatch" + fi + + ############################## + # Device APNS Opportunistic Topic Status (Should be 'Ok') + user_opportunistic_topic_status=$( + echo "${user_apns_stats}" | \ + /usr/bin/grep -Ezo '\s\s+status:\s+[A-Za-z]+' | \ + /usr/bin/awk -F ':' '{print $2}' | \ + /usr/bin/xargs + ) + + write_to_ea_history "${user_opportunistic_topic_status}" "${local_ea_history_apns_user_opportunistic_topic_status}" + write_to_ea_inventory "${local_ea_inventory_apns_user_opportunistic_topic_status}" "${user_opportunistic_topic_status}" + + ######################################## + # Compiled Device and User Comparison Results + if [[ + "${apple_mgmt_cert}" == "${device_push_topics_fixup[0]}" && + "${apple_mgmt_cert}" == "${user_push_topics_fixup[0]}" + ]]; then + write_to_ea_history "Valid" "${local_ea_history_apns_topic_description}" + write_to_ea_inventory "${local_ea_inventory_apns_topic_key}" "Valid" + apns_topic_matches="true" + else + + write_to_ea_history "[ERROR] Mismatch!" "${local_ea_history_apns_topic_description}" + write_to_ea_inventory "${local_ea_inventory_apns_topic_key}" "Invalid" + + if [[ "${apple_mgmt_cert}" == "${device_push_topics_fixup[0]}" ]]; then + write_to_ea_history "Valid" "${local_ea_history_apns_and_device_topics}" + write_to_ea_inventory "${local_ea_inventory_apns_and_device_topics}" "Valid" + else + write_to_ea_history "[ERROR] Mismatch!" "${local_ea_history_apns_and_device_topics}" + write_to_ea_inventory "${local_ea_inventory_apns_and_device_topics}" "Invalid" + fi + + if [[ "${apple_mgmt_cert}" == "${user_push_topics_fixup[0]}" ]]; then + write_to_ea_history "Valid" "${local_ea_history_apns_and_user_topics}" + write_to_ea_inventory "${local_ea_inventory_apns_and_user_topics}" "Valid" + else + write_to_ea_history "[ERROR] Mismatch!" "${local_ea_history_apns_and_user_topics}" + write_to_ea_inventory "${local_ea_inventory_apns_and_user_topics}" "Invalid" + fi + + fi + +fi + +if [[ "${mdm_profile_matches}" == "true" && "${apns_topic_matches}" == "true" ]]; then + write_to_ea_history "Valid" "${local_ea_history_compiled_description}" + write_to_ea_inventory "${local_ea_inventory_compiled_key}" "Valid" +else + write_to_ea_history "Invalid" "${local_ea_history_compiled_description}" + write_to_ea_inventory "${local_ea_inventory_compiled_key}" "Invalid" +fi + +exit 0 \ No newline at end of file diff --git a/Jamf Pro/Extension Attributes/Get-LastMDMPush.sh b/Jamf Pro/Extension Attributes/Get-LastMDMPush.sh new file mode 100644 index 0000000..8183087 --- /dev/null +++ b/Jamf Pro/Extension Attributes/Get-LastMDMPush.sh @@ -0,0 +1,274 @@ +#!/bin/bash +# set -x + +#################################################################################################### +# Script Name: Get-LastMDMPush.sh +# By: Zack Thompson / Created: 11/3/2023 +# Version: 1.0.0 / Updated: 11/3/2023 / By: ZT +# +# Description: This script gets the time stamp of the +# last Push Notification received by the MDM Client. +# +#################################################################################################### + +################################################## +# Set variables for your environment + +# Pass a value in the first argument to "test" the script and not write to the local EA files. +testing="${1}" + +# Jamf Pro Server URL +jamf_pro_server=$( /usr/bin/defaults read /Library/Preferences/com.jamfsoftware.jamf.plist jss_url ) + +# APNS Cert Topic +# Can be obtained from https://identity.apple.com/pushcert/ +# or https://:8443/pushNotificationCertificate.html +if [[ "${jamf_pro_server}" =~ .*production.* ]]; then + apple_mgmt_cert="com.apple.mgmt.External.> "${local_ea_history}" + + else + + echo "${time_stamp} | ${local_ea_history_identifier}${message}" + + fi + +} + +report_result() { + + # Arguments + # $1 = (str) Message that will be recorded to the configured locations + + local message="${1}" + + write_to_ea_history "${message}" + write_to_ea_inventory "${local_ea_inventory_identifier}" "${message}" + echo "${message}" + exit 0 + +} + +check_last_connection() { + + # Check if the last connected date is older than date variance. + # Arguments + # $1 = (str) a date in string format + # $2 = (str) the expected format of the date string + # $3 = (int) date variance; in number of days + # $4 = (str) Additional message to prefix the output + + fixed_date="$( fixup_space_in_string "${1}" )" + + if [[ + $( convert_date "${fixed_date}" "${2}" "%s" ) \ + -lt $( /bin/date -j -v-"${3}"d +"%s" ) + ]]; then + + echo "${4} > [WARNING] Last connection was over seven days: ${fixed_date}" + + else + + echo "${4} > Last connection was less than seven days: ${fixed_date}" + + fi + +} + +convert_date(){ + + # Convert a formatted date string into another format + # Arguments + # $1 = (str) a date in string format + # $2 = (str) the expected format of the date string + # $3 = (str) the desired format of the string + + /bin/date -j -f "${2}" "$( fixup_space_in_string "${1}" )" +"${3}" + +} + +fixup_space_in_string(){ + + # Convert unicode spaces in a string into a basic space + # Arguments + # $1 = (str) a string + + /usr/bin/sed 's/[[:space:]]/ /g' <<< "${1}" + +} + +################################################## +# Bits staged, collect the information... + +# Check APNS status for the MDM Client service +apns_stats=$( /System/Library/PrivateFrameworks/ApplePushService.framework/apsctl status ) + +# Device Channel +device_apns_stats=$( /usr/bin/osascript -l JavaScript << EndOfScript + + var apns_stats=\`$apns_stats\` + + apns_stats.match( + /(^\s+application port name:\s+)com.apple.aps.mdmclient.daemon.push.production(.|\n)+?(?=\1)/gm + ) + +EndOfScript +) + +write_to_ea_history "${device_apns_stats}" + +device_last_push_date=$( + echo "${device_apns_stats}" | \ + /usr/bin/awk -F 'last push notification:' '{print $2}' | \ + /usr/bin/awk -F ' \\(' '{print $1}' | \ + /usr/bin/xargs +) +device_last_push_topic=$( + echo "${device_apns_stats}" | \ + /usr/bin/awk -F 'last push notification topic:' '{print $2}' | \ + /usr/bin/xargs +) + +# User Channel +user_apns_stats=$( /usr/bin/osascript -l JavaScript << EndOfScript + + var apns_stats=\`$apns_stats\` + + apns_stats.match( + /(^\s+application port name:\s+)com.apple.aps.mdmclient.agent.push.production(.|\n)+?(?=\1)/gm + ) + +EndOfScript +) + +write_to_ea_history "${user_apns_stats}" + +user_last_push_date=$( + echo "${user_apns_stats}" | \ + /usr/bin/awk -F 'last push notification:' '{print $2}' | \ + /usr/bin/awk -F ' \\(' '{print $1}' | \ + /usr/bin/xargs +) +user_last_push_topic=$( + echo "${user_apns_stats}" | \ + /usr/bin/awk -F 'last push notification topic:' '{print $2}' | \ + /usr/bin/xargs +) + +if [[ + "${apple_mgmt_cert}" == "${device_last_push_topic}" && + "${apple_mgmt_cert}" == "${user_last_push_topic}" +]]; then + write_to_ea_history "APNS Topic matches" +else + write_to_ea_history "[ERROR] APNS Topic does not match!" + + if [[ "${apple_mgmt_cert}" != "${device_last_push_topic}" ]]; then + write_to_ea_history "Device APNS Topic mismatch: ${device_last_push_topic}" + fi + + if [[ "${apple_mgmt_cert}" == "${user_last_push_topic}" ]]; then + write_to_ea_history "User APNS Topic mismatch: ${user_last_push_topic}" + fi + +fi + +# Check if the more recent date is older than seven days +write_to_ea_history "$( + check_last_connection "${device_last_push_date}" \ + "${default_date_format}" $last_connected_variance "Device Push" +)" +write_to_ea_history "$( + check_last_connection "${user_last_push_date}" \ + "${default_date_format}" $last_connected_variance "User Push" +)" + +# Convert dates to epoch to easily compare +if [[ + $( convert_date "${device_last_push_date}" "${default_date_format}" "%s" ) -gt \ + $( convert_date "${user_last_push_date}" "${default_date_format}" "%s" ) +]]; then + + # Convert dates for logging + write_to_ea_history "Reporting device channel date" + report_result "$( + convert_date "${device_last_push_date}" "${default_date_format}" "${jamfpro_ea_date_format}" + )" + +else + + # Convert dates for logging + write_to_ea_history "Reporting user channel date" + report_result "$( + convert_date "${user_last_push_date}" "${default_date_format}" "${jamfpro_ea_date_format}" + )" + +fi diff --git a/Jamf Pro/Extension Attributes/Verify-APNSCertTopic.sh b/Jamf Pro/Extension Attributes/Verify-APNSCertTopic.sh new file mode 100644 index 0000000..a5a8d2f --- /dev/null +++ b/Jamf Pro/Extension Attributes/Verify-APNSCertTopic.sh @@ -0,0 +1,329 @@ +#!/bin/bash +# set -x + +#################################################################################################### +# Script Name: Verify-APNSCertTopic.sh +# By: Zack Thompson / Created: 11/3/2023 +# Version: 1.0.0 / Updated: 11/3/2023 / By: ZT +# +# Description: This script checks if the the APNS MDM +# Client and MDM Profile management topics match. +# +#################################################################################################### + +################################################## +# Set variables for your environment + +# Pass a value in the first argument to "test" the script and not write to the local EA files. +testing="${1}" + +# Jamf Pro Server URL +jamf_pro_server=$( /usr/bin/defaults read /Library/Preferences/com.jamfsoftware.jamf.plist jss_url ) + +# APNS Cert Topic +# Can be obtained from https://identity.apple.com/pushcert/ +# or https://:8443/pushNotificationCertificate.html +if [[ "${jamf_pro_server}" =~ .*production.* ]]; then + apple_mgmt_cert="com.apple.mgmt.External.> "${local_ea_history}" + + else + + echo "${time_stamp} | ${local_ea_history_identifier}${message}" + + fi + +} + +report_result() { + + # Arguments + # $1 = (str) Message that will be recorded to the configured locations + + local message="${1}" + + write_to_ea_history "${message}" + write_to_ea_inventory "${local_ea_inventory_identifier}" "${message}" + echo "${message}" + exit 0 + +} + +PlistBuddy_Helper() { + # Helper function to interact with plists. + + # Arguments + # $1 = (str) action to perform on the plist + # The "print" action expects to work with text (passed to PlistBuddy + # via stdin), which can be generated via "print_xml" + # $2 = (str) Path to plist or generated xml + # $3 = (str) Key or key path to read + # $4 = (str) Type that will be used for the value + # $5 = (str) Value to be set to the passed key + + local action="${1}" + local plist="${2}" + local key="${3}" + local type="${4}" + local value="${5}" + + if [[ "${action}" = "print_xml" ]]; then + + # Dump plist file as XML + /usr/libexec/PlistBuddy -x -c "print" "${plist}" 2> /dev/null + + elif [[ "${action}" = "print" ]]; then + + # Read plist "str" (as a heredoc) and print the passed key + /usr/libexec/PlistBuddy -c "Print :${key}" /dev/stdin <<< "${plist}" 2> /dev/null + + elif [[ "${action}" = "add" ]]; then + + # Configure values + /usr/libexec/PlistBuddy -c "Add :${key} ${type} ${value}" "${plist}" > /dev/null 2>&1 || \ + /usr/libexec/PlistBuddy -c "Set :${key} ${value}" "${plist}" > /dev/null 2>&1 + + elif [[ "${action}" = "delete" ]]; then + + # Delete a key + /usr/libexec/PlistBuddy -c "Delete :${key} ${type}" "${plist}" > /dev/null 2>&1 + + elif [[ "${action}" = "clear" ]]; then + + # Clear a key's value + /usr/libexec/PlistBuddy -c "clear ${type}" "${plist}" > /dev/null 2>&1 + + fi + +} + +################################################## +# Bits staged, collect the information... + +# Dump installed Profiles to stdout in XML format +all_profiles=$( /usr/bin/profiles show -cached --output "stdout-xml" ) + +# Get the number of installed profiles +number_of_profiles=$( + PlistBuddy_Helper "print" "${all_profiles}" "_computerlevel" | \ + /usr/bin/grep -a -E "^ Dict {$" | /usr/bin/wc -l | /usr/bin/xargs +) + +mdm_profile_matches="Unable to validate MDM Profile" + +# Loop through the Profile, searching for the one we're looking for. +for (( count=0; count < number_of_profiles; ++count )); do + + if [[ "${break_loop}" == "true" ]]; then + break + fi + + identifier=$( + PlistBuddy_Helper "print" "${all_profiles}" "_computerlevel:${count}:ProfileIdentifier" + ) + + if [[ "${identifier}" == "${mdm_profile_identifier}" ]]; then + + number_of_profile_items=$( + PlistBuddy_Helper "print" "${all_profiles}" "_computerlevel:${count}:ProfileItems" | \ + /usr/bin/grep -a -E "^ Dict {$" | /usr/bin/wc -l | /usr/bin/xargs + ) + + for (( + profile_items_count=0; + profile_items_count < number_of_profile_items; + ++profile_items_count + )); do + + if [[ "${break_loop}" == "true" ]]; then + break + fi + + payload_type=$( + PlistBuddy_Helper "print" "${all_profiles}" \ + "_computerlevel:${count}:ProfileItems:${profile_items_count}:PayloadType" + ) + + if [[ "${payload_type}" == "com.apple.mdm" ]]; then + + payload_content_topic=$( + PlistBuddy_Helper "print" "${all_profiles}" \ + "_computerlevel:${count}:ProfileItems:${profile_items_count}:PayloadContent:Topic" + ) + + if [[ "${payload_content_topic}" == "${apple_mgmt_cert}" ]]; then + + write_to_ea_history "MDM Profile's APNS Topic is valid" + mdm_profile_matches="true" + break_loop="true" + + else + + write_to_ea_history "[ERROR] MDM Profile's APNS Topic is invalid!" + write_to_ea_history "MDM Profile APNS Topic: ${payload_content_topic}" + break_loop="true" + mdm_profile_matches="false" + + fi + + fi + + done + + fi + +done + +# Check APNS status for the MDM Client service +apns_stats=$( /System/Library/PrivateFrameworks/ApplePushService.framework/apsctl status ) + +if [[ -z "${apns_stats}" ]]; then + + apns_topic_matches="Unable to validate APNS Topic" + +else + + # Device Channel + device_apns_stats=$( /usr/bin/osascript -l JavaScript << EndOfScript + + var apns_stats=\`$apns_stats\` + + apns_stats.match( + /(^\s+application port name:\s+)com.apple.aps.mdmclient.daemon.push.production(.|\n)+?(?=\1)/gm + ) + +EndOfScript +) + device_last_push_topic=$( + echo "${device_apns_stats}" | \ + /usr/bin/awk -F 'last push notification topic:' '{print $2}' | \ + /usr/bin/xargs + ) + + # User Channel + user_apns_stats=$( /usr/bin/osascript -l JavaScript << EndOfScript + + var apns_stats=\`$apns_stats\` + + apns_stats.match( + /(^\s+application port name:\s+)com.apple.aps.mdmclient.agent.push.production(.|\n)+?(?=\1)/gm + ) + +EndOfScript +) + user_last_push_topic=$( + echo "${user_apns_stats}" | \ + /usr/bin/awk -F 'last push notification topic:' '{print $2}' | \ + /usr/bin/xargs + ) + + if [[ + "${apple_mgmt_cert}" == "${device_last_push_topic}" && + "${apple_mgmt_cert}" == "${user_last_push_topic}" + ]]; then + write_to_ea_history "APNS Topics are valid" + apns_topic_matches="true" + else + + write_to_ea_history "[ERROR] APNS Topic does not match!" + apns_topic_matches="" + + if [[ "${apple_mgmt_cert}" != "${device_last_push_topic}" ]]; then + write_to_ea_history "Device APNS Topic mismatch: ${device_last_push_topic}" + apns_topic_matches+=" Device APNS Topic mismatch;" + fi + + if [[ "${apple_mgmt_cert}" == "${user_last_push_topic}" ]]; then + write_to_ea_history "User APNS Topic mismatch: ${user_last_push_topic}" + apns_topic_matches+=" User APNS Topic mismatch;" + fi + + fi + +fi + +if [[ "${mdm_profile_matches}" = "true" && "${apns_topic_matches}" = "true" ]]; then + report_result "Valid" +else + + # Hold statuses + return_result="" + + if [[ "${mdm_profile_matches}" = "false" ]]; then + return_result+=" MDM Profile Mismatch;" + elif [[ "${mdm_profile_matches}" != "true" ]]; then + return_result+=" ${mdm_profile_matches};" + fi + + if [[ "${apns_topic_matches}" != "true" ]]; then + return_result+=" ${apns_topic_matches}" + fi + +fi + +# Trim leading space +return_result="${return_result## }" +# Trim trailing ; +report_result "${return_result%%;}"