Leverage a client-side LaunchDaemon, script and .plist trio to determine computer health, based on the Mac’s ability to execute an inventory update policy

Background
In the spring of 2022, I renewed my Utah’s driver license and noted it wouldn’t expire for six years. When I obtained my Ohio’s driver license last Halloween, I was tickled with the option for an eight-year expiration: “Yes, please!”
When I enrolled a Mac in our Dev lane yesterday, I was also pleased that its Jamf Pro-related certificates won’t expire for more than three years. (Although, by the time you’re reading this, that box has probably already been nuked-and-paved. Thrice.)
If we base a Mac’s compliance solely on the presence of valid MDM certificates, we’re probably allowing too many computers access to sensitive data
However, if at next week’s traffic stop the police officer simply confirmed I had a valid driver’s license and sent me on my way with a warning to “slow down” — never double-checking what I’ve actually been up to using the computer in the police cruiser — I could continue not worrying about all those unpaid parking tickets.
Similarly, just because a Mac has valid MDM certificates doesn’t guarantee its enrollment is healthy.
Overview
The Jamf Pro Health Check script executes on the following approach:
- Creates a client-side LaunchDaemon and script pair which marks the Mac as
unhealthy
each morning shortly after midnight (local time) and immediately after each restart (i.e., negative trust). - Adding this script to your recurring Jamf Pro inventory update policy will then mark the Mac as
healthy
when the policy executes successfully; end-users can also self-remediate by logging into Self Service and manually running your modified “update computer inventory” policy. - You can then leverage a vendor’s ability to read client-side
.plist
values to determine if the Mac ishealthy
orunhealthy
(based on the Mac’s ability to successfully execute the assigned Jamf Pro inventory update policies).
Assumptions
While the project does include a Jamf Pro Computer Extension Attribute which can be used with Smart Groups, this approach presumes you’ll be leveraging something similar to Palo Alto Networks GlobalProtect HIP-Based Policy Enforcement to read the value of ${key}
from ${plistFilepath}
.
Implementation
A. Customize and add the Jamf Pro Health Check script to your Jamf Pro server
- Review and adjust the
Organization Variables
as required- Reverse Domain Name Notation (i.e., com.company.division):
reverseDomainNameNotation
- Script Human-readable Name:
humanReadableScriptName
- Organization’s Directory (i.e., where your client-side scripts reside; must previously exist):
organizationDirectory
- Organization’s Script Name:
organizationScriptName
- Property List “Key” for which the value will be set:
key
- Property List “Healthy Value”:
healthyValue
- Property List “Unhealthy Value”:
unhealthyValue
- Vendor’s Directory (validated to ensure vendor’s software is installed; must previously exist):
vendorDirectory
- Reverse Domain Name Notation (i.e., com.company.division):
- Modify the variables in the Jamf-Pro-Health-Check-EA.zsh to match your organizational customizations made in Step No. 1.
- Add your modified
Jamf Pro Health Check
script and its Extension Attribute to your Jamf Pro server - Specify the following for Settings > Computer Management > Scripts > Options > Parameter Labels
- Parameter 4:
Script Log Location (i.e., Your organization's default location for client-side logs)
- Parameter 5:
Configuration Files to Reset (i.e., None (blank) | All | LaunchDaemon | Script | Uninstall )
- Parameter 4:
- Click Save

Jamf-Pro-Health-Check.zsh
Latest version available on GitHub.
#!/bin/zsh --no-rcs # shellcheck shell=bash # shellcheck disable=SC2001 #################################################################################################### # # Jamf Pro Health Check # https://snelson.us/jphc # # Overview: # # 1. This script creates a client-side LaunchDaemon which marks the Mac as "unhealthy" # each morning shortly after midnight. # # 2. Adding this script to your Jamf Pro daily inventory update policy will mark the Mac # as "healthy" each time the policy is executed successfully. # # 3. Leverage a vendor's ability to read client-side `.plist` values to determine if the Mac is # "healthy" or "unhealthy", based on the Mac's ability to update its inventory with the # Jamf Pro server. # #################################################################################################### # # HISTORY # # Version 0.0.1, 25-Jan-2024, Dan K. Snelson (@dan-snelson) # - Original version, with code and inspiration from: # - [robjschroeder](https://github.com/robjschroeder) # - [bigmacadmin](https://github.com/bigmacadmin) # - [drtaru](https://github.com/drtaru) # # Version 0.0.2, 26-Jan-2024, Dan K. Snelson (@dan-snelson) # - LaunchDaemon modifications # # Version 0.0.3, 26-Jan-2024, Dan K. Snelson (@dan-snelson) # - LaunchDaemon modifications # - Logging modifications # # Version 0.0.4, 26-Jan-2024, Dan K. Snelson (@dan-snelson) # - Conditional LaunchDaemon unloading (to avoid "Boot-out failed: 5: Input/output error") # # Version 0.0.5, 27-Jan-2024, Dan K. Snelson (@dan-snelson) # - Added `resetConfiguration` options: None (blank) | All | LaunchDaemon | Script | Uninstall # - Added logging to "unhealthy" script # # Version 0.0.6, 27-Jan-2024, Dan K. Snelson (@dan-snelson) # - Corrected LaunchDaemon loading # # Version 0.0.7, 19-Mar-2024, Dan K. Snelson (@dan-snelson) # Added `--no-rcs` to the `#!/bin/zsh` shebang # #################################################################################################### #################################################################################################### # # Global Variables # #################################################################################################### export PATH=/usr/bin:/bin:/usr/sbin:/sbin # Script Version scriptVersion="0.0.7" # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # Jamf Pro Script Parameters # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # Parameter 4: Script Log (i.e., Your organization's default location for client-side logs) scriptLog="${4:-"/var/log/org.churchofjesuschrist.log"}" # Parameter 5: Configuration Files to Reset (i.e., None (blank) | All | LaunchDaemon | Script | Uninstall) resetConfiguration="${5:-""}" # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # Organization Variables # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # Organization's Reverse Domain Name Notation (i.e., com.company.division) reverseDomainNameNotation="org.churchofjesuschrist" # Script Human-readable Name humanReadableScriptName="Jamf Pro Health Check" # Organization's Directory (i.e., where your client-side scripts reside; must previously exist) organizationDirectory="/path/to/your/client-side/scripts/" # Organization's Script Name organizationScriptName="jphc" # LaunchDaemon Name & Path launchDaemonName="${reverseDomainNameNotation}.${organizationScriptName}.plist" launchDaemonPath="/Library/LaunchDaemons/${launchDaemonName}" # Property List File plistFilepath="/Library/Preferences/${reverseDomainNameNotation}.${organizationScriptName}.plist" # Property List "Key" for which the value will be set key="${humanReadableScriptName}" # Property List "Healthy Value" healthyValue="true" # Property List "Unhealthy Value" unhealthyValue="false" # Vendor's Directory (validated to ensure vendor's software is installed; must previously exist) vendorDirectory="/Library/Application Support/PaloAltoNetworks/GlobalProtect/" # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # Computer Variables # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # computerName=$( scutil --get ComputerName ) serialNumber=$( ioreg -rd1 -c IOPlatformExpertDevice | awk -F'"' '/IOPlatformSerialNumber/{print $4}' ) modelName=$( /usr/libexec/PlistBuddy -c 'Print :0:_items:0:machine_name' /dev/stdin <<< "$(system_profiler -xml SPHardwareDataType)" ) # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # Operating System Variables # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # osVersion=$( sw_vers -productVersion ) osVersionExtra=$( sw_vers -productVersionExtra ) osBuild=$( sw_vers -buildVersion ) osMajorVersion=$( echo "${osVersion}" | awk -F '.' '{print $1}' ) # Report RSR sub-version if applicable if [[ -n $osVersionExtra ]] && [[ "${osMajorVersion}" -ge 13 ]]; then osVersion="${osVersion} ${osVersionExtra}"; fi #################################################################################################### # # Functions # #################################################################################################### # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # Client-side Logging # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # function updateScriptLog() { echo "${organizationScriptName} ($scriptVersion): $( date +%Y-%m-%d\ %H:%M:%S ) - ${1}" | tee -a "${scriptLog}" } function preFlight() { updateScriptLog "[PRE-FLIGHT] ${1}" } function logComment() { updateScriptLog " ${1}" } function notice() { updateScriptLog "[NOTICE] ${1}" } function info() { updateScriptLog "[INFO] ${1}" } function debugVerbose() { if [[ "$debugMode" == "verbose" ]]; then updateScriptLog "[DEBUG VERBOSE] ${1}" fi } function debug() { if [[ "$debugMode" == "true" ]]; then updateScriptLog "[DEBUG] ${1}" fi } function errorOut(){ updateScriptLog "[ERROR] ${1}" } function error() { updateScriptLog "[ERROR] ${1}" let errorCount++ } function warning() { updateScriptLog "[WARNING] ${1}" let errorCount++ } function fatal() { updateScriptLog "[FATAL ERROR] ${1}" exit 1 } function quitOut(){ updateScriptLog "[QUIT] ${1}" } # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # Reset Configuration # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # function resetConfiguration() { notice "Reset Configuration: ${1}" case ${1} in "All" ) info "Reset All Configuration Files … " # Reset LaunchDaemon info "Reset LaunchDaemon … " launchDaemonStatus if [[ -n "${launchDaemonStatus}" ]]; then logComment "Unload '${launchDaemonPath}' … " launchctl bootout system "${launchDaemonPath}" launchDaemonStatus fi logComment "Removing '${launchDaemonPath}' … " rm -f "${launchDaemonPath}" 2>&1 logComment "Removed '${launchDaemonPath}'" # Reset Script info "Reset Script … " logComment "Removing '${organizationDirectory}/${organizationScriptName}-unhealthy.zsh' … " rm -f "${organizationDirectory}/${organizationScriptName}-unhealthy.zsh" logComment "Removed '${organizationDirectory}/${organizationScriptName}-unhealthy.zsh' " ;; "LaunchDaemon" ) info "Reset LaunchDaemon … " launchDaemonStatus if [[ -n "${launchDaemonStatus}" ]]; then logComment "Unload '${launchDaemonPath}' … " launchctl bootout system "${launchDaemonPath}" launchDaemonStatus fi logComment "Removing '${launchDaemonPath}' … " rm -f "${launchDaemonPath}" 2>&1 logComment "Removed '${launchDaemonPath}'" ;; "Script" ) info "Reset Script … " logComment "Removing '${organizationDirectory}/${organizationScriptName}-unhealthy.zsh' … " rm -f "${organizationDirectory}/${organizationScriptName}-unhealthy.zsh" logComment "Removed '${organizationDirectory}/${organizationScriptName}-unhealthy.zsh' " ;; "Uninstall" ) warning "*** UNINSTALLING ${humanReadableScriptName} ***" # Uninstall LaunchDaemon info "Uninstall LaunchDaemon … " launchDaemonStatus if [[ -n "${launchDaemonStatus}" ]]; then logComment "Unload '${launchDaemonPath}' … " launchctl bootout system "${launchDaemonPath}" launchDaemonStatus fi logComment "Removing '${launchDaemonPath}' … " rm -f "${launchDaemonPath}" 2>&1 logComment "Removed '${launchDaemonPath}'" # Uninstall Script info "Uninstall Script … " logComment "Removing '${organizationDirectory}/${organizationScriptName}-unhealthy.zsh' … " rm -f "${organizationDirectory}/${organizationScriptName}-unhealthy.zsh" logComment "Removed '${organizationDirectory}/${organizationScriptName}-unhealthy.zsh' " # Uninstall .plist info "Uninstall .plist … " logComment "Removing '${plistFilepath}' … " rm -f "${plistFilepath}" logComment "Removed '${plistFilepath}'" # Exit logComment "Uninstalled all ${humanReadableScriptName} configuration files" notice "Thanks for using ${humanReadableScriptName}!" exit 0 ;; * ) warning "None of the expected reset options was entered; don't reset anything" ;; esac } # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # Write "Healthy" Plist Value # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # function writeHealthyPlistValue() { info "Write Healthy Plist Value: \"${key}\" \"${healthyValue}\" " /usr/bin/defaults write "${plistFilepath}" "${key}" -string "${healthyValue}" } # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # Write "Unhealthy" Plist Value # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # function writeUnhealthyPlistValue() { info "Write Healthy Plist Value: '${key}' '${unhealthyValue}'" defaults write "${plistFilepath}" "${key}" -string "${unhealthyValue}" } # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # Read Plist Value # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # function readPlistValue() { info "Read Plist Value: '${key}'" writtenValue=$( defaults read "${plistFilepath}" "${key}" 2>&1 ) logComment "'${key}' is set to '${writtenValue}'" } # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # Create "Unhealthy" Script # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # function createUnhealthyScript() { info "Create 'Unhealthy' Script: ${organizationDirectory}/${organizationScriptName}-unhealthy.zsh" # The following creates a script that writes the "unhealthy" value to the client-side .plist. # (Note: Leave a full return at the end of the content before the last "ENDOFUNHEALTHYSCRIPT" line.) ( cat <<ENDOFUNHEALTHYSCRIPT #!/bin/zsh #################################################################################################### # # Jamf Pro Health Check: Write Unhealthy Value # https://snelson.us/jphc # #################################################################################################### #################################################################################################### # # Global Variables # #################################################################################################### export PATH=/usr/bin:/bin:/usr/sbin:/sbin #################################################################################################### # # Functions # #################################################################################################### # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # Client-side Logging # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # function updateScriptLog() { echo "${organizationScriptName}-unhealthy ($scriptVersion): \$( date +%Y-%m-%d\ %H:%M:%S ) - \${1}" } #################################################################################################### # # Program # #################################################################################################### updateScriptLog "\n\n***\n* Jamf Pro Health Check: Write Unhealthy Value\n***\n" updateScriptLog "Current Status" defaults read "${plistFilepath}" "${key}" updateScriptLog "Change Status" defaults write "${plistFilepath}" "${key}" -string "${unhealthyValue}" updateScriptLog "Updated Status" defaults read "${plistFilepath}" "${key}" exit 0 ENDOFUNHEALTHYSCRIPT ) > "${organizationDirectory}/${organizationScriptName}-unhealthy.zsh" logComment "Unhealthy script created" logComment "Setting permissions …" chmod 755 "${organizationDirectory}/${organizationScriptName}-unhealthy.zsh" chown root:wheel "${organizationDirectory}/${organizationScriptName}-unhealthy.zsh" } # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # Create LaunchDaemon # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # function createLaunchDaemon() { info "Create LaunchDaemon" # The following creates the LaunchDaemon file which executes the "unhealthy" script # (Note: Leave a full return at the end of the content before the last "ENDOFLAUNCHDAEMON" line.) logComment "Creating '${launchDaemonPath}' …" ( cat <<ENDOFLAUNCHDAEMON <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>Label</key> <string>${launchDaemonName}</string> <key>UserName</key> <string>root</string> <key>ProgramArguments</key> <array> <string>/bin/zsh</string> <string>${organizationDirectory}/${organizationScriptName}-unhealthy.zsh</string> </array> <key>RunAtLoad</key> <true/> <key>StartCalendarInterval</key> <dict> <key>Hour</key> <integer>0</integer> <key>Minute</key> <integer>1</integer> </dict> <key>StandardErrorPath</key> <string>${scriptLog}</string> <key>StandardOutPath</key> <string>${scriptLog}</string> </dict> </plist> ENDOFLAUNCHDAEMON ) > "${launchDaemonPath}" logComment "Setting permissions for '${launchDaemonPath}' …" chmod 644 "${launchDaemonPath}" chown root:wheel "${launchDaemonPath}" logComment "Loading '${launchDaemonName}' …" launchctl bootstrap system "${launchDaemonPath}" launchctl start "${launchDaemonPath}" } # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # LaunchDaemon Status # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # function launchDaemonStatus() { info "LaunchDaemon Status" launchDaemonStatus=$( launchctl list | grep "${launchDaemonName}" ) if [[ -n "${launchDaemonStatus}" ]]; then logComment "${launchDaemonStatus}" else logComment "${launchDaemonName} is NOT loaded" fi } #################################################################################################### # # Pre-flight Checks # #################################################################################################### # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # Pre-flight Check: Client-side Logging # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # if [[ ! -f "${scriptLog}" ]]; then touch "${scriptLog}" if [[ -f "${scriptLog}" ]]; then preFlight "Created specified scriptLog: ${scriptLog}" else fatal "Unable to create specified scriptLog '${scriptLog}'; exiting.\n\n(Is this script running as 'root' ?)" fi else preFlight "Specified scriptLog '${scriptLog}' exists; writing log entries to it" fi # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # Pre-flight Check: Logging Preamble # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # preFlight "\n\n###\n# $humanReadableScriptName (${scriptVersion})\n# https://snelson.us/jphc\n###\n" preFlight "Initiating …" # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # Pre-flight Check: Confirm script is running as root # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # if [[ $(id -u) -ne 0 ]]; then fatal "This script must be run as root; exiting." fi # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # Pre-flight Check: Validate Organization Directory # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # if [[ -d "${organizationDirectory}" ]]; then preFlight "Specified Organization Directory of '${organizationDirectory}' exists; proceeding …" else fatal "The specified Organization Directory of '${organizationDirectory}' is NOT found; exiting." fi # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # Pre-flight Check: Validate Vendor Directory # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # if [[ -d "${vendorDirectory}" ]]; then preFlight "Specified Vendor Directory of '${vendorDirectory}' exists; proceeding …" else fatal "The specified Vendor Directory of '${vendorDirectory}' is NOT found; exiting." fi # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # Pre-flight Check: Complete # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # preFlight "Complete!" #################################################################################################### # # Program # #################################################################################################### # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # Reset Configuration # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # resetConfiguration "${resetConfiguration}" # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # Script Validation / Creation # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # notice "*** VALIDATING SCRIPT ***" if [[ -f "${organizationDirectory}/${organizationScriptName}-unhealthy.zsh" ]]; then logComment "Unhealthy script '"${organizationDirectory}/${organizationScriptName}-unhealthy.zsh"' exists" else createUnhealthyScript fi # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # LaunchDaemon Validation / Creation # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # notice "*** VALIDATING LAUNCHDAEMON ***" logComment "Checking for LaunchDaemon '${launchDaemonPath}' …" if [[ -f "${launchDaemonPath}" ]]; then logComment "LaunchDaemon '${launchDaemonPath}' exists" launchDaemonStatus if [[ -n "${launchDaemonStatus}" ]]; then logComment "${launchDaemonName} IS loaded" else logComment "Loading '${launchDaemonName}' …" launchctl bootstrap system "${launchDaemonPath}" launchctl start "${launchDaemonPath}" launchDaemonStatus fi else createLaunchDaemon fi # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # Status Checks # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # notice "*** STATUS CHECKS ***" logComment "I/O pause …" sleep 1.3 launchDaemonStatus writeHealthyPlistValue readPlistValue # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # Exit # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # notice "*** Thank you! ***" exit 0
C. Testing Jamf Pro Health Check
During our initial testing, we only executed the Jamf Pro Health Check script once on computers used by individuals who opted-in to our internal Beta Test program.

Following this approach, after a day or two, all opt-in Beta Test Computer Records should be marked as unhealthy
since there isn’t (yet) a Jamf Pro inventory update policy to mark the computers as healthy
.
If you can’t wait that long, simply restart your test Mac and review its .plist
and client-side logs.
Client-side Logs
.plist
defaults read ${plistFilepath} "${key}"
Initial Run
Running script Jamf Pro Health Check (0.0.6)... Script exit code: 0 Script result: jphc (0.0.6): 2024-01-27 05:35:11 - [PRE-FLIGHT] Specified scriptLog '/var/log/org.churchofjesuschrist.log' exists; writing log entries to it jphc (0.0.6): 2024-01-27 05:35:11 - [PRE-FLIGHT] ### # Jamf Pro Health Check (0.0.6) # https:/snelson.us/jphc ### jphc (0.0.6): 2024-01-27 05:35:11 - [PRE-FLIGHT] Initiating … jphc (0.0.6): 2024-01-27 05:35:11 - [PRE-FLIGHT] Specified Organization Directory of '/path/to/your/client-side/scripts/' exists; proceeding … jphc (0.0.6): 2024-01-27 05:35:11 - [PRE-FLIGHT] Specified Vendor Directory of '/Library/Application Support/PaloAltoNetworks/GlobalProtect/' exists; proceeding … jphc (0.0.6): 2024-01-27 05:35:11 - [PRE-FLIGHT] Complete! jphc (0.0.6): 2024-01-27 05:35:11 - [NOTICE] Reset Configuration: jphc (0.0.6): 2024-01-27 05:35:11 - [WARNING] None of the expected reset options was entered; don't reset anything jphc (0.0.6): 2024-01-27 05:35:11 - [NOTICE] *** VALIDATING SCRIPT *** jphc (0.0.6): 2024-01-27 05:35:11 - [INFO] Create 'Unhealthy' Script: /path/to/your/client-side/scripts/jphc-unhealthy.zsh jphc (0.0.6): 2024-01-27 05:35:11 - Unhealthy script created jphc (0.0.6): 2024-01-27 05:35:11 - Setting permissions … jphc (0.0.6): 2024-01-27 05:35:11 - [NOTICE] *** VALIDATING LAUNCHDAEMON *** jphc (0.0.6): 2024-01-27 05:35:11 - Checking for LaunchDaemon '/Library/LaunchDaemons/org.churchofjesuschrist.jphc.plist' … jphc (0.0.6): 2024-01-27 05:35:11 - [INFO] Create LaunchDaemon jphc (0.0.6): 2024-01-27 05:35:11 - Creating '/Library/LaunchDaemons/org.churchofjesuschrist.jphc.plist' … jphc (0.0.6): 2024-01-27 05:35:11 - Setting permissions for '/Library/LaunchDaemons/org.churchofjesuschrist.jphc.plist' … jphc (0.0.6): 2024-01-27 05:35:11 - Loading 'org.churchofjesuschrist.jphc.plist' … jphc (0.0.6): 2024-01-27 05:35:11 - [NOTICE] *** STATUS CHECKS *** jphc (0.0.6): 2024-01-27 05:35:11 - I/O pause … jphc (0.0.6): 2024-01-27 05:35:12 - [INFO] LaunchDaemon Status jphc (0.0.6): 2024-01-27 05:35:12 - - 0 org.churchofjesuschrist.jphc.plist jphc (0.0.6): 2024-01-27 05:35:12 - [INFO] Write Healthy Plist Value: "Jamf Pro Health Check" "true" jphc (0.0.6): 2024-01-27 05:35:12 - [INFO] Read Plist Value: 'Jamf Pro Health Check' jphc (0.0.6): 2024-01-27 05:35:12 - 'Jamf Pro Health Check' is set to 'true' jphc (0.0.6): 2024-01-27 05:35:12 - [NOTICE] *** Thank you! ***
Script
Reset Configuration: Running script Jamf Pro Health Check (0.0.6)... Script exit code: 0 Script result: jphc (0.0.6): 2024-01-27 05:38:50 - [PRE-FLIGHT] Specified scriptLog '/var/log/org.churchofjesuschrist.log' exists; writing log entries to it jphc (0.0.6): 2024-01-27 05:38:50 - [PRE-FLIGHT] ### # Jamf Pro Health Check (0.0.6) # https:/snelson.us/jphc ### jphc (0.0.6): 2024-01-27 05:38:50 - [PRE-FLIGHT] Initiating … jphc (0.0.6): 2024-01-27 05:38:50 - [PRE-FLIGHT] Specified Organization Directory of '/path/to/your/client-side/scripts/' exists; proceeding … jphc (0.0.6): 2024-01-27 05:38:50 - [PRE-FLIGHT] Specified Vendor Directory of '/Library/Application Support/PaloAltoNetworks/GlobalProtect/' exists; proceeding … jphc (0.0.6): 2024-01-27 05:38:50 - [PRE-FLIGHT] Complete! jphc (0.0.6): 2024-01-27 05:38:50 - [NOTICE] Reset Configuration: Script jphc (0.0.6): 2024-01-27 05:38:50 - [INFO] Reset Script … jphc (0.0.6): 2024-01-27 05:38:50 - Removing '/path/to/your/client-side/scripts/jphc-unhealthy.zsh' … jphc (0.0.6): 2024-01-27 05:38:50 - Removed '/path/to/your/client-side/scripts/jphc-unhealthy.zsh' jphc (0.0.6): 2024-01-27 05:38:50 - [NOTICE] *** VALIDATING SCRIPT *** jphc (0.0.6): 2024-01-27 05:38:50 - [INFO] Create 'Unhealthy' Script: /path/to/your/client-side/scripts/jphc-unhealthy.zsh jphc (0.0.6): 2024-01-27 05:38:50 - Unhealthy script created jphc (0.0.6): 2024-01-27 05:38:50 - Setting permissions … jphc (0.0.6): 2024-01-27 05:38:50 - [NOTICE] *** VALIDATING LAUNCHDAEMON *** jphc (0.0.6): 2024-01-27 05:38:50 - Checking for LaunchDaemon '/Library/LaunchDaemons/org.churchofjesuschrist.jphc.plist' … jphc (0.0.6): 2024-01-27 05:38:50 - LaunchDaemon '/Library/LaunchDaemons/org.churchofjesuschrist.jphc.plist' exists jphc (0.0.6): 2024-01-27 05:38:50 - [INFO] LaunchDaemon Status jphc (0.0.6): 2024-01-27 05:38:50 - - 0 org.churchofjesuschrist.jphc.plist jphc (0.0.6): 2024-01-27 05:38:50 - org.churchofjesuschrist.jphc.plist IS loaded jphc (0.0.6): 2024-01-27 05:38:50 - [NOTICE] *** STATUS CHECKS *** jphc (0.0.6): 2024-01-27 05:38:50 - I/O pause … jphc (0.0.6): 2024-01-27 05:38:52 - [INFO] LaunchDaemon Status jphc (0.0.6): 2024-01-27 05:38:52 - - 0 org.churchofjesuschrist.jphc.plist jphc (0.0.6): 2024-01-27 05:38:52 - [INFO] Write Healthy Plist Value: "Jamf Pro Health Check" "true" jphc (0.0.6): 2024-01-27 05:38:52 - [INFO] Read Plist Value: 'Jamf Pro Health Check' jphc (0.0.6): 2024-01-27 05:38:52 - 'Jamf Pro Health Check' is set to 'true' jphc (0.0.6): 2024-01-27 05:38:52 - [NOTICE] *** Thank you! ***
Uninstall
Reset Configuration: Running script Jamf Pro Health Check (0.0.6)... Script exit code: 0 Script result: jphc (0.0.6): 2024-01-27 05:31:15 - [PRE-FLIGHT] Specified scriptLog '/var/log/org.churchofjesuschrist.log' exists; writing log entries to it jphc (0.0.6): 2024-01-27 05:31:15 - [PRE-FLIGHT] ### # Jamf Pro Health Check (0.0.6) # https:/snelson.us/jphc ### jphc (0.0.6): 2024-01-27 05:31:15 - [PRE-FLIGHT] Initiating … jphc (0.0.6): 2024-01-27 05:31:15 - [PRE-FLIGHT] Specified Organization Directory of '/path/to/your/client-side/scripts/' exists; proceeding … jphc (0.0.6): 2024-01-27 05:31:15 - [PRE-FLIGHT] Specified Vendor Directory of '/Library/Application Support/PaloAltoNetworks/GlobalProtect/' exists; proceeding … jphc (0.0.6): 2024-01-27 05:31:15 - [PRE-FLIGHT] Complete! jphc (0.0.6): 2024-01-27 05:31:15 - [NOTICE] Reset Configuration: Uninstall jphc (0.0.6): 2024-01-27 05:31:15 - [WARNING] *** UNINSTALLING Jamf Pro Health Check *** jphc (0.0.6): 2024-01-27 05:31:15 - [INFO] Uninstall LaunchDaemon … jphc (0.0.6): 2024-01-27 05:31:15 - [INFO] LaunchDaemon Status jphc (0.0.6): 2024-01-27 05:31:15 - - 0 org.churchofjesuschrist.jphc.plist jphc (0.0.6): 2024-01-27 05:31:15 - Unload '/Library/LaunchDaemons/org.churchofjesuschrist.jphc.plist' … jphc (0.0.6): 2024-01-27 05:31:15 - [INFO] LaunchDaemon Status jphc (0.0.6): 2024-01-27 05:31:15 - org.churchofjesuschrist.jphc.plist is NOT loaded jphc (0.0.6): 2024-01-27 05:31:15 - Removing '/Library/LaunchDaemons/org.churchofjesuschrist.jphc.plist' … jphc (0.0.6): 2024-01-27 05:31:15 - Removed '/Library/LaunchDaemons/org.churchofjesuschrist.jphc.plist' jphc (0.0.6): 2024-01-27 05:31:15 - [INFO] Uninstall Script … jphc (0.0.6): 2024-01-27 05:31:15 - Removing '/path/to/your/client-side/scripts/jphc-unhealthy.zsh' … jphc (0.0.6): 2024-01-27 05:31:15 - Removed '/path/to/your/client-side/scripts/jphc-unhealthy.zsh' jphc (0.0.6): 2024-01-27 05:31:15 - [INFO] Uninstall .plist … jphc (0.0.6): 2024-01-27 05:31:15 - Removing '/Library/Preferences/org.churchofjesuschrist.jphc.plist' … jphc (0.0.6): 2024-01-27 05:31:15 - Removed '/Library/Preferences/org.churchofjesuschrist.jphc.plist' jphc (0.0.6): 2024-01-27 05:31:15 - Uninstalled all Jamf Pro Health Check configuration files jphc (0.0.6): 2024-01-27 05:31:15 - [NOTICE] Thanks for using Jamf Pro Health Check!
When you’ve validated all is working as expected, update your inventory updating policies as detailed in B. Modify your Inventory Updating policies.