Skip to content

Instantly share code, notes, and snippets.

@angelorobo
Last active July 17, 2026 19:37
Show Gist options
  • Select an option

  • Save angelorobo/313e10a4e32503fb55d8118010f2fa3d to your computer and use it in GitHub Desktop.

Select an option

Save angelorobo/313e10a4e32503fb55d8118010f2fa3d to your computer and use it in GitHub Desktop.
Huntress post-install for Swif V2
#!/bin/zsh
#
# Huntress post-install script for Swif.ai
#
# Before deploying:
# 1. Replace ACCOUNT_KEY with the 32-character Huntress Account Key.
# 2. Replace ORGANIZATION_KEY with the exact Huntress Organization Key.
# 3. Deploy HuntressSystemExtensionProfile.mobileconfig before this app.
#
# This script must run as root.
#
set -u
readonly ACCOUNT_KEY="REPLACE_WITH_32_CHARACTER_ACCOUNT_KEY"
readonly ORGANIZATION_KEY="REPLACE_WITH_EXACT_ORGANIZATION_KEY"
readonly TAGS=""
readonly DEPLOYMENT_SCRIPT_URL="https://raw.githubusercontent.com/huntresslabs/deployment-scripts/refs/heads/main/Bash/mac/InstallHuntress-macOS-bash.sh"
readonly HUNTRESS_PROFILE_IDENTIFIER="com.huntress.app"
readonly HUNTRESS_APP="/Applications/Huntress.app"
readonly HUNTRESS_BINARY="${HUNTRESS_APP}/Contents/MacOS/Huntress"
readonly LOG_FILE="/var/log/HuntressSwifInstaller.log"
TEMP_SCRIPT=""
REINSTALL_REQUIRED=false
log()
{
local message="$*"
echo "$(date '+%Y-%m-%d %H:%M:%S') -- ${message}" |
/usr/bin/tee -a "$LOG_FILE"
}
cleanup()
{
local exit_code=$?
trap - EXIT
if [[ -n "$TEMP_SCRIPT" && -f "$TEMP_SCRIPT" ]]; then
/bin/rm -f "$TEMP_SCRIPT"
fi
exit "$exit_code"
}
trap cleanup EXIT
is_huntress_healthy()
{
if [[ ! -x "$HUNTRESS_BINARY" ]]; then
return 1
fi
local status_output
status_output="$("$HUNTRESS_BINARY" status 2>&1)" || return 1
echo "$status_output" | /usr/bin/grep -Eiq \
'Full Disk Access for Agent:[[:space:]]*true' || return 1
echo "$status_output" | /usr/bin/grep -Eiq \
'Extension Status:[[:space:]]*installed' || return 1
echo "$status_output" | /usr/bin/grep -Eiq \
'Full Disk Access for Extension:[[:space:]]*true' || return 1
echo "$status_output" | /usr/bin/grep -Eiq \
'EDR status:[[:space:]]*enabled' || return 1
echo "$status_output" | /usr/bin/grep -Eiq \
'Preauthorization Status:[[:space:]]*granted' || return 1
return 0
}
log "Starting Huntress installation through Swif.ai."
#
# Confirm root execution.
#
if [[ "$EUID" -ne 0 ]]; then
log "ERROR: This script must run as root."
exit 1
fi
#
# Protect the log file because it may contain deployment details.
#
/usr/bin/touch "$LOG_FILE"
/bin/chmod 600 "$LOG_FILE"
#
# Validate the Huntress Account Key format.
#
if [[ ! "$ACCOUNT_KEY" =~ ^[[:xdigit:]]{32}$ ]]; then
log "ERROR: ACCOUNT_KEY must be a 32-character hexadecimal Huntress Account Key."
exit 1
fi
#
# Confirm the Organization Key was configured.
#
if [[ -z "$ORGANIZATION_KEY" ||
"$ORGANIZATION_KEY" == "REPLACE_WITH_EXACT_ORGANIZATION_KEY" ]]; then
log "ERROR: ORGANIZATION_KEY has not been configured."
exit 1
fi
#
# Verify the Huntress configuration profile.
#
# Use 'profiles list' and check the top-level PayloadIdentifier.
# The previous nested-payload check could produce a false negative because
# macOS does not always display nested payload details in 'profiles show'.
#
profile_output="$(/usr/bin/profiles list -type configuration 2>&1 || true)"
if echo "$profile_output" |
/usr/bin/grep -Fq "$HUNTRESS_PROFILE_IDENTIFIER"; then
log "Huntress MDM permission profile is installed."
else
log "ERROR: Huntress configuration profile ${HUNTRESS_PROFILE_IDENTIFIER} is not installed."
log "Deploy HuntressSystemExtensionProfile.mobileconfig before installing Huntress."
log "Current configuration-profile output follows:"
echo "$profile_output" >> "$LOG_FILE"
exit 2
fi
#
# Treat an existing, fully configured installation as successful.
#
# If Huntress exists but EDR or preauthorization is incomplete, run the
# official deployment script with its reinstall option.
#
if [[ -d "$HUNTRESS_APP" ]]; then
if is_huntress_healthy; then
log "Huntress is already installed, provisioned, and running."
exit 0
fi
log "An incomplete or unhealthy Huntress installation was found."
log "The deployment script will run with the reinstall option."
REINSTALL_REQUIRED=true
fi
#
# Download the current official Huntress deployment script.
#
TEMP_SCRIPT="$(/usr/bin/mktemp /private/tmp/HuntressDeployment.XXXXXX)"
if [[ -z "$TEMP_SCRIPT" || ! -f "$TEMP_SCRIPT" ]]; then
log "ERROR: Could not create the temporary deployment script."
exit 1
fi
/usr/bin/curl \
--fail \
--location \
--silent \
--show-error \
--retry 3 \
--retry-delay 5 \
--connect-timeout 30 \
"$DEPLOYMENT_SCRIPT_URL" \
--output "$TEMP_SCRIPT"
curl_exit=$?
if [[ "$curl_exit" -ne 0 ]]; then
log "ERROR: Failed to download the official Huntress deployment script."
log "curl returned exit code ${curl_exit}."
exit "$curl_exit"
fi
if [[ ! -s "$TEMP_SCRIPT" ]]; then
log "ERROR: The downloaded Huntress deployment script is empty."
exit 1
fi
/bin/chmod 700 "$TEMP_SCRIPT"
#
# Identify Swif.ai as the deployment tool in Huntress support logs.
#
/usr/bin/sed -i '' \
's/^rmm="Unspecified RMM"$/rmm="Swif.ai"/' \
"$TEMP_SCRIPT"
#
# Build the official Huntress deployment arguments.
#
install_arguments=(
-a "$ACCOUNT_KEY"
-o "$ORGANIZATION_KEY"
-i
)
if [[ -n "$TAGS" ]]; then
install_arguments+=(
-t "$TAGS"
)
fi
if [[ "$REINSTALL_REQUIRED" == true ]]; then
install_arguments+=(
-r
)
fi
log "Running the official Huntress deployment script."
#
# Do not use 'set -x' or print the arguments because they contain the
# Huntress Account Key.
#
/bin/zsh "$TEMP_SCRIPT" "${install_arguments[@]}" >> "$LOG_FILE" 2>&1
install_exit=$?
if [[ "$install_exit" -ne 0 ]]; then
log "ERROR: Huntress deployment failed with exit code ${install_exit}."
log "Review ${LOG_FILE} and /Users/Shared/HuntressInstaller.log."
exit "$install_exit"
fi
log "Huntress deployment script completed successfully."
#
# Allow the system extension and EDR services time to initialize.
#
attempt=1
maximum_attempts=6
while [[ "$attempt" -le "$maximum_attempts" ]]; do
if is_huntress_healthy; then
log "Huntress installation and EDR readiness verification succeeded."
exit 0
fi
log "Huntress readiness check ${attempt}/${maximum_attempts} is not complete."
if [[ "$attempt" -lt "$maximum_attempts" ]]; then
/bin/sleep 5
fi
attempt=$((attempt + 1))
done
#
# The Huntress installer succeeded, but activation can be asynchronous.
# Return success here so Munki does not immediately reinstall the package.
# The Swif installcheck_script should independently verify EDR readiness.
#
log "WARNING: The Huntress installer completed, but EDR readiness is still initializing."
if [[ -x "$HUNTRESS_BINARY" ]]; then
log "Current Huntress status:"
"$HUNTRESS_BINARY" status >> "$LOG_FILE" 2>&1 || true
fi
log "Recheck later with: sudo ${HUNTRESS_BINARY} status"
exit 0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment