#!/usr/bin/env bash

#########################################################################################
#### azure-ad-audit.sh — Audit Azure Entra ID for stale users, MFA gaps, risky      ####
#### sign-ins, excessive permissions, and service principal hygiene via az CLI        ####
#### Requires: bash 4+, az CLI, jq                                                  ####
####                                                                                 ####
#### Author: Phil Connor                                                             ####
#### Contact: contact@mylinux.work                                                   ####
#### License: MIT                                                                    ####
#### Version 1.01                                                                    ####
####                                                                                 ####
#### Usage:                                                                          ####
####   ./azure-ad-audit.sh --full                                                    ####
####                                                                                 ####
#### See --help for all options.                                                     ####
#########################################################################################

set -euo pipefail

# ── Colors (pre-initialized) ─────────────────────────────────────────
RED="" GREEN="" YELLOW="" BLUE="" CYAN="" BOLD="" DIM="" RESET=""

setup_colors() {
    if [[ "${COLOR:-auto}" == "never" ]]; then
        return
    fi
    if [[ "${COLOR:-auto}" == "always" ]] || [[ -t 1 ]]; then
        RED='\033[0;31m'
        GREEN='\033[0;32m'
        YELLOW='\033[0;33m'
        BLUE='\033[0;34m'
        CYAN='\033[0;36m'
        BOLD='\033[1m'
        DIM='\033[2m'
        RESET='\033[0m'
    fi
}

# ── Logging ───────────────────────────────────────────────────────────
log()     { echo -e "${BLUE}[INFO]${RESET} $*"; }
warn()    { echo -e "${YELLOW}[WARN]${RESET} $*" >&2; }
err()     { echo -e "${RED}[ERROR]${RESET} $*" >&2; }
verbose() { if [[ "$VERBOSE" == "true" ]]; then echo -e "${DIM}[DEBUG]${RESET} $*"; fi; }
die()     { err "$*"; exit 1; }

# ── Severity counters ────────────────────────────────────────────────
TOTAL_CRIT=0
TOTAL_WARN=0
TOTAL_INFO=0
TOTAL_OK=0

flag_crit() { ((TOTAL_CRIT++)) || true; }
flag_warn() { ((TOTAL_WARN++)) || true; }
flag_info() { ((TOTAL_INFO++)) || true; }
flag_ok()   { ((TOTAL_OK++)) || true; }

# ── Defaults ──────────────────────────────────────────────────────────
RUN_MODE=""
STALE_DAYS="${STALE_DAYS:-90}"
VERBOSE="${VERBOSE:-false}"
COLOR="${COLOR:-auto}"

# ── State ─────────────────────────────────────────────────────────────
SCRIPT_NAME="$(basename "$0")"
readonly SCRIPT_NAME
START_TIME=""

# ── Dependency checks ────────────────────────────────────────────────
check_deps() {
    command -v az &>/dev/null || die "az CLI is required (https://aka.ms/install-azure-cli)"
    command -v jq &>/dev/null || die "jq is required"
}

check_credentials() {
    if ! az account show &>/dev/null 2>&1; then
        die "Not logged in to Azure CLI — run 'az login' first"
    fi
    verbose "Azure CLI authenticated"
}

# ── Date helpers ─────────────────────────────────────────────────────
days_since() {
    local date_str="$1"
    if [[ -z "$date_str" || "$date_str" == "null" || "$date_str" == "None" ]]; then
        echo "never"
        return
    fi
    local then_epoch now_epoch
    then_epoch=$(date -d "${date_str}" +%s 2>/dev/null || echo 0)
    now_epoch=$(date +%s)
    if [[ "$then_epoch" -eq 0 ]]; then
        echo "unknown"
        return
    fi
    echo $(( (now_epoch - then_epoch) / 86400 ))
}

days_until() {
    local date_str="$1"
    if [[ -z "$date_str" || "$date_str" == "null" || "$date_str" == "None" ]]; then
        echo "unknown"
        return
    fi
    local target_epoch now_epoch
    target_epoch=$(date -d "${date_str}" +%s 2>/dev/null || echo 0)
    now_epoch=$(date +%s)
    if [[ "$target_epoch" -eq 0 ]]; then
        echo "unknown"
        return
    fi
    echo $(( (target_epoch - now_epoch) / 86400 ))
}

# ══════════════════════════════════════════════════════════════════════
#                       STALE USERS AUDIT
# ══════════════════════════════════════════════════════════════════════
audit_stale_users() {
    log "Auditing stale user accounts (threshold: ${STALE_DAYS} days)..."
    echo ""

    printf "  %-36s %-24s %-20s %-10s %s\n" \
        "UPN" "DISPLAY_NAME" "LAST_SIGN_IN" "DAYS_IDLE" "SEVERITY"
    printf "  %s\n" "$(printf '%.0s─' {1..110})"

    local users_json
    # shellcheck disable=SC2016
    users_json=$(az rest --method GET \
        --url 'https://graph.microsoft.com/v1.0/users?$select=userPrincipalName,displayName,signInActivity,accountEnabled&$top=999' \
        2>/dev/null || echo '{"value":[]}')

    echo "$users_json" | jq -c '.value[]? // empty' 2>/dev/null | while IFS= read -r user; do
        local upn display_name enabled last_sign_in
        upn=$(echo "$user" | jq -r '.userPrincipalName // "unknown"' 2>/dev/null)
        display_name=$(echo "$user" | jq -r '.displayName // "unknown"' 2>/dev/null)
        enabled=$(echo "$user" | jq -r '.accountEnabled // true' 2>/dev/null)
        last_sign_in=$(echo "$user" | jq -r '.signInActivity.lastSignInDateTime // "null"' 2>/dev/null)

        [[ "$enabled" == "false" ]] && continue

        local idle_days last_sign_display
        idle_days=$(days_since "$last_sign_in")

        if [[ "$last_sign_in" == "null" || -z "$last_sign_in" ]]; then
            last_sign_display="Never"
        else
            last_sign_display="${last_sign_in:0:10}"
        fi

        if [[ "$idle_days" == "never" ]]; then
            printf "  %-36s %-24s %-20s %-10s %b%s%b\n" \
                "${upn:0:34}" "${display_name:0:22}" "$last_sign_display" \
                "N/A" "$YELLOW" "WARN" "$RESET"
            flag_warn
        elif [[ "$idle_days" == "unknown" ]]; then
            verbose "Skipping ${upn}: unable to parse sign-in date"
        elif [[ "$idle_days" -gt "$STALE_DAYS" ]]; then
            printf "  %-36s %-24s %-20s %-10s %b%s%b\n" \
                "${upn:0:34}" "${display_name:0:22}" "$last_sign_display" \
                "$idle_days" "$YELLOW" "WARN" "$RESET"
            flag_warn
        else
            verbose "User ${upn}: active (${idle_days}d idle)"
            flag_ok
        fi
    done

    echo ""
}

# ══════════════════════════════════════════════════════════════════════
#                       MFA AUDIT
# ══════════════════════════════════════════════════════════════════════
audit_mfa() {
    log "Auditing MFA registration status..."
    echo ""

    printf "  %-36s %-14s %-10s %s\n" \
        "UPN" "MFA_STATUS" "IS_ADMIN" "SEVERITY"
    printf "  %s\n" "$(printf '%.0s─' {1..80})"

    local reg_json
    # shellcheck disable=SC2016
    reg_json=$(az rest --method GET \
        --url 'https://graph.microsoft.com/v1.0/reports/credentialUserRegistrationDetails?$top=999' \
        2>/dev/null || echo '{"value":[]}')

    local admin_upns
    admin_upns=$(az rest --method GET \
        --url 'https://graph.microsoft.com/v1.0/directoryRoles' \
        2>/dev/null | jq -r '.value[]? | select(.displayName | test("Admin|Administrator"; "i")) | .id' 2>/dev/null || true)

    local admin_members=""
    while IFS= read -r role_id; do
        [[ -z "$role_id" ]] && continue
        local members
        members=$(az rest --method GET \
            --url "https://graph.microsoft.com/v1.0/directoryRoles/${role_id}/members" \
            2>/dev/null | jq -r '.value[]?.userPrincipalName // empty' 2>/dev/null || true)
        admin_members="${admin_members}${members}"$'\n'
    done <<< "$admin_upns"

    echo "$reg_json" | jq -c '.value[]? // empty' 2>/dev/null | while IFS= read -r entry; do
        local upn mfa_registered
        upn=$(echo "$entry" | jq -r '.userPrincipalName // "unknown"' 2>/dev/null)
        mfa_registered=$(echo "$entry" | jq -r '.isMfaRegistered // false' 2>/dev/null)

        local is_admin="No"
        if echo "$admin_members" | grep -qi "^${upn}$" 2>/dev/null; then
            is_admin="Yes"
        fi

        local mfa_display severity
        if [[ "$mfa_registered" == "true" ]]; then
            mfa_display="Registered"
            severity="OK"
            printf "  %-36s %-14s %-10s %b%s%b\n" \
                "${upn:0:34}" "$mfa_display" "$is_admin" "$GREEN" "$severity" "$RESET"
            flag_ok
        else
            mfa_display="Not registered"
            if [[ "$is_admin" == "Yes" ]]; then
                severity="CRITICAL"
                printf "  %-36s %-14s %-10s %b%s%b\n" \
                    "${upn:0:34}" "$mfa_display" "$is_admin" "$RED" "$severity" "$RESET"
                flag_crit
            else
                severity="WARN"
                printf "  %-36s %-14s %-10s %b%s%b\n" \
                    "${upn:0:34}" "$mfa_display" "$is_admin" "$YELLOW" "$severity" "$RESET"
                flag_warn
            fi
        fi
    done

    echo ""
}

# ══════════════════════════════════════════════════════════════════════
#                       ADMIN ROLES AUDIT
# ══════════════════════════════════════════════════════════════════════
audit_admins() {
    log "Auditing privileged role assignments..."
    echo ""

    printf "  %-36s %-28s %-20s %s\n" \
        "UPN" "ROLE" "SCOPE" "SEVERITY"
    printf "  %s\n" "$(printf '%.0s─' {1..95})"

    local owner_json
    owner_json=$(az role assignment list --role "Owner" --all 2>/dev/null || echo '[]')

    echo "$owner_json" | jq -c '.[]? // empty' 2>/dev/null | while IFS= read -r assignment; do
        local upn role scope
        upn=$(echo "$assignment" | jq -r '.principalName // "unknown"' 2>/dev/null)
        role=$(echo "$assignment" | jq -r '.roleDefinitionName // "unknown"' 2>/dev/null)
        scope=$(echo "$assignment" | jq -r '.scope // "/"' 2>/dev/null)

        [[ -z "$upn" || "$upn" == "unknown" ]] && continue

        local scope_display
        scope_display="${scope##*/}"
        [[ -z "$scope_display" ]] && scope_display="$scope"

        printf "  %-36s %-28s %-20s %b%s%b\n" \
            "${upn:0:34}" "${role:0:26}" "${scope_display:0:18}" \
            "$CYAN" "INFO" "$RESET"
        flag_info
    done

    local ga_json
    ga_json=$(az rest --method GET \
        --url 'https://graph.microsoft.com/v1.0/directoryRoles' \
        2>/dev/null | jq -c '.value[]? | select(.displayName == "Global Administrator")' 2>/dev/null || echo '')

    if [[ -n "$ga_json" ]]; then
        local ga_role_id
        ga_role_id=$(echo "$ga_json" | jq -r '.id' 2>/dev/null)

        local ga_members
        ga_members=$(az rest --method GET \
            --url "https://graph.microsoft.com/v1.0/directoryRoles/${ga_role_id}/members" \
            2>/dev/null || echo '{"value":[]}')

        local ga_count
        ga_count=$(echo "$ga_members" | jq '[.value[]?] | length' 2>/dev/null || echo 0)

        echo "$ga_members" | jq -c '.value[]? // empty' 2>/dev/null | while IFS= read -r member; do
            local m_upn
            m_upn=$(echo "$member" | jq -r '.userPrincipalName // "unknown"' 2>/dev/null)

            printf "  %-36s %-28s %-20s %b%s%b\n" \
                "${m_upn:0:34}" "Global Administrator" "Tenant" \
                "$CYAN" "INFO" "$RESET"
            flag_info
        done

        if [[ "$ga_count" -gt 5 ]]; then
            echo ""
            warn "Excessive Global Administrators: ${ga_count} found (recommended: ≤5)"
            printf "  %-36s %-28s %-20s %b%s%b\n" \
                "— policy —" "Global Admin count: ${ga_count}" ">5 threshold" \
                "$YELLOW" "WARN" "$RESET"
            flag_warn
        elif [[ "$ga_count" -gt 0 ]]; then
            verbose "Global Administrator count: ${ga_count} (within threshold)"
            flag_ok
        fi
    fi

    echo ""
}

# ══════════════════════════════════════════════════════════════════════
#                       SERVICE PRINCIPALS AUDIT
# ══════════════════════════════════════════════════════════════════════
audit_service_principals() {
    log "Auditing service principal credentials..."
    echo ""

    printf "  %-30s %-14s %-20s %-14s %s\n" \
        "APP_NAME" "CRED_TYPE" "EXPIRY" "STATUS" "SEVERITY"
    printf "  %s\n" "$(printf '%.0s─' {1..100})"

    local sp_json
    sp_json=$(az ad sp list --all --query "[].{appDisplayName:appDisplayName,appId:appId,keyCredentials:keyCredentials,passwordCredentials:passwordCredentials}" 2>/dev/null || echo '[]')

    echo "$sp_json" | jq -c '.[]? // empty' 2>/dev/null | while IFS= read -r sp; do
        local app_name app_id
        app_name=$(echo "$sp" | jq -r '.appDisplayName // "unnamed"' 2>/dev/null)
        app_id=$(echo "$sp" | jq -r '.appId // "unknown"' 2>/dev/null)

        [[ "$app_name" == "unnamed" || -z "$app_name" ]] && app_name="$app_id"

        echo "$sp" | jq -c '.passwordCredentials[]? // empty' 2>/dev/null | while IFS= read -r cred; do
            local end_date
            end_date=$(echo "$cred" | jq -r '.endDateTime // "null"' 2>/dev/null)

            local remaining status severity
            remaining=$(days_until "$end_date")

            if [[ "$remaining" == "unknown" ]]; then
                status="Unknown"
                severity="INFO"
                printf "  %-30s %-14s %-20s %-14s %b%s%b\n" \
                    "${app_name:0:28}" "Password" "Unknown" "$status" \
                    "$CYAN" "$severity" "$RESET"
                flag_info
            elif [[ "$remaining" -lt 0 ]]; then
                status="Expired"
                severity="WARN"
                printf "  %-30s %-14s %-20s %-14s %b%s%b\n" \
                    "${app_name:0:28}" "Password" "${end_date:0:10}" "$status" \
                    "$YELLOW" "$severity" "$RESET"
                flag_warn
            elif [[ "$remaining" -lt 30 ]]; then
                status="Expiring (${remaining}d)"
                severity="WARN"
                printf "  %-30s %-14s %-20s %-14s %b%s%b\n" \
                    "${app_name:0:28}" "Password" "${end_date:0:10}" "$status" \
                    "$YELLOW" "$severity" "$RESET"
                flag_warn
            else
                verbose "SP ${app_name}: password credential valid (${remaining}d remaining)"
                flag_ok
            fi
        done

        echo "$sp" | jq -c '.keyCredentials[]? // empty' 2>/dev/null | while IFS= read -r cred; do
            local end_date
            end_date=$(echo "$cred" | jq -r '.endDateTime // "null"' 2>/dev/null)

            local remaining status severity
            remaining=$(days_until "$end_date")

            if [[ "$remaining" == "unknown" ]]; then
                status="Unknown"
                severity="INFO"
                printf "  %-30s %-14s %-20s %-14s %b%s%b\n" \
                    "${app_name:0:28}" "Certificate" "Unknown" "$status" \
                    "$CYAN" "$severity" "$RESET"
                flag_info
            elif [[ "$remaining" -lt 0 ]]; then
                status="Expired"
                severity="WARN"
                printf "  %-30s %-14s %-20s %-14s %b%s%b\n" \
                    "${app_name:0:28}" "Certificate" "${end_date:0:10}" "$status" \
                    "$YELLOW" "$severity" "$RESET"
                flag_warn
            elif [[ "$remaining" -lt 30 ]]; then
                status="Expiring (${remaining}d)"
                severity="WARN"
                printf "  %-30s %-14s %-20s %-14s %b%s%b\n" \
                    "${app_name:0:28}" "Certificate" "${end_date:0:10}" "$status" \
                    "$YELLOW" "$severity" "$RESET"
                flag_warn
            else
                verbose "SP ${app_name}: key credential valid (${remaining}d remaining)"
                flag_ok
            fi
        done
    done

    echo ""
}

# ══════════════════════════════════════════════════════════════════════
#                       GUEST USERS AUDIT
# ══════════════════════════════════════════════════════════════════════
audit_guests() {
    log "Auditing guest user accounts (threshold: ${STALE_DAYS} days)..."
    echo ""

    printf "  %-36s %-20s %-20s %s\n" \
        "UPN" "CREATED" "LAST_ACTIVITY" "SEVERITY"
    printf "  %s\n" "$(printf '%.0s─' {1..90})"

    local guests_json
    # shellcheck disable=SC2016
    guests_json=$(az rest --method GET \
        --url 'https://graph.microsoft.com/v1.0/users?$filter=userType%20eq%20%27Guest%27&$select=userPrincipalName,displayName,createdDateTime,signInActivity&$top=999' \
        2>/dev/null || echo '{"value":[]}')

    echo "$guests_json" | jq -c '.value[]? // empty' 2>/dev/null | while IFS= read -r guest; do
        local upn created last_activity
        upn=$(echo "$guest" | jq -r '.userPrincipalName // "unknown"' 2>/dev/null)
        created=$(echo "$guest" | jq -r '.createdDateTime // "null"' 2>/dev/null)
        last_activity=$(echo "$guest" | jq -r '.signInActivity.lastSignInDateTime // "null"' 2>/dev/null)

        local created_display last_display
        if [[ "$created" == "null" || -z "$created" ]]; then
            created_display="Unknown"
        else
            created_display="${created:0:10}"
        fi

        if [[ "$last_activity" == "null" || -z "$last_activity" ]]; then
            last_display="Never"
        else
            last_display="${last_activity:0:10}"
        fi

        local idle_days
        idle_days=$(days_since "$last_activity")

        if [[ "$idle_days" == "never" ]]; then
            printf "  %-36s %-20s %-20s %b%s%b\n" \
                "${upn:0:34}" "$created_display" "$last_display" \
                "$YELLOW" "WARN" "$RESET"
            flag_warn
        elif [[ "$idle_days" == "unknown" ]]; then
            verbose "Guest ${upn}: unable to determine activity"
            flag_info
        elif [[ "$idle_days" -gt "$STALE_DAYS" ]]; then
            printf "  %-36s %-20s %-20s %b%s%b\n" \
                "${upn:0:34}" "$created_display" "$last_display" \
                "$YELLOW" "WARN" "$RESET"
            flag_warn
        else
            verbose "Guest ${upn}: active (${idle_days}d idle)"
            flag_ok
        fi
    done

    echo ""
}

# ══════════════════════════════════════════════════════════════════════
#                       SUMMARY
# ══════════════════════════════════════════════════════════════════════
print_summary() {
    local elapsed
    elapsed=$(( $(date +%s) - START_TIME ))

    echo ""
    echo "  ══════════════════════════════════════════"
    echo "  Azure Entra ID Audit Summary"
    echo "  ══════════════════════════════════════════"
    printf "  %-20s %b%d%b\n" "CRITICAL:" "$RED" "$TOTAL_CRIT" "$RESET"
    printf "  %-20s %b%d%b\n" "WARN:" "$YELLOW" "$TOTAL_WARN" "$RESET"
    printf "  %-20s %b%d%b\n" "INFO:" "$CYAN" "$TOTAL_INFO" "$RESET"
    printf "  %-20s %b%d%b\n" "OK:" "$GREEN" "$TOTAL_OK" "$RESET"
    echo "  ──────────────────────────────────────────"
    printf "  Completed in %ds\n" "$elapsed"
    echo ""

    if [[ "$TOTAL_CRIT" -gt 0 ]]; then
        echo -e "  ${RED}${BOLD}Action required:${RESET} ${TOTAL_CRIT} critical finding(s)"
        echo ""
        echo "  Top recommendations:"
        echo "    • Enable MFA for all admin accounts immediately"
        echo "    • Review and remove stale user accounts"
        echo "    • Rotate expired service principal credentials"
        echo "    • Reduce the number of Global Administrators to ≤5"
        echo "    • Remove inactive guest accounts"
        echo ""
    elif [[ "$TOTAL_WARN" -gt 0 ]]; then
        echo -e "  ${YELLOW}Review recommended:${RESET} ${TOTAL_WARN} warning(s)"
        echo ""
        echo "  Suggestions:"
        echo "    • Disable or remove stale user accounts"
        echo "    • Enforce MFA registration for all users"
        echo "    • Renew expiring service principal credentials"
        echo "    • Clean up inactive guest accounts"
        echo ""
    else
        echo -e "  ${GREEN}All checks passed${RESET}"
        echo ""
    fi
}

# ══════════════════════════════════════════════════════════════════════
#                       USAGE
# ══════════════════════════════════════════════════════════════════════
show_help() {
    cat <<EOF
${BOLD}${SCRIPT_NAME}${RESET} — Azure Entra ID Auditor

Audit Azure Entra ID (Azure AD) for stale users, MFA gaps, excessive
permissions, service principal hygiene, and guest accounts via az CLI.

${BOLD}MODES${RESET}
  --full                Run all audits
  --stale-users         Find users with no sign-in activity > N days
  --mfa                 Check MFA registration status
  --admins              Audit privileged role assignments
  --service-principals  Audit service principal credential expiry
  --guests              Find stale guest accounts

${BOLD}OPTIONS${RESET}
  --stale-days N        Override stale threshold in days (default: 90)
  --verbose             Debug output
  --no-color            Disable colored output
  --help                Show this help message

${BOLD}ENVIRONMENT VARIABLES${RESET}
  STALE_DAYS            Days before a user is considered stale (default: 90)
  VERBOSE               Enable verbose output (true/false)
  COLOR                 Color mode: auto, always, never

${BOLD}PREREQUISITES${RESET}
  • Azure CLI authenticated: az login
  • Microsoft Graph API permissions for sign-in activity and reports
  • Reader role or higher for role assignment queries

${BOLD}EXAMPLES${RESET}
  # Full audit
  ${SCRIPT_NAME} --full

  # Check stale users only
  ${SCRIPT_NAME} --stale-users

  # MFA audit with custom stale threshold
  ${SCRIPT_NAME} --mfa --stale-days 60

  # Service principal credential check
  ${SCRIPT_NAME} --service-principals

  # Guest user audit
  ${SCRIPT_NAME} --guests

${BOLD}EXIT CODES${RESET}
  0   All checks passed
  1   Warnings found (review recommended)
  2   Critical findings (action required)
EOF
}

# ══════════════════════════════════════════════════════════════════════
#                       PARSE ARGS
# ══════════════════════════════════════════════════════════════════════
parse_args() {
    local modes=()

    while [[ $# -gt 0 ]]; do
        case "$1" in
            --full)
                modes=(stale-users mfa admins service-principals guests)
                shift ;;
            --stale-users)
                modes+=(stale-users); shift ;;
            --mfa)
                modes+=(mfa); shift ;;
            --admins)
                modes+=(admins); shift ;;
            --service-principals)
                modes+=(service-principals); shift ;;
            --guests)
                modes+=(guests); shift ;;
            --stale-days)
                STALE_DAYS="${2:?--stale-days requires a value}"; shift 2 ;;
            --verbose)
                VERBOSE="true"; shift ;;
            --no-color)
                COLOR="never"; shift ;;
            --help|-h)
                setup_colors; show_help; exit 0 ;;
            *)
                die "Unknown option: $1 (see --help)" ;;
        esac
    done

    if [[ ${#modes[@]} -eq 0 ]]; then
        err "No audit mode specified"
        echo "Run ${SCRIPT_NAME} --help for usage" >&2
        exit 1
    fi

    RUN_MODE="${modes[*]}"
}

# ══════════════════════════════════════════════════════════════════════
#                       MAIN
# ══════════════════════════════════════════════════════════════════════
main() {
    parse_args "$@"
    setup_colors
    check_deps
    check_credentials

    START_TIME=$(date +%s)

    echo ""
    echo -e "${BOLD}Azure Entra ID Auditor${RESET}"
    echo -e "Mode:   ${RUN_MODE}"
    echo -e "Time:   $(date -u +%Y-%m-%dT%H:%M:%SZ)"
    echo ""

    for mode in $RUN_MODE; do
        case "$mode" in
            stale-users)         audit_stale_users ;;
            mfa)                 audit_mfa ;;
            admins)              audit_admins ;;
            service-principals)  audit_service_principals ;;
            guests)              audit_guests ;;
        esac
    done

    print_summary

    if [[ "$TOTAL_CRIT" -gt 0 ]]; then
        exit 2
    elif [[ "$TOTAL_WARN" -gt 0 ]]; then
        exit 1
    fi
    exit 0
}

main "$@"
