Gather the data you need — on-demand — while eliminating the need for short-term Extension Attributes
Background
For long-term needs, Jamf Pro Computer Extension Attributes are indispensable, but during software pilots, you only occasionally need potential vendor data from endpoints and creating multiple EAs you’ll only use temporarily can lead to database bloat.
We leveraged swiftDialog to easily allow our opt-in Beta Testers to submit on-demand feedback regarding CrowdStrike Falcon’s configuration, which also eliminated the creation of multiple short-term Extension Attributes.
The CrowdStrike Falcon Inspector script gathers the following information which is both displayed to the user and captured in the Jamf Pro Policy log:
- Installation
- Version
- System Extension
- Agent ID
- Heartbeats
Script result: 2023-04-07 04:11:27 - ### # CrowdStrike Falcon Inspector (0.0.2) ### 2023-04-07 04:11:27 - Script running as "root"; proceeding … 2023-04-07 04:11:27 - macOS 13 installed; proceeding ... 2023-04-07 04:11:28 - swiftDialog version 2.1.0.4148 found; proceeding... 2023-04-07 04:11:28 - CrowdStrike Falcon installed; proceeding … 2023-04-07 04:11:28 - Create Welcome Dialog … 2023-04-07 04:11:47 - Results for dan 2023-04-07 04:11:47 - Installation Status: Installed 2023-04-07 04:11:47 - Version: 6.51.16403.0 2023-04-07 04:11:47 - System Extension: Loaded 2023-04-07 04:11:47 - Agent ID: 9******************************9 2023-04-07 04:11:47 - Heartbeats: 30 | 120 | 240 | 360 | 720 2023-04-07 04:11:47 - Elapsed Time: 0h:0m:8s 2023-04-07 04:12:06 - End-of-line. 2023-04-07 04:12:06 - Quitting … 2023-04-07 04:12:07 - Exiting … 2023-04-07 04:12:07 - Removing /var/tmp/dialogWelcomeLog.5hzO … 2023-04-07 04:12:07 - Goodbye!
Configuration
Complete the following steps for easy, on-demand inspection of CrowdStrike Falcon.
A. Add the CrowdStrike Falcon Inspector script to your Jamf Pro server
- Add the
CrowdStrike Falcon Inspectorscript to your Jamf Pro server - Specify the following for Options > Parameter Labels
- Parameter 4:
Script Log Location - Parameter 5:
Debug Mode [ true (default) | false ] - Parameter 6:
Anticipation Duration (in seconds)
- Parameter 4:
- Click Save

#!/bin/bash
####################################################################################################
#
# CrowdStrike Falcon Inspector
#
# Purpose: Displays an end-user message about CrowdStrike Falcon via swiftDialog
#
####################################################################################################
#
# HISTORY
#
# Version 0.0.1, 11-Nov-2022, Dan K. Snelson (@dan-snelson)
# Original, proof-of-concept version
# (Variables lifted from Jason Broccardo's https://github.com/zoocoup/CrowdStrikeEAsforJamfPro)
#
# Version 0.0.2, 11-Nov-2022, Dan K. Snelson (@dan-snelson)
# Corrected button enablement on completion
#
####################################################################################################
####################################################################################################
#
# Variables
#
####################################################################################################
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Global Variables
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
scriptVersion="0.0.2"
export PATH=/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin/
loggedInUser=$( echo "show State:/Users/ConsoleUser" | scutil | awk '/Name :/ { print $3 }' )
osVersion=$( sw_vers -productVersion )
osMajorVersion=$( echo "${osVersion}" | awk -F '.' '{print $1}' )
dialogApp="/usr/local/bin/dialog"
dialogWelcomeLog=$( mktemp /var/tmp/dialogWelcomeLog.XXXX )
scriptLog="${4:-"/var/tmp/com.company.log"}"
debugMode="${5:-"true"}"
anticipationDuration="${6:-"3"}"
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Welcome Dialog Title, Message and Icon
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
title="CrowdStrike Falcon Inspector ($scriptVersion)"
message="This script analyzes the installation of CrowdStrike Falcon then reports the findings in a this window. \n\nPlease wait …"
# icon="/Applications/Falcon.app"
icon="https://ics.services.jamfcloud.com/icon/hash_c9f81b098ecb0a2d527dd9fe464484892f1df5990d439fa680d54362023a5b5a"
# overlayIcon=$( defaults read /Library/Preferences/com.jamfsoftware.jamf.plist self_service_app_path )
button1text="Wait"
infobuttontext="KB8675309"
infobuttonaction="https://servicenow.company.com/support?id=kb_article_view&sysparm_article=${infobuttontext}"
welcomeProgressText="Initializing …"
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Welcome Dialog Settings and Features
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
dialogWelcome="$dialogApp \
--title \"$title\" \
--message \"$message\" \
--icon \"$icon\" \
--button1text \"$button1text\" \
--button1disabled \
--infobuttontext \"$infobuttontext\" \
--infobuttonaction \"$infobuttonaction\" \
--progress \
--progresstext \"$welcomeProgressText\" \
--moveable \
--titlefont size=22 \
--messagefont size=14 \
--iconsize 135 \
--width 650 \
--height 350 \
--commandfile \"$dialogWelcomeLog\" "
# --overlayicon \"$overlayIcon\" \
####################################################################################################
#
# Functions
#
####################################################################################################
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Client-side Script Logging
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
function updateScriptLog() {
echo -e "$( date +%Y-%m-%d\ %H:%M:%S ) - ${1}" | tee -a "${scriptLog}"
}
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# JAMF Display Message (for fallback in case swiftDialog fails to install)
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
function jamfDisplayMessage() {
updateScriptLog "Jamf Display Message: ${1}"
/usr/local/jamf/bin/jamf displayMessage -message "${1}" &
}
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Check for / install swiftDialog (Thanks big bunches, @acodega!)
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
function dialogCheck() {
# Get the URL of the latest PKG From the Dialog GitHub repo
dialogURL=$(curl --silent --fail "https://api.github.com/repos/bartreardon/swiftDialog/releases/latest" | awk -F '"' "/browser_download_url/ && /pkg\"/ { print \$4; exit }")
# Expected Team ID of the downloaded PKG
expectedDialogTeamID="PWA5E9TQ59"
# Check for Dialog and install if not found
if [ ! -e "/Library/Application Support/Dialog/Dialog.app" ]; then
updateScriptLog "Dialog not found. Installing..."
# Create temporary working directory
workDirectory=$( /usr/bin/basename "$0" )
tempDirectory=$( /usr/bin/mktemp -d "/private/tmp/$workDirectory.XXXXXX" )
# Download the installer package
/usr/bin/curl --location --silent "$dialogURL" -o "$tempDirectory/Dialog.pkg"
# Verify the download
teamID=$(/usr/sbin/spctl -a -vv -t install "$tempDirectory/Dialog.pkg" 2>&1 | awk '/origin=/ {print $NF }' | tr -d '()')
# Install the package if Team ID validates
if [ "$expectedDialogTeamID" = "$teamID" ] || [ "$expectedDialogTeamID" = "" ]; then
/usr/sbin/installer -pkg "$tempDirectory/Dialog.pkg" -target /
else
jamfDisplayMessage "Dialog Team ID verification failed."
exit 1
fi
# Remove the temporary working directory when done
/bin/rm -Rf "$tempDirectory"
else
updateScriptLog "swiftDialog version $(dialog --version) found; proceeding..."
fi
}
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Quit Script (thanks, @bartreadon!)
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
function quitScript() {
updateScriptLog "Quitting …"
updateWelcomeDialog "quit: "
sleep 1
updateScriptLog "Exiting …"
# Remove dialogWelcomeLog
if [[ -e ${dialogWelcomeLog} ]]; then
updateScriptLog "Removing ${dialogWelcomeLog} …"
rm "${dialogWelcomeLog}"
fi
updateScriptLog "Goodbye!"
exit "${1}"
}
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Update Welcome Dialog
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
function updateWelcomeDialog() {
sleep 0.3
echo "${1}" >> "${dialogWelcomeLog}"
}
####################################################################################################
#
# Pre-flight Checks
#
####################################################################################################
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Client-side Logging
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
if [[ ! -f "${scriptLog}" ]]; then
touch "${scriptLog}"
updateScriptLog "*** Created log file via script ***"
fi
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Logging preamble
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
if [[ ${debugMode} == "true" ]]; then
updateScriptLog "\n\n###\n# DEBUG MODE | CrowdStrike Falcon Inspector (${scriptVersion})\n###\n"
else
updateScriptLog "\n\n###\n# CrowdStrike Falcon Inspector (${scriptVersion})\n###\n"
fi
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Confirm script is running as root
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
if [[ $(id -u) -ne 0 ]]; then
updateScriptLog "This script must be run as root; exiting."
quitScript "1"
else
updateScriptLog "Script running as \"root\"; proceeding …"
fi
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Validate Operating System
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
if [[ "${osMajorVersion}" -ge 11 ]] ; then
updateScriptLog "macOS ${osMajorVersion} installed; proceeding ..."
else
updateScriptLog "macOS ${osMajorVersion} installed; exiting"
quitScript "1"
fi
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Validate swiftDialog is installed
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
dialogCheck
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Validate CrowdStrike Falcon installation (or exit with error)
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
if [[ -e /Applications/Falcon.app/Contents/MacOS/Falcon ]]; then
updateScriptLog "CrowdStrike Falcon installed; proceeding …"
else
updateScriptLog "CrowdStrike Falcon not installed; exiting"
quitScript "1"
fi
####################################################################################################
#
# Program
#
####################################################################################################
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Create Welcome Dialog
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
updateScriptLog "Create Welcome Dialog …"
eval "$dialogWelcome" & sleep 0.3
if [[ ${debugMode} == "true" ]]; then
updateWelcomeDialog "title: DEBUG MODE | $title"
updateWelcomeDialog "message: DEBUG MODE. Please wait for ${anticipationDuration} seconds …"
updateWelcomeDialog "progresstext: DEBUG MODE. Pausing for ${anticipationDuration} seconds"
sleep "${anticipationDuration}"
falconVersion="DEBUG"
systemExtensionStatus="DEBUG"
falconAgentID="DEBUG"
falconHeartbeats6="DEBUG"
else
updateWelcomeDialog "progress: 5"
updateWelcomeDialog "progresstext: Inspecting …"
sleep "${anticipationDuration}"
SECONDS="0"
# CrowdStrike Falcon Inspection: Installation
updateWelcomeDialog "progress: 18"
updateWelcomeDialog "progresstext: Installation …"
# CrowdStrike Falcon Inspection: Version
falconVersion=$( /Applications/Falcon.app/Contents/Resources/falconctl stats | awk '/version/ {print $2}' )
updateWelcomeDialog "progress: 36"
updateWelcomeDialog "progresstext: Version …"
# CrowdStrike Falcon Inspection: System Extension List
systemExtensionTest=$( systemextensionsctl list | awk '/com.crowdstrike.falcon.Agent/ {print $7,$8}' | wc -l )
if [[ "${systemExtensionTest}" -gt 0 ]]; then
systemExtensionStatus="Loaded"
else
systemExtensionStatus="Likely **not** running"
fi
updateWelcomeDialog "progress: 54"
updateWelcomeDialog "progresstext: System Extension …"
# CrowdStrike Falcon Inspection: Agent ID
falconAgentID=$( /Applications/Falcon.app/Contents/Resources/falconctl stats | awk '/agentID/ {print $2}' | tr '[:upper:]' '[:lower:]' | sed 's/\-//g' )
updateWelcomeDialog "progress: 72"
updateWelcomeDialog "progresstext: Agent ID …"
# CrowdStrike Falcon Inspection: Heartbeats
falconHeartbeats6=$( /Applications/Falcon.app/Contents/Resources/falconctl stats | awk '/SensorHeartbeatMacV4/ {print $4,$5,$6,$7,$8}' | sed 's/ /\ | /g' )
updateWelcomeDialog "progress: 90"
updateWelcomeDialog "progresstext: Heartbeats …"
# Capture results to log
updateScriptLog "Results for ${loggedInUser}"
updateScriptLog "Installation Status: Installed"
updateScriptLog "Version: ${falconVersion}"
updateScriptLog "System Extension: ${systemExtensionStatus}"
updateScriptLog "Agent ID: ${falconAgentID}"
updateScriptLog "Heartbeats: ${falconHeartbeats6}"
updateScriptLog "Elapsed Time: $(printf '%dh:%dm:%ds\n' $((SECONDS/3600)) $((SECONDS%3600/60)) $((SECONDS%60)))"
# Display results to user
timestamp="$( date '+%Y-%m-%d-%H%M%S' )"
updateWelcomeDialog "message: **Results for ${loggedInUser} on ${timestamp}** \n\n- **Installation Status:** Installed \n- **Version:** ${falconVersion} \n- **System Extension:** ${systemExtensionStatus} \n- **Agent ID:** ${falconAgentID} \n- **Heartbeats:** ${falconHeartbeats6}"
updateWelcomeDialog "progress: complete"
updateWelcomeDialog "progresstext: Complete!"
sleep "${anticipationDuration}"
fi
updateWelcomeDialog "button1text: Done"
updateWelcomeDialog "button1: enable"
updateWelcomeDialog "progress: 100"
updateWelcomeDialog "progresstext: Elapsed Time: $(printf '%dh:%dm:%ds\n' $((SECONDS/3600)) $((SECONDS%3600/60)) $((SECONDS%60)))"
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Exit
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
wait
updateScriptLog "End-of-line."
quitScript "0"
B. Create a Jamf Pro Policy to execute CrowdStrike Falcon Inspector
- Create a new Jamf Pro Policy, using the following as a guide for Options > General:
- Set Display Name to
CrowdStrike Falcon Inspector (0.0.2)
- Set Execution Frequency to
Ongoing
- Set Display Name to
- Select the Scripts payload and add the
CrowdStrike Falcon Inspectorscript, specifying the following Parameter Values- Script Log Location:
/var/log/com.company.log
- Debug Mode:
false - Anticipation Duration (in seconds):
3
- Script Log Location:

- Adjust Scope to your liking; we use our custom CrowdStrike Falcon Smart Computer Group
- Use the following for Self Service
- Self Service Display Name:
CrowdStrike Falcon Inspector (0.0.2) - Button Name Before Initiation:
Inspect - Button Name After Initiation:
Reinspect
- Icon:
(download) - Description:
- Self Service Display Name:
Performs the following tests on the CrowdStrike Falcon agent: - Validates agent installation - Reports agent version - Confirms System Extension installation - Reports agent ID - Reports the two-minute client-to-server heartbeats for last 1, 4, 8, 12 and 24 hours
- Click Save