v1.0.0 = Initial Version

Some MDM client health check scripts
This commit is contained in:
Zack T
2024-06-11 10:40:05 -07:00
parent ffce742a76
commit 8e1c85118e
7 changed files with 1842 additions and 0 deletions

View File

@@ -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 "<result>${return_result}</result>"
exit 0

View File

@@ -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 "<result>${return_result}</result>"
exit 0

View File

@@ -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 "<result>${return_result}</result>"
exit 0

View File

@@ -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 "<result>${return_result}</result>"
exit 0

View File

@@ -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://<jps.url.org>:8443/pushNotificationCertificate.html
if [[ "${jamf_pro_server}" =~ .*production.* ]]; then
apple_mgmt_cert="com.apple.mgmt.External.<INSERT_APNs_TOPIC_GUID_HERE"
elif [[ "${jamf_pro_server}" =~ .*development.* ]]; then
apple_mgmt_cert="com.apple.mgmt.External.INSERT_APNs_TOPIC_GUID_HERE"
fi
# MDM Profile Identifier
mdm_profile_identifier="00000000-0000-0000-A000-4A414D460003"
# The number of days before reporting device as "inactive."
last_connected_variance=7
# The date format expected from date fields generated by `apns_stats`.
default_date_format="%b %d, %Y at %H:%M:%S %p"
# The format of the date string that will be used for reporting.
jamfpro_ea_date_format="%Y-%m-%d %H:%M:%S"
# 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="Get-APNSMDMClientHealth.sh: "
####################
# Compiled Results
local_ea_history_compiled_description="APNS/MDM Management Topics: "
local_ea_inventory_compiled_key="apns_mdm_mgmt_topics"
# MDM Profile APNS Topic
local_ea_history_mdm_profile_description="MDM Management Topic: "
local_ea_inventory_mdm_profile_key="mdm_apns_topic"
# APNS Cert and Local Push Topic Comparison
local_ea_history_apns_topic_description="APNS Topics: "
local_ea_inventory_apns_topic_key="apns_topics"
# APNS Cert and Device Push Topic Comparison
local_ea_history_apns_and_device_topics="APNS Cert and Device Topics: "
local_ea_inventory_apns_and_device_topics="apns_and_device_topics"
# APNS Cert and User Push Topic Comparison
local_ea_history_apns_and_user_topics="APNS Cert and User Topics: "
local_ea_inventory_apns_and_user_topics="apns_and_user_topics"
####################
# APNS Device Channel Reporting Variables
# APNS Device Last Push Date
local_ea_history_apns_device_last_push_date="APNS Device Last Push Date: "
local_ea_inventory_apns_device_last_push_date="apns_device_last_push_date"
# APNS Device Persistent Connection Status
local_ea_history_apns_device_persistent_conn_status="APNS Device Persistent Connection Status: "
local_ea_inventory_apns_device_persistent_conn_status="apns_device_persistent_conn_status"
# APNS Device Push Topics
local_ea_history_apns_device_push_topics="APNS Device Push Topics: "
local_ea_inventory_apns_device_push_topics="apns_device_push_topics"
# APNS Device Opportunistic Topic Status
local_ea_history_apns_device_opportunistic_topic_status="APNS Device Opportunistic Topic Status: "
local_ea_inventory_apns_device_opportunistic_topic_status="apns_device_opportunistic_topic_status"
####################
# APNS User Channel Reporting Variables
# APNS User Last Push Date
local_ea_history_apns_user_last_push_date="APNS User Last Push Date: "
local_ea_inventory_apns_user_last_push_date="apns_user_last_push_date"
# APNS User Persistent Connection Status
local_ea_history_apns_user_persistent_conn_status="APNS User Persistent Connection Status: "
local_ea_inventory_apns_user_persistent_conn_status="apns_user_persistent_conn_status"
# APNS User Push Topics
local_ea_history_apns_user_push_topics="APNS User Push Topics: "
local_ea_inventory_apns_user_push_topics="apns_user_push_topics"
# APNS User Opportunistic Topic Status
local_ea_history_apns_user_opportunistic_topic_status="APNS User Opportunistic Topic Status: "
local_ea_inventory_apns_user_opportunistic_topic_status="apns_user_opportunistic_topic_status"
##################################################
# 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_inventory() {
# Arguments
# $1 = (str) Plist key that the message value will be assigned too
# $2 = (str) Message that will be assigned to the key
local key="${1}"
local value="${2}"
if [[ "${locally_log}" == "true" && -z "${debug}" ]]; then
if [[ ! -e "${local_ea_inventory}" ]]; then
/bin/mkdir -p "$( /usr/bin/dirname "${local_ea_inventory}" )"
/usr/bin/touch "${local_ea_inventory}"
fi
/usr/bin/defaults write "${local_ea_inventory}" "${key}" "${value}"
elif [[ -n "${debug}" ]]; then
write_to_ea_history "key: ${key} > 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

View File

@@ -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://<jps.url.org>:8443/pushNotificationCertificate.html
if [[ "${jamf_pro_server}" =~ .*production.* ]]; then
apple_mgmt_cert="com.apple.mgmt.External.<INSERT_APNs_TOPIC_GUID_HERE"
elif [[ "${jamf_pro_server}" =~ .*development.* ]]; then
apple_mgmt_cert="com.apple.mgmt.External.INSERT_APNs_TOPIC_GUID_HERE"
fi
# The number of days before reporting device as "inactive."
last_connected_variance=7
# The date format expected from date fields generated by `apns_stats`.
default_date_format="%b %d, %Y at %H:%M:%S %p"
# The format of the date string that will be used for reporting.
jamfpro_ea_date_format="%Y-%m-%d %H:%M:%S"
# 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_history_identifier="Last MDM Push Received: "
local_ea_inventory="/opt/ManagedFrameworks/Inventory.plist"
local_ea_inventory_identifier="apns_mdm_health"
##################################################
# Functions
write_to_ea_inventory() {
# Arguments
# $1 = (str) Plist key that the message value will be assigned too
# $2 = (str) Message that will be assigned to the key
local key="${1}"
local value="${2}"
if [[ "${locally_log}" == "true" && -z "${testing}" ]]; then
if [[ ! -e "${local_ea_inventory}" ]]; then
/bin/mkdir -p "$( /usr/bin/dirname "${local_ea_inventory}" )"
/usr/bin/touch "${local_ea_inventory}"
fi
/usr/bin/defaults write "${local_ea_inventory}" "${key}" "${value}"
fi
}
write_to_ea_history() {
# Arguments
# $1 = (str) Message that will be written to a log file
local message="${1}"
time_stamp=$( /bin/date +%Y-%m-%d\ %H:%M:%S )
if [[ "${locally_log}" == "true" && -z "${testing}" ]]; 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} | ${local_ea_history_identifier}${message}" >> "${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 "<result>${message}</result>"
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

View File

@@ -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://<jps.url.org>:8443/pushNotificationCertificate.html
if [[ "${jamf_pro_server}" =~ .*production.* ]]; then
apple_mgmt_cert="com.apple.mgmt.External.<INSERT_APNs_TOPIC_GUID_HERE"
elif [[ "${jamf_pro_server}" =~ .*development.* ]]; then
apple_mgmt_cert="com.apple.mgmt.External.INSERT_APNs_TOPIC_GUID_HERE"
fi
# MDM Profile Identifier
mdm_profile_identifier="00000000-0000-0000-A000-4A414D460003"
# 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_history_identifier="APNS/MDM Management Topics: "
local_ea_inventory="/opt/ManagedFrameworks/Inventory.plist"
local_ea_inventory_identifier="apns_mdm_health"
##################################################
# Functions
write_to_ea_inventory() {
# Arguments
# $1 = (str) Plist key that the message value will be assigned too
# $2 = (str) Message that will be assigned to the key
local key="${1}"
local value="${2}"
if [[ "${locally_log}" == "true" && -z "${testing}" ]]; then
if [[ ! -e "${local_ea_inventory}" ]]; then
/bin/mkdir -p "$( /usr/bin/dirname "${local_ea_inventory}" )"
/usr/bin/touch "${local_ea_inventory}"
fi
/usr/bin/defaults write "${local_ea_inventory}" "${key}" "${value}"
fi
}
write_to_ea_history() {
# Arguments
# $1 = (str) Message that will be written to a log file
local message="${1}"
time_stamp=$( /bin/date +%Y-%m-%d\ %H:%M:%S )
if [[ "${locally_log}" == "true" && -z "${testing}" ]]; 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} | ${local_ea_history_identifier}${message}" >> "${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 "<result>${message}</result>"
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%%;}"