Created
July 17, 2026 17:20
-
-
Save angelorobo/71e723c94b220123b4ac94037d6cd40f to your computer and use it in GitHub Desktop.
Huntress post-install script for Swif
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/bin/zsh | |
| # | |
| # Huntress post-install script for Swif.ai | |
| # | |
| # Requirements: | |
| # 1. Deploy HuntressSystemExtensionProfile.mobileconfig before this script. | |
| # 2. Replace ACCOUNT_KEY and ORGANIZATION_KEY below. | |
| # 3. Run as root through Swif/Munki. | |
| # | |
| 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_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() | |
| { | |
| [[ -x "$HUNTRESS_BINARY" ]] || return 1 | |
| /usr/bin/pgrep -x "HuntressAgent" >/dev/null 2>&1 || return 1 | |
| /usr/bin/pgrep -x "HuntressUpdater" >/dev/null 2>&1 || return 1 | |
| 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." | |
| if [[ "$EUID" -ne 0 ]]; then | |
| log "ERROR: This script must run as root." | |
| exit 1 | |
| fi | |
| if [[ ! "$ACCOUNT_KEY" =~ ^[[:xdigit:]]{32}$ ]]; then | |
| log "ERROR: ACCOUNT_KEY must be a 32-character hexadecimal Huntress Account Key." | |
| exit 1 | |
| fi | |
| if [[ -z "$ORGANIZATION_KEY" || | |
| "$ORGANIZATION_KEY" == "REPLACE_WITH_EXACT_ORGANIZATION_KEY" ]]; then | |
| log "ERROR: ORGANIZATION_KEY has not been configured." | |
| exit 1 | |
| fi | |
| # | |
| # Confirm that the Huntress MDM profile arrived before activating the | |
| # system extension. This prevents approval prompts on the endpoint. | |
| # | |
| profile_output="$(/usr/bin/profiles show -type configuration 2>/dev/null || true)" | |
| if ! echo "$profile_output" | /usr/bin/grep -q "com.huntress.sysext" || | |
| ! echo "$profile_output" | /usr/bin/grep -q "7W6HQ9J9XA"; then | |
| log "ERROR: The Huntress system-extension configuration profile is not installed." | |
| log "Deploy HuntressSystemExtensionProfile.mobileconfig before installing Huntress." | |
| exit 2 | |
| fi | |
| log "Huntress MDM permission profile is installed." | |
| # | |
| # Make retries idempotent. A complete, healthy installation is success, | |
| # not an installation error. | |
| # | |
| 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 | |
| TEMP_SCRIPT="$(/usr/bin/mktemp /private/tmp/HuntressDeployment.XXXXXX)" || { | |
| log "ERROR: Could not create temporary deployment script." | |
| exit 1 | |
| } | |
| /usr/bin/curl \ | |
| --fail \ | |
| --location \ | |
| --silent \ | |
| --show-error \ | |
| --retry 3 \ | |
| --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." | |
| exit "$curl_exit" | |
| 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" | |
| 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 enable shell tracing here because it would expose the 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." | |
| # | |
| # Readiness can take a short time after installation. Do not return failure | |
| # solely because the extension has not finished activating yet. | |
| # | |
| if is_huntress_healthy; then | |
| log "Huntress installation and EDR readiness verification succeeded." | |
| else | |
| log "WARNING: The installer succeeded, but Huntress readiness is still initializing." | |
| log "Verify later with: ${HUNTRESS_BINARY} status" | |
| fi | |
| exit 0 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment