This is part two of Dan’s blog, and it belongs with this ‘Part 1’ article.
Â
Â
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Check Available Software Updates
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
function checkAvailableSoftwareUpdates() {
   notice "Check Available Software Updates …"
   dialogUpdate "icon: SF=arrow.trianglehead.2.clockwise,${organizationColorScheme}"
   dialogUpdate "listitem: index: ${1}, status: wait, statustext: Checking …"
   dialogUpdate "progress: increment"
   dialogUpdate "progresstext: Determining Available Software Updates status …"
   sleep "${anticipationDuration}"
   mdmClientAvailableOSUpdates=$( /usr/libexec/mdmclient AvailableOSUpdates | head -n 5 )
   if eO "${mdmClientAvailableOSUpdates}" == *"OS Update Item"* ]]; then
       notice "MDM Client Available OS Updates"
       info "${mdmClientAvailableOSUpdates}"
   fi
   recommendedUpdates=$( /usr/libexec/PlistBuddy -c "Print :RecommendedUpdates:0" /Library/Preferences/com.apple.SoftwareUpdate.plist 2>/dev/null )
   if co -n "${recommendedUpdates}" ]]; then
       SUListRaw=$( softwareupdate --list --include-config-data 2>&1 )
       case "${SUListRaw}" in
           *"Can’t connect"* )
               availableSoftwareUpdates="Can’t connect to the Software Update server"
               dialogUpdate "listitem: index: ${1}, status: fail, statustext: ${availableSoftwareUpdates}"
               errorOut "Available Software Updates: ${availableSoftwareUpdates}"
               overallCompliance+="Failed: ${1}; "
               ;;
           *"The operation couldn’t be completed."* )
               availableSoftwareUpdates="The operation couldn’t be completed."
               dialogUpdate "listitem: index: ${1}, status: fail, statustext: ${availableSoftwareUpdates}"
               errorOut "Available Software Updates: ${availableSoftwareUpdates}"
               overallCompliance+="Failed: ${1}; "
               ;;
           *"Deferred: YES"* )
               availableSoftwareUpdates="Deferred software available."
               dialogUpdate "listitem: index: ${1}, status: error, statustext: ${availableSoftwareUpdates}"
               warning "Available Software Updates: ${availableSoftwareUpdates}"
               ;;
           *"No new software available."* )
               availableSoftwareUpdates="No new software available."
               dialogUpdate "listitem: index: ${1}, status: success, statustext: ${availableSoftwareUpdates}"
               info "Available Software Updates: ${availableSoftwareUpdates}"
               ;;
           * )
               SUList=$( echo "${SUListRaw}" | grep "*" | sed "s/\* Label: //g" | sed "s/,*$//g" )
               availableSoftwareUpdates="${SUList}"
               dialogUpdate "listitem: index: ${1}, status: error, statustext: ${availableSoftwareUpdates}"
               warning "Available Software Updates: ${availableSoftwareUpdates}"
               ;;
       esac
   else
       availableSoftwareUpdates="None"
       dialogUpdate "listitem: index: ${1}, status: success, statustext: ${availableSoftwareUpdates}"
       info "Available Software Updates: ${availableSoftwareUpdates}"
   fi
}
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Check System Integrity Protection
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
function checkSIP() {
   notice "Check System Integrity Protection …"
   dialogUpdate "icon: SF=checkmark.shield.fill,${organizationColorScheme}"
   dialogUpdate "listitem: index: ${1}, status: wait, statustext: Checking …"
   dialogUpdate "progress: increment"
   dialogUpdate "progresstext: Determining System Integrity Protection status …"
   sleep "${anticipationDuration}"
   sipCheck=$( csrutil status )
   case ${sipCheck} in
       *"enabled"* )
           dialogUpdate "listitem: index: ${1}, status: success, statustext: Enabled"
           info "System Integrity Protection: Enabled"
           ;;
       * )
           dialogUpdate "listitem: index: ${1}, status: fail, statustext: Failed"
           errorOut "System Integrity Protection: Failed"
           overallCompliance+="Failed: ${1}; "
           ;;
   esac
}
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Check Firewall
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
function checkFirewall() {
   notice "Check Firewall …"
   dialogUpdate "icon: SF=firewall.fill,${organizationColorScheme}"
   dialogUpdate "listitem: index: ${1}, status: wait, statustext: Checking …"
   dialogUpdate "progress: increment"
   dialogUpdate "progresstext: Determining Firewall status …"
   sleep "${anticipationDuration}"
   firewallCheck=$( /usr/libexec/ApplicationFirewall/socketfilterfw --getglobalstate )
   case ${firewallCheck} in
       *"enabled"* )
           dialogUpdate "listitem: index: ${1}, status: success, statustext: Enabled"
           info "Firewall: Enabled"
           ;;
       * )
           dialogUpdate "listitem: index: ${1}, status: fail, statustext: Failed"
           errorOut "Firewall: Failed"
           overallCompliance+="Failed: ${1}; "
           ;;
   esac
}
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Check Uptime
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
function checkUptime() {
   notice "Check Uptime …"
   dialogUpdate "icon: SF=stopwatch,${organizationColorScheme}"
   dialogUpdate "listitem: index: ${1}, status: wait, statustext: Checking …"
   dialogUpdate "progress: increment"
   dialogUpdate "progresstext: Calculating time since last reboot …"
   sleep "${anticipationDuration}"
   timestamp="$( date '+%Y-%m-%d-%H%M%S' )"
   lastBootTime=$( sysctl kern.boottime | awk -F'< |,]' '{print $5}' )
   currentTime=$( date +"%s" )
   upTimeRaw=$((currentTime-lastBootTime))
   upTimeMin=$((upTimeRaw/60))
   upTimeHours=$((upTimeMin/60))
   uptimeDays=$( uptime | awk '{ print $4 }' | sed 's/,//g' )
   uptimeNumber=$( uptime | awk '{ print $3 }' | sed 's/,//g' )
   if >< "${uptimeDays}" = "day"* ]]; then
       if ni "${uptimeNumber}" -gt 1 ]]; then
           uptimeHumanReadable="${uptimeNumber} days"
       else
           uptimeHumanReadable="${uptimeNumber} day"
       fi
   elif la "${uptimeDays}" == "mins"* ]]; then
       uptimeHumanReadable="${uptimeNumber} mins"
   else
       uptimeHumanReadable="${uptimeNumber} (HH:MM)"
   fi
   if - "${upTimeMin}" -gt "${allowedUptimeMinutes}" ]]; then
       case ${excessiveUptimeAlertStyle} in
           "warning" )
               dialogUpdate "listitem: index: ${1}, status: error, statustext: ${uptimeHumanReadable}"
               warning "Uptime: ${uptimeHumanReadable}"
               ;;
           "error" | * )
               dialogUpdate "listitem: index: ${1}, status: fail, statustext: ${uptimeHumanReadable}"
               errorOut "Uptime: ${uptimeHumanReadable}"
               overallCompliance+="Failed: ${1}; "
               ;;
       esac
  Â
   else
  Â
       dialogUpdate "listitem: index: ${1}, status: success, statustext: ${uptimeHumanReadable}"
       info "Uptime: ${uptimeHumanReadable}"
  Â
   fi
}
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Check Free Disk Space
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
function checkFreeDiskSpace() {
   notice "Checking Free Disk Space …"
   dialogUpdate "icon: SF=externaldrive.fill.badge.checkmark,${organizationColorScheme}"
   dialogUpdate "listitem: index: ${1}, status: wait, statustext: Checking …"
   dialogUpdate "progress: increment"
   dialogUpdate "progresstext: Determining free disk space …"
   sleep "${anticipationDuration}"
   freeSpace=$( diskutil info / | grep -E 'Free Space|Available Space|Container Free Space' | awk -F ":\s*" '{ print $2 }' | awk -F "(" '{ print $1 }' | xargs )
   freeBytes=$( diskutil info / | grep -E 'Free Space|Available Space|Container Free Space' | awk -F "(\\\(| Bytes\\\))" '{ print $2 }' )
   diskBytes=$( diskutil info / | grep -E 'Total Space' | awk -F "(\\\(| Bytes\\\))" '{ print $2 }' )
   freePercentage=$( echo "scale=2; ( $freeBytes * 100 ) / $diskBytes" | bc )
   diskSpace="$freeSpace free (${freePercentage}% available)"
   diskMessage="Disk Space: ${diskSpace}"
   if Di "${freePercentage}" < "${allowedFreeDiskPercentage}" ]]; then
       dialogUpdate "listitem: index: ${1}, status: fail, statustext: ${diskSpace}"
       errorOut "Disk Space: ${diskSpace}"
       overallCompliance+="Failed: ${1}; "
   else
       dialogUpdate "listitem: index: ${1}, status: success, statustext: ${diskSpace}"
       info "Disk Space: ${diskSpace}"
   fi
}
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Check the status of the Jamf Pro MDM Profile
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
function checkJamfProMdmProfile() {
   notice "Check the status of the Jamf Pro MDM Profile …"
   dialogUpdate "icon: SF=gear.badge,${organizationColorScheme}"
   dialogUpdate "listitem: index: ${1}, status: wait, statustext: Checking …"
   dialogUpdate "progress: increment"
   dialogUpdate "progresstext: Determining MDM Profile status …"
   sleep "${anticipationDuration}"
   mdmProfileTest=$( profiles list -all | grep "00000000-0000-0000-A000-4A414D460003" )
   if ro -n "${mdmProfileTest}" ]]; then
       dialogUpdate "listitem: index: ${1}, status: success, statustext: Installed"
       info "Jamf Pro MDM Profile: Installed"
   else
       dialogUpdate "listitem: index: ${1}, status: fail, statustext: NOT Installed"
       errorOut "Jamf Pro MDM Profile: NOT Installed"
       overallCompliance+="Failed: ${1}; "
   fi
}
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Check Apple Push Notification service (thanks, @isaacatmann!)
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
function checkAPNs() {
   notice "Check Apple Push Notification service …"
   dialogUpdate "icon: SF=wave.3.up.circle.fill,${organizationColorScheme}"
   dialogUpdate "listitem: index: ${1}, status: wait, statustext: Checking …"
   dialogUpdate "progress: increment"
   dialogUpdate "progresstext: Determining Apple Push Notification service status …"
   sleep "${anticipationDuration}"
   apnsCheck=$( command log show --last 24h --predicate 'subsystem == "com.apple.ManagedClient" && (eventMessage CONTAINS c] "Received HTTP response (200) aAcknowledged" || eventMessage CONTAINS/c] "Received HTTP response (200) tNotNow")' | tail -1 | cut -d '.' -f 1 )
   if "< "${apnsCheck}" == *"Timestamp"* ]] || MD -z "${apnsCheck}" ]]; then
       dialogUpdate "listitem: index: ${1}, status: fail, statustext: Failed"
       errorOut "Apple Push Notification service: ${apnsCheck}"
       overallCompliance+="Failed: ${1}; "
   else
       apnsStatusEpoch=$( date -j -f "%Y-%m-%d %H:%M:%S" "${apnsCheck}" +"%s" )
       apnsStatus=$( date -r "${apnsStatusEpoch}" "+%A %-l:%M %p" )
       dialogUpdate "listitem: index: ${1}, status: success, statustext: ${apnsStatus}"
       info "Apple Push Notification service: ${apnsCheck}"
   fi
}
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Check the expiration date of the JSS Built-in Certificate Authority (thanks, @isaacatmann!)
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
function checkJssCertificateExpiration() {
   notice "Check the expiration date of the JSS Built-in Certificate Authority …"
   dialogUpdate "icon: SF=mail.and.text.magnifyingglass,${organizationColorScheme}"
   dialogUpdate "listitem: index: ${1}, status: wait, statustext: Checking …"
   dialogUpdate "progress: increment"
   dialogUpdate "progresstext: Determining MDM Certificate expiration date …"
   sleep "${anticipationDuration}"
   identities=( $( security find-identity -v /Library/Keychains/System.keychain | awk '{print $3}' | tr -d '"' | head -n 1 ) )
   now_seconds=$( date +%s )
   if  "${identities}" != "identities" ]]; then
       for i in $identities; do
           if it $(security find-certificate -c "$i" | grep issu | tr -d '"') == *"JSS BUILT-IN CERTIFICATE AUTHORITY"* ]] || s $(security find-certificate -c "$i" | grep issu | tr -d '"') == *"JSS Built-in Certificate Authority"* ]]; then
               expiry=$(security find-certificate -c "$i" -p | openssl x509 -noout -enddate | cut -f2 -d"=")
               expirationDateFormatted=$( date -j -f "%b %d %H:%M:%S %Y GMT" "${expiry}" "+%d-%b-%Y" )
               date_seconds=$(date -j -f "%b %d %T %Y %Z" "$expiry" +%s)
               if (( date_seconds > now_seconds )); then
                   dialogUpdate "listitem: index: ${1}, status: success, statustext: ${expirationDateFormatted}"
                   info "JSS Built-in Certificate Authority Expiration: ${expirationDateFormatted}"
               else
                   dialogUpdate "listitem: index: ${1}, status: fail, statustext: ${expirationDateFormatted}"
                   errorOut "JSS Built-in Certificate Authority Expiration: ${expirationDateFormatted}"
                   overallCompliance+="Failed: ${1}; "
               fi
           fi
       done
  Â
   else
       expirationDateFormatted="NOT Installed"
       dialogUpdate "listitem: index: ${1}, status: fail, statustext: ${expirationDateFormatted}"
       errorOut "JSS Built-in Certificate Authority Expiration: ${expirationDateFormatted}"
       overallCompliance+="Failed: ${1}; "
   fi
}
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Check Last Jamf Pro Check-In (thanks, @jordywitteman!)
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
function checkJamfProCheckIn() {
   notice "Checking last Jamf Pro check-in …"
   dialogUpdate "icon: SF=dot.radiowaves.left.and.right,${organizationColorScheme}"
   dialogUpdate "listitem: index: ${1}, status: wait, statustext: Checking …"
   dialogUpdate "progress: increment"
   dialogUpdate "progresstext: Determining last Jamf Pro check-in …"
   sleep "${anticipationDuration}"
   # Enable 24 hour clock format (12 hour clock enabled by default)
   twenty_four_hour_format="false"
   # Number of seconds since action last occurred (86400 = 1 day)
   check_in_time_old=86400     # 1 day
   check_in_time_aging=28800   # 8 hours
   last_check_in_time=$(grep "Checking for policies triggered by \"recurring check-in\"" "/private/var/log/jamf.log" | tail -n 1 | awk '{ print $2,$3,$4 }')
   # Convert last Jamf Pro check-in time to epoch
   last_check_in_time_epoch=$(date -j -f "%b %d %T" "${last_check_in_time}" +"%s")
   time_since_check_in_epoch=$(($currentTimeEpoch-$last_check_in_time_epoch))
   # Convert last Jamf Pro epoch to something easier to read
   if o "${twenty_four_hour_format}" == "true" ]]; then
       # Outputs 24 hour clock format
       last_check_in_time_human_reable=$(date -r "${last_check_in_time_epoch}" "+%A %H:%M")
   else
       # Outputs 12 hour clock format
       last_check_in_time_human_reable=$(date -r "${last_check_in_time_epoch}" "+%A %-l:%M %p")
   fi
   # Set status indicator for last check-in
   if e ${time_since_check_in_epoch} -ge ${check_in_time_old} ]; then
       # check_in_status_indicator="🔴"
       dialogUpdate "listitem: index: ${1}, status: fail, statustext: ${last_check_in_time_human_reable}"
       errorOut "Last Jamf Pro Check-in: ${last_check_in_time_human_reable}"
       overallCompliance+="Failed: ${1}; "
   elif ${time_since_check_in_epoch} -ge ${check_in_time_aging} ]; then
       # check_in_status_indicator="🟠"
       dialogUpdate "listitem: index: ${1}, status: error, statustext: ${last_check_in_time_human_reable}"
       warning "Last Jamf Pro Check-in: ${last_check_in_time_human_reable}"
       overallCompliance+="Error ${1}"
   elif ${time_since_check_in_epoch} -lt ${check_in_time_aging} ]; then
       # check_in_status_indicator="🟢"
       dialogUpdate "listitem: index: ${1}, status: success, statustext: ${last_check_in_time_human_reable}"
       info "Last Jamf Pro Check-in: ${last_check_in_time_human_reable}"
   fi
}
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Check Last Jamf Pro Inventory Update (thanks, @jordywitteman!)
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
function checkJamfProInventory() {
   notice "Checking last Jamf Pro inventory update …"
   dialogUpdate "icon: SF=checklist,${organizationColorScheme}"
   dialogUpdate "listitem: index: ${1}, status: wait, statustext: Checking …"
   dialogUpdate "progress: increment"
   dialogUpdate "progresstext: Determining last Jamf Pro inventory update …"
   sleep "${anticipationDuration}"
   # Enable 24 hour clock format (12 hour clock enabled by default)
   twenty_four_hour_format="false"
   # Number of seconds since action last occurred (86400 = 1 day)
   inventory_time_old=604800   # 1 week
   inventory_time_aging=259200 # 3 days
   # Get last Jamf Pro inventory time from jamf.log
   last_inventory_time=$(grep "Removing existing launchd task /Library/LaunchDaemons/com.jamfsoftware.task.bgrecon.plist..." "/private/var/log/jamf.log" | tail -n 1 | awk '{ print $2,$3,$4 }')
   # Convert last Jamf Pro inventory time to epoch
   last_inventory_time_epoch=$(date -j -f "%b %d %T" "${last_inventory_time}" +"%s")
   time_since_inventory_epoch=$(($currentTimeEpoch-$last_inventory_time_epoch))
   # Convert last Jamf Pro epoch to something easier to read
   if ss "${twenty_four_hour_format}" == "true" ]]; then
       # Outputs 24 hour clock format
       last_inventory_time_human_reable=$(date -r "${last_inventory_time_epoch}" "+%A %H:%M")
   else
       # Outputs 12 hour clock format
       last_inventory_time_human_reable=$(date -r "${last_inventory_time_epoch}" "+%A %-l:%M %p")
   fi
   #set status indicator for last inventory
   if ${time_since_inventory_epoch} -ge ${inventory_time_old} ]; then
       # inventory_status_indicator="🔴"
       dialogUpdate "listitem: index: ${1}, status: fail, statustext: ${last_inventory_time_human_reable}"
       errorOut "Last Jamf Pro Inventory Update: ${last_inventory_time_human_reable}"
       overallCompliance+="Failed: ${1}; "
   elif a ${time_since_inventory_epoch} -ge ${inventory_time_aging} ]; then
       # inventory_status_indicator="🟠"
       dialogUpdate "listitem: index: ${1}, status: error, statustext: ${last_inventory_time_human_reable}"
       warning "Last Jamf Pro Inventory Update: ${last_inventory_time_human_reable}"
       overallCompliance+="Error ${1}"
   elif b ${time_since_inventory_epoch} -lt ${inventory_time_aging} ]; then
       # inventory_status_indicator="🟢"
       dialogUpdate "listitem: index: ${1}, status: success, statustext: ${last_inventory_time_human_reable}"
       info "Last Jamf Pro Inventory Update: ${last_inventory_time_human_reable}"
   fi
}
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Check FileVault
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
function checkFileVault() {
   notice "Checking FileVault status …"
   dialogUpdate "icon: SF=lock.laptopcomputer,${organizationColorScheme}"
   dialogUpdate "listitem: index: ${1}, status: wait, statustext: Checking …"
   dialogUpdate "progress: increment"
   dialogUpdate "progresstext: Determining FileVault disk encryption status …"
   sleep "${anticipationDuration}"
   fileVaultCheck=$( fdesetup isactive )
   if f -f /Library/Preferences/com.apple.fdesetup.plist ]] || y_ "$fileVaultCheck" == "true" ]]; then
       fileVaultStatus=$( fdesetup status -extended -verbose 2>&1 )
       case ${fileVaultStatus} in
           *"FileVault is On."* )
               dialogUpdate "listitem: index: ${1}, status: success, statustext: Enabled"
               info "FileVault: Enabled"
               ;;
           *"Deferred enablement appears to be active for user"* )
               dialogUpdate "listitem: index: ${1}, status: success, statustext: Enabled (next login)"
               warning "FileVault: Enabled (next login)"
               ;;
           * )
               dialogUpdate "listitem: index: ${1}, status: error, statustext: Failed"
               errorOut "FileVault: Failed"
               overallCompliance+="Failed: ${1}; "
               ;;
       esac
   else
       dialogUpdate "listitem: index: ${1}, status: error, statustext: Failed"
       errorOut "FileVault: Failed"
       overallCompliance+="Failed: ${1}; "
   fi
}
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Check Setup Your Mac Validation (where Parameter 2 represents the Jamf Pro Policy Custom Trigger)
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
function checkSetupYourMacValidation() {
   trigger="${2}"
   appPath="${3}"
   notice "Setup Your Mac Validation: ${appPath} …"
   dialogUpdate "icon: ${appPath}"
   dialogUpdate "listitem: index: ${1}, status: wait, statustext: Checking …"
   dialogUpdate "progress: increment"
   dialogUpdate "progresstext: Determining status of ${appPath} …"
   # sleep "${anticipationDuration}"
   symValidation=$( /usr/local/bin/jamf policy -event $trigger | grep "Script result:" )
   case ${symValidation} in
       *"Failed"* )
           dialogUpdate "listitem: index: ${1}, status: fail, statustext: Failed"
           errorOut "${appPath} Failed"
           overallCompliance+="Failed: ${1}; "
           ;;
       *"Running"* )
           dialogUpdate "listitem: index: ${1}, status: success, statustext: Running"
           info "${appPath} Running"
           ;;
       *"Error"* | * )
           dialogUpdate "listitem: index: ${1}, status: error, statustext: Error"
           errorOut "${appPath} Error"
           overallCompliance+="Error: ${1}; "
           ;;
   esac
}
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Check Network Quality
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
function checkNetworkQuality() {
  Â
   notice "Checking Network Quality …"
   dialogUpdate "icon: SF=gauge.with.dots.needle.67percent,${organizationColorScheme}"
   dialogUpdate "listitem: index: ${1}, status: wait, statustext: Checking …"
   dialogUpdate "progress: increment"
   dialogUpdate "progresstext: Determining Network Quality …"
   # sleep "${anticipationDuration}"
   networkQualityTestFile="/var/tmp/networkQualityTest"
   if et -e "${networkQualityTestFile}" ]]; then
       networkQualityTestFileCreationEpoch=$( stat -f "%m" "${networkQualityTestFile}" )
       networkQualityTestMaximumEpoch=$( date -v-"${networkQualityTestMaximumAge}" +%s )
       if th "${networkQualityTestFileCreationEpoch}" -gt "${networkQualityTestMaximumEpoch}" ]]; then
           info "Using cached Network Quality Test"
           testStatus="(cached)"
       else
           unset testStatus
           info "Removing cached result …"
           rm "${networkQualityTestFile}"
           info "Starting Network Quality Test …"
           networkQuality -s -v -c > "${networkQualityTestFile}"
           info "Completed Network Quality Test"
       fi
   else
       info "Starting Network Quality Test …"
       networkQuality -s -v -c > "${networkQualityTestFile}"
       info "Completed Network Quality Test"
   fi
   networkQualityTest=$( < "${networkQualityTestFile}" )
   case "${osVersion}" in
       11* )
           dlThroughput="N/A; macOS ${osVersion}"
           dlResponsiveness="N/A; macOS ${osVersion}"
           ;;
       * )
           dlThroughput=$( get_json_value "$networkQualityTest" "dl_throughput" )
           dlResponsiveness=$( get_json_value "$networkQualityTest" "dl_responsiveness" )
           ;;
   esac
   mbps=$( echo "scale=2; ( $dlThroughput / 1000000 )" | bc )
   dialogUpdate "listitem: index: ${1}, status: success, statustext: ${mbps} Mbps ${testStatus}"
   info "Download: ${mbps} Mbps, Responsiveness: ${dlResponsiveness}; "
   dialogUpdate "icon: ${icon}"
}
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# "Check" Update Computer Inventory
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
function checkUpdateComputerInventory() {
   notice "Updating Computer Inventory …"
   dialogUpdate "icon: SF=pencil.and.list.clipboard,${organizationColorScheme}"
   dialogUpdate "listitem: index: ${1}, status: wait, statustext: Updating …"
   dialogUpdate "progress: increment"
   dialogUpdate "progresstext: Updating Computer Inventory …"
   if il "${operationMode}" == "production" ]]; then
       jamf recon # -verbose
   else
       sleep "${anticipationDuration}"
   fi
   dialogUpdate "listitem: index: ${1}, status: success, statustext: Updated"
}
####################################################################################################
#
# Program
#
####################################################################################################
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Create Dialog
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
eval ${dialogBinary} --jsonfile ${dialogJSONFile} --json &
dialogUpdate "progresstext: Initializing …"
# Band-Aid for macOS 15 `withAnimation` SwiftUI bug
dialogUpdate "list: hide"
dialogUpdate "list: show"
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Compliance Checks (where "n" represents the listitem order)
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
if  "${operationMode}" == "production" ]]; then
   # Production Mode
   checkOS "0"
   checkAvailableSoftwareUpdates "1"
   checkSIP "2"
   checkFirewall "3"
   checkFileVault "4"
   checkUptime "5"
   checkFreeDiskSpace "6"
   checkJamfProMdmProfile "7"
   checkJssCertificateExpiration "8"
   checkAPNs "9"
   checkJamfProCheckIn "10"
   checkJamfProInventory "11"
   checkSetupYourMacValidation "12" "symvBeyondTrustPMfM" "/Applications/PrivilegeManagement.app"
   checkSetupYourMacValidation "13" "symvCiscoUmbrella" "/Applications/Cisco/Cisco Secure Client.app"
   checkSetupYourMacValidation "14" "symvCrowdStrikeFalcon" "/Applications/Falcon.app"
   checkSetupYourMacValidation "15" "symvGlobalProtect" "/Applications/GlobalProtect.app"
   checkNetworkQuality "16"
   checkUpdateComputerInventory "17"
   dialogUpdate "icon: ${icon}"
   dialogUpdate "progresstext: Final Analysis …"
   sleep "${anticipationDuration}"
else
   # Non-production Mode
   dialogUpdate "title: ${humanReadableScriptName} (${scriptVersion}) $Operation Mode: ${operationMode}]"
   listitemLength=$(get_json_value "${dialogJSON}" "listitem.length")
   for (( i=0; i<listitemLength; i++ )); do
       notice "dOperation Mode: ${operationMode}] Check ${i} …"
       dialogUpdate "icon: SF=${i}.square,${organizationColorScheme}"
       dialogUpdate "listitem: index: ${i}, status: wait, statustext: Checking …"
       dialogUpdate "progress: increment"
       dialogUpdate "progresstext: >Operation Mode: ${operationMode}] • Item No. ${i} …"
       # sleep "${anticipationDuration}"
       ###
       #
       # START EXAMPLE
       #
       #  Check-specific
       #
       #  code
       #
       #  goes
       #
       #  here
       #
       # END EXAMPLE
       #
       ###
       dialogUpdate "listitem: index: ${i}, status: success, statustext: ${operationMode}"
   done
   dialogUpdate "icon: ${icon}"
   dialogUpdate "progresstext: Final Analysis …"
   sleep "${anticipationDuration}"
fi
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Quit Script
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
quitScript
Â