Tutorial

New updates and improvements to Roundfleet.

Browser Data Management and Privacy Compliance on macOS

Implement comprehensive browser data management and privacy compliance across your Roundfleet devices. This tutorial covers multi-browser data clearing, privacy policy enforcement, data retention management, and automated compliance workflows for enterprise environments.

Understanding Browser Data Management

Browser data encompasses various types of user information:

  • Browsing history - Website visit records and timestamps
  • Cookies and local storage - Session data and user preferences
  • Cache files - Temporary web content and resources
  • Download history - File download records and metadata
  • Form data and passwords - Autofill information and credentials
  • Extensions and settings - Browser configuration and add-ons

Basic Browser History Clearing

Clear Google Chrome History

#!/bin/bash

# Clear Google Chrome browsing history
clear_chrome_history() {
    echo "=== Clearing Google Chrome History ==="
    
    # Get logged-in user
    local logged_user
    logged_user=$(stat -f%Su /dev/console 2>/dev/null)
    
    if [[ -z "$logged_user" || "$logged_user" == "root" ]]; then
        echo "❌ No active user session found"
        return 1
    fi
    
    echo "👤 Target user: $logged_user"
    
    # Chrome profile path
    local chrome_profile="/Users/$logged_user/Library/Application Support/Google/Chrome/Default"
    
    # Check if Chrome is installed and profile exists
    if [[ ! -d "$chrome_profile" ]]; then
        echo "âš ī¸  Chrome profile not found for user: $logged_user"
        return 1
    fi
    
    # Kill Chrome processes if running
    pkill -f "Google Chrome" 2>/dev/null
    sleep 2
    
    # Clear history file
    if sudo -u "$logged_user" rm -f "$chrome_profile/History" 2>/dev/null; then
        echo "✅ Chrome history cleared for user: $logged_user"
    else
        echo "❌ Failed to clear Chrome history"
        return 1
    fi
    
    return 0
}

# Execute function
clear_chrome_history

Clear Firefox History

#!/bin/bash

# Clear Firefox browsing history
clear_firefox_history() {
    echo "=== Clearing Firefox History ==="
    
    # Get logged-in user
    local logged_user
    logged_user=$(stat -f%Su /dev/console 2>/dev/null)
    
    if [[ -z "$logged_user" || "$logged_user" == "root" ]]; then
        echo "❌ No active user session found"
        return 1
    fi
    
    echo "👤 Target user: $logged_user"
    
    # Firefox profiles path
    local firefox_profiles="/Users/$logged_user/Library/Application Support/Firefox/Profiles"
    
    # Check if Firefox profiles exist
    if [[ ! -d "$firefox_profiles" ]]; then
        echo "âš ī¸  Firefox profiles not found for user: $logged_user"
        return 1
    fi
    
    # Kill Firefox processes if running
    pkill -f "firefox" 2>/dev/null
    sleep 2
    
    # Clear history from all Firefox profiles
    local profiles_cleared=0
    for profile_dir in "$firefox_profiles"/*; do
        if [[ -d "$profile_dir" ]]; then
            # Remove places.sqlite (contains history)
            if sudo -u "$logged_user" rm -f "$profile_dir/places.sqlite" 2>/dev/null; then
                profiles_cleared=$((profiles_cleared + 1))
                echo "✅ Cleared history for profile: $(basename "$profile_dir")"
            fi
        fi
    done
    
    if [[ $profiles_cleared -gt 0 ]]; then
        echo "✅ Firefox history cleared from $profiles_cleared profile(s)"
        return 0
    else
        echo "❌ Failed to clear Firefox history"
        return 1
    fi
}

# Execute function
clear_firefox_history

Enterprise Browser Data Management System

#!/bin/bash

# Roundfleet Enterprise Browser Data Management System
# Comprehensive privacy compliance, data lifecycle management, and multi-browser support

# Configuration
LOG_FILE="/var/log/roundfleet_browser_data.log"
CONFIG_DIR="/etc/roundfleet/browser_management"
POLICIES_DIR="$CONFIG_DIR/policies"
REPORTS_DIR="$CONFIG_DIR/reports"
COMPLIANCE_DIR="$CONFIG_DIR/compliance"
BACKUP_DIR="/var/backups/browser_configs"

# Supported browsers and their data locations
declare -A BROWSER_PATHS=(
    ["chrome"]="/Library/Application Support/Google/Chrome"
    ["firefox"]="/Library/Application Support/Firefox"
    ["safari"]="/Library/Safari"
    ["edge"]="/Library/Application Support/Microsoft Edge"
    ["opera"]="/Library/Application Support/com.operasoftware.Opera"
    ["brave"]="/Library/Application Support/BraveSoftware/Brave-Browser"
    ["vivaldi"]="/Library/Application Support/Vivaldi"
)

# Browser data types and corresponding files
declare -A DATA_TYPES=(
    ["history"]="History,places.sqlite,History.db"
    ["cookies"]="Cookies,cookies.sqlite,Cookies.binarycookies"
    ["cache"]="Cache,cache2,WebKit/NetworkCache"
    ["downloads"]="Downloads,downloads.sqlite"
    ["passwords"]="Login Data,key4.db,logins.json"
    ["bookmarks"]="Bookmarks,bookmarks.sqlite,Bookmarks.plist"
    ["extensions"]="Extensions,extensions.sqlite,Extensions"
    ["settings"]="Preferences,prefs.js,com.apple.Safari.plist"
)

# Privacy policy templates
declare -A PRIVACY_POLICIES=(
    ["strict"]="clear_all_daily,no_persistent_cookies,history_retention_1day"
    ["moderate"]="clear_history_weekly,selective_cookies,history_retention_7days"
    ["lenient"]="clear_cache_monthly,allow_cookies,history_retention_30days"
    ["compliance"]="audit_all,encrypt_data,gdpr_compliance,history_retention_legal"
    ["education"]="clear_daily_schedule,safe_browsing,limited_downloads"
    ["healthcare"]="hipaa_compliant,no_data_retention,audit_all_access"
    ["finance"]="sox_compliant,encrypted_storage,detailed_audit"
)

# Compliance frameworks
declare -A COMPLIANCE_FRAMEWORKS=(
    ["gdpr"]="right_to_erasure,data_minimization,consent_required,audit_trails"
    ["hipaa"]="phi_protection,access_controls,audit_logs,encryption_required"
    ["sox"]="financial_data_protection,retention_policies,access_monitoring"
    ["coppa"]="child_privacy_protection,parental_consent,data_deletion"
    ["ccpa"]="california_privacy_rights,data_transparency,deletion_rights"
)

# Logging function
log_action() {
    echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" | tee -a "$LOG_FILE"
}

# Setup directories
setup_directories() {
    for dir in "$CONFIG_DIR" "$POLICIES_DIR" "$REPORTS_DIR" "$COMPLIANCE_DIR" "$BACKUP_DIR"; do
        if [[ ! -d "$dir" ]]; then
            mkdir -p "$dir"
            log_action "Created directory: $dir"
        fi
    done
}

# Get all users with browser data
get_browser_users() {
    local users=()
    
    # Get all users with UID >= 500 (regular users)
    while IFS= read -r user; do
        local user_home
        user_home=$(dscl . read "/Users/$user" NFSHomeDirectory 2>/dev/null | awk '{print $2}')
        
        if [[ -n "$user_home" && -d "$user_home" ]]; then
            # Check if user has any browser data
            for browser in "${!BROWSER_PATHS[@]}"; do
                local browser_path="$user_home${BROWSER_PATHS[$browser]}"
                if [[ -d "$browser_path" ]]; then
                    users+=("$user")
                    break
                fi
            done
        fi
    done < <(dscl . list /Users UniqueID | awk '$2 >= 500 {print $1}')
    
    printf '%s\n' "${users[@]}"
}

# Detect installed browsers for a user
detect_user_browsers() {
    local username="$1"
    local user_home
    user_home=$(dscl . read "/Users/$username" NFSHomeDirectory 2>/dev/null | awk '{print $2}')
    
    if [[ -z "$user_home" ]]; then
        return 1
    fi
    
    local installed_browsers=()
    
    for browser in "${!BROWSER_PATHS[@]}"; do
        local browser_path="$user_home${BROWSER_PATHS[$browser]}"
        if [[ -d "$browser_path" ]]; then
            installed_browsers+=("$browser")
        fi
    done
    
    printf '%s\n' "${installed_browsers[@]}"
}

# Clear specific browser data type
clear_browser_data() {
    local username="$1"
    local browser="$2"
    local data_type="$3"
    local backup="${4:-false}"
    
    log_action "Clearing $data_type from $browser for user: $username"
    
    local user_home
    user_home=$(dscl . read "/Users/$username" NFSHomeDirectory 2>/dev/null | awk '{print $2}')
    
    if [[ -z "$user_home" ]]; then
        log_action "❌ User not found: $username"
        return 1
    fi
    
    local browser_path="$user_home${BROWSER_PATHS[$browser]}"
    
    if [[ ! -d "$browser_path" ]]; then
        log_action "âš ī¸  Browser $browser not found for user: $username"
        return 1
    fi
    
    # Kill browser processes
    case "$browser" in
        "chrome")
            pkill -f "Google Chrome" 2>/dev/null
            ;;
        "firefox")
            pkill -f "firefox" 2>/dev/null
            ;;
        "safari")
            pkill -f "Safari" 2>/dev/null
            ;;
        "edge")
            pkill -f "Microsoft Edge" 2>/dev/null
            ;;
        *)
            pkill -f "$browser" 2>/dev/null
            ;;
    esac
    
    sleep 2
    
    # Get data files for this type
    local data_files="${DATA_TYPES[$data_type]}"
    IFS=',' read -ra FILES <<< "$data_files"
    
    local cleared_count=0
    
    for file_pattern in "${FILES[@]}"; do
        # Find and process matching files
        while IFS= read -r -d '' file; do
            if [[ -f "$file" || -d "$file" ]]; then
                # Backup if requested
                if [[ "$backup" == "true" ]]; then
                    backup_browser_data "$username" "$browser" "$file"
                fi
                
                # Clear the data
                if sudo -u "$username" rm -rf "$file" 2>/dev/null; then
                    cleared_count=$((cleared_count + 1))
                    log_action "✅ Cleared: $file"
                else
                    log_action "❌ Failed to clear: $file"
                fi
            fi
        done < <(find "$browser_path" -name "$file_pattern" -print0 2>/dev/null)
    done
    
    log_action "Cleared $cleared_count data files for $data_type in $browser"
    return 0
}

# Comprehensive browser data audit
audit_browser_data() {
    log_action "Starting comprehensive browser data audit"
    
    local audit_report="$REPORTS_DIR/browser_audit_$(date '+%Y%m%d_%H%M%S').json"
    
    cat > "$audit_report" << EOF
{
    "audit_metadata": {
        "timestamp": "$(date -Iseconds)",
        "hostname": "$(hostname)",
        "os_version": "$(sw_vers -productVersion)",
        "generator": "Roundfleet Browser Data Manager"
    },
    "user_browser_data": [
EOF

    local first=true
    local total_users=0
    local users_with_data=0
    
    # Audit each user
    for user in $(get_browser_users); do
        total_users=$((total_users + 1))
        users_with_data=$((users_with_data + 1))
        
        if [[ "$first" == true ]]; then
            first=false
        else
            echo "," >> "$audit_report"
        fi
        
        local user_home
        user_home=$(dscl . read "/Users/$user" NFSHomeDirectory 2>/dev/null | awk '{print $2}')
        
        local user_browsers
        user_browsers=$(detect_user_browsers "$user")
        
        # Analyze data for each browser
        local browser_data="["
        local browser_first=true
        
        for browser in $user_browsers; do
            if [[ "$browser_first" == true ]]; then
                browser_first=false
            else
                browser_data+=","
            fi
            
            local data_analysis
            data_analysis=$(analyze_browser_data "$user" "$browser")
            
            browser_data+="{\"browser\": \"$browser\", \"data\": $data_analysis}"
        done
        
        browser_data+="]"
        
        cat >> "$audit_report" << EOF
        {
            "username": "$user",
            "user_home": "$user_home",
            "browsers": $browser_data,
            "last_login": "$(last -1 "$user" | head -1 | awk '{print $4, $5, $6, $7}' || echo 'Never')",
            "privacy_risk_score": $(calculate_privacy_risk "$user")
        }
EOF
        
        log_action "Audited user: $user"
    done
    
    cat >> "$audit_report" << EOF
    ],
    "summary": {
        "total_users": $total_users,
        "users_with_browser_data": $users_with_data,
        "supported_browsers": $(echo "${!BROWSER_PATHS[@]}" | tr ' ' '\n' | jq -R . | jq -s .),
        "data_types_monitored": $(echo "${!DATA_TYPES[@]}" | tr ' ' '\n' | jq -R . | jq -s .)
    }
}
EOF

    log_action "✅ Browser data audit completed: $audit_report"
    echo "$audit_report"
}

# Analyze browser data for a specific user and browser
analyze_browser_data() {
    local username="$1"
    local browser="$2"
    
    local user_home
    user_home=$(dscl . read "/Users/$username" NFSHomeDirectory 2>/dev/null | awk '{print $2}')
    local browser_path="$user_home${BROWSER_PATHS[$browser]}"
    
    local data_summary="{"
    local type_first=true
    
    for data_type in "${!DATA_TYPES[@]}"; do
        if [[ "$type_first" == true ]]; then
            type_first=false
        else
            data_summary+=","
        fi
        
        local file_count=0
        local total_size=0
        
        local data_files="${DATA_TYPES[$data_type]}"
        IFS=',' read -ra FILES <<< "$data_files"
        
        for file_pattern in "${FILES[@]}"; do
            while IFS= read -r -d '' file; do
                if [[ -f "$file" ]]; then
                    file_count=$((file_count + 1))
                    local size
                    size=$(stat -f%z "$file" 2>/dev/null || echo 0)
                    total_size=$((total_size + size))
                elif [[ -d "$file" ]]; then
                    file_count=$((file_count + 1))
                    local size
                    size=$(du -sk "$file" 2>/dev/null | awk '{print $1*1024}' || echo 0)
                    total_size=$((total_size + size))
                fi
            done < <(find "$browser_path" -name "$file_pattern" -print0 2>/dev/null)
        done
        
        data_summary+="\"$data_type\": {\"file_count\": $file_count, \"total_size_bytes\": $total_size}"
    done
    
    data_summary+="}"
    echo "$data_summary"
}

# Calculate privacy risk score for a user
calculate_privacy_risk() {
    local username="$1"
    local risk_score=0
    
    # Analyze data retention and privacy risks
    local user_browsers
    user_browsers=$(detect_user_browsers "$username")
    
    for browser in $user_browsers; do
        local data_analysis
        data_analysis=$(analyze_browser_data "$username" "$browser")
        
        # Simple risk calculation based on data volume
        local history_size
        history_size=$(echo "$data_analysis" | jq -r '.history.total_size_bytes // 0')
        
        if [[ $history_size -gt 10485760 ]]; then  # > 10MB
            risk_score=$((risk_score + 3))
        elif [[ $history_size -gt 1048576 ]]; then  # > 1MB
            risk_score=$((risk_score + 2))
        elif [[ $history_size -gt 0 ]]; then
            risk_score=$((risk_score + 1))
        fi
    done
    
    # Cap at 10
    if [[ $risk_score -gt 10 ]]; then
        risk_score=10
    fi
    
    echo "$risk_score"
}

# Apply privacy policy to users
apply_privacy_policy() {
    local policy_name="$1"
    local target_users="$2"
    
    log_action "Applying privacy policy: $policy_name"
    
    local policy_config="${PRIVACY_POLICIES[$policy_name]}"
    if [[ -z "$policy_config" ]]; then
        log_action "❌ Unknown privacy policy: $policy_name"
        return 1
    fi
    
    # Get target users
    local users=()
    if [[ -n "$target_users" ]]; then
        IFS=',' read -ra users <<< "$target_users"
    else
        while IFS= read -r user; do
            users+=("$user")
        done < <(get_browser_users)
    fi
    
    # Parse policy configuration
    IFS=',' read -ra POLICY_RULES <<< "$policy_config"
    
    for user in "${users[@]}"; do
        log_action "Applying policy '$policy_name' to user: $user"
        
        for rule in "${POLICY_RULES[@]}"; do
            case "$rule" in
                "clear_all_daily")
                    schedule_daily_cleanup "$user" "all"
                    ;;
                "clear_history_weekly")
                    schedule_weekly_cleanup "$user" "history"
                    ;;
                "clear_cache_monthly")
                    schedule_monthly_cleanup "$user" "cache"
                    ;;
                "no_persistent_cookies")
                    clear_browser_data "$user" "all" "cookies"
                    ;;
                "audit_all")
                    enable_comprehensive_audit "$user"
                    ;;
                "gdpr_compliance")
                    configure_gdpr_compliance "$user"
                    ;;
                "hipaa_compliant")
                    configure_hipaa_compliance "$user"
                    ;;
            esac
        done
        
        log_action "✅ Policy applied to user: $user"
    done
    
    return 0
}

# Schedule automated cleanup
schedule_daily_cleanup() {
    local username="$1"
    local data_type="$2"
    
    log_action "Scheduling daily cleanup for user: $username, data: $data_type"
    
    # Create LaunchAgent for user
    local launch_agent_path="/Users/$username/Library/LaunchAgents/com.roundfleet.browser-cleanup.plist"
    
    cat > "$launch_agent_path" << EOF
<?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>com.roundfleet.browser-cleanup</string>
    <key>ProgramArguments</key>
    <array>
        <string>/usr/local/bin/roundfleet-browser-cleanup</string>
        <string>--user</string>
        <string>$username</string>
        <string>--data-type</string>
        <string>$data_type</string>
    </array>
    <key>StartCalendarInterval</key>
    <dict>
        <key>Hour</key>
        <integer>2</integer>
        <key>Minute</key>
        <integer>0</integer>
    </dict>
    <key>RunAtLoad</key>
    <false/>
</dict>
</plist>
EOF
    
    chown "$username:staff" "$launch_agent_path"
    log_action "✅ Daily cleanup scheduled for user: $username"
}

# Generate compliance report
generate_compliance_report() {
    local framework="$1"
    
    log_action "Generating compliance report for framework: $framework"
    
    local compliance_report="$COMPLIANCE_DIR/compliance_${framework}_$(date '+%Y%m%d_%H%M%S').json"
    
    cat > "$compliance_report" << EOF
{
    "compliance_metadata": {
        "timestamp": "$(date -Iseconds)",
        "framework": "$framework",
        "hostname": "$(hostname)",
        "generator": "Roundfleet Browser Compliance Manager"
    },
    "compliance_assessment": {
        "framework_requirements": $(get_framework_requirements "$framework"),
        "current_status": $(assess_compliance_status "$framework"),
        "recommendations": $(generate_compliance_recommendations "$framework"),
        "risk_assessment": $(calculate_compliance_risk "$framework")
    },
    "user_compliance": [
EOF

    local first=true
    
    # Assess compliance for each user
    for user in $(get_browser_users); do
        if [[ "$first" == true ]]; then
            first=false
        else
            echo "," >> "$compliance_report"
        fi
        
        local user_compliance
        user_compliance=$(assess_user_compliance "$user" "$framework")
        
        cat >> "$compliance_report" << EOF
        {
            "username": "$user",
            "compliance_status": $user_compliance
        }
EOF
    done
    
    cat >> "$compliance_report" << EOF
    ]
}
EOF

    log_action "✅ Compliance report generated: $compliance_report"
    echo "$compliance_report"
}

# Get framework requirements
get_framework_requirements() {
    local framework="$1"
    
    case "$framework" in
        "gdpr")
            echo '{"data_minimization": true, "right_to_erasure": true, "consent_required": true, "audit_trails": true}'
            ;;
        "hipaa")
            echo '{"phi_protection": true, "access_controls": true, "audit_logs": true, "encryption_required": true}'
            ;;
        "sox")
            echo '{"financial_data_protection": true, "retention_policies": true, "access_monitoring": true}'
            ;;
        "coppa")
            echo '{"child_privacy_protection": true, "parental_consent": true, "data_deletion": true}'
            ;;
        *)
            echo '{"general_privacy": true, "basic_audit": true}'
            ;;
    esac
}

# Assess compliance status
assess_compliance_status() {
    local framework="$1"
    
    local compliance_score=0
    local total_checks=0
    
    # Check basic privacy controls
    total_checks=$((total_checks + 1))
    if [[ -f "$POLICIES_DIR/privacy_policy.conf" ]]; then
        compliance_score=$((compliance_score + 1))
    fi
    
    # Check audit logging
    total_checks=$((total_checks + 1))
    if [[ -f "$LOG_FILE" ]]; then
        compliance_score=$((compliance_score + 1))
    fi
    
    # Framework-specific checks
    case "$framework" in
        "gdpr")
            total_checks=$((total_checks + 2))
            # Check data retention policies
            if [[ -f "$POLICIES_DIR/data_retention.conf" ]]; then
                compliance_score=$((compliance_score + 1))
            fi
            # Check consent management
            if [[ -f "$POLICIES_DIR/consent_management.conf" ]]; then
                compliance_score=$((compliance_score + 1))
            fi
            ;;
        "hipaa")
            total_checks=$((total_checks + 1))
            # Check encryption
            if system_profiler SPStorageDataType | grep -q "Encrypted: Yes"; then
                compliance_score=$((compliance_score + 1))
            fi
            ;;
    esac
    
    local compliance_percentage
    compliance_percentage=$(awk "BEGIN {printf \"%.0f\", ($compliance_score/$total_checks)*100}")
    
    echo "{\"score\": $compliance_score, \"total_checks\": $total_checks, \"percentage\": $compliance_percentage, \"status\": \"$([ $compliance_percentage -ge 80 ] && echo 'compliant' || echo 'non_compliant')\"}"
}

# Assess user compliance
assess_user_compliance() {
    local username="$1"
    local framework="$2"
    
    local privacy_risk
    privacy_risk=$(calculate_privacy_risk "$username")
    
    local compliance_status="compliant"
    if [[ $privacy_risk -gt 7 ]]; then
        compliance_status="high_risk"
    elif [[ $privacy_risk -gt 4 ]]; then
        compliance_status="medium_risk"
    fi
    
    echo "{\"privacy_risk_score\": $privacy_risk, \"status\": \"$compliance_status\"}"
}

# Backup browser data before clearing
backup_browser_data() {
    local username="$1"
    local browser="$2"
    local data_path="$3"
    
    local timestamp
    timestamp=$(date '+%Y%m%d_%H%M%S')
    local backup_file="$BACKUP_DIR/browser_backup_${username}_${browser}_${timestamp}.tar.gz"
    
    if tar -czf "$backup_file" -C "$(dirname "$data_path")" "$(basename "$data_path")" 2>/dev/null; then
        log_action "✅ Browser data backed up: $backup_file"
        echo "$backup_file"
    else
        log_action "❌ Failed to backup browser data: $data_path"
        return 1
    fi
}

# Main execution function
main() {
    local action="${1:-audit}"
    local parameter="$2"
    local additional_param="$3"
    local extra_param="$4"
    
    log_action "=== Roundfleet Browser Data Management Started ==="
    log_action "Action: $action"
    log_action "Parameter: ${parameter:-N/A}"
    
    setup_directories
    
    case "$action" in
        "clear")
            if [[ -z "$parameter" || -z "$additional_param" ]]; then
                echo "Usage: $0 clear <browser> <data_type> [username] [backup]"
                echo "Browsers: ${!BROWSER_PATHS[*]}"
                echo "Data types: ${!DATA_TYPES[*]}"
                exit 1
            fi
            local target_user="${extra_param:-$(stat -f%Su /dev/console 2>/dev/null)}"
            clear_browser_data "$target_user" "$parameter" "$additional_param" "${5:-false}"
            ;;
        "audit")
            audit_browser_data
            ;;
        "policy")
            if [[ -z "$parameter" ]]; then
                echo "Available privacy policies:"
                for policy in "${!PRIVACY_POLICIES[@]}"; do
                    echo "  - $policy: ${PRIVACY_POLICIES[$policy]}"
                done
                echo ""
                echo "Usage: $0 policy <policy_name> [target_users]"
                exit 1
            fi
            apply_privacy_policy "$parameter" "$additional_param"
            ;;
        "compliance")
            if [[ -z "$parameter" ]]; then
                echo "Available compliance frameworks:"
                for framework in "${!COMPLIANCE_FRAMEWORKS[@]}"; do
                    echo "  - $framework: ${COMPLIANCE_FRAMEWORKS[$framework]}"
                done
                echo ""
                echo "Usage: $0 compliance <framework>"
                exit 1
            fi
            generate_compliance_report "$parameter"
            ;;
        "detect")
            local target_user="${parameter:-$(stat -f%Su /dev/console 2>/dev/null)}"
            echo "Browsers detected for user '$target_user':"
            detect_user_browsers "$target_user"
            ;;
        *)
            echo "Usage: $0 {clear|audit|policy|compliance|detect}"
            echo "  clear       - Clear specific browser data"
            echo "  audit       - Generate comprehensive browser data audit"
            echo "  policy      - Apply privacy policy to users"
            echo "  compliance  - Generate compliance report"
            echo "  detect      - Detect installed browsers for user"
            exit 1
            ;;
    esac
    
    log_action "=== Browser data management completed ==="
}

# Execute main function
main "$@"

Advanced Browser Management Features

Multi-Browser Data Analysis

#!/bin/bash

# Comprehensive multi-browser data analysis
analyze_all_browsers() {
    echo "=== Multi-Browser Data Analysis ==="
    
    local analysis_report="$REPORTS_DIR/browser_analysis_$(date '+%Y%m%d_%H%M%S').json"
    
    cat > "$analysis_report" << EOF
{
    "analysis_metadata": {
        "timestamp": "$(date -Iseconds)",
        "hostname": "$(hostname)"
    },
    "browser_usage_analysis": {
EOF

    local browser_first=true
    
    # Analyze each supported browser
    for browser in "${!BROWSER_PATHS[@]}"; do
        if [[ "$browser_first" == true ]]; then
            browser_first=false
        else
            echo "," >> "$analysis_report"
        fi
        
        local users_with_browser=0
        local total_data_size=0
        
        # Count users and data size for this browser
        for user in $(get_browser_users); do
            local user_browsers
            user_browsers=$(detect_user_browsers "$user")
            
            if echo "$user_browsers" | grep -q "^$browser$"; then
                users_with_browser=$((users_with_browser + 1))
                
                local browser_data
                browser_data=$(analyze_browser_data "$user" "$browser")
                
                # Sum up data sizes
                for data_type in "${!DATA_TYPES[@]}"; do
                    local size
                    size=$(echo "$browser_data" | jq -r ".$data_type.total_size_bytes // 0")
                    total_data_size=$((total_data_size + size))
                done
            fi
        done
        
        cat >> "$analysis_report" << EOF
        "$browser": {
            "users_count": $users_with_browser,
            "total_data_size_bytes": $total_data_size,
            "average_data_per_user": $(( users_with_browser > 0 ? total_data_size / users_with_browser : 0 ))
        }
EOF
    done
    
    cat >> "$analysis_report" << EOF
    }
}
EOF

    echo "📊 Browser analysis completed: $analysis_report"
}

Automated Privacy Cleanup

#!/bin/bash

# Automated privacy cleanup based on data age and policy
automated_privacy_cleanup() {
    local retention_days="${1:-7}"
    local dry_run="${2:-false}"
    
    echo "=== Automated Privacy Cleanup ==="
    echo "Retention period: $retention_days days"
    echo "Dry run: $dry_run"
    
    local cleanup_report="$REPORTS_DIR/privacy_cleanup_$(date '+%Y%m%d_%H%M%S').json"
    
    cat > "$cleanup_report" << EOF
{
    "cleanup_metadata": {
        "timestamp": "$(date -Iseconds)",
        "retention_days": $retention_days,
        "dry_run": $dry_run
    },
    "cleanup_results": [
EOF

    local first=true
    local total_cleaned=0
    
    # Process each user
    for user in $(get_browser_users); do
        local user_home
        user_home=$(dscl . read "/Users/$user" NFSHomeDirectory 2>/dev/null | awk '{print $2}')
        
        for browser in $(detect_user_browsers "$user"); do
            local browser_path="$user_home${BROWSER_PATHS[$browser]}"
            
            # Find old data files
            while IFS= read -r -d '' file; do
                local file_age_days
                file_age_days=$(( ($(date +%s) - $(stat -f%m "$file")) / 86400 ))
                
                if [[ $file_age_days -gt $retention_days ]]; then
                    if [[ "$first" == true ]]; then
                        first=false
                    else
                        echo "," >> "$cleanup_report"
                    fi
                    
                    cat >> "$cleanup_report" << EOF
        {
            "user": "$user",
            "browser": "$browser",
            "file": "$file",
            "age_days": $file_age_days,
            "action": "$([ "$dry_run" == "true" ] && echo "would_delete" || echo "deleted")"
        }
EOF
                    
                    if [[ "$dry_run" != "true" ]]; then
                        if sudo -u "$user" rm -rf "$file" 2>/dev/null; then
                            total_cleaned=$((total_cleaned + 1))
                        fi
                    fi
                fi
            done < <(find "$browser_path" -type f -print0 2>/dev/null)
        done
    done
    
    cat >> "$cleanup_report" << EOF
    ],
    "summary": {
        "total_files_processed": $total_cleaned
    }
}
EOF

    echo "🧹 Privacy cleanup completed: $cleanup_report"
}

Best Practices

🔒 Privacy and Security

  • Data minimization principles with automated cleanup policies
  • Consent management for data collection and processing
  • Encryption standards for sensitive browser data
  • Access controls with role-based data management permissions

📋 Compliance Management

  • Multi-framework support (GDPR, HIPAA, SOX, COPPA, CCPA)
  • Automated compliance assessment with regular auditing
  • Data retention policies aligned with legal requirements
  • Audit trails with comprehensive logging and reporting

🔧 Enterprise Operations

  • Fleet-wide deployment of privacy policies and data management
  • Scheduled cleanup operations with customizable retention periods
  • Backup and recovery capabilities for browser configurations
  • Integration support with existing security and compliance systems

🚀 User Experience

  • Non-disruptive operations with browser process management
  • Selective data clearing preserving important user preferences
  • Transparent reporting on data management activities
  • Flexible policy application based on user roles and requirements

Important Notes

  • Browser compatibility varies across different applications and versions
  • User data backup recommended before implementing aggressive cleanup policies
  • Performance impact minimal when operations are scheduled during off-hours
  • Legal compliance requirements vary by jurisdiction and industry
  • User notification may be required for certain data management activities
  • Regular policy review needed to adapt to changing privacy regulations

Manage Bluetooth Menu on Status Bar in macOS

Managing the visibility of system menus in the status bar is essential for maintaining a consistent user experience across your Mac fleet. This tutorial shows you how to control the Bluetooth menu display on macOS devices using shell scripts.

Why Manage Bluetooth Menu Visibility

Controlling the Bluetooth menu visibility helps with:

  • Consistent user experience: Standardize interface elements across all devices
  • Quick access management: Provide users with convenient Bluetooth controls
  • Support efficiency: Reduce support tickets by ensuring easy access to Bluetooth settings
  • Enterprise compliance: Maintain consistent UI standards across the organization
  • User productivity: Enable quick Bluetooth connection management

Understanding Control Center Configuration

macOS uses the Control Center preference system to manage status bar items. The Bluetooth menu is controlled through the com.apple.controlcenter.plist file with these key values:

  • Value 18: Show Bluetooth menu in status bar
  • Value 0: Hide Bluetooth menu from status bar

Basic Bluetooth Menu Management

Show Bluetooth Menu in Status Bar

#!/bin/bash

# Script to show Bluetooth menu on status bar
CurrentUser=$(ls -l /dev/console | awk '/ / { print $3 }')
CurrentUserUID=$(id -u "$CurrentUser")

launchctl asuser $CurrentUserUID sudo -iu "$CurrentUser" defaults -currentHost write com.apple.controlcenter.plist Bluetooth -int 18

echo "Bluetooth menu enabled on status bar for user: $CurrentUser"

Hide Bluetooth Menu from Status Bar

#!/bin/bash

# Script to hide Bluetooth menu from status bar
CurrentUser=$(ls -l /dev/console | awk '/ / { print $3 }')
CurrentUserUID=$(id -u "$CurrentUser")

launchctl asuser $CurrentUserUID sudo -iu "$CurrentUser" defaults -currentHost write com.apple.controlcenter.plist Bluetooth -int 0

echo "Bluetooth menu hidden from status bar for user: $CurrentUser"

Enhanced Bluetooth Menu Management

Comprehensive Bluetooth Status Script

#!/bin/bash

# Enhanced Bluetooth menu management with validation
DEVICE_NAME=$(scutil --get ComputerName)
CURRENT_USER=$(ls -l /dev/console | awk '/ / { print $3 }')
CURRENT_USER_UID=$(id -u "$CURRENT_USER")
LOG_FILE="/var/log/roundfleet_bluetooth_menu.log"

# Function to log messages
log_message() {
    echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" | tee -a "$LOG_FILE"
}

# Function to get current Bluetooth menu status
get_bluetooth_status() {
    local status=$(launchctl asuser $CURRENT_USER_UID sudo -iu "$CURRENT_USER" defaults -currentHost read com.apple.controlcenter.plist Bluetooth 2>/dev/null)
    echo "$status"
}

# Function to show Bluetooth menu
show_bluetooth_menu() {
    launchctl asuser $CURRENT_USER_UID sudo -iu "$CURRENT_USER" defaults -currentHost write com.apple.controlcenter.plist Bluetooth -int 18
    log_message "Bluetooth menu enabled on $DEVICE_NAME for user $CURRENT_USER"
}

# Function to hide Bluetooth menu
hide_bluetooth_menu() {
    launchctl asuser $CURRENT_USER_UID sudo -iu "$CURRENT_USER" defaults -currentHost write com.apple.controlcenter.plist Bluetooth -int 0
    log_message "Bluetooth menu hidden on $DEVICE_NAME for user $CURRENT_USER"
}

# Function to validate current state
validate_bluetooth_state() {
    local current_status=$(get_bluetooth_status)
    log_message "Current Bluetooth menu status: $current_status"
    
    if [ "$current_status" = "18" ]; then
        echo "✅ Bluetooth menu is currently visible in status bar"
    elif [ "$current_status" = "0" ]; then
        echo "❌ Bluetooth menu is currently hidden from status bar"
    else
        echo "âš ī¸  Bluetooth menu status is undefined or not set"
    fi
}

# Main execution
log_message "Starting Bluetooth menu management on $DEVICE_NAME"

# Check current status
validate_bluetooth_state

# Example: Show Bluetooth menu (uncomment to use)
# show_bluetooth_menu

# Example: Hide Bluetooth menu (uncomment to use)
# hide_bluetooth_menu

# Verify change
validate_bluetooth_state
log_message "Bluetooth menu management completed"

Interactive Bluetooth Menu Manager

#!/bin/bash

# Interactive Bluetooth menu manager
CURRENT_USER=$(ls -l /dev/console | awk '/ / { print $3 }')
CURRENT_USER_UID=$(id -u "$CURRENT_USER")

# Function to get current status
get_current_status() {
    local status=$(launchctl asuser $CURRENT_USER_UID sudo -iu "$CURRENT_USER" defaults -currentHost read com.apple.controlcenter.plist Bluetooth 2>/dev/null)
    case "$status" in
        18) echo "visible" ;;
        0) echo "hidden" ;;
        *) echo "undefined" ;;
    esac
}

# Function to toggle Bluetooth menu
toggle_bluetooth_menu() {
    local current_status=$(get_current_status)
    
    if [ "$current_status" = "visible" ]; then
        launchctl asuser $CURRENT_USER_UID sudo -iu "$CURRENT_USER" defaults -currentHost write com.apple.controlcenter.plist Bluetooth -int 0
        echo "Bluetooth menu has been hidden from status bar"
    else
        launchctl asuser $CURRENT_USER_UID sudo -iu "$CURRENT_USER" defaults -currentHost write com.apple.controlcenter.plist Bluetooth -int 18
        echo "Bluetooth menu has been shown in status bar"
    fi
}

# Display current status
echo "Roundfleet Bluetooth Menu Manager"
echo "==============================="
echo "Device: $(scutil --get ComputerName)"
echo "User: $CURRENT_USER"
echo "Current Bluetooth menu status: $(get_current_status)"
echo ""

# Provide options
echo "Options:"
echo "1. Show Bluetooth menu"
echo "2. Hide Bluetooth menu"
echo "3. Toggle Bluetooth menu"
echo "4. Check current status"
echo ""

read -p "Enter your choice (1-4): " choice

case $choice in
    1)
        launchctl asuser $CURRENT_USER_UID sudo -iu "$CURRENT_USER" defaults -currentHost write com.apple.controlcenter.plist Bluetooth -int 18
        echo "✅ Bluetooth menu is now visible in status bar"
        ;;
    2)
        launchctl asuser $CURRENT_USER_UID sudo -iu "$CURRENT_USER" defaults -currentHost write com.apple.controlcenter.plist Bluetooth -int 0
        echo "❌ Bluetooth menu is now hidden from status bar"
        ;;
    3)
        toggle_bluetooth_menu
        ;;
    4)
        echo "Current status: $(get_current_status)"
        ;;
    *)
        echo "Invalid choice. Please run the script again."
        ;;
esac

Advanced Control Center Management

Comprehensive Control Center Configuration

#!/bin/bash

# Comprehensive Control Center menu management
CURRENT_USER=$(ls -l /dev/console | awk '/ / { print $3 }')
CURRENT_USER_UID=$(id -u "$CURRENT_USER")

# Define Control Center menu items and their values
declare -A control_center_items=(
    ["Bluetooth"]="18"
    ["WiFi"]="18"
    ["AirDrop"]="18"
    ["Focus"]="18"
    ["StageManager"]="18"
    ["Display"]="18"
    ["Sound"]="18"
    ["NowPlaying"]="18"
    ["ScreenMirroring"]="18"
    ["Battery"]="18"
    ["Clock"]="18"
    ["UserSwitcher"]="18"
)

# Function to configure Control Center item
configure_control_center_item() {
    local item="$1"
    local value="$2"
    local action="$3"
    
    launchctl asuser $CURRENT_USER_UID sudo -iu "$CURRENT_USER" defaults -currentHost write com.apple.controlcenter.plist "$item" -int "$value"
    
    if [ "$value" = "18" ]; then
        echo "✅ $item: Enabled in status bar"
    else
        echo "❌ $item: Disabled in status bar"
    fi
}

# Function to show all Control Center items
show_all_items() {
    echo "Enabling all Control Center items..."
    for item in "${!control_center_items[@]}"; do
        configure_control_center_item "$item" "18"
    done
}

# Function to hide all Control Center items
hide_all_items() {
    echo "Disabling all Control Center items..."
    for item in "${!control_center_items[@]}"; do
        configure_control_center_item "$item" "0"
    done
}

# Function to show current status of all items
show_current_status() {
    echo "Current Control Center Status:"
    echo "=============================="
    
    for item in "${!control_center_items[@]}"; do
        local current_value=$(launchctl asuser $CURRENT_USER_UID sudo -iu "$CURRENT_USER" defaults -currentHost read com.apple.controlcenter.plist "$item" 2>/dev/null)
        
        case "$current_value" in
            18) echo "✅ $item: Visible" ;;
            0) echo "❌ $item: Hidden" ;;
            *) echo "âš ī¸  $item: Not configured" ;;
        esac
    done
}

# Function to configure essential items only
configure_essential_items() {
    echo "Configuring essential Control Center items..."
    
    # Essential items for most users
    essential_items=("Bluetooth" "WiFi" "Sound" "Battery" "Clock")
    
    # Hide all items first
    hide_all_items
    
    # Show only essential items
    for item in "${essential_items[@]}"; do
        configure_control_center_item "$item" "18"
    done
}

# Main menu
echo "Roundfleet Control Center Manager"
echo "==============================="
echo "Device: $(scutil --get ComputerName)"
echo "User: $CURRENT_USER"
echo ""

show_current_status

echo ""
echo "Management Options:"
echo "1. Show all Control Center items"
echo "2. Hide all Control Center items"
echo "3. Show essential items only"
echo "4. Show only Bluetooth menu"
echo "5. Hide only Bluetooth menu"
echo "6. Check current status"
echo ""

read -p "Enter your choice (1-6): " choice

case $choice in
    1) show_all_items ;;
    2) hide_all_items ;;
    3) configure_essential_items ;;
    4) configure_control_center_item "Bluetooth" "18" ;;
    5) configure_control_center_item "Bluetooth" "0" ;;
    6) show_current_status ;;
    *) echo "Invalid choice. Please run the script again." ;;
esac

echo ""
echo "Configuration completed. Changes may require logout/login to take full effect."

Enterprise Deployment Scripts

Bulk Bluetooth Menu Configuration

#!/bin/bash

# Bulk Bluetooth menu configuration for enterprise deployment
COMPANY_NAME="Roundfleet"
DEPLOYMENT_DATE=$(date +"%Y-%m-%d")
LOG_FILE="/var/log/roundfleet_bluetooth_deployment.log"
REPORT_FILE="/tmp/bluetooth_deployment_report_$(date +%Y%m%d_%H%M%S).txt"

# Configuration settings
BLUETOOTH_ENABLED=true  # Set to false to disable
FORCE_RESTART_CONTROL_CENTER=true

# Function to log messages
log_message() {
    echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" | tee -a "$LOG_FILE"
}

# Function to get device information
get_device_info() {
    local device_name=$(scutil --get ComputerName)
    local device_serial=$(system_profiler SPHardwareDataType | grep "Serial Number" | awk '{print $4}')
    local macos_version=$(sw_vers -productVersion)
    local current_user=$(ls -l /dev/console | awk '/ / { print $3 }')
    
    echo "Device: $device_name"
    echo "Serial: $device_serial"
    echo "macOS: $macos_version"
    echo "User: $current_user"
}

# Function to configure Bluetooth menu
configure_bluetooth_menu() {
    local enable_bluetooth="$1"
    local current_user=$(ls -l /dev/console | awk '/ / { print $3 }')
    local current_user_uid=$(id -u "$current_user")
    
    if [ "$enable_bluetooth" = true ]; then
        launchctl asuser $current_user_uid sudo -iu "$current_user" defaults -currentHost write com.apple.controlcenter.plist Bluetooth -int 18
        log_message "Bluetooth menu enabled for user $current_user"
        echo "✅ Bluetooth menu enabled"
    else
        launchctl asuser $current_user_uid sudo -iu "$current_user" defaults -currentHost write com.apple.controlcenter.plist Bluetooth -int 0
        log_message "Bluetooth menu disabled for user $current_user"
        echo "❌ Bluetooth menu disabled"
    fi
}

# Function to restart Control Center
restart_control_center() {
    local current_user=$(ls -l /dev/console | awk '/ / { print $3 }')
    local current_user_uid=$(id -u "$current_user")
    
    # Kill Control Center process to force reload
    launchctl asuser $current_user_uid sudo -iu "$current_user" killall ControlCenter 2>/dev/null
    log_message "Control Center restarted for user $current_user"
}

# Function to validate deployment
validate_deployment() {
    local current_user=$(ls -l /dev/console | awk '/ / { print $3 }')
    local current_user_uid=$(id -u "$current_user")
    local bluetooth_status=$(launchctl asuser $current_user_uid sudo -iu "$current_user" defaults -currentHost read com.apple.controlcenter.plist Bluetooth 2>/dev/null)
    
    if [ "$BLUETOOTH_ENABLED" = true ] && [ "$bluetooth_status" = "18" ]; then
        echo "✅ Deployment successful - Bluetooth menu is visible"
        log_message "Deployment validation successful"
        return 0
    elif [ "$BLUETOOTH_ENABLED" = false ] && [ "$bluetooth_status" = "0" ]; then
        echo "✅ Deployment successful - Bluetooth menu is hidden"
        log_message "Deployment validation successful"
        return 0
    else
        echo "❌ Deployment validation failed"
        log_message "Deployment validation failed - Expected: $BLUETOOTH_ENABLED, Got: $bluetooth_status"
        return 1
    fi
}

# Main deployment process
echo "$COMPANY_NAME Bluetooth Menu Deployment" > "$REPORT_FILE"
echo "=========================================" >> "$REPORT_FILE"
echo "Date: $DEPLOYMENT_DATE" >> "$REPORT_FILE"
echo "" >> "$REPORT_FILE"

get_device_info >> "$REPORT_FILE"
echo "" >> "$REPORT_FILE"

log_message "Starting Bluetooth menu deployment"
echo "Starting deployment..." >> "$REPORT_FILE"

# Configure Bluetooth menu
configure_bluetooth_menu $BLUETOOTH_ENABLED

# Restart Control Center if requested
if [ "$FORCE_RESTART_CONTROL_CENTER" = true ]; then
    restart_control_center
    sleep 2
fi

# Validate deployment
if validate_deployment; then
    echo "Status: SUCCESS" >> "$REPORT_FILE"
else
    echo "Status: FAILED" >> "$REPORT_FILE"
fi

log_message "Deployment completed"
echo "Deployment completed. Report saved to: $REPORT_FILE"
cat "$REPORT_FILE"

Remote Bluetooth Menu Management

#!/bin/bash

# Remote Bluetooth menu management with JSON reporting
CENTRAL_SERVER="your-roundfleet-server.com"
DEVICE_ID=$(system_profiler SPHardwareDataType | grep "Serial Number" | awk '{print $4}')
REPORT_FILE="/tmp/bluetooth_menu_report_${DEVICE_ID}.json"

# Function to create JSON report
create_json_report() {
    local device_name=$(scutil --get ComputerName)
    local device_user=$(ls -l /dev/console | awk '/ / { print $3 }')
    local device_user_uid=$(id -u "$device_user")
    local os_version=$(sw_vers -productVersion)
    local timestamp=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
    
    # Get current Bluetooth menu status
    local bluetooth_status=$(launchctl asuser $device_user_uid sudo -iu "$device_user" defaults -currentHost read com.apple.controlcenter.plist Bluetooth 2>/dev/null)
    
    cat > "$REPORT_FILE" << EOF
{
  "device_info": {
    "device_id": "$DEVICE_ID",
    "device_name": "$device_name",
    "user": "$device_user",
    "os_version": "$os_version",
    "timestamp": "$timestamp"
  },
  "bluetooth_menu": {
    "status": "$bluetooth_status",
    "visible": $([ "$bluetooth_status" = "18" ] && echo "true" || echo "false"),
    "configured": $([ -n "$bluetooth_status" ] && echo "true" || echo "false")
  },
  "control_center": {
    "items": {
EOF

    # Check other Control Center items
    local items=("WiFi" "AirDrop" "Focus" "Display" "Sound" "NowPlaying" "Battery" "Clock")
    local first_item=true
    
    for item in "${items[@]}"; do
        local item_status=$(launchctl asuser $device_user_uid sudo -iu "$device_user" defaults -currentHost read com.apple.controlcenter.plist "$item" 2>/dev/null)
        
        if [ "$first_item" = false ]; then
            echo "," >> "$REPORT_FILE"
        fi
        
        echo "      \"$item\": {" >> "$REPORT_FILE"
        echo "        \"status\": \"$item_status\"," >> "$REPORT_FILE"
        echo "        \"visible\": $([ "$item_status" = "18" ] && echo "true" || echo "false")" >> "$REPORT_FILE"
        echo "      }" >> "$REPORT_FILE"
        
        first_item=false
    done
    
    echo "" >> "$REPORT_FILE"
    echo "    }" >> "$REPORT_FILE"
    echo "  }" >> "$REPORT_FILE"
    echo "}" >> "$REPORT_FILE"
}

# Function to apply configuration from server
apply_server_config() {
    local config_url="https://$CENTRAL_SERVER/api/device-config/$DEVICE_ID"
    
    # Download configuration (example)
    # curl -s "$config_url" -o "/tmp/device_config.json"
    
    # For demonstration, we'll use a local example
    echo "Applying server configuration..."
    
    # Example: Enable Bluetooth menu
    local current_user=$(ls -l /dev/console | awk '/ / { print $3 }')
    local current_user_uid=$(id -u "$current_user")
    
    launchctl asuser $current_user_uid sudo -iu "$current_user" defaults -currentHost write com.apple.controlcenter.plist Bluetooth -int 18
    
    echo "Server configuration applied successfully"
}

# Main execution
echo "Roundfleet Remote Bluetooth Menu Management"
echo "========================================"
echo "Device ID: $DEVICE_ID"

# Create initial report
create_json_report

# Display current status
echo "Current Bluetooth menu status: $(grep -o '"visible": [^,]*' "$REPORT_FILE" | head -1 | cut -d' ' -f2)"

# Apply server configuration if needed
# apply_server_config

# Create final report
create_json_report

echo "Report generated: $REPORT_FILE"
echo "Device reporting completed"

# Optional: Send to central server
# curl -X POST -H "Content-Type: application/json" -d @"$REPORT_FILE" "https://$CENTRAL_SERVER/api/device-reports"

Best Practices for Status Bar Management

1. User Experience Considerations

  • Maintain consistent status bar layouts across all devices
  • Provide essential tools while avoiding clutter
  • Consider user workflow requirements

2. Deployment Strategy

  • Test configuration changes on a small group first
  • Document standard configurations for different user types
  • Provide rollback procedures

3. Change Management

  • Notify users of interface changes in advance
  • Provide training materials for new configurations
  • Monitor support requests after changes

4. Monitoring and Maintenance

  • Regular audits of status bar configurations
  • Automated compliance checking
  • User feedback collection

Troubleshooting Common Issues

Issue: Changes Not Taking Effect

# Force Control Center restart
killall ControlCenter
sleep 2

# Check if preferences are properly written
defaults -currentHost read com.apple.controlcenter.plist Bluetooth

Issue: Permission Denied

# Verify user context
current_user=$(ls -l /dev/console | awk '/ / { print $3 }')
echo "Current user: $current_user"

# Check user permissions
id "$current_user"

Issue: macOS Version Compatibility

# Check macOS version
macos_version=$(sw_vers -productVersion)
echo "macOS version: $macos_version"

# For macOS 12.0 and below, use different preference location
if [[ "$macos_version" < "12.0" ]]; then
    echo "Using legacy preferences location"
    # Use different defaults domain for older versions
fi

Issue: Preferences Not Persisting

# Force preferences synchronization
defaults -currentHost synchronize

# Check if preferences file exists
ls -la ~/Library/Preferences/ByHost/com.apple.controlcenter.*

Conclusion

Managing Bluetooth menu visibility in the status bar is a simple but effective way to standardize the user experience across your Mac fleet. These scripts provide:

  • Consistent interface: Standardized status bar layouts
  • Remote management: Centralized control over UI elements
  • User productivity: Quick access to essential controls
  • Enterprise compliance: Maintaining organizational standards

Regular implementation of these status bar management practices will help ensure a consistent and productive user experience across your entire Mac fleet.

For more advanced Control Center management, consider integrating these scripts with your existing device management and configuration tools.

Bluetooth Management on macOS

Control and manage Bluetooth settings across your Roundfleet devices using advanced command-line tools. This tutorial covers Bluetooth status monitoring, power state management, and enterprise-grade fleet control with comprehensive logging and security features.

Understanding macOS Bluetooth Management

macOS provides comprehensive Bluetooth control through several mechanisms:

  • defaults - Direct manipulation of Bluetooth preferences via plist files
  • bluetoothd - The core Bluetooth daemon that handles all Bluetooth operations
  • launchctl - Service management for starting/stopping Bluetooth services
  • blued - Legacy Bluetooth daemon name used in older macOS versions

The primary configuration file is located at /Library/Preferences/com.apple.Bluetooth with the ControllerPowerState key controlling the power state.

Basic Bluetooth Status Management

Check Bluetooth Status

#!/bin/bash

# Check current Bluetooth power state
check_bluetooth_status() {
    local status
    status=$(defaults read /Library/Preferences/com.apple.Bluetooth ControllerPowerState 2>/dev/null)
    
    if [[ "$status" == "1" ]]; then
        echo "Bluetooth is ON"
        return 0
    elif [[ "$status" == "0" ]]; then
        echo "Bluetooth is OFF"
        return 1
    else
        echo "Bluetooth status unknown or not configured"
        return 2
    fi
}

# Execute status check
check_bluetooth_status

Turn Bluetooth ON

#!/bin/bash

# Turn Bluetooth ON using defaults and daemon restart
turn_bluetooth_on() {
    echo "Turning Bluetooth ON..."
    
    # Set Bluetooth power state to ON
    sudo defaults write /Library/Preferences/com.apple.Bluetooth ControllerPowerState -int 1
    
    # Restart Bluetooth daemon (try both modern and legacy daemon names)
    if pgrep bluetoothd >/dev/null 2>&1; then
        sudo killall -HUP bluetoothd
        echo "Bluetooth daemon (bluetoothd) restarted"
    elif pgrep blued >/dev/null 2>&1; then
        sudo killall -HUP blued
        echo "Bluetooth daemon (blued) restarted"
    else
        echo "Warning: Bluetooth daemon not found"
    fi
    
    # Wait for changes to take effect
    sleep 3
    
    # Verify the change
    if check_bluetooth_status >/dev/null; then
        echo "✅ Bluetooth successfully turned ON"
        return 0
    else
        echo "❌ Failed to turn Bluetooth ON"
        return 1
    fi
}

# Helper function for status checking
check_bluetooth_status() {
    local status
    status=$(defaults read /Library/Preferences/com.apple.Bluetooth ControllerPowerState 2>/dev/null)
    [[ "$status" == "1" ]]
}

# Execute
turn_bluetooth_on

Turn Bluetooth OFF

#!/bin/bash

# Turn Bluetooth OFF using defaults and daemon restart
turn_bluetooth_off() {
    echo "Turning Bluetooth OFF..."
    
    # Set Bluetooth power state to OFF
    sudo defaults write /Library/Preferences/com.apple.Bluetooth ControllerPowerState -int 0
    
    # Restart Bluetooth daemon
    if pgrep bluetoothd >/dev/null 2>&1; then
        sudo killall -HUP bluetoothd
        echo "Bluetooth daemon (bluetoothd) restarted"
    elif pgrep blued >/dev/null 2>&1; then
        sudo killall -HUP blued
        echo "Bluetooth daemon (blued) restarted"
    else
        echo "Warning: Bluetooth daemon not found"
    fi
    
    # Wait for changes to take effect
    sleep 3
    
    # Verify the change
    if ! check_bluetooth_status >/dev/null; then
        echo "✅ Bluetooth successfully turned OFF"
        return 0
    else
        echo "❌ Failed to turn Bluetooth OFF"
        return 1
    fi
}

# Helper function for status checking
check_bluetooth_status() {
    local status
    status=$(defaults read /Library/Preferences/com.apple.Bluetooth ControllerPowerState 2>/dev/null)
    [[ "$status" == "1" ]]
}

# Execute
turn_bluetooth_off

Advanced Bluetooth Management with launchctl

Using launchctl for Service Management

#!/bin/bash

# Advanced Bluetooth control using launchctl service management
bluetooth_service_control() {
    local action="$1"  # on, off, restart, status
    local daemon_name
    
    # Determine the correct daemon name based on macOS version
    if launchctl list | grep -q "com.apple.bluetoothd"; then
        daemon_name="com.apple.bluetoothd"
    elif launchctl list | grep -q "com.apple.blued"; then
        daemon_name="com.apple.blued"
    else
        echo "❌ Bluetooth daemon not found in launchctl"
        return 1
    fi
    
    case "$action" in
        "on")
            echo "Enabling Bluetooth..."
            sudo defaults write /Library/Preferences/com.apple.Bluetooth ControllerPowerState -int 1
            sudo launchctl stop "$daemon_name"
            sleep 2
            sudo launchctl start "$daemon_name"
            sleep 3
            echo "✅ Bluetooth enabled using launchctl"
            ;;
        "off")
            echo "Disabling Bluetooth..."
            sudo defaults write /Library/Preferences/com.apple.Bluetooth ControllerPowerState -int 0
            sudo launchctl stop "$daemon_name"
            sleep 2
            sudo launchctl start "$daemon_name"
            sleep 3
            echo "✅ Bluetooth disabled using launchctl"
            ;;
        "restart")
            echo "Restarting Bluetooth service..."
            sudo launchctl stop "$daemon_name"
            sleep 2
            sudo launchctl start "$daemon_name"
            sleep 3
            echo "✅ Bluetooth service restarted"
            ;;
        "status")
            echo "Bluetooth daemon status: $daemon_name"
            if launchctl list | grep -q "$daemon_name"; then
                echo "✅ Bluetooth service is running"
                
                # Check power state
                local power_state
                power_state=$(defaults read /Library/Preferences/com.apple.Bluetooth ControllerPowerState 2>/dev/null)
                echo "Power state: $([[ "$power_state" == "1" ]] && echo "ON" || echo "OFF")"
            else
                echo "❌ Bluetooth service is not running"
            fi
            ;;
        *)
            echo "Usage: bluetooth_service_control {on|off|restart|status}"
            return 1
            ;;
    esac
}

# Examples
bluetooth_service_control "status"
# bluetooth_service_control "on"
# bluetooth_service_control "off"
# bluetooth_service_control "restart"

Enterprise Bluetooth Management System

#!/bin/bash

# Roundfleet Enterprise Bluetooth Management System
# Comprehensive Bluetooth control with logging, monitoring, and fleet management

# Configuration
LOG_FILE="/var/log/roundfleet_bluetooth.log"
CONFIG_FILE="/etc/roundfleet/bluetooth_config.conf"
BACKUP_DIR="/var/backups/roundfleet/bluetooth"
API_ENDPOINT="https://api.roundfleet.com/v1/bluetooth"

# Create directory structure
setup_directories() {
    mkdir -p "$(dirname "$LOG_FILE")" "$BACKUP_DIR" "$(dirname "$CONFIG_FILE")"
    touch "$LOG_FILE"
}

# Logging function
log_action() {
    echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" | tee -a "$LOG_FILE"
}

# Get detailed Bluetooth information
get_bluetooth_info() {
    local info_json="{"
    
    # Power state
    local power_state
    power_state=$(defaults read /Library/Preferences/com.apple.Bluetooth ControllerPowerState 2>/dev/null || echo "unknown")
    info_json+="\"power_state\": \"$power_state\","
    
    # Daemon status
    local daemon_running=false
    if pgrep bluetoothd >/dev/null 2>&1 || pgrep blued >/dev/null 2>&1; then
        daemon_running=true
    fi
    info_json+="\"daemon_running\": $daemon_running,"
    
    # macOS version
    local macos_version
    macos_version=$(sw_vers -productVersion)
    info_json+="\"macos_version\": \"$macos_version\","
    
    # System hardware
    local hardware_model
    hardware_model=$(system_profiler SPHardwareDataType | grep "Model Name" | awk -F': ' '{print $2}' | xargs)
    info_json+="\"hardware_model\": \"$hardware_model\","
    
    # Bluetooth controller info
    local bt_controller=""
    if system_profiler SPBluetoothDataType >/dev/null 2>&1; then
        bt_controller=$(system_profiler SPBluetoothDataType | grep -A5 "Apple Bluetooth Software" | grep "Version" | awk -F': ' '{print $2}' | xargs)
    fi
    info_json+="\"bluetooth_version\": \"$bt_controller\","
    
    # Timestamp
    info_json+="\"timestamp\": \"$(date -u +%Y-%m-%dT%H:%M:%SZ)\""
    info_json+="}"
    
    echo "$info_json"
}

# Backup current Bluetooth configuration
backup_bluetooth_config() {
    local backup_file="$BACKUP_DIR/bluetooth_backup_$(date +%Y%m%d_%H%M%S).plist"
    
    if [[ -f "/Library/Preferences/com.apple.Bluetooth.plist" ]]; then
        cp "/Library/Preferences/com.apple.Bluetooth.plist" "$backup_file"
        log_action "Bluetooth configuration backed up to: $backup_file"
        echo "$backup_file"
    else
        log_action "WARNING: Bluetooth preference file not found for backup"
        return 1
    fi
}

# Set Bluetooth state with comprehensive validation
set_bluetooth_state() {
    local desired_state="$1"  # "on" or "off"
    local force_restart="${2:-false}"
    
    # Validate input
    if [[ "$desired_state" != "on" && "$desired_state" != "off" ]]; then
        log_action "ERROR: Invalid state specified. Use 'on' or 'off'"
        return 1
    fi
    
    # Get current state
    local current_state
    current_state=$(defaults read /Library/Preferences/com.apple.Bluetooth ControllerPowerState 2>/dev/null)
    
    local target_value
    if [[ "$desired_state" == "on" ]]; then
        target_value=1
    else
        target_value=0
    fi
    
    # Check if change is needed
    if [[ "$current_state" == "$target_value" && "$force_restart" == "false" ]]; then
        log_action "Bluetooth already in desired state: $desired_state"
        return 0
    fi
    
    # Create backup before changes
    backup_bluetooth_config
    
    # Set new state
    log_action "Setting Bluetooth state to: $desired_state"
    sudo defaults write /Library/Preferences/com.apple.Bluetooth ControllerPowerState -int "$target_value"
    
    # Restart Bluetooth daemon
    restart_bluetooth_daemon
    
    # Wait for changes to propagate
    sleep 5
    
    # Verify the change
    local new_state
    new_state=$(defaults read /Library/Preferences/com.apple.Bluetooth ControllerPowerState 2>/dev/null)
    
    if [[ "$new_state" == "$target_value" ]]; then
        log_action "✅ Bluetooth successfully set to: $desired_state"
        return 0
    else
        log_action "❌ Failed to set Bluetooth to: $desired_state"
        return 1
    fi
}

# Restart Bluetooth daemon with error handling
restart_bluetooth_daemon() {
    log_action "Restarting Bluetooth daemon..."
    
    # Try modern bluetoothd first
    if pgrep bluetoothd >/dev/null 2>&1; then
        if sudo killall -HUP bluetoothd 2>/dev/null; then
            log_action "Bluetooth daemon (bluetoothd) restarted successfully"
            return 0
        else
            log_action "WARNING: Failed to restart bluetoothd with HUP signal"
        fi
    fi
    
    # Try legacy blued
    if pgrep blued >/dev/null 2>&1; then
        if sudo killall -HUP blued 2>/dev/null; then
            log_action "Bluetooth daemon (blued) restarted successfully"
            return 0
        else
            log_action "WARNING: Failed to restart blued with HUP signal"
        fi
    fi
    
    # Try launchctl approach
    local daemon_service=""
    if launchctl list | grep -q "com.apple.bluetoothd"; then
        daemon_service="com.apple.bluetoothd"
    elif launchctl list | grep -q "com.apple.blued"; then
        daemon_service="com.apple.blued"
    fi
    
    if [[ -n "$daemon_service" ]]; then
        log_action "Attempting launchctl restart for: $daemon_service"
        sudo launchctl stop "$daemon_service" 2>/dev/null
        sleep 2
        sudo launchctl start "$daemon_service" 2>/dev/null
        log_action "Bluetooth service restarted via launchctl"
        return 0
    fi
    
    log_action "ERROR: Could not restart Bluetooth daemon"
    return 1
}

# Monitor Bluetooth connectivity and paired devices
monitor_bluetooth_devices() {
    log_action "Starting Bluetooth device monitoring..."
    
    # Get current power state
    local power_state
    power_state=$(defaults read /Library/Preferences/com.apple.Bluetooth ControllerPowerState 2>/dev/null)
    
    if [[ "$power_state" != "1" ]]; then
        log_action "Bluetooth is OFF - no devices to monitor"
        return 0
    fi
    
    # Check for system_profiler availability
    if ! command -v system_profiler >/dev/null 2>&1; then
        log_action "WARNING: system_profiler not available for device monitoring"
        return 1
    fi
    
    # Get Bluetooth device information
    local bt_devices
    bt_devices=$(system_profiler SPBluetoothDataType 2>/dev/null | grep -A10 "Devices:" || echo "No devices found")
    
    log_action "Bluetooth devices status:"
    echo "$bt_devices" | while IFS= read -r line; do
        log_action "  $line"
    done
    
    # Count connected devices
    local connected_count
    connected_count=$(echo "$bt_devices" | grep -c "Connected: Yes" || echo "0")
    log_action "Total connected Bluetooth devices: $connected_count"
    
    return 0
}

# Generate comprehensive Bluetooth report
generate_bluetooth_report() {
    local report_file="/tmp/bluetooth_report_$(date +%Y%m%d_%H%M%S).json"
    
    log_action "Generating Bluetooth report: $report_file"
    
    {
        echo "{"
        echo "  \"report_type\": \"bluetooth_status\","
        echo "  \"timestamp\": \"$(date -u +%Y-%m-%dT%H:%M:%SZ)\","
        echo "  \"hostname\": \"$(hostname)\","
        echo "  \"device_info\": $(get_bluetooth_info),"
        
        # System information
        echo "  \"system_info\": {"
        echo "    \"macos_version\": \"$(sw_vers -productVersion)\","
        echo "    \"build_version\": \"$(sw_vers -buildVersion)\","
        echo "    \"hardware_uuid\": \"$(system_profiler SPHardwareDataType | grep 'Hardware UUID' | awk -F': ' '{print $2}' | xargs)\""
        echo "  },"
        
        # Bluetooth preferences
        echo "  \"bluetooth_preferences\": {"
        if [[ -f "/Library/Preferences/com.apple.Bluetooth.plist" ]]; then
            echo "    \"preferences_file_exists\": true,"
            echo "    \"file_size\": $(stat -f%z "/Library/Preferences/com.apple.Bluetooth.plist"),"
            echo "    \"last_modified\": \"$(stat -f%Sm -t%Y-%m-%dT%H:%M:%SZ "/Library/Preferences/com.apple.Bluetooth.plist")\""
        else
            echo "    \"preferences_file_exists\": false"
        fi
        echo "  }"
        echo "}"
    } > "$report_file"
    
    log_action "Bluetooth report generated successfully"
    echo "$report_file"
}

# Security compliance check
check_bluetooth_security() {
    log_action "Performing Bluetooth security compliance check..."
    
    local security_issues=()
    
    # Check if Bluetooth is enabled when it should be disabled
    if [[ -f "$CONFIG_FILE" ]] && grep -q "BLUETOOTH_POLICY=disabled" "$CONFIG_FILE"; then
        local current_state
        current_state=$(defaults read /Library/Preferences/com.apple.Bluetooth ControllerPowerState 2>/dev/null)
        
        if [[ "$current_state" == "1" ]]; then
            security_issues+=("Bluetooth enabled despite policy requiring disabled state")
        fi
    fi
    
    # Check for Bluetooth discoverability (if system_profiler available)
    if command -v system_profiler >/dev/null 2>&1; then
        local discoverable
        discoverable=$(system_profiler SPBluetoothDataType 2>/dev/null | grep -i "discoverable" || echo "unknown")
        
        if echo "$discoverable" | grep -qi "yes"; then
            security_issues+=("Bluetooth is discoverable - potential security risk")
        fi
    fi
    
    # Report security status
    if [[ ${#security_issues[@]} -eq 0 ]]; then
        log_action "✅ Bluetooth security compliance check passed"
        return 0
    else
        log_action "âš ī¸  Bluetooth security issues found:"
        for issue in "${security_issues[@]}"; do
            log_action "  - $issue"
        done
        return 1
    fi
}

# Main management function
main() {
    local action="${1:-status}"
    local parameter="$2"
    
    setup_directories
    log_action "Roundfleet Bluetooth Management started with action: $action"
    
    case "$action" in
        "on"|"enable")
            set_bluetooth_state "on"
            ;;
        "off"|"disable")
            set_bluetooth_state "off"
            ;;
        "restart"|"reload")
            restart_bluetooth_daemon
            ;;
        "status"|"info")
            get_bluetooth_info | python3 -m json.tool 2>/dev/null || get_bluetooth_info
            ;;
        "monitor")
            monitor_bluetooth_devices
            ;;
        "report")
            generate_bluetooth_report
            ;;
        "security")
            check_bluetooth_security
            ;;
        "backup")
            backup_bluetooth_config
            ;;
        "force-on")
            set_bluetooth_state "on" true
            ;;
        "force-off")
            set_bluetooth_state "off" true
            ;;
        *)
            echo "Usage: $0 {on|off|restart|status|monitor|report|security|backup|force-on|force-off}"
            echo ""
            echo "Commands:"
            echo "  on/enable    - Turn Bluetooth ON"
            echo "  off/disable  - Turn Bluetooth OFF"
            echo "  restart      - Restart Bluetooth daemon"
            echo "  status       - Show detailed Bluetooth status"
            echo "  monitor      - Monitor connected devices"
            echo "  report       - Generate comprehensive report"
            echo "  security     - Run security compliance check"
            echo "  backup       - Backup current configuration"
            echo "  force-on     - Force Bluetooth ON (restart daemon)"
            echo "  force-off    - Force Bluetooth OFF (restart daemon)"
            exit 1
            ;;
    esac
    
    log_action "Roundfleet Bluetooth Management completed with action: $action"
}

# Execute main function with all arguments
main "$@"

Quick Management Functions

Simple Status Check

#!/bin/bash

# Quick Bluetooth status check with color output
bluetooth_quick_status() {
    local status
    status=$(defaults read /Library/Preferences/com.apple.Bluetooth ControllerPowerState 2>/dev/null)
    
    case "$status" in
        "1")
            echo "đŸ”ĩ Bluetooth: ON"
            ;;
        "0")
            echo "âšĒ Bluetooth: OFF"
            ;;
        *)
            echo "❓ Bluetooth: UNKNOWN"
            ;;
    esac
}

bluetooth_quick_status

Toggle Bluetooth State

#!/bin/bash

# Toggle Bluetooth between ON and OFF states
toggle_bluetooth() {
    local current_state
    current_state=$(defaults read /Library/Preferences/com.apple.Bluetooth ControllerPowerState 2>/dev/null)
    
    if [[ "$current_state" == "1" ]]; then
        echo "Bluetooth is ON, turning OFF..."
        sudo defaults write /Library/Preferences/com.apple.Bluetooth ControllerPowerState -int 0
        sudo killall -HUP bluetoothd 2>/dev/null || sudo killall -HUP blued 2>/dev/null
        echo "✅ Bluetooth turned OFF"
    else
        echo "Bluetooth is OFF, turning ON..."
        sudo defaults write /Library/Preferences/com.apple.Bluetooth ControllerPowerState -int 1
        sudo killall -HUP bluetoothd 2>/dev/null || sudo killall -HUP blued 2>/dev/null
        echo "✅ Bluetooth turned ON"
    fi
}

toggle_bluetooth

Configuration Templates

Bluetooth Policy Configuration

# /etc/roundfleet/bluetooth_config.conf
# Roundfleet Bluetooth Management Configuration

# Policy settings
BLUETOOTH_POLICY="enabled"  # enabled, disabled, user_controlled
AUTO_DISABLE_ON_IDLE="false"
IDLE_TIMEOUT_MINUTES="30"

# Security settings
ALLOW_DISCOVERABLE="false"
REQUIRE_PAIRING_CONFIRMATION="true"
LOG_DEVICE_CONNECTIONS="true"

# Monitoring settings
MONITOR_INTERVAL_SECONDS="300"
ALERT_ON_NEW_DEVICES="true"
COMPLIANCE_CHECK_ENABLED="true"

# Backup settings
AUTO_BACKUP_ENABLED="true"
BACKUP_RETENTION_DAYS="30"

Troubleshooting Common Issues

Bluetooth Daemon Not Responding

#!/bin/bash

# Troubleshoot and fix Bluetooth daemon issues
fix_bluetooth_daemon() {
    echo "Diagnosing Bluetooth daemon issues..."
    
    # Check if daemon is running
    if ! pgrep bluetoothd >/dev/null 2>&1 && ! pgrep blued >/dev/null 2>&1; then
        echo "❌ No Bluetooth daemon found running"
        
        # Try to start via launchctl
        if launchctl list | grep -q "com.apple.bluetoothd"; then
            echo "Starting bluetoothd via launchctl..."
            sudo launchctl start com.apple.bluetoothd
        elif launchctl list | grep -q "com.apple.blued"; then
            echo "Starting blued via launchctl..."
            sudo launchctl start com.apple.blued
        else
            echo "❌ Bluetooth service not found in launchctl"
            return 1
        fi
    fi
    
    # Force restart if still having issues
    echo "Force restarting Bluetooth system..."
    sudo pkill -f bluetooth
    sleep 3
    
    # Restart via launchctl
    for service in "com.apple.bluetoothd" "com.apple.blued"; do
        if launchctl list | grep -q "$service"; then
            sudo launchctl stop "$service" 2>/dev/null
            sleep 2
            sudo launchctl start "$service" 2>/dev/null
            echo "Restarted service: $service"
        fi
    done
    
    # Verify recovery
    sleep 5
    if pgrep bluetoothd >/dev/null 2>&1 || pgrep blued >/dev/null 2>&1; then
        echo "✅ Bluetooth daemon recovery successful"
        return 0
    else
        echo "❌ Bluetooth daemon recovery failed"
        return 1
    fi
}

fix_bluetooth_daemon

Reset Bluetooth Configuration

#!/bin/bash

# Reset Bluetooth to factory defaults
reset_bluetooth_config() {
    echo "âš ī¸  Resetting Bluetooth configuration to defaults..."
    
    # Create backup
    if [[ -f "/Library/Preferences/com.apple.Bluetooth.plist" ]]; then
        cp "/Library/Preferences/com.apple.Bluetooth.plist" "/tmp/bluetooth_backup_$(date +%s).plist"
        echo "Backup created in /tmp/"
    fi
    
    # Stop Bluetooth services
    sudo launchctl stop com.apple.bluetoothd 2>/dev/null
    sudo launchctl stop com.apple.blued 2>/dev/null
    
    # Remove configuration files
    sudo rm -f "/Library/Preferences/com.apple.Bluetooth.plist"
    sudo rm -f "/Library/Preferences/ByHost/com.apple.Bluetooth.*.plist"
    
    # Restart services
    sudo launchctl start com.apple.bluetoothd 2>/dev/null
    sudo launchctl start com.apple.blued 2>/dev/null
    
    # Set default state
    sleep 3
    sudo defaults write /Library/Preferences/com.apple.Bluetooth ControllerPowerState -int 1
    sudo killall -HUP bluetoothd 2>/dev/null || sudo killall -HUP blued 2>/dev/null
    
    echo "✅ Bluetooth configuration reset completed"
}

# Uncomment to execute
# reset_bluetooth_config

Important Technical Notes

Daemon Management

  • bluetoothd: Modern Bluetooth daemon (macOS 10.10+)
  • blued: Legacy Bluetooth daemon (older macOS versions)
  • killall -HUP: Sends hangup signal to restart daemon gracefully
  • launchctl: Preferred method for service management

Configuration Details

  • File Location: /Library/Preferences/com.apple.Bluetooth
  • Power State Key: ControllerPowerState
  • Values: 1 (ON), 0 (OFF)
  • Persistence: Changes persist across reboots

Security Considerations

  1. Administrative Privileges: All Bluetooth modifications require sudo
  2. Daemon Restart: Changes only take effect after daemon restart
  3. User Impact: Turning off Bluetooth disconnects all paired devices
  4. Policy Compliance: Monitor for unauthorized Bluetooth changes

Best Practices

  1. Always backup configurations before making changes
  2. Test daemon restart methods for your macOS version
  3. Monitor for delays - daemon restart can take several seconds
  4. Implement logging for audit trails and troubleshooting
  5. Use launchctl for more reliable service management
  6. Validate changes after applying modifications
  7. Consider user impact when disabling Bluetooth remotely
  8. Test scripts thoroughly before fleet deployment

Remember to validate all scripts on test devices before deploying across your Roundfleet environment, and be aware that Bluetooth changes may take a few minutes to fully propagate through the system.

Battery Management on macOS

Monitor and manage battery health, performance, and lifecycle across your Roundfleet devices using advanced battery monitoring tools and enterprise battery management systems. This tutorial covers battery health monitoring, power optimization, compliance tracking, and enterprise battery lifecycle management.

Understanding macOS Battery Management

macOS provides several command-line tools for battery management and monitoring:

  • pmset - Power management settings and battery status monitoring
  • system_profiler - Comprehensive system and battery information
  • ioreg - I/O Registry information including battery details
  • Battery Health Management - macOS built-in battery optimization
  • Low Power Mode - System-level power conservation

Basic Battery Operations

View Battery Status

#!/bin/bash

# Basic battery status
pmset -g batt

echo "Battery status retrieved successfully"

Enhanced Battery Information

#!/bin/bash

# Comprehensive battery information with detailed analysis
get_comprehensive_battery_info() {
    echo "=== Comprehensive Battery Analysis ==="
    
    # Basic battery status
    echo "Battery Status Overview:"
    pmset -g batt
    
    echo -e "\nDetailed Battery Health:"
    system_profiler SPPowerDataType
    
    echo -e "\nPower Management Settings:"
    pmset -g
    
    echo -e "\nBattery Registry Information:"
    ioreg -n AppleSmartBattery -r
    
    echo -e "\nThermal State:"
    pmset -g therm
    
    echo -e "\nPower Source Details:"
    pmset -g ps
}

# Execute comprehensive analysis
get_comprehensive_battery_info

Battery Management Categories

Battery Device Classifications

#!/bin/bash

# Enterprise battery management categories for monitoring and policy enforcement
declare -A BATTERY_DEVICE_CATEGORIES=(
    ["executive_mobile"]="Executive MacBooks requiring maximum uptime and reliability"
    ["creative_workstation"]="High-performance MacBooks for creative professionals with intensive usage"
    ["developer_laptop"]="Development MacBooks with consistent high CPU usage and long sessions"
    ["field_service"]="Field service MacBooks requiring extended battery life and durability"
    ["education_fleet"]="Educational MacBooks with shared usage patterns and budget constraints"
    ["conference_room"]="Meeting room MacBooks for presentations and video conferencing"
    ["backup_devices"]="Backup and loaner devices with infrequent usage patterns"
    ["legacy_systems"]="Older MacBooks requiring specialized battery management"
    ["testing_lab"]="Testing and QA devices with variable usage patterns"
    ["kiosk_display"]="Kiosk MacBooks with continuous operation requirements"
)

# Battery health thresholds
declare -A HEALTH_THRESHOLDS=(
    ["executive_mobile"]="excellent:90,good:80,warning:70,critical:60"
    ["creative_workstation"]="excellent:85,good:75,warning:65,critical:55"
    ["developer_laptop"]="excellent:85,good:75,warning:65,critical:55"
    ["field_service"]="excellent:95,good:85,warning:75,critical:65"
    ["education_fleet"]="excellent:80,good:70,warning:60,critical:50"
    ["conference_room"]="excellent:85,good:75,warning:65,critical:55"
    ["backup_devices"]="excellent:75,good:65,warning:55,critical:45"
    ["legacy_systems"]="excellent:70,good:60,warning:50,critical:40"
    ["testing_lab"]="excellent:80,good:70,warning:60,critical:50"
    ["kiosk_display"]="excellent:90,good:80,warning:70,critical:60"
)

# Usage pattern classifications
declare -A USAGE_PATTERNS=(
    ["executive_mobile"]="intensive_daily"
    ["creative_workstation"]="heavy_continuous"
    ["developer_laptop"]="consistent_high"
    ["field_service"]="extended_mobile"
    ["education_fleet"]="shared_moderate"
    ["conference_room"]="intermittent_plugged"
    ["backup_devices"]="minimal_occasional"
    ["legacy_systems"]="light_maintenance"
    ["testing_lab"]="variable_testing"
    ["kiosk_display"]="continuous_plugged"
)

print_battery_categories() {
    echo "=== Battery Management Categories ==="
    for category in "${!BATTERY_DEVICE_CATEGORIES[@]}"; do
        echo "Category: $category"
        echo "  Description: ${BATTERY_DEVICE_CATEGORIES[$category]}"
        echo "  Health Thresholds: ${HEALTH_THRESHOLDS[$category]}"
        echo "  Usage Pattern: ${USAGE_PATTERNS[$category]}"
        echo ""
    done
}

# Display available categories
print_battery_categories

Battery Management Policies

Power Management Policy Engine

#!/bin/bash

# Battery management policies for different organizational requirements
declare -A BATTERY_POLICIES=(
    ["maximum_performance"]="Performance-first policy with minimal power restrictions"
    ["balanced_efficiency"]="Balanced performance and battery life optimization"
    ["extended_battery_life"]="Maximum battery life with performance optimization"
    ["enterprise_standard"]="Standard enterprise battery management with monitoring"
    ["high_security_mobile"]="Security-focused mobile battery management"
    ["creative_professional"]="Optimized for creative workflows with high power demands"
    ["field_operations"]="Extended operation for field service and remote work"
    ["compliance_strict"]="Strict compliance with battery health and lifecycle tracking"
)

# Policy configurations
get_battery_policy() {
    local policy_type="$1"
    
    case "$policy_type" in
        "maximum_performance")
            cat << EOF
{
    "power_mode": "high_performance",
    "battery_health_management": false,
    "low_power_mode_threshold": 5,
    "sleep_settings": {
        "display_sleep": 30,
        "system_sleep": 60,
        "disk_sleep": 10
    },
    "processor_performance": "maximum",
    "graphics_switching": "high_performance_gpu",
    "background_app_refresh": true,
    "location_services": "full",
    "notification_optimization": false,
    "thermal_management": "performance_first",
    "charging_optimization": false,
    "battery_monitoring": "basic",
    "compliance_tracking": false,
    "lifecycle_management": false
}
EOF
            ;;
        "extended_battery_life")
            cat << EOF
{
    "power_mode": "low_power_extended",
    "battery_health_management": true,
    "low_power_mode_threshold": 20,
    "sleep_settings": {
        "display_sleep": 5,
        "system_sleep": 10,
        "disk_sleep": 5
    },
    "processor_performance": "efficient",
    "graphics_switching": "integrated_gpu_only",
    "background_app_refresh": false,
    "location_services": "essential_only",
    "notification_optimization": true,
    "thermal_management": "battery_first",
    "charging_optimization": true,
    "optimized_charging": true,
    "battery_monitoring": "comprehensive",
    "compliance_tracking": true,
    "lifecycle_management": true,
    "usage_analytics": true
}
EOF
            ;;
        "enterprise_standard")
            cat << EOF
{
    "power_mode": "balanced",
    "battery_health_management": true,
    "low_power_mode_threshold": 15,
    "sleep_settings": {
        "display_sleep": 15,
        "system_sleep": 30,
        "disk_sleep": 10
    },
    "processor_performance": "balanced",
    "graphics_switching": "automatic",
    "background_app_refresh": true,
    "location_services": "standard",
    "notification_optimization": true,
    "thermal_management": "balanced",
    "charging_optimization": true,
    "optimized_charging": true,
    "battery_monitoring": "enterprise",
    "compliance_tracking": true,
    "lifecycle_management": true,
    "usage_analytics": true,
    "health_alerting": true,
    "fleet_reporting": true,
    "maintenance_scheduling": true
}
EOF
            ;;
        "field_operations")
            cat << EOF
{
    "power_mode": "extended_field",
    "battery_health_management": true,
    "low_power_mode_threshold": 25,
    "sleep_settings": {
        "display_sleep": 3,
        "system_sleep": 5,
        "disk_sleep": 3
    },
    "processor_performance": "efficient_high",
    "graphics_switching": "integrated_preferred",
    "background_app_refresh": "selective",
    "location_services": "gps_optimized",
    "notification_optimization": true,
    "thermal_management": "conservative",
    "charging_optimization": true,
    "optimized_charging": true,
    "battery_monitoring": "field_focused",
    "compliance_tracking": true,
    "lifecycle_management": true,
    "usage_analytics": true,
    "field_reporting": true,
    "emergency_mode": true,
    "offline_capability": true
}
EOF
            ;;
        *)
            echo "Unknown battery policy: $policy_type"
            return 1
            ;;
    esac
}

# Apply battery policy
apply_battery_policy() {
    local policy="$1"
    local config_file="/tmp/battery_policy.json"
    
    echo "Applying battery policy: $policy"
    
    get_battery_policy "$policy" > "$config_file"
    
    if [[ ! -f "$config_file" ]]; then
        echo "❌ Failed to generate policy configuration"
        return 1
    fi
    
    echo "✅ Battery policy applied successfully"
    echo "Configuration: $config_file"
    
    # Display key policy settings
    echo "=== Policy Summary ==="
    echo "Power Mode: $(jq -r '.power_mode' "$config_file")"
    echo "Battery Health Management: $(jq -r '.battery_health_management' "$config_file")"
    echo "Low Power Threshold: $(jq -r '.low_power_mode_threshold' "$config_file")%"
    echo "Processor Performance: $(jq -r '.processor_performance' "$config_file")"
    echo "Charging Optimization: $(jq -r '.charging_optimization' "$config_file")"
    
    # Apply actual power management settings
    apply_power_settings "$config_file"
    
    return 0
}

# Apply power management settings
apply_power_settings() {
    local config_file="$1"
    
    echo "Applying power management settings..."
    
    # Extract settings from JSON
    local display_sleep
    display_sleep=$(jq -r '.sleep_settings.display_sleep' "$config_file")
    local system_sleep
    system_sleep=$(jq -r '.sleep_settings.system_sleep' "$config_file")
    local disk_sleep
    disk_sleep=$(jq -r '.sleep_settings.disk_sleep' "$config_file")
    
    # Apply sleep settings
    sudo pmset -c displaysleep "$display_sleep" || echo "Warning: Could not set display sleep"
    sudo pmset -c sleep "$system_sleep" || echo "Warning: Could not set system sleep"
    sudo pmset -c disksleep "$disk_sleep" || echo "Warning: Could not set disk sleep"
    
    # Apply battery-specific settings
    sudo pmset -b displaysleep $((display_sleep / 2)) || echo "Warning: Could not set battery display sleep"
    sudo pmset -b sleep $((system_sleep / 2)) || echo "Warning: Could not set battery system sleep"
    
    echo "✅ Power settings applied successfully"
}

Advanced Battery Monitoring

Battery Health Analytics

#!/bin/bash

# Comprehensive battery health monitoring and analytics
monitor_battery_health() {
    local device_category="$1"
    local monitoring_profile="${2:-standard}"
    local health_report="/tmp/battery_health_$(date +%Y%m%d_%H%M%S).json"
    
    echo "=== Battery Health Monitoring ==="
    echo "Device Category: $device_category"
    echo "Monitoring Profile: $monitoring_profile"
    
    # Initialize health report
    cat > "$health_report" << EOF
{
    "device_category": "$device_category",
    "monitoring_profile": "$monitoring_profile",
    "scan_timestamp": "$(date -Iseconds)",
    "hostname": "$(hostname)",
    "battery_analysis": {}
}
EOF
    
    # Extract battery information
    echo "Collecting battery data..."
    local battery_info
    battery_info=$(system_profiler SPPowerDataType)
    
    # Parse key battery metrics
    local cycle_count
    cycle_count=$(echo "$battery_info" | grep "Cycle Count:" | awk -F': ' '{print $2}' | tr -d ' ')
    
    local condition
    condition=$(echo "$battery_info" | grep "Condition:" | awk -F': ' '{print $2}' | tr -d ' ')
    
    local max_capacity
    max_capacity=$(echo "$battery_info" | grep "Maximum Capacity:" | awk -F': ' '{print $2}' | tr -d ' %')
    
    local state_of_charge
    state_of_charge=$(echo "$battery_info" | grep "State of Charge" | awk -F': ' '{print $2}' | tr -d ' %')
    
    local charging_status
    charging_status=$(pmset -g batt | grep -o "charging\|discharging\|charged" | head -1)
    
    local time_remaining
    time_remaining=$(pmset -g batt | grep -o "[0-9][0-9]*:[0-9][0-9]* remaining" | awk '{print $1}')
    
    local power_source
    power_source=$(pmset -g batt | grep "Now drawing from" | awk -F"'" '{print $2}')
    
    # Advanced battery analytics
    echo "Performing advanced analytics..."
    
    # Calculate battery health score
    local health_score=100
    
    # Cycle count impact
    if [[ $cycle_count -gt 1000 ]]; then
        ((health_score -= 20))
    elif [[ $cycle_count -gt 500 ]]; then
        ((health_score -= 10))
    fi
    
    # Capacity impact
    if [[ $max_capacity -lt 80 ]]; then
        ((health_score -= 25))
    elif [[ $max_capacity -lt 90 ]]; then
        ((health_score -= 15))
    fi
    
    # Condition impact
    if [[ "$condition" == "Service Recommended" ]]; then
        ((health_score -= 30))
    elif [[ "$condition" == "Replace Soon" ]]; then
        ((health_score -= 50))
    elif [[ "$condition" == "Replace Now" ]]; then
        ((health_score -= 70))
    fi
    
    # Determine health status
    local health_status="excellent"
    if [[ $health_score -lt 60 ]]; then
        health_status="critical"
    elif [[ $health_score -lt 70 ]]; then
        health_status="poor"
    elif [[ $health_score -lt 80 ]]; then
        health_status="warning"
    elif [[ $health_score -lt 90 ]]; then
        health_status="good"
    fi
    
    # Temperature monitoring
    local temperature_celsius="unknown"
    if command -v powermetrics &>/dev/null; then
        temperature_celsius=$(sudo powermetrics -n 1 -s battery | grep "Temperature:" | awk '{print $2}' | tr -d '°C' 2>/dev/null || echo "unknown")
    fi
    
    # Update health report with collected data
    jq --argjson cycle_count "${cycle_count:-0}" \
       --arg condition "$condition" \
       --argjson max_capacity "${max_capacity:-0}" \
       --argjson state_of_charge "${state_of_charge:-0}" \
       --arg charging_status "$charging_status" \
       --arg time_remaining "$time_remaining" \
       --arg power_source "$power_source" \
       --argjson health_score "$health_score" \
       --arg health_status "$health_status" \
       --arg temperature "$temperature_celsius" \
       '.battery_analysis = {
          "cycle_count": $cycle_count,
          "condition": $condition,
          "maximum_capacity_percent": $max_capacity,
          "current_charge_percent": $state_of_charge,
          "charging_status": $charging_status,
          "time_remaining": $time_remaining,
          "power_source": $power_source,
          "health_score": $health_score,
          "health_status": $health_status,
          "temperature_celsius": $temperature
        }' "$health_report" > "${health_report}.tmp" && mv "${health_report}.tmp" "$health_report"
    
    # Generate recommendations
    local recommendations=()
    
    if [[ $cycle_count -gt 800 ]]; then
        recommendations+=("Consider battery replacement planning")
    fi
    
    if [[ $max_capacity -lt 85 ]]; then
        recommendations+=("Monitor battery capacity degradation")
    fi
    
    if [[ "$condition" != "Normal" ]]; then
        recommendations+=("Schedule battery service appointment")
    fi
    
    if [[ $state_of_charge -lt 20 && "$charging_status" == "discharging" ]]; then
        recommendations+=("Connect to power source immediately")
    fi
    
    # Add recommendations to report
    jq --argjson recommendations "$(printf '%s\n' "${recommendations[@]}" | jq -R . | jq -s .)" \
       '.recommendations = $recommendations' \
       "$health_report" > "${health_report}.tmp" && mv "${health_report}.tmp" "$health_report"
    
    # Display results
    echo ""
    echo "Battery Health Analysis Results:"
    echo "  Overall Health Score: $health_score/100 ($health_status)"
    echo "  Cycle Count: ${cycle_count:-0}"
    echo "  Condition: $condition"
    echo "  Maximum Capacity: ${max_capacity:-0}%"
    echo "  Current Charge: ${state_of_charge:-0}%"
    echo "  Charging Status: $charging_status"
    echo "  Time Remaining: ${time_remaining:-N/A}"
    echo "  Power Source: $power_source"
    echo "  Temperature: ${temperature_celsius}°C"
    
    if [[ ${#recommendations[@]} -gt 0 ]]; then
        echo "  Recommendations:"
        for rec in "${recommendations[@]}"; do
            echo "    - $rec"
        done
    else
        echo "  ✅ No immediate action required"
    fi
    
    echo "  Health Report: $health_report"
    
    # Log health monitoring
    audit_log "Battery health monitoring completed: $device_category (Score: $health_score/100, Status: $health_status)"
    
    return 0
}

Enterprise Battery Management System

#!/bin/bash

# Roundfleet Enterprise Battery Management System
# Comprehensive battery monitoring, optimization, and lifecycle management

# Configuration
CONFIG_DIR="/etc/roundfleet/battery"
LOG_FILE="/var/log/roundfleet_battery_management.log"
DATA_DIR="/var/data/roundfleet/battery"
REPORTS_DIR="/var/reports/roundfleet/battery"
AUDIT_LOG="/var/log/roundfleet_battery_audit.log"
BACKUP_DIR="/var/backups/roundfleet/battery"

# Create required directories
create_directories() {
    local directories=("$CONFIG_DIR" "$DATA_DIR" "$REPORTS_DIR" "$BACKUP_DIR")
    
    for dir in "${directories[@]}"; do
        if [[ ! -d "$dir" ]]; then
            sudo mkdir -p "$dir"
            sudo chmod 755 "$dir"
        fi
    done
}

# Logging functions
log_action() {
    echo "$(date '+%Y-%m-%d %H:%M:%S') [INFO] $1" | tee -a "$LOG_FILE"
}

log_error() {
    echo "$(date '+%Y-%m-%d %H:%M:%S') [ERROR] $1" | tee -a "$LOG_FILE" >&2
}

audit_log() {
    echo "$(date '+%Y-%m-%d %H:%M:%S') [AUDIT] $1" | tee -a "$AUDIT_LOG"
}

# Battery database management
initialize_battery_database() {
    local db_file="$DATA_DIR/battery_fleet_database.json"
    
    if [[ ! -f "$db_file" ]]; then
        cat > "$db_file" << EOF
{
    "version": "1.0",
    "created": "$(date -Iseconds)",
    "fleet_devices": {},
    "battery_policies": {},
    "health_monitoring": {},
    "performance_metrics": {},
    "maintenance_schedule": {},
    "compliance_tracking": {}
}
EOF
        log_action "Battery fleet database initialized: $db_file"
    fi
}

# Fleet-wide battery discovery
discover_battery_fleet() {
    local discovery_file="$DATA_DIR/battery_fleet_discovery_$(date +%Y%m%d_%H%M%S).json"
    
    log_action "Starting fleet-wide battery discovery"
    
    echo "=== Battery Fleet Discovery ==="
    
    # Device identification
    local device_serial
    device_serial=$(system_profiler SPHardwareDataType | grep "Serial Number" | awk -F': ' '{print $2}' | tr -d ' ')
    
    local device_model
    device_model=$(system_profiler SPHardwareDataType | grep "Model Name" | awk -F': ' '{print $2}' | tr -d ' ')
    
    local device_identifier
    device_identifier=$(system_profiler SPHardwareDataType | grep "Model Identifier" | awk -F': ' '{print $2}' | tr -d ' ')
    
    # Battery hardware information
    echo "Analyzing battery hardware..."
    local battery_hardware
    battery_hardware=$(ioreg -n AppleSmartBattery -r | grep -E "(MaxCapacity|DesignCapacity|CycleCount|Temperature|Voltage|Current)")
    
    local max_capacity_mah
    max_capacity_mah=$(echo "$battery_hardware" | grep "MaxCapacity" | awk -F'= ' '{print $2}' | tr -d ' ')
    
    local design_capacity_mah
    design_capacity_mah=$(echo "$battery_hardware" | grep "DesignCapacity" | awk -F'= ' '{print $2}' | tr -d ' ')
    
    local current_voltage
    current_voltage=$(echo "$battery_hardware" | grep "Voltage" | awk -F'= ' '{print $2}' | tr -d ' ')
    
    local current_amperage
    current_amperage=$(echo "$battery_hardware" | grep "Current" | awk -F'= ' '{print $2}' | tr -d ' ')
    
    # Power management configuration
    echo "Examining power management configuration..."
    local power_config
    power_config=$(pmset -g custom)
    
    # Battery usage patterns
    echo "Analyzing usage patterns..."
    local usage_stats=()
    
    # Check if battery health management is enabled
    local health_mgmt_enabled
    health_mgmt_enabled=$(pmset -g | grep "Battery Health Management" | awk '{print $4}' || echo "unknown")
    
    # Check optimized battery charging
    local optimized_charging
    optimized_charging=$(pmset -g | grep "Optimized Battery Charging" | awk '{print $4}' || echo "unknown")
    
    # Generate discovery report
    cat > "$discovery_file" << EOF
{
    "discovery_timestamp": "$(date -Iseconds)",
    "device_info": {
        "hostname": "$(hostname)",
        "serial_number": "$device_serial",
        "model_name": "$device_model",
        "model_identifier": "$device_identifier",
        "os_version": "$(sw_vers -productVersion)"
    },
    "battery_hardware": {
        "max_capacity_mah": ${max_capacity_mah:-0},
        "design_capacity_mah": ${design_capacity_mah:-0},
        "current_voltage": ${current_voltage:-0},
        "current_amperage": ${current_amperage:-0}
    },
    "power_management": {
        "health_management_enabled": "$health_mgmt_enabled",
        "optimized_charging_enabled": "$optimized_charging"
    },
    "discovery_metadata": {
        "discovery_method": "enterprise_automated",
        "discovery_version": "1.0"
    }
}
EOF
    
    log_action "Battery fleet discovery completed: $discovery_file"
    
    # Display summary
    echo ""
    echo "Discovery Summary:"
    echo "  Device: $device_model ($device_identifier)"
    echo "  Serial: $device_serial"
    echo "  Battery Capacity: ${max_capacity_mah:-0} mAh (Design: ${design_capacity_mah:-0} mAh)"
    echo "  Health Management: $health_mgmt_enabled"
    echo "  Optimized Charging: $optimized_charging"
    echo "  Discovery Report: $discovery_file"
    
    return 0
}

# Battery optimization engine
optimize_battery_performance() {
    local optimization_profile="$1"
    local target_usage="${2:-standard}"
    local optimization_report="$REPORTS_DIR/battery_optimization_$(date +%Y%m%d_%H%M%S).json"
    
    log_action "Starting battery optimization (Profile: $optimization_profile, Usage: $target_usage)"
    
    echo "=== Battery Performance Optimization ==="
    echo "Optimization Profile: $optimization_profile"
    echo "Target Usage: $target_usage"
    
    # Initialize optimization report
    cat > "$optimization_report" << EOF
{
    "optimization_profile": "$optimization_profile",
    "target_usage": "$target_usage",
    "start_timestamp": "$(date -Iseconds)",
    "hostname": "$(hostname)",
    "optimizations_applied": [],
    "performance_improvements": {},
    "recommendations": []
}
EOF
    
    local optimizations_applied=()
    local performance_before={}
    local performance_after={}
    
    # Capture baseline performance
    echo "Capturing baseline performance..."
    local baseline_charge
    baseline_charge=$(pmset -g batt | grep -o "[0-9]*%" | tr -d '%' | head -1)
    
    case "$optimization_profile" in
        "maximum_battery_life")
            echo "Applying maximum battery life optimizations..."
            
            # Enable low power mode
            sudo pmset -b lowpowermode 1 2>/dev/null && {
                optimizations_applied+=("low_power_mode_enabled")
                echo "  ✅ Low power mode enabled"
            }
            
            # Reduce display brightness
            if command -v brightness &>/dev/null; then
                brightness 0.3 && {
                    optimizations_applied+=("display_brightness_reduced")
                    echo "  ✅ Display brightness reduced"
                }
            fi
            
            # Optimize sleep settings for battery
            sudo pmset -b displaysleep 2 sleep 5 disksleep 3 && {
                optimizations_applied+=("sleep_settings_optimized")
                echo "  ✅ Sleep settings optimized for battery"
            }
            
            # Disable unnecessary services
            sudo pmset -b ttyskeepawake 0 && {
                optimizations_applied+=("tty_sleep_optimized")
                echo "  ✅ TTY sleep optimization enabled"
            }
            ;;
            
        "balanced_performance")
            echo "Applying balanced performance optimizations..."
            
            # Enable battery health management
            if pmset -g | grep -q "Battery Health Management.*0"; then
                # Note: Battery Health Management can't be controlled via pmset in newer macOS versions
                optimizations_applied+=("health_management_status_checked")
                echo "  â„šī¸  Battery Health Management status verified"
            fi
            
            # Optimize charging patterns
            sudo pmset -b acwake 0 && {
                optimizations_applied+=("ac_wake_optimized")
                echo "  ✅ AC wake optimization applied"
            }
            
            # Set balanced sleep settings
            sudo pmset -b displaysleep 10 sleep 15 disksleep 10 && {
                optimizations_applied+=("balanced_sleep_settings")
                echo "  ✅ Balanced sleep settings applied"
            }
            ;;
            
        "performance_priority")
            echo "Applying performance priority optimizations..."
            
            # Disable power nap on battery
            sudo pmset -b powernap 0 && {
                optimizations_applied+=("power_nap_disabled")
                echo "  ✅ Power Nap disabled on battery"
            }
            
            # Optimize for performance
            sudo pmset -b displaysleep 30 sleep 60 disksleep 30 && {
                optimizations_applied+=("performance_sleep_settings")
                echo "  ✅ Performance-focused sleep settings applied"
            }
            
            # Keep system awake during critical tasks
            sudo pmset -b ttyskeepawake 1 && {
                optimizations_applied+=("system_awake_optimization")
                echo "  ✅ System awake optimization for performance"
            }
            ;;
            
        "field_operations")
            echo "Applying field operations optimizations..."
            
            # Ultra-conservative power settings
            sudo pmset -b displaysleep 1 sleep 3 disksleep 1 && {
                optimizations_applied+=("ultra_conservative_sleep")
                echo "  ✅ Ultra-conservative sleep settings for field use"
            }
            
            # Disable all wake events
            sudo pmset -b wake 0 womp 0 && {
                optimizations_applied+=("wake_events_disabled")
                echo "  ✅ Wake events disabled for maximum battery conservation"
            }
            
            # Enable hibernation
            sudo pmset -b hibernatemode 25 && {
                optimizations_applied+=("hibernation_enabled")
                echo "  ✅ Hibernation enabled for extended standby"
            }
            ;;
            
        *)
            echo "❌ Unknown optimization profile: $optimization_profile"
            return 1
            ;;
    esac
    
    # Wait for changes to take effect
    echo "Waiting for optimizations to take effect..."
    sleep 5
    
    # Capture post-optimization performance
    local optimized_charge
    optimized_charge=$(pmset -g batt | grep -o "[0-9]*%" | tr -d '%' | head -1)
    
    # Update optimization report
    jq --argjson optimizations "$(printf '%s\n' "${optimizations_applied[@]}" | jq -R . | jq -s .)" \
       --argjson baseline_charge "${baseline_charge:-0}" \
       --argjson optimized_charge "${optimized_charge:-0}" \
       '.optimizations_applied = $optimizations |
        .performance_improvements = {
          "baseline_charge": $baseline_charge,
          "optimized_charge": $optimized_charge,
          "charge_preservation": ($optimized_charge - $baseline_charge)
        } |
        .end_timestamp = "'"$(date -Iseconds)"'"' \
       "$optimization_report" > "${optimization_report}.tmp" && mv "${optimization_report}.tmp" "$optimization_report"
    
    echo ""
    echo "Optimization Results:"
    echo "  Profile: $optimization_profile"
    echo "  Optimizations Applied: ${#optimizations_applied[@]}"
    echo "  Baseline Charge: ${baseline_charge:-0}%"
    echo "  Current Charge: ${optimized_charge:-0}%"
    echo "  Report: $optimization_report"
    
    audit_log "Battery optimization completed: $optimization_profile (${#optimizations_applied[@]} optimizations)"
    
    return 0
}

# Fleet battery analytics
generate_fleet_analytics() {
    local analytics_type="$1"
    local time_period="${2:-30_days}"
    local analytics_report="$REPORTS_DIR/battery_analytics_${analytics_type}_$(date +%Y%m%d_%H%M%S).json"
    
    log_action "Generating fleet battery analytics: $analytics_type ($time_period)"
    
    echo "=== Fleet Battery Analytics ==="
    echo "Analytics Type: $analytics_type"
    echo "Time Period: $time_period"
    
    case "$analytics_type" in
        "health_overview")
            generate_health_overview_analytics "$analytics_report" "$time_period"
            ;;
        "usage_patterns")
            generate_usage_patterns_analytics "$analytics_report" "$time_period"
            ;;
        "performance_trends")
            generate_performance_trends_analytics "$analytics_report" "$time_period"
            ;;
        "maintenance_forecast")
            generate_maintenance_forecast_analytics "$analytics_report" "$time_period"
            ;;
        "compliance_report")
            generate_compliance_analytics "$analytics_report" "$time_period"
            ;;
        *)
            log_error "Unknown analytics type: $analytics_type"
            return 1
            ;;
    esac
    
    log_action "✅ Fleet analytics generated: $analytics_report"
    echo "Analytics report saved to: $analytics_report"
}

# Battery compliance monitoring
monitor_battery_compliance() {
    local compliance_framework="$1"
    local compliance_report="$REPORTS_DIR/battery_compliance_$(date +%Y%m%d_%H%M%S).json"
    
    log_action "Starting battery compliance monitoring: $compliance_framework"
    
    echo "=== Battery Compliance Monitoring ==="
    echo "Framework: $compliance_framework"
    
    # Initialize compliance report
    cat > "$compliance_report" << EOF
{
    "compliance_framework": "$compliance_framework",
    "scan_timestamp": "$(date -Iseconds)",
    "hostname": "$(hostname)",
    "compliance_checks": {},
    "violations": [],
    "recommendations": []
}
EOF
    
    local violations=()
    local compliance_score=100
    
    case "$compliance_framework" in
        "enterprise_standard")
            # Check battery health management
            if ! pmset -g | grep -q "Battery Health Management.*1"; then
                violations+=("battery_health_management_disabled")
                ((compliance_score -= 20))
            fi
            
            # Check optimized charging
            if ! pmset -g | grep -q "Optimized Battery Charging.*1"; then
                violations+=("optimized_charging_disabled")
                ((compliance_score -= 15))
            fi
            
            # Check power source logging
            if [[ ! -f "/var/log/powermanagement.log" ]]; then
                violations+=("power_management_logging_missing")
                ((compliance_score -= 10))
            fi
            ;;
            
        "environmental_compliance")
            # Check battery condition
            local condition
            condition=$(system_profiler SPPowerDataType | grep "Condition:" | awk -F': ' '{print $2}' | tr -d ' ')
            
            if [[ "$condition" != "Normal" ]]; then
                violations+=("battery_condition_degraded")
                ((compliance_score -= 30))
            fi
            
            # Check cycle count
            local cycle_count
            cycle_count=$(system_profiler SPPowerDataType | grep "Cycle Count:" | awk -F': ' '{print $2}' | tr -d ' ')
            
            if [[ $cycle_count -gt 1000 ]]; then
                violations+=("high_cycle_count_environmental_concern")
                ((compliance_score -= 25))
            fi
            ;;
            
        *)
            echo "❌ Unknown compliance framework: $compliance_framework"
            return 1
            ;;
    esac
    
    # Update compliance report
    jq --argjson violations "$(printf '%s\n' "${violations[@]}" | jq -R . | jq -s .)" \
       --argjson compliance_score "$compliance_score" \
       '.violations = $violations |
        .compliance_score = $compliance_score |
        .end_timestamp = "'"$(date -Iseconds)"'"' \
       "$compliance_report" > "${compliance_report}.tmp" && mv "${compliance_report}.tmp" "$compliance_report"
    
    echo ""
    echo "Compliance Results:"
    echo "  Framework: $compliance_framework"
    echo "  Compliance Score: $compliance_score/100"
    echo "  Violations Found: ${#violations[@]}"
    
    if [[ ${#violations[@]} -gt 0 ]]; then
        echo "  Violations:"
        for violation in "${violations[@]}"; do
            echo "    - $violation"
        done
    else
        echo "  ✅ No violations found"
    fi
    
    echo "  Compliance Report: $compliance_report"
    
    audit_log "Battery compliance monitoring completed: $compliance_framework (Score: $compliance_score/100)"
    
    return 0
}

# Main function with command routing
main() {
    local command="$1"
    shift
    
    # Initialize
    create_directories
    initialize_battery_database
    
    case "$command" in
        "status")
            # Enhanced battery status
            get_comprehensive_battery_info
            ;;
        "health_check")
            monitor_battery_health "$@"
            ;;
        "discover_fleet")
            discover_battery_fleet
            ;;
        "optimize")
            optimize_battery_performance "$@"
            ;;
        "apply_policy")
            apply_battery_policy "$@"
            ;;
        "fleet_analytics")
            generate_fleet_analytics "$@"
            ;;
        "compliance_check")
            monitor_battery_compliance "$@"
            ;;
        "show_categories")
            print_battery_categories
            ;;
        "show_policies")
            for policy in maximum_performance balanced_efficiency extended_battery_life enterprise_standard high_security_mobile creative_professional field_operations compliance_strict; do
                echo "Policy: $policy"
                get_battery_policy "$policy" | jq .
                echo ""
            done
            ;;
        *)
            echo "Roundfleet Enterprise Battery Management System"
            echo "Usage: $0 <command> [options]"
            echo ""
            echo "Commands:"
            echo "  status                                    - Enhanced battery status and information"
            echo "  health_check <category> [profile]        - Comprehensive battery health monitoring"
            echo "  discover_fleet                           - Fleet-wide battery discovery"
            echo "  optimize <profile> [usage]               - Battery performance optimization"
            echo "  apply_policy <policy>                    - Apply battery management policy"
            echo "  fleet_analytics <type> [period]          - Generate fleet battery analytics"
            echo "  compliance_check <framework>             - Battery compliance monitoring"
            echo "  show_categories                          - Show battery device categories"
            echo "  show_policies                            - Show battery management policies"
            echo ""
            echo "Examples:"
            echo "  $0 status"
            echo "  $0 health_check executive_mobile enterprise"
            echo "  $0 optimize maximum_battery_life mobile"
            echo "  $0 apply_policy enterprise_standard"
            echo "  $0 fleet_analytics health_overview 30_days"
            echo "  $0 compliance_check enterprise_standard"
            ;;
    esac
}

# Execute main function with all arguments
main "$@"

Fleet Deployment Configuration

Fleet Configuration Example

{
    "fleet_name": "Roundfleet Enterprise Battery Management",
    "deployment_date": "2025-07-07",
    "devices": [
        {
            "hostname": "mac-executive-01.company.com",
            "category": "executive_mobile",
            "policy": "enterprise_standard"
        },
        {
            "hostname": "mac-creative-01.company.com", 
            "category": "creative_workstation",
            "policy": "creative_professional"
        },
        {
            "hostname": "mac-field-01.company.com",
            "category": "field_service",
            "policy": "field_operations"
        }
    ],
    "monitoring_schedule": {
        "health_checks": "daily",
        "performance_analytics": "weekly",
        "compliance_audits": "monthly"
    }
}

Security Considerations

Battery Security

  • Power Management Integrity - Ensure power management settings cannot be tampered with
  • Battery Health Monitoring - Continuous monitoring for security-related battery issues
  • Thermal Management - Monitor battery temperature for security and safety
  • Charging Security - Secure charging protocols and malware protection
  • Physical Security - Monitor for battery tampering or replacement

Compliance Framework

  • Environmental Compliance - Battery disposal and lifecycle compliance
  • Health & Safety - Battery safety monitoring and incident reporting
  • Energy Efficiency - Power consumption tracking and optimization
  • Asset Management - Battery replacement and maintenance tracking
  • Audit Trails - Comprehensive logging of all battery-related operations

Performance Optimization

Battery Performance

  • Charging Optimization - Intelligent charging patterns and health preservation
  • Power Efficiency - System-level power consumption optimization
  • Thermal Management - Temperature-based performance optimization
  • Usage Analytics - Pattern recognition and optimization recommendations
  • Lifecycle Extension - Proactive measures to extend battery lifespan

Troubleshooting Guide

Common Issues

Battery Not Charging

  • Check charging cable and adapter functionality
  • Verify charging port for debris or damage
  • Reset SMC (System Management Controller)
  • Check for software-based charging restrictions

Rapid Battery Drain

  • Identify power-hungry applications with Activity Monitor
  • Check for runaway processes consuming CPU
  • Verify display brightness and other power settings
  • Monitor background app refresh and location services

Battery Health Degradation

  • Monitor cycle count and capacity trends
  • Check for extreme temperature exposure
  • Verify charging patterns and optimize for longevity
  • Consider battery replacement based on health metrics

Diagnostic Commands

# Comprehensive battery status
pmset -g batt

# Detailed battery health
system_profiler SPPowerDataType

# Power management settings
pmset -g

# Battery registry information
ioreg -n AppleSmartBattery -r

# Thermal state monitoring
pmset -g therm

Important Notes

  • Battery Safety - Monitor temperature and charging patterns for safety
  • Lifecycle Management - Proactive monitoring and replacement planning
  • Environmental Impact - Proper battery disposal and recycling procedures
  • Performance Impact - Balance battery optimization with system performance needs
  • Compliance Requirements - Maintain compliance with environmental and safety standards
  • Documentation - Keep detailed records of battery health and maintenance activities

Battery Charging Limit Management on macOS

Manage battery charging limits across your Roundfleet devices to optimize battery health and implement enterprise power management policies. This tutorial covers installation of battery management tools, charging limit configuration, persistence settings, and comprehensive fleet-wide battery health monitoring.

Understanding Battery Charging Limits

Battery charging limits help preserve battery health by preventing overcharging, especially beneficial for devices that remain plugged in continuously:

Why Set Charging Limits?

  • Battery Longevity - Prevents degradation from constant 100% charge
  • Heat Reduction - Lower charge levels generate less heat during operation
  • Enterprise Cost Savings - Extended battery life reduces replacement costs
  • Power Management - Optimized charging for stationary workstations
  • Environmental Benefits - Longer battery life reduces electronic waste

Battery Management Tools

  • bclm - Battery Charge Limit Max (primary tool)
  • SMC - System Management Controller (hardware interface)
  • Homebrew - Package manager for macOS tools
  • Power Management - Built-in macOS power controls

Prerequisites and Installation

Install Homebrew Package Manager

#!/bin/bash

# Install Homebrew package manager
echo "đŸē Installing Homebrew package manager..."

# Check if Homebrew is already installed
if command -v brew >/dev/null 2>&1; then
    echo "â„šī¸ Homebrew is already installed"
    echo "Homebrew version: $(brew --version | head -1)"
else
    echo "Installing Homebrew..."
    /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
    
    if [[ $? -eq 0 ]]; then
        echo "✅ Homebrew installed successfully"
    else
        echo "❌ Homebrew installation failed"
        exit 1
    fi
fi

# Verify installation and add to PATH if needed
if [[ -f /opt/homebrew/bin/brew ]]; then
    echo 'eval "$(/opt/homebrew/bin/brew shellenv)"' >> ~/.zprofile
    eval "$(/opt/homebrew/bin/brew shellenv)"
elif [[ -f /usr/local/bin/brew ]]; then
    echo 'eval "$(/usr/local/bin/brew shellenv)"' >> ~/.zprofile
    eval "$(/usr/local/bin/brew shellenv)"
fi

echo "Homebrew location: $(which brew)"

Install BCLM (Battery Charge Limit Max)

#!/bin/bash

# Install bclm (Battery Charge Limit Max)
echo "🔋 Installing bclm (Battery Charge Limit Max)..."

# Ensure Homebrew is available
if ! command -v brew >/dev/null 2>&1; then
    echo "❌ Homebrew not found. Please install Homebrew first."
    exit 1
fi

# Install bclm
echo "Adding zackelia/formulae tap..."
if brew tap zackelia/formulae; then
    echo "✅ Tap added successfully"
else
    echo "❌ Failed to add tap"
    exit 1
fi

echo "Installing bclm..."
if brew install bclm; then
    echo "✅ bclm installed successfully"
else
    echo "❌ bclm installation failed"
    exit 1
fi

# Verify installation
if command -v bclm >/dev/null 2>&1; then
    echo "bclm location: $(which bclm)"
    echo "Testing bclm access..."
    
    # Test read access (doesn't require sudo)
    if bclm read >/dev/null 2>&1; then
        echo "✅ bclm is working correctly"
        echo "Current charging limit: $(bclm read)%"
    else
        echo "âš ī¸ bclm installed but may require additional permissions"
    fi
else
    echo "❌ bclm not found in PATH"
    exit 1
fi

Basic Charging Limit Management

Set Charging Limit

#!/bin/bash

# Set battery charging limit
LIMIT="$1"

if [[ -z "$LIMIT" ]]; then
    echo "❌ Usage: $0 <percentage>"
    echo "Example: $0 80"
    echo "Valid range: 50-100"
    exit 1
fi

# Validate limit range
if [[ "$LIMIT" -lt 50 || "$LIMIT" -gt 100 ]]; then
    echo "❌ Invalid limit: $LIMIT"
    echo "Charging limit must be between 50% and 100%"
    exit 1
fi

echo "🔋 Setting battery charging limit to $LIMIT%..."

# Get current limit for comparison
CURRENT_LIMIT=$(bclm read 2>/dev/null)
if [[ -n "$CURRENT_LIMIT" ]]; then
    echo "Current limit: $CURRENT_LIMIT%"
fi

# Set new charging limit
if sudo bclm write "$LIMIT"; then
    echo "✅ Charging limit set to $LIMIT%"
    
    # Verify the setting
    NEW_LIMIT=$(bclm read 2>/dev/null)
    if [[ "$NEW_LIMIT" == "$LIMIT" ]]; then
        echo "✅ Setting verified: $NEW_LIMIT%"
    else
        echo "âš ī¸ Warning: Verification shows $NEW_LIMIT% instead of $LIMIT%"
    fi
else
    echo "❌ Failed to set charging limit"
    exit 1
fi

echo "â„šī¸ Note: Restart may be required for changes to take effect"

Read Current Charging Limit

#!/bin/bash

# Read current battery charging limit
echo "🔍 Reading current battery charging limit..."

if command -v bclm >/dev/null 2>&1; then
    CURRENT_LIMIT=$(bclm read 2>/dev/null)
    
    if [[ -n "$CURRENT_LIMIT" ]]; then
        echo "Current charging limit: $CURRENT_LIMIT%"
        
        # Provide context about the limit
        if [[ "$CURRENT_LIMIT" -eq 100 ]]; then
            echo "â„šī¸ Battery charges to maximum capacity (no limit set)"
        elif [[ "$CURRENT_LIMIT" -ge 80 ]]; then
            echo "â„šī¸ Conservative charging limit for battery longevity"
        elif [[ "$CURRENT_LIMIT" -ge 60 ]]; then
            echo "â„šī¸ Moderate charging limit for extended battery life"
        else
            echo "â„šī¸ Aggressive charging limit for maximum battery preservation"
        fi
    else
        echo "❌ Unable to read charging limit"
        echo "This may indicate bclm is not properly installed or lacks permissions"
        exit 1
    fi
else
    echo "❌ bclm not found. Please install bclm first."
    exit 1
fi

Make Charging Limit Persistent

#!/bin/bash

# Make charging limit persistent across reboots
echo "💾 Making charging limit persistent..."

if ! command -v bclm >/dev/null 2>&1; then
    echo "❌ bclm not found. Please install bclm first."
    exit 1
fi

# Get current limit
CURRENT_LIMIT=$(bclm read 2>/dev/null)
if [[ -z "$CURRENT_LIMIT" ]]; then
    echo "❌ Unable to read current charging limit"
    exit 1
fi

echo "Current charging limit: $CURRENT_LIMIT%"

# Make persistent
if sudo bclm persist; then
    echo "✅ Charging limit ($CURRENT_LIMIT%) is now persistent"
    echo "The limit will be maintained across system reboots"
else
    echo "❌ Failed to make charging limit persistent"
    exit 1
fi

echo "â„šī¸ To remove persistence, run: sudo bclm unpersist"

Remove Charging Limit Persistence

#!/bin/bash

# Remove charging limit persistence
echo "🔄 Removing charging limit persistence..."

if ! command -v bclm >/dev/null 2>&1; then
    echo "❌ bclm not found. Please install bclm first."
    exit 1
fi

# Get current limit before removing persistence
CURRENT_LIMIT=$(bclm read 2>/dev/null)
if [[ -n "$CURRENT_LIMIT" ]]; then
    echo "Current charging limit: $CURRENT_LIMIT%"
fi

# Remove persistence
if sudo bclm unpersist; then
    echo "✅ Charging limit persistence removed"
    echo "The limit may reset to 100% after next reboot"
else
    echo "❌ Failed to remove charging limit persistence"
    exit 1
fi

echo "â„šī¸ To restore persistence, run: sudo bclm persist"

Advanced Battery Management

Enterprise Battery Health Check

#!/bin/bash

# Comprehensive battery health assessment
echo "🔋 Performing comprehensive battery health check..."

# Check if battery is present
if ! system_profiler SPPowerDataType | grep -q "Battery Information"; then
    echo "❌ No battery found on this system"
    exit 1
fi

echo "=== Battery Health Assessment ==="

# Get battery information
BATTERY_INFO=$(system_profiler SPPowerDataType)

# Extract key metrics
CYCLE_COUNT=$(echo "$BATTERY_INFO" | grep "Cycle Count" | awk '{print $3}')
CONDITION=$(echo "$BATTERY_INFO" | grep "Condition" | awk '{print $2}')
MAX_CAPACITY=$(echo "$BATTERY_INFO" | grep "Maximum Capacity" | awk '{print $3}' | sed 's/%//')

echo "Battery Condition: $CONDITION"
echo "Cycle Count: $CYCLE_COUNT"
echo "Maximum Capacity: $MAX_CAPACITY%"

# Check charging limit if bclm is available
if command -v bclm >/dev/null 2>&1; then
    CHARGING_LIMIT=$(bclm read 2>/dev/null)
    if [[ -n "$CHARGING_LIMIT" ]]; then
        echo "Charging Limit: $CHARGING_LIMIT%"
    else
        echo "Charging Limit: Not set (100%)"
    fi
fi

# Power adapter information
POWER_ADAPTER=$(echo "$BATTERY_INFO" | grep -A5 "AC Charger Information" | grep "Wattage" | awk '{print $2}')
if [[ -n "$POWER_ADAPTER" ]]; then
    echo "Power Adapter: ${POWER_ADAPTER}W"
fi

# Health assessment
echo -e "\n=== Health Assessment ==="

if [[ "$CONDITION" == "Normal" ]]; then
    echo "✅ Battery condition is normal"
elif [[ "$CONDITION" == "Replace Soon" ]]; then
    echo "âš ī¸ Battery should be replaced soon"
elif [[ "$CONDITION" == "Replace Now" ]]; then
    echo "❌ Battery needs immediate replacement"
else
    echo "â„šī¸ Battery condition: $CONDITION"
fi

if [[ -n "$CYCLE_COUNT" ]]; then
    if [[ "$CYCLE_COUNT" -lt 500 ]]; then
        echo "✅ Cycle count is healthy ($CYCLE_COUNT cycles)"
    elif [[ "$CYCLE_COUNT" -lt 1000 ]]; then
        echo "âš ī¸ Moderate cycle count ($CYCLE_COUNT cycles)"
    else
        echo "❌ High cycle count ($CYCLE_COUNT cycles)"
    fi
fi

if [[ -n "$MAX_CAPACITY" ]]; then
    if [[ "$MAX_CAPACITY" -ge 90 ]]; then
        echo "✅ Maximum capacity is excellent ($MAX_CAPACITY%)"
    elif [[ "$MAX_CAPACITY" -ge 80 ]]; then
        echo "✅ Maximum capacity is good ($MAX_CAPACITY%)"
    elif [[ "$MAX_CAPACITY" -ge 70 ]]; then
        echo "âš ī¸ Maximum capacity is declining ($MAX_CAPACITY%)"
    else
        echo "❌ Maximum capacity is poor ($MAX_CAPACITY%)"
    fi
fi

# Recommendations
echo -e "\n=== Recommendations ==="

if [[ -z "$CHARGING_LIMIT" || "$CHARGING_LIMIT" -eq 100 ]]; then
    echo "💡 Consider setting a charging limit (80-90%) for better battery health"
fi

if [[ "$CYCLE_COUNT" -gt 1000 && "$MAX_CAPACITY" -lt 80 ]]; then
    echo "💡 Battery replacement may be needed soon"
fi

Optimized Charging Limit Recommendations

#!/bin/bash

# Provide charging limit recommendations based on usage patterns
echo "đŸŽ¯ Analyzing optimal charging limit recommendations..."

# Get device model and usage information
DEVICE_MODEL=$(system_profiler SPHardwareDataType | grep "Model Name" | awk -F': ' '{print $2}')
UPTIME=$(uptime | awk '{print $3}' | sed 's/,//')

echo "Device: $DEVICE_MODEL"
echo "Current uptime: $UPTIME"

# Check if device is primarily plugged in
AC_POWER_COUNT=$(pmset -g log | grep -c "Using AC" 2>/dev/null || echo "0")
BATTERY_POWER_COUNT=$(pmset -g log | grep -c "Using Batt" 2>/dev/null || echo "0")

echo -e "\n=== Usage Pattern Analysis ==="

if [[ "$AC_POWER_COUNT" -gt "$BATTERY_POWER_COUNT" ]]; then
    USAGE_TYPE="Desktop/Stationary"
    RECOMMENDED_LIMIT=80
    echo "Usage pattern: Primarily AC powered"
    echo "Recommendation: Set charging limit to $RECOMMENDED_LIMIT%"
else
    USAGE_TYPE="Mobile/Portable"
    RECOMMENDED_LIMIT=90
    echo "Usage pattern: Frequently on battery"
    echo "Recommendation: Set charging limit to $RECOMMENDED_LIMIT%"
fi

# Get current battery health
BATTERY_CONDITION=$(system_profiler SPPowerDataType | grep "Condition" | awk '{print $2}')
MAX_CAPACITY=$(system_profiler SPPowerDataType | grep "Maximum Capacity" | awk '{print $3}' | sed 's/%//')

if [[ -n "$MAX_CAPACITY" && "$MAX_CAPACITY" -lt 85 ]]; then
    RECOMMENDED_LIMIT=75
    echo "âš ī¸ Battery health is declining, recommended limit: $RECOMMENDED_LIMIT%"
fi

# Check current setting
if command -v bclm >/dev/null 2>&1; then
    CURRENT_LIMIT=$(bclm read 2>/dev/null)
    
    if [[ -n "$CURRENT_LIMIT" ]]; then
        echo "Current limit: $CURRENT_LIMIT%"
        
        if [[ "$CURRENT_LIMIT" -eq "$RECOMMENDED_LIMIT" ]]; then
            echo "✅ Current setting is optimal"
        else
            echo "💡 Consider adjusting to $RECOMMENDED_LIMIT% for optimal battery health"
        fi
    else
        echo "Current limit: Not set (100%)"
        echo "💡 Recommended action: Set charging limit to $RECOMMENDED_LIMIT%"
    fi
fi

echo -e "\n=== Implementation Command ==="
echo "To set recommended limit: sudo bclm write $RECOMMENDED_LIMIT"
echo "To make persistent: sudo bclm persist"

Enterprise Battery Management Script

#!/bin/bash

# Roundfleet Battery Management Tool
# Comprehensive battery charging limit management for enterprise environments

# Configuration
LOG_FILE="/var/log/roundfleet_battery.log"
BACKUP_DIR="/var/backups/roundfleet/battery"
REPORT_DIR="/var/reports/roundfleet/battery"
CONFIG_FILE="/etc/roundfleet/battery_policy.conf"

# Battery policy settings
DEFAULT_CHARGING_LIMIT=80
MOBILE_DEVICE_LIMIT=90
STATIONARY_DEVICE_LIMIT=75
ENFORCE_BATTERY_POLICY=false
HEALTH_CHECK_ENABLED=true
ALERT_CAPACITY_THRESHOLD=80
ALERT_CYCLE_THRESHOLD=1000

# Logging function
log_action() {
    echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" | tee -a "$LOG_FILE"
}

# Setup directories
setup_directories() {
    for dir in "$BACKUP_DIR" "$REPORT_DIR" "$(dirname "$CONFIG_FILE")"; do
        if [[ ! -d "$dir" ]]; then
            sudo mkdir -p "$dir"
            log_action "Created directory: $dir"
        fi
    done
}

# Check if device has a battery
check_battery_presence() {
    if system_profiler SPPowerDataType | grep -q "Battery Information"; then
        return 0
    else
        echo "❌ No battery found on this system"
        log_action "No battery detected on device"
        return 1
    fi
}

# Install battery management tools
install_battery_tools() {
    echo "🔧 Installing battery management tools..."
    log_action "Battery tools installation started"
    
    # Check and install Homebrew
    if ! command -v brew >/dev/null 2>&1; then
        echo "Installing Homebrew..."
        /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
        
        # Add to PATH
        if [[ -f /opt/homebrew/bin/brew ]]; then
            eval "$(/opt/homebrew/bin/brew shellenv)"
        elif [[ -f /usr/local/bin/brew ]]; then
            eval "$(/usr/local/bin/brew shellenv)"
        fi
    fi
    
    # Install bclm
    if ! command -v bclm >/dev/null 2>&1; then
        echo "Installing bclm..."
        brew tap zackelia/formulae && brew install bclm
        
        if command -v bclm >/dev/null 2>&1; then
            echo "✅ bclm installed successfully"
            log_action "bclm installed successfully"
        else
            echo "❌ bclm installation failed"
            log_action "bclm installation failed"
            return 1
        fi
    else
        echo "✅ bclm already installed"
    fi
    
    return 0
}

# Generate comprehensive battery report
generate_battery_report() {
    local report_file="$REPORT_DIR/battery_report_$(date +%Y%m%d_%H%M%S).txt"
    
    echo "📊 Generating comprehensive battery report..."
    
    {
        echo "Roundfleet Battery Management Report"
        echo "Generated: $(date)"
        echo "Device: $(hostname)"
        echo "================================="
        echo ""
        
        # System information
        echo "=== System Information ==="
        system_profiler SPHardwareDataType | grep -E "Model Name|Model Identifier|Processor|Memory"
        echo ""
        
        # Battery hardware information
        echo "=== Battery Hardware Information ==="
        local battery_info=$(system_profiler SPPowerDataType)
        echo "$battery_info" | grep -E "Condition|Cycle Count|Maximum Capacity|Manufacturer|Device Name|Pack Lot Code|PCB Lot Code|Firmware Version|Hardware Revision"
        echo ""
        
        # Current charging limit
        echo "=== Charging Limit Configuration ==="
        if command -v bclm >/dev/null 2>&1; then
            local current_limit=$(bclm read 2>/dev/null)
            if [[ -n "$current_limit" ]]; then
                echo "Current charging limit: $current_limit%"
                
                # Check if persistent
                local smc_value=$(sudo bclm read 2>/dev/null)
                if [[ "$smc_value" == "$current_limit" ]]; then
                    echo "Persistence status: Enabled"
                else
                    echo "Persistence status: Disabled"
                fi
            else
                echo "Current charging limit: Not set (100%)"
                echo "Persistence status: N/A"
            fi
        else
            echo "bclm status: Not installed"
        fi
        echo ""
        
        # Power usage analysis
        echo "=== Power Usage Analysis ==="
        echo "Power adapter connected: $(system_profiler SPPowerDataType | grep -q "AC Charger Information" && echo "Yes" || echo "No")"
        
        # Get power adapter info if available
        local adapter_info=$(system_profiler SPPowerDataType | grep -A3 "AC Charger Information" | grep "Wattage")
        if [[ -n "$adapter_info" ]]; then
            echo "Power adapter: $(echo "$adapter_info" | awk '{print $2}')W"
        fi
        
        # Battery temperature and voltage
        echo "Battery temperature: $(ioreg -l | grep Temperature | awk '{print $3/100}' | head -1)°C"
        echo "Battery voltage: $(ioreg -l | grep Voltage | awk '{print $3/1000}' | head -1)V"
        echo ""
        
        # Health assessment
        echo "=== Battery Health Assessment ==="
        local condition=$(echo "$battery_info" | grep "Condition" | awk '{print $2}')
        local cycle_count=$(echo "$battery_info" | grep "Cycle Count" | awk '{print $3}')
        local max_capacity=$(echo "$battery_info" | grep "Maximum Capacity" | awk '{print $3}' | sed 's/%//')
        
        echo "Overall condition: $condition"
        echo "Cycle count: $cycle_count"
        echo "Maximum capacity: $max_capacity%"
        
        # Health scoring
        local health_score=100
        
        if [[ "$condition" != "Normal" ]]; then
            health_score=$((health_score - 20))
        fi
        
        if [[ -n "$cycle_count" ]]; then
            if [[ "$cycle_count" -gt 1000 ]]; then
                health_score=$((health_score - 20))
            elif [[ "$cycle_count" -gt 500 ]]; then
                health_score=$((health_score - 10))
            fi
        fi
        
        if [[ -n "$max_capacity" ]]; then
            if [[ "$max_capacity" -lt 70 ]]; then
                health_score=$((health_score - 30))
            elif [[ "$max_capacity" -lt 80 ]]; then
                health_score=$((health_score - 20))
            elif [[ "$max_capacity" -lt 90 ]]; then
                health_score=$((health_score - 10))
            fi
        fi
        
        echo "Health score: $health_score/100"
        
        # Recommendations
        echo ""
        echo "=== Recommendations ==="
        
        if [[ "$health_score" -ge 80 ]]; then
            echo "✅ Battery health is good"
            echo "💡 Consider setting charging limit to 80% for optimal longevity"
        elif [[ "$health_score" -ge 60 ]]; then
            echo "âš ī¸ Battery health is declining"
            echo "💡 Set charging limit to 75% and monitor closely"
        else
            echo "❌ Battery health is poor"
            echo "💡 Consider battery replacement and immediate charging limit to 70%"
        fi
        
        # Policy compliance check
        if [[ "$ENFORCE_BATTERY_POLICY" == "true" ]]; then
            echo ""
            echo "=== Policy Compliance ==="
            echo "Battery policy enforcement: ENABLED"
            echo "Default charging limit: $DEFAULT_CHARGING_LIMIT%"
            
            if [[ -n "$current_limit" ]]; then
                if [[ "$current_limit" -eq "$DEFAULT_CHARGING_LIMIT" ]]; then
                    echo "Compliance status: ✅ COMPLIANT"
                else
                    echo "Compliance status: ❌ NON-COMPLIANT"
                    echo "Current: $current_limit%, Required: $DEFAULT_CHARGING_LIMIT%"
                fi
            else
                echo "Compliance status: ❌ NON-COMPLIANT (no limit set)"
            fi
        fi
        
    } > "$report_file"
    
    echo "📊 Report saved to: $report_file"
    log_action "Battery report generated: $report_file"
}

# Set optimal charging limit based on usage pattern
set_optimal_charging_limit() {
    local force_limit="$1"
    
    echo "đŸŽ¯ Determining optimal charging limit..."
    
    if ! check_battery_presence; then
        return 1
    fi
    
    # Install tools if needed
    if ! command -v bclm >/dev/null 2>&1; then
        if ! install_battery_tools; then
            echo "❌ Failed to install required tools"
            return 1
        fi
    fi
    
    local recommended_limit="$DEFAULT_CHARGING_LIMIT"
    
    # Override with forced limit if provided
    if [[ -n "$force_limit" ]]; then
        recommended_limit="$force_limit"
        echo "Using forced limit: $recommended_limit%"
    else
        # Analyze usage pattern
        echo "Analyzing device usage pattern..."
        
        # Check if device is primarily stationary (simplified detection)
        local model=$(system_profiler SPHardwareDataType | grep "Model Name" | awk -F': ' '{print $2}')
        if echo "$model" | grep -qi "mac studio\|mac pro\|imac"; then
            recommended_limit="$STATIONARY_DEVICE_LIMIT"
            echo "Detected stationary device, recommended limit: $recommended_limit%"
        else
            recommended_limit="$MOBILE_DEVICE_LIMIT"
            echo "Detected mobile device, recommended limit: $recommended_limit%"
        fi
        
        # Adjust based on battery health
        local max_capacity=$(system_profiler SPPowerDataType | grep "Maximum Capacity" | awk '{print $3}' | sed 's/%//')
        if [[ -n "$max_capacity" && "$max_capacity" -lt 85 ]]; then
            recommended_limit=75
            echo "Adjusted for battery health: $recommended_limit%"
        fi
    fi
    
    # Set the charging limit
    echo "Setting charging limit to $recommended_limit%..."
    
    if sudo bclm write "$recommended_limit"; then
        echo "✅ Charging limit set to $recommended_limit%"
        
        # Make persistent
        if sudo bclm persist; then
            echo "✅ Charging limit made persistent"
            log_action "Charging limit set to $recommended_limit% and made persistent"
        else
            echo "âš ī¸ Failed to make charging limit persistent"
            log_action "Charging limit set to $recommended_limit% but persistence failed"
        fi
        
        # Verify setting
        local verify_limit=$(bclm read 2>/dev/null)
        if [[ "$verify_limit" == "$recommended_limit" ]]; then
            echo "✅ Setting verified: $verify_limit%"
        else
            echo "âš ī¸ Verification failed: expected $recommended_limit%, got $verify_limit%"
        fi
    else
        echo "❌ Failed to set charging limit"
        log_action "Failed to set charging limit to $recommended_limit%"
        return 1
    fi
}

# Monitor battery health and alert on issues
monitor_battery_health() {
    echo "🔍 Monitoring battery health..."
    
    if ! check_battery_presence; then
        return 1
    fi
    
    local battery_info=$(system_profiler SPPowerDataType)
    local condition=$(echo "$battery_info" | grep "Condition" | awk '{print $2}')
    local cycle_count=$(echo "$battery_info" | grep "Cycle Count" | awk '{print $3}')
    local max_capacity=$(echo "$battery_info" | grep "Maximum Capacity" | awk '{print $3}' | sed 's/%//')
    
    local alerts_triggered=0
    
    # Check condition
    if [[ "$condition" != "Normal" ]]; then
        echo "🚨 ALERT: Battery condition is $condition"
        log_action "ALERT: Battery condition is $condition"
        ((alerts_triggered++))
    fi
    
    # Check cycle count
    if [[ -n "$cycle_count" && "$cycle_count" -gt "$ALERT_CYCLE_THRESHOLD" ]]; then
        echo "🚨 ALERT: High cycle count - $cycle_count cycles"
        log_action "ALERT: High cycle count - $cycle_count cycles"
        ((alerts_triggered++))
    fi
    
    # Check capacity
    if [[ -n "$max_capacity" && "$max_capacity" -lt "$ALERT_CAPACITY_THRESHOLD" ]]; then
        echo "🚨 ALERT: Low maximum capacity - $max_capacity%"
        log_action "ALERT: Low maximum capacity - $max_capacity%"
        ((alerts_triggered++))
    fi
    
    if [[ "$alerts_triggered" -eq 0 ]]; then
        echo "✅ No battery health alerts"
        log_action "Battery health monitoring: No alerts"
    else
        echo "âš ī¸ $alerts_triggered battery health alert(s) triggered"
        log_action "Battery health monitoring: $alerts_triggered alerts triggered"
    fi
    
    return $alerts_triggered
}

# Main execution function
main() {
    local action="${1:-help}"
    local target="${2:-}"
    
    log_action "=== Roundfleet Battery Management Started ==="
    
    setup_directories
    
    case "$action" in
        "install"|"setup")
            install_battery_tools
            ;;
        "report"|"status")
            generate_battery_report
            ;;
        "set")
            if [[ -n "$target" ]]; then
                set_optimal_charging_limit "$target"
            else
                set_optimal_charging_limit
            fi
            ;;
        "read"|"current")
            if command -v bclm >/dev/null 2>&1; then
                local current=$(bclm read 2>/dev/null)
                if [[ -n "$current" ]]; then
                    echo "Current charging limit: $current%"
                else
                    echo "No charging limit set (100%)"
                fi
            else
                echo "❌ bclm not installed"
            fi
            ;;
        "persist")
            if command -v bclm >/dev/null 2>&1; then
                if sudo bclm persist; then
                    echo "✅ Charging limit made persistent"
                else
                    echo "❌ Failed to make charging limit persistent"
                fi
            else
                echo "❌ bclm not installed"
            fi
            ;;
        "unpersist")
            if command -v bclm >/dev/null 2>&1; then
                if sudo bclm unpersist; then
                    echo "✅ Charging limit persistence removed"
                else
                    echo "❌ Failed to remove charging limit persistence"
                fi
            else
                echo "❌ bclm not installed"
            fi
            ;;
        "monitor")
            monitor_battery_health
            ;;
        "health")
            if check_battery_presence; then
                local battery_info=$(system_profiler SPPowerDataType)
                echo "=== Battery Health Summary ==="
                echo "$battery_info" | grep -E "Condition|Cycle Count|Maximum Capacity"
                
                if command -v bclm >/dev/null 2>&1; then
                    local limit=$(bclm read 2>/dev/null)
                    echo "Charging Limit: ${limit:-100}%"
                fi
            fi
            ;;
        "help"|*)
            echo "Roundfleet Battery Management Tool"
            echo "Usage: $0 [action] [options]"
            echo ""
            echo "Actions:"
            echo "  install               - Install battery management tools (Homebrew, bclm)"
            echo "  report                - Generate comprehensive battery report"
            echo "  set [limit]           - Set optimal charging limit (or specify percentage)"
            echo "  read                  - Read current charging limit"
            echo "  persist               - Make charging limit persistent"
            echo "  unpersist             - Remove charging limit persistence"
            echo "  monitor               - Monitor battery health and trigger alerts"
            echo "  health                - Show battery health summary"
            echo "  help                  - Show this help message"
            echo ""
            echo "Examples:"
            echo "  $0 install             # Install required tools"
            echo "  $0 set 80              # Set 80% charging limit"
            echo "  $0 set                 # Set optimal limit based on device type"
            echo "  $0 report              # Generate detailed report"
            echo ""
            echo "Charging Limit Guidelines:"
            echo "  50-100%     - Valid range"
            echo "  80%         - Recommended for most devices"
            echo "  75%         - For stationary/desktop Macs"
            echo "  90%         - For mobile/laptop Macs"
            ;;
    esac
    
    log_action "=== Roundfleet Battery Management Completed ==="
}

# Execute main function
main "$@"

Battery Health Monitoring

Automated Health Checks

# Schedule daily battery health monitoring
create_health_monitoring_schedule() {
    local plist_file="$HOME/Library/LaunchAgents/com.roundfleet.battery-monitor.plist"
    
    cat > "$plist_file" << EOF
<?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>com.roundfleet.battery-monitor</string>
    <key>ProgramArguments</key>
    <array>
        <string>/bin/bash</string>
        <string>$(realpath "$0")</string>
        <string>monitor</string>
    </array>
    <key>StartCalendarInterval</key>
    <dict>
        <key>Hour</key>
        <integer>9</integer>
        <key>Minute</key>
        <integer>0</integer>
    </dict>
    <key>RunAtLoad</key>
    <false/>
</dict>
</plist>
EOF
    
    launchctl load "$plist_file" 2>/dev/null
    echo "✅ Daily battery monitoring scheduled"
}

Charging Limit Recommendations

Device TypeRecommended LimitReasoning
Desktop Macs75-80%Always plugged in, prioritize longevity
Laptop Macs (Stationary)80%Mostly plugged in usage
Laptop Macs (Mobile)90%Need higher capacity for portability
Degraded Battery70-75%Extend remaining battery life

Important Notes

  • Supported Devices - Only works on Mac devices with batteries
  • Administrative Privileges - Requires sudo access for SMC modifications
  • System Compatibility - Compatible with modern macOS versions
  • Restart Requirements - Some changes may require system restart
  • Fleet Deployment - Test on individual devices before bulk deployment
  • Battery Health - Monitor battery condition regularly for optimal results

Manage Badge Notifications on macOS

Control and manage badge notifications across your Roundfleet devices using command-line tools. This tutorial covers removing badge notifications for specific apps, managing dock-wide notifications, and implementing enterprise notification policies.

Understanding Badge Notifications

Badge notifications are the red circular icons that appear above application icons in the macOS dock, typically displaying numbers to indicate unread items like emails, messages, or updates. While useful for individual users, enterprise environments often require centralized notification management.

Key Features

  • App-specific control - Remove badges from individual applications
  • Dock-wide management - Clear all badge notifications at once
  • Automatic restoration - Badges reappear when applications are opened
  • System preference integration - Works with macOS notification settings

Remove Badge Notifications for Specific Apps

Basic Badge Removal

#!/bin/bash

# Remove badge notification for a specific application
APP_NAME="Mail"

defaults write com.apple.systempreferences AttentionPrefBundleIDs 0 && killall "$APP_NAME"

echo "Badge notification removed for $APP_NAME"

Enhanced App Badge Management

#!/bin/bash

# Advanced badge notification removal with validation
remove_app_badge() {
    local app_name="$1"
    
    if [[ -z "$app_name" ]]; then
        echo "❌ Error: Application name required"
        return 1
    fi
    
    # Check if application is running
    if pgrep -x "$app_name" > /dev/null; then
        echo "📱 Removing badge notification for $app_name..."
        
        # Remove badge notification
        defaults write com.apple.systempreferences AttentionPrefBundleIDs 0
        
        # Terminate and restart application to apply changes
        if killall "$app_name" 2>/dev/null; then
            echo "✅ Badge notification removed for $app_name"
            echo "â„šī¸  Note: Badge will reappear when $app_name is reopened"
        else
            echo "âš ī¸  Warning: Could not restart $app_name (may not be running)"
        fi
    else
        echo "â„šī¸  $app_name is not currently running"
        defaults write com.apple.systempreferences AttentionPrefBundleIDs 0
        echo "✅ Badge notification setting updated for $app_name"
    fi
}

# Usage examples
remove_app_badge "Mail"
remove_app_badge "Messages"
remove_app_badge "Calendar"

Common Applications Badge Removal

#!/bin/bash

# Remove badge notifications for common enterprise applications
COMMON_APPS=("Mail" "Messages" "Calendar" "Reminders" "FaceTime" "App Store" "System Preferences")

echo "🧹 Removing badge notifications for common applications..."

for app in "${COMMON_APPS[@]}"; do
    echo "Processing $app..."
    
    # Set notification preference
    defaults write com.apple.systempreferences AttentionPrefBundleIDs 0
    
    # Kill application if running
    if pgrep -x "$app" > /dev/null; then
        killall "$app" 2>/dev/null
        echo "  ✅ Badge cleared for $app"
    else
        echo "  â­ī¸  $app not running, preference updated"
    fi
done

echo "🎉 Badge notification cleanup completed"

Remove All Badge Notifications (Dock-wide)

Basic Dock Badge Clearing

#!/bin/bash

# Remove all badge notifications from the dock
defaults write com.apple.systempreferences AttentionPrefBundleIDs 0 && killall Dock

echo "All badge notifications cleared from dock"

Comprehensive Dock Management

#!/bin/bash

# Advanced dock badge notification management
clear_all_dock_badges() {
    echo "đŸ—ī¸  Clearing all badge notifications from dock..."
    
    # Backup current dock preferences
    local backup_file="/tmp/dock_backup_$(date +%s).plist"
    defaults export com.apple.dock "$backup_file"
    echo "📋 Dock preferences backed up to: $backup_file"
    
    # Clear badge notifications
    defaults write com.apple.systempreferences AttentionPrefBundleIDs 0
    
    # Get list of running dock applications
    local dock_apps
    dock_apps=$(osascript -e 'tell application "System Events" to get name of every application process whose background only is false')
    
    echo "🔄 Restarting dock to apply changes..."
    killall Dock
    
    # Wait for dock to restart
    sleep 3
    
    echo "✅ All badge notifications cleared from dock"
    echo "â„šī¸  Badges will reappear when applications receive new notifications"
    
    return 0
}

# Execute dock badge clearing
clear_all_dock_badges

Enterprise Badge Management Script

#!/bin/bash

# Roundfleet Badge Notification Management Tool
# Centralized control of badge notifications across enterprise devices

# Configuration
LOG_FILE="/var/log/roundfleet_badges.log"
CONFIG_FILE="/etc/roundfleet/badge_policy.conf"
BACKUP_DIR="/var/backups/roundfleet/badges"

# Logging function
log_action() {
    echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" | tee -a "$LOG_FILE"
}

# Create necessary directories
setup_directories() {
    sudo mkdir -p "$(dirname "$LOG_FILE")" 2>/dev/null
    sudo mkdir -p "$BACKUP_DIR" 2>/dev/null
    sudo mkdir -p "$(dirname "$CONFIG_FILE")" 2>/dev/null
}

# Load configuration
load_config() {
    if [[ -f "$CONFIG_FILE" ]]; then
        source "$CONFIG_FILE"
        log_action "Configuration loaded from $CONFIG_FILE"
    else
        # Default configuration
        BADGE_POLICY="disabled"  # Options: enabled, disabled, selective
        ALLOWED_BADGE_APPS=("Calendar" "Reminders")
        BLOCKED_BADGE_APPS=("App Store" "System Preferences")
        AUTO_CLEAR_INTERVAL=3600  # 1 hour
        
        log_action "Using default configuration"
    fi
}

# Backup current badge settings
backup_badge_settings() {
    local backup_file="$BACKUP_DIR/badge_settings_$(date +%Y%m%d_%H%M%S).plist"
    
    defaults export com.apple.systempreferences "$backup_file" 2>/dev/null
    
    if [[ -f "$backup_file" ]]; then
        log_action "Badge settings backed up to: $backup_file"
        echo "$backup_file"
    else
        log_action "Warning: Could not backup badge settings"
        return 1
    fi
}

# Get current badge status
get_badge_status() {
    echo "📊 Current Badge Notification Status:"
    echo "======================================"
    
    # Check system preferences setting
    local attention_pref
    attention_pref=$(defaults read com.apple.systempreferences AttentionPrefBundleIDs 2>/dev/null || echo "not set")
    echo "System AttentionPrefBundleIDs: $attention_pref"
    
    # List applications with potential badges
    echo -e "\n📱 Applications that may show badges:"
    local badge_apps=("Mail" "Messages" "Calendar" "Reminders" "FaceTime" "App Store" "System Preferences" "Contacts")
    
    for app in "${badge_apps[@]}"; do
        if pgrep -x "$app" > /dev/null; then
            echo "  đŸŸĸ $app (running)"
        else
            echo "  âšĒ $app (not running)"
        fi
    done
    
    # Check dock processes
    echo -e "\nđŸ—ī¸  Dock status:"
    if pgrep -x "Dock" > /dev/null; then
        echo "  đŸŸĸ Dock is running"
    else
        echo "  🔴 Dock is not running"
    fi
}

# Apply badge policy
apply_badge_policy() {
    log_action "Applying badge policy: $BADGE_POLICY"
    
    case "$BADGE_POLICY" in
        "disabled")
            disable_all_badges
            ;;
        "enabled")
            enable_all_badges
            ;;
        "selective")
            apply_selective_policy
            ;;
        *)
            log_action "Error: Unknown badge policy: $BADGE_POLICY"
            return 1
            ;;
    esac
}

# Disable all badge notifications
disable_all_badges() {
    echo "đŸšĢ Disabling all badge notifications..."
    
    backup_badge_settings
    
    # Set system preference to disable badges
    defaults write com.apple.systempreferences AttentionPrefBundleIDs 0
    
    # Restart dock to apply changes
    killall Dock 2>/dev/null
    
    log_action "All badge notifications disabled"
    echo "✅ All badge notifications have been disabled"
}

# Enable all badge notifications
enable_all_badges() {
    echo "✅ Enabling all badge notifications..."
    
    backup_badge_settings
    
    # Remove the restriction (delete the key)
    defaults delete com.apple.systempreferences AttentionPrefBundleIDs 2>/dev/null
    
    # Restart dock to apply changes
    killall Dock 2>/dev/null
    
    log_action "All badge notifications enabled"
    echo "✅ All badge notifications have been enabled"
}

# Apply selective badge policy
apply_selective_policy() {
    echo "đŸŽ¯ Applying selective badge policy..."
    
    # For selective policy, we need to manage individual app notifications
    # This requires more complex notification management
    
    for app in "${BLOCKED_BADGE_APPS[@]}"; do
        echo "  đŸšĢ Blocking badges for $app"
        # Kill app to clear current badge
        killall "$app" 2>/dev/null
    done
    
    # Set system preference
    defaults write com.apple.systempreferences AttentionPrefBundleIDs 0
    
    log_action "Selective badge policy applied"
    echo "✅ Selective badge policy has been applied"
}

# Monitor and auto-clear badges
monitor_badges() {
    echo "đŸ‘ī¸  Starting badge monitoring (interval: ${AUTO_CLEAR_INTERVAL}s)..."
    
    while true; do
        if [[ "$BADGE_POLICY" == "disabled" ]]; then
            # Clear any badges that may have appeared
            defaults write com.apple.systempreferences AttentionPrefBundleIDs 0
            log_action "Auto-cleared badges during monitoring"
        fi
        
        sleep "$AUTO_CLEAR_INTERVAL"
    done
}

# Generate badge management report
generate_report() {
    local report_file="/tmp/roundfleet_badge_report_$(date +%Y%m%d_%H%M%S).txt"
    
    {
        echo "Roundfleet Badge Notification Report"
        echo "=================================="
        echo "Generated: $(date)"
        echo "Hostname: $(hostname)"
        echo "Policy: $BADGE_POLICY"
        echo ""
        
        echo "System Configuration:"
        echo "  AttentionPrefBundleIDs: $(defaults read com.apple.systempreferences AttentionPrefBundleIDs 2>/dev/null || echo 'not set')"
        echo ""
        
        echo "Application Status:"
        local apps=("Mail" "Messages" "Calendar" "Reminders" "App Store")
        for app in "${apps[@]}"; do
            if pgrep -x "$app" > /dev/null; then
                echo "  $app: Running"
            else
                echo "  $app: Not running"
            fi
        done
        
        echo ""
        echo "Recent Actions:"
        tail -10 "$LOG_FILE" 2>/dev/null || echo "No recent log entries"
        
    } > "$report_file"
    
    echo "📄 Badge management report generated: $report_file"
    log_action "Report generated: $report_file"
}

# Main function
main() {
    case "${1:-status}" in
        "disable")
            setup_directories
            load_config
            log_action "=== Badge Management: Disable All ==="
            disable_all_badges
            ;;
        "enable")
            setup_directories
            load_config
            log_action "=== Badge Management: Enable All ==="
            enable_all_badges
            ;;
        "policy")
            setup_directories
            load_config
            log_action "=== Badge Management: Apply Policy ==="
            apply_badge_policy
            ;;
        "monitor")
            setup_directories
            load_config
            log_action "=== Badge Management: Start Monitoring ==="
            monitor_badges
            ;;
        "report")
            setup_directories
            load_config
            generate_report
            ;;
        "status"|*)
            setup_directories
            load_config
            get_badge_status
            ;;
    esac
}

# Execute main function with parameters
main "$@"

Badge Notification Management Commands

Quick Reference

TaskCommand
Remove specific app badgedefaults write com.apple.systempreferences AttentionPrefBundleIDs 0 && killall AppName
Clear all dock badgesdefaults write com.apple.systempreferences AttentionPrefBundleIDs 0 && killall Dock
Check current settingdefaults read com.apple.systempreferences AttentionPrefBundleIDs
Reset to defaultdefaults delete com.apple.systempreferences AttentionPrefBundleIDs

Application-Specific Examples

# Common applications
defaults write com.apple.systempreferences AttentionPrefBundleIDs 0 && killall Mail
defaults write com.apple.systempreferences AttentionPrefBundleIDs 0 && killall Messages
defaults write com.apple.systempreferences AttentionPrefBundleIDs 0 && killall "App Store"
defaults write com.apple.systempreferences AttentionPrefBundleIDs 0 && killall Calendar

Troubleshooting

Common Issues

  1. Badges reappear after clearing

    • This is normal behavior; badges return when apps receive new notifications
    • Use monitoring scripts for persistent clearing
  2. Application won't restart

    • Some apps may need manual restart
    • Check if app is set to launch at login
  3. Dock doesn't update

    • Try forcing dock restart: killall Dock && sleep 2 && open /System/Library/CoreServices/Dock.app

Verification Commands

# Check if setting was applied
defaults read com.apple.systempreferences AttentionPrefBundleIDs

# List running applications
ps aux | grep -E "(Mail|Messages|Calendar)" | grep -v grep

# Monitor dock process
ps aux | grep Dock | grep -v grep

Important Notes

  • Temporary effect: Badge notifications will reappear when applications receive new notifications
  • System restart: Settings persist across system restarts
  • User experience: Consider user notification needs before enterprise-wide deployment
  • Application behavior: Some apps may require manual restart to apply changes
  • Testing recommended: Test on individual devices before fleet-wide deployment

Enterprise Deployment

For enterprise deployment, consider:

  1. Policy configuration - Define which applications should show badges
  2. User communication - Inform users about notification changes
  3. Monitoring setup - Implement automated badge clearing if required
  4. Backup procedures - Save original settings before making changes
  5. Rollback plan - Ability to restore original notification behavior

Automatic App Launch Management on macOS

Streamline enterprise productivity by automatically launching essential applications on user login across your Roundfleet devices. This tutorial covers LaunchAgent configuration, user-specific app management, security validation, and centralized deployment strategies.

Understanding macOS App Launch Mechanisms

macOS provides several mechanisms for automatic application launching:

  • LaunchAgents - User-specific applications that launch at login
  • LaunchDaemons - System-wide services that start at boot
  • Login Items - User-configured applications in System Preferences
  • MDM Configurations - Enterprise-managed launch configurations

Basic Automatic App Launch

Simple App Launch Configuration

#!/bin/bash

# Basic app launch setup for single application
APP_NAME="Messages"
PLIST_NAME="com.${APP_NAME}.plist"
LAUNCH_AGENTS_DIR="/Library/LaunchAgents"

# Create LaunchAgent plist
cat > "${LAUNCH_AGENTS_DIR}/${PLIST_NAME}" << EOF
<?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>KeepAlive</key>
    <false/>
    <key>Label</key>
    <string>${PLIST_NAME}</string>
    <key>Program</key>
    <string>/System/Applications/${APP_NAME}.app/Contents/MacOS/${APP_NAME}</string>
    <key>RunAtLoad</key>
    <true/>
</dict>
</plist>
EOF

echo "LaunchAgent created for ${APP_NAME}"

Enhanced App Launch with Validation

#!/bin/bash

# Enhanced app launch with validation
setup_app_launch() {
    local app_name="$1"
    local app_path="$2"
    local plist_name="com.roundfleet.${app_name}.plist"
    
    echo "Setting up automatic launch for: $app_name"
    
    # Validate app exists
    if [[ ! -d "$app_path" ]]; then
        echo "Error: Application not found at $app_path"
        return 1
    fi
    
    # Validate executable
    local executable_path="${app_path}/Contents/MacOS/${app_name}"
    if [[ ! -x "$executable_path" ]]; then
        echo "Error: Executable not found or not executable: $executable_path"
        return 1
    fi
    
    # Create LaunchAgent
    cat > "/Library/LaunchAgents/${plist_name}" << EOF
<?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>KeepAlive</key>
    <false/>
    <key>Label</key>
    <string>${plist_name}</string>
    <key>Program</key>
    <string>${executable_path}</string>
    <key>RunAtLoad</key>
    <true/>
    <key>StandardErrorPath</key>
    <string>/var/log/roundfleet_${app_name}.error.log</string>
    <key>StandardOutPath</key>
    <string>/var/log/roundfleet_${app_name}.out.log</string>
</dict>
</plist>
EOF

    echo "LaunchAgent configured successfully for $app_name"
    return 0
}

# Example usage
setup_app_launch "Messages" "/System/Applications/Messages.app"

Enterprise Application Launch Management

#!/bin/bash

# Roundfleet Enterprise Application Launch Management
# Centralized control of automatic app launches across fleet devices

# Configuration
LOG_FILE="/var/log/roundfleet_app_launch.log"
CONFIG_DIR="/etc/roundfleet/app_launch"
LAUNCH_AGENTS_DIR="/Library/LaunchAgents"
USER_LAUNCH_AGENTS_DIR="~/Library/LaunchAgents"
BACKUP_DIR="/var/backups/launch_agents"

# Application configuration database
declare -A ENTERPRISE_APPS=(
    ["productivity_suite"]="Slack,Microsoft Teams,Notion,1Password 7 - Password Manager"
    ["development_tools"]="Xcode,Terminal,Visual Studio Code,Docker Desktop"
    ["design_suite"]="Adobe Photoshop 2023,Sketch,Figma,Adobe Illustrator 2023"
    ["communication"]="Messages,Mail,Zoom,Microsoft Outlook"
    ["security_tools"]="Little Snitch 5,1Password 7 - Password Manager,Malwarebytes Anti-Malware"
)

# User profile configurations
declare -A USER_PROFILES=(
    ["developer"]="development_tools,communication,security_tools"
    ["designer"]="design_suite,communication,productivity_suite"
    ["manager"]="productivity_suite,communication"
    ["security"]="security_tools,communication,productivity_suite"
    ["default"]="communication"
)

# Logging function
log_action() {
    echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" | tee -a "$LOG_FILE"
}

# Create necessary directories
setup_directories() {
    for dir in "$CONFIG_DIR" "$BACKUP_DIR"; do
        if [[ ! -d "$dir" ]]; then
            mkdir -p "$dir"
            log_action "Created directory: $dir"
        fi
    done
}

# Validate application path and executable
validate_application() {
    local app_name="$1"
    local app_path=""
    
    log_action "Validating application: $app_name"
    
    # Common application paths to check
    local search_paths=(
        "/Applications"
        "/System/Applications"
        "/Applications/Utilities"
        "/System/Applications/Utilities"
    )
    
    # Find application
    for base_path in "${search_paths[@]}"; do
        local potential_path="${base_path}/${app_name}.app"
        if [[ -d "$potential_path" ]]; then
            app_path="$potential_path"
            break
        fi
    done
    
    if [[ -z "$app_path" ]]; then
        log_action "❌ Application not found: $app_name"
        return 1
    fi
    
    # Validate executable
    local executable_path="${app_path}/Contents/MacOS/${app_name}"
    if [[ ! -x "$executable_path" ]]; then
        # Try alternative executable name (some apps use different names)
        local info_plist="${app_path}/Contents/Info.plist"
        if [[ -f "$info_plist" ]]; then
            local bundle_executable
            bundle_executable=$(defaults read "$info_plist" CFBundleExecutable 2>/dev/null)
            if [[ -n "$bundle_executable" ]]; then
                executable_path="${app_path}/Contents/MacOS/${bundle_executable}"
            fi
        fi
        
        if [[ ! -x "$executable_path" ]]; then
            log_action "❌ Executable not found or not executable: $executable_path"
            return 1
        fi
    fi
    
    log_action "✅ Application validated: $app_name at $app_path"
    echo "$app_path"
    return 0
}

# Create LaunchAgent plist for application
create_launch_agent() {
    local app_name="$1"
    local app_path="$2"
    local user_specific="${3:-false}"
    local delay="${4:-0}"
    
    local plist_name="com.roundfleet.${app_name// /_}.plist"
    local target_dir="$LAUNCH_AGENTS_DIR"
    
    if [[ "$user_specific" == "true" ]]; then
        target_dir="$USER_LAUNCH_AGENTS_DIR"
    fi
    
    log_action "Creating LaunchAgent for: $app_name"
    
    # Get executable path
    local executable_path="${app_path}/Contents/MacOS/${app_name}"
    local info_plist="${app_path}/Contents/Info.plist"
    
    if [[ -f "$info_plist" ]]; then
        local bundle_executable
        bundle_executable=$(defaults read "$info_plist" CFBundleExecutable 2>/dev/null)
        if [[ -n "$bundle_executable" ]]; then
            executable_path="${app_path}/Contents/MacOS/${bundle_executable}"
        fi
    fi
    
    # Create plist content
    cat > "${target_dir}/${plist_name}" << EOF
<?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>${plist_name}</string>
    <key>Program</key>
    <string>${executable_path}</string>
    <key>RunAtLoad</key>
    <true/>
    <key>KeepAlive</key>
    <false/>
    <key>StandardErrorPath</key>
    <string>/var/log/roundfleet_$(echo "$app_name" | tr ' ' '_').error.log</string>
    <key>StandardOutPath</key>
    <string>/var/log/roundfleet_$(echo "$app_name" | tr ' ' '_').out.log</string>
EOF

    # Add delay if specified
    if [[ "$delay" -gt 0 ]]; then
        cat >> "${target_dir}/${plist_name}" << EOF
    <key>StartInterval</key>
    <integer>$delay</integer>
EOF
    fi
    
    # Add environment variables for enterprise apps
    cat >> "${target_dir}/${plist_name}" << EOF
    <key>EnvironmentVariables</key>
    <dict>
        <key>ROUNDFLEET_MANAGED</key>
        <string>true</string>
        <key>ENTERPRISE_MODE</key>
        <string>enabled</string>
    </dict>
</dict>
</plist>
EOF

    # Set proper permissions
    chmod 644 "${target_dir}/${plist_name}"
    
    log_action "✅ LaunchAgent created: ${plist_name}"
    return 0
}

# Remove LaunchAgent for application
remove_launch_agent() {
    local app_name="$1"
    local user_specific="${2:-false}"
    
    local plist_name="com.roundfleet.${app_name// /_}.plist"
    local target_dir="$LAUNCH_AGENTS_DIR"
    
    if [[ "$user_specific" == "true" ]]; then
        target_dir="$USER_LAUNCH_AGENTS_DIR"
    fi
    
    local plist_path="${target_dir}/${plist_name}"
    
    if [[ -f "$plist_path" ]]; then
        # Unload if loaded
        launchctl unload "$plist_path" 2>/dev/null || true
        
        # Remove file
        rm -f "$plist_path"
        log_action "✅ LaunchAgent removed: $plist_name"
        return 0
    else
        log_action "âš ī¸  LaunchAgent not found: $plist_name"
        return 1
    fi
}

# Deploy applications for user profile
deploy_user_profile() {
    local profile_name="$1"
    local username="${2:-$(whoami)}"
    
    log_action "Deploying user profile: $profile_name for user: $username"
    
    # Get profile configuration
    local profile_config="${USER_PROFILES[$profile_name]}"
    if [[ -z "$profile_config" ]]; then
        log_action "❌ Unknown user profile: $profile_name"
        return 1
    fi
    
    # Backup existing configuration
    backup_launch_agents
    
    local success_count=0
    local total_count=0
    local failed_apps=()
    
    # Process each app suite in profile
    IFS=',' read -ra SUITES <<< "$profile_config"
    for suite in "${SUITES[@]}"; do
        local suite_apps="${ENTERPRISE_APPS[$suite]}"
        if [[ -z "$suite_apps" ]]; then
            log_action "âš ī¸  Unknown app suite: $suite"
            continue
        fi
        
        # Process each app in suite
        IFS=',' read -ra APPS <<< "$suite_apps"
        for app in "${APPS[@]}"; do
            total_count=$((total_count + 1))
            
            # Validate and deploy app
            local app_path
            if app_path=$(validate_application "$app"); then
                if create_launch_agent "$app" "$app_path" false 0; then
                    success_count=$((success_count + 1))
                    log_action "✅ Deployed: $app"
                else
                    failed_apps+=("$app")
                fi
            else
                failed_apps+=("$app")
            fi
        done
    done
    
    # Generate deployment report
    generate_deployment_report "$profile_name" "$username" "$success_count" "$total_count" "${failed_apps[@]}"
    
    log_action "Profile deployment completed: $success_count/$total_count successful"
    return $((total_count - success_count))
}

# Backup existing LaunchAgents
backup_launch_agents() {
    local backup_timestamp
    backup_timestamp=$(date '+%Y%m%d_%H%M%S')
    local backup_file="$BACKUP_DIR/launch_agents_backup_$backup_timestamp.tar.gz"
    
    log_action "Creating LaunchAgents backup: $backup_file"
    
    if tar -czf "$backup_file" -C /Library LaunchAgents 2>/dev/null; then
        log_action "✅ Backup created: $backup_file"
        return 0
    else
        log_action "❌ Backup failed"
        return 1
    fi
}

# Generate deployment report
generate_deployment_report() {
    local profile_name="$1"
    local username="$2"
    local success_count="$3"
    local total_count="$4"
    shift 4
    local failed_apps=("$@")
    
    local report_file="$CONFIG_DIR/deployment_report_$(date '+%Y%m%d_%H%M%S').json"
    
    log_action "Generating deployment report: $report_file"
    
    cat > "$report_file" << EOF
{
    "deployment_metadata": {
        "timestamp": "$(date -Iseconds)",
        "profile_name": "$profile_name",
        "username": "$username",
        "hostname": "$(hostname)",
        "generator": "Roundfleet App Launch Manager"
    },
    "deployment_summary": {
        "total_applications": $total_count,
        "successful_deployments": $success_count,
        "failed_deployments": $((total_count - success_count)),
        "success_rate": $(awk "BEGIN {printf \"%.2f\", ($success_count/$total_count)*100}")
    },
    "failed_applications": [
EOF

    # Add failed apps
    local first=true
    for app in "${failed_apps[@]}"; do
        if [[ "$first" == true ]]; then
            first=false
        else
            echo "," >> "$report_file"
        fi
        echo "        \"$app\"" >> "$report_file"
    done
    
    cat >> "$report_file" << EOF
    ],
    "system_info": {
        "os_version": "$(sw_vers -productVersion)",
        "build_version": "$(sw_vers -buildVersion)",
        "serial_number": "$(system_profiler SPHardwareDataType | grep 'Serial Number' | awk '{print $4}')"
    }
}
EOF

    log_action "✅ Deployment report generated: $report_file"
    echo "$report_file"
}

# List all configured LaunchAgents
list_configured_apps() {
    log_action "Listing configured automatic launch applications"
    
    echo "=== Roundfleet Managed LaunchAgents ==="
    
    local agent_count=0
    for plist_file in "$LAUNCH_AGENTS_DIR"/com.roundfleet.*.plist; do
        if [[ -f "$plist_file" ]]; then
            local label
            local program
            label=$(defaults read "$plist_file" Label 2>/dev/null || echo "Unknown")
            program=$(defaults read "$plist_file" Program 2>/dev/null || echo "Unknown")
            
            echo "Label: $label"
            echo "Program: $program"
            echo "File: $plist_file"
            echo "---"
            
            agent_count=$((agent_count + 1))
        fi
    done
    
    echo "Total managed LaunchAgents: $agent_count"
}

# Validate all configured apps
validate_all_apps() {
    log_action "Validating all configured applications"
    
    local validation_report="$CONFIG_DIR/validation_report_$(date '+%Y%m%d_%H%M%S').json"
    local valid_count=0
    local invalid_count=0
    local invalid_apps=()
    
    cat > "$validation_report" << EOF
{
    "validation_timestamp": "$(date -Iseconds)",
    "hostname": "$(hostname)",
    "validation_results": [
EOF

    local first=true
    for plist_file in "$LAUNCH_AGENTS_DIR"/com.roundfleet.*.plist; do
        if [[ -f "$plist_file" ]]; then
            if [[ "$first" == true ]]; then
                first=false
            else
                echo "," >> "$validation_report"
            fi
            
            local label
            local program
            local exists="false"
            local executable="false"
            
            label=$(defaults read "$plist_file" Label 2>/dev/null || echo "Unknown")
            program=$(defaults read "$plist_file" Program 2>/dev/null || echo "Unknown")
            
            if [[ -f "$program" ]]; then
                exists="true"
                if [[ -x "$program" ]]; then
                    executable="true"
                    valid_count=$((valid_count + 1))
                else
                    invalid_count=$((invalid_count + 1))
                    invalid_apps+=("$label")
                fi
            else
                invalid_count=$((invalid_count + 1))
                invalid_apps+=("$label")
            fi
            
            cat >> "$validation_report" << EOF
        {
            "label": "$label",
            "program": "$program",
            "file_exists": $exists,
            "executable": $executable,
            "valid": $([ "$exists" = "true" ] && [ "$executable" = "true" ] && echo "true" || echo "false")
        }
EOF
        fi
    done
    
    cat >> "$validation_report" << EOF
    ],
    "validation_summary": {
        "total_agents": $((valid_count + invalid_count)),
        "valid_agents": $valid_count,
        "invalid_agents": $invalid_count
    }
}
EOF

    log_action "✅ Validation completed: $valid_count valid, $invalid_count invalid"
    log_action "Validation report: $validation_report"
    
    if [[ $invalid_count -gt 0 ]]; then
        log_action "Invalid applications found: ${invalid_apps[*]}"
    fi
    
    echo "$validation_report"
}

# Clean up invalid or orphaned LaunchAgents
cleanup_launch_agents() {
    log_action "Cleaning up invalid LaunchAgents"
    
    local cleanup_count=0
    local cleanup_report="$CONFIG_DIR/cleanup_report_$(date '+%Y%m%d_%H%M%S').txt"
    
    echo "Roundfleet LaunchAgent Cleanup Report" > "$cleanup_report"
    echo "Generated: $(date)" >> "$cleanup_report"
    echo "======================================" >> "$cleanup_report"
    
    for plist_file in "$LAUNCH_AGENTS_DIR"/com.roundfleet.*.plist; do
        if [[ -f "$plist_file" ]]; then
            local program
            program=$(defaults read "$plist_file" Program 2>/dev/null || echo "")
            
            if [[ -n "$program" ]] && [[ ! -x "$program" ]]; then
                local label
                label=$(defaults read "$plist_file" Label 2>/dev/null || echo "Unknown")
                
                log_action "Removing invalid LaunchAgent: $label"
                echo "Removed: $label ($program not found/executable)" >> "$cleanup_report"
                
                # Unload if loaded
                launchctl unload "$plist_file" 2>/dev/null || true
                
                # Remove file
                rm -f "$plist_file"
                cleanup_count=$((cleanup_count + 1))
            fi
        fi
    done
    
    echo "Total cleaned up: $cleanup_count" >> "$cleanup_report"
    log_action "✅ Cleanup completed: $cleanup_count agents removed"
    echo "$cleanup_report"
}

# Test application launch
test_app_launch() {
    local app_name="$1"
    local plist_name="com.roundfleet.${app_name// /_}.plist"
    local plist_path="$LAUNCH_AGENTS_DIR/$plist_name"
    
    if [[ ! -f "$plist_path" ]]; then
        log_action "❌ LaunchAgent not found: $plist_name"
        return 1
    fi
    
    log_action "Testing application launch: $app_name"
    
    # Load the LaunchAgent
    if launchctl load "$plist_path" 2>/dev/null; then
        log_action "✅ LaunchAgent loaded successfully"
        
        # Wait a moment and check if process is running
        sleep 2
        if pgrep -f "$app_name" >/dev/null; then
            log_action "✅ Application is running: $app_name"
            return 0
        else
            log_action "âš ī¸  Application may not have started properly"
            return 1
        fi
    else
        log_action "❌ Failed to load LaunchAgent"
        return 1
    fi
}

# Main execution function
main() {
    local action="${1:-list}"
    local profile_name="$2"
    local username="$3"
    
    log_action "=== Roundfleet App Launch Management Started ==="
    log_action "Action: $action"
    log_action "Profile: ${profile_name:-N/A}"
    log_action "User: ${username:-$(whoami)}"
    
    # Setup
    setup_directories
    
    case "$action" in
        "deploy")
            if [[ -z "$profile_name" ]]; then
                echo "Available profiles:"
                for profile in "${!USER_PROFILES[@]}"; do
                    echo "  - $profile: ${USER_PROFILES[$profile]}"
                done
                echo ""
                echo "Usage: $0 deploy <profile_name> [username]"
                exit 1
            fi
            deploy_user_profile "$profile_name" "$username"
            ;;
        "list")
            list_configured_apps
            ;;
        "validate")
            validate_all_apps
            ;;
        "cleanup")
            cleanup_launch_agents
            ;;
        "test")
            if [[ -z "$profile_name" ]]; then
                echo "Usage: $0 test <app_name>"
                exit 1
            fi
            test_app_launch "$profile_name"
            ;;
        "remove")
            if [[ -z "$profile_name" ]]; then
                echo "Usage: $0 remove <app_name>"
                exit 1
            fi
            remove_launch_agent "$profile_name"
            ;;
        "backup")
            backup_launch_agents
            ;;
        *)
            echo "Usage: $0 {deploy|list|validate|cleanup|test|remove|backup}"
            echo "  deploy   - Deploy user profile applications"
            echo "  list     - List configured LaunchAgents"
            echo "  validate - Validate all configured applications"
            echo "  cleanup  - Remove invalid LaunchAgents"
            echo "  test     - Test specific application launch"
            echo "  remove   - Remove specific LaunchAgent"
            echo "  backup   - Backup current LaunchAgents"
            exit 1
            ;;
    esac
    
    log_action "=== App launch management completed ==="
}

# Execute main function
main "$@"

Advanced LaunchAgent Configuration

Conditional App Launch

#!/bin/bash

# Create conditional LaunchAgent based on system state
create_conditional_launch_agent() {
    local app_name="$1"
    local app_path="$2"
    local condition="$3"  # network, power, time
    
    local plist_name="com.roundfleet.conditional.${app_name// /_}.plist"
    
    cat > "/Library/LaunchAgents/${plist_name}" << EOF
<?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>${plist_name}</string>
    <key>Program</key>
    <string>${app_path}/Contents/MacOS/${app_name}</string>
    <key>RunAtLoad</key>
    <true/>
EOF

    case "$condition" in
        "network")
            cat >> "/Library/LaunchAgents/${plist_name}" << EOF
    <key>KeepAlive</key>
    <dict>
        <key>NetworkState</key>
        <true/>
    </dict>
EOF
            ;;
        "power")
            cat >> "/Library/LaunchAgents/${plist_name}" << EOF
    <key>KeepAlive</key>
    <dict>
        <key>PowerManagement</key>
        <true/>
    </dict>
EOF
            ;;
        "time")
            cat >> "/Library/LaunchAgents/${plist_name}" << EOF
    <key>StartCalendarInterval</key>
    <dict>
        <key>Hour</key>
        <integer>9</integer>
        <key>Minute</key>
        <integer>0</integer>
    </dict>
EOF
            ;;
    esac
    
    cat >> "/Library/LaunchAgents/${plist_name}" << EOF
</dict>
</plist>
EOF

    echo "Conditional LaunchAgent created: $plist_name"
}

Resource-Aware App Launch

#!/bin/bash

# Create resource-aware LaunchAgent with throttling
create_resource_aware_agent() {
    local app_name="$1"
    local app_path="$2"
    local cpu_limit="$3"    # percentage
    local memory_limit="$4" # MB
    
    local plist_name="com.roundfleet.resource.${app_name// /_}.plist"
    
    cat > "/Library/LaunchAgents/${plist_name}" << EOF
<?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>${plist_name}</string>
    <key>Program</key>
    <string>${app_path}/Contents/MacOS/${app_name}</string>
    <key>RunAtLoad</key>
    <true/>
    <key>ThrottleInterval</key>
    <integer>60</integer>
    <key>SoftResourceLimits</key>
    <dict>
        <key>CPU</key>
        <integer>$cpu_limit</integer>
        <key>Mem</key>
        <integer>$((memory_limit * 1024 * 1024))</integer>
    </dict>
    <key>HardResourceLimits</key>
    <dict>
        <key>CPU</key>
        <integer>$((cpu_limit + 10))</integer>
        <key>Mem</key>
        <integer>$((memory_limit * 1024 * 1024 * 2))</integer>
    </dict>
</dict>
</plist>
EOF

    echo "Resource-aware LaunchAgent created: $plist_name"
}

User Profile Management

Dynamic Profile Assignment

#!/bin/bash

# Assign profile based on user attributes
assign_user_profile() {
    local username="$1"
    
    # Get user information
    local user_groups
    user_groups=$(groups "$username" 2>/dev/null)
    
    # Determine profile based on group membership
    if [[ "$user_groups" =~ developer|engineering ]]; then
        echo "developer"
    elif [[ "$user_groups" =~ design|creative ]]; then
        echo "designer"
    elif [[ "$user_groups" =~ manager|executive ]]; then
        echo "manager"
    elif [[ "$user_groups" =~ security|admin ]]; then
        echo "security"
    else
        echo "default"
    fi
}

# Auto-configure user on first login
auto_configure_user() {
    local username="$(whoami)"
    local assigned_profile
    assigned_profile=$(assign_user_profile "$username")
    
    echo "Auto-configuring user: $username"
    echo "Assigned profile: $assigned_profile"
    
    # Deploy profile
    deploy_user_profile "$assigned_profile" "$username"
}

Profile Templates

#!/bin/bash

# Create custom profile template
create_profile_template() {
    local template_name="$1"
    local template_file="$CONFIG_DIR/profiles/${template_name}.json"
    
    mkdir -p "$(dirname "$template_file")"
    
    cat > "$template_file" << EOF
{
    "profile_name": "$template_name",
    "description": "Custom profile template",
    "applications": [
        {
            "name": "Application Name",
            "path": "/Applications/App.app",
            "required": true,
            "delay": 0,
            "conditions": []
        }
    ],
    "settings": {
        "auto_update": true,
        "notifications": true,
        "logging": true
    }
}
EOF

    echo "Profile template created: $template_file"
}

Security and Validation

Application Security Verification

#!/bin/bash

# Verify application security before launch
verify_app_security() {
    local app_path="$1"
    
    echo "=== Application Security Verification ==="
    
    # Check code signature
    if codesign -v "$app_path" 2>/dev/null; then
        echo "✅ Code signature valid"
    else
        echo "❌ Code signature invalid or missing"
        return 1
    fi
    
    # Check notarization
    if spctl -a -v "$app_path" 2>/dev/null | grep -q "accepted"; then
        echo "✅ Application notarized"
    else
        echo "âš ī¸  Application not notarized"
    fi
    
    # Check quarantine attributes
    if xattr -l "$app_path" | grep -q "com.apple.quarantine"; then
        echo "âš ī¸  Application has quarantine attribute"
    else
        echo "✅ No quarantine attributes"
    fi
    
    # Check for suspicious characteristics
    local info_plist="${app_path}/Contents/Info.plist"
    if [[ -f "$info_plist" ]]; then
        local bundle_id
        bundle_id=$(defaults read "$info_plist" CFBundleIdentifier 2>/dev/null)
        echo "Bundle ID: $bundle_id"
        
        # Check for suspicious bundle identifiers
        if [[ "$bundle_id" =~ (malware|hack|crack) ]]; then
            echo "❌ Suspicious bundle identifier detected"
            return 1
        fi
    fi
    
    echo "✅ Security verification completed"
    return 0
}

Enterprise Compliance Checks

#!/bin/bash

# Check enterprise compliance requirements
check_enterprise_compliance() {
    local app_path="$1"
    
    echo "=== Enterprise Compliance Check ==="
    
    # Check if app is in approved list
    local approved_apps_file="/etc/roundfleet/approved_apps.txt"
    if [[ -f "$approved_apps_file" ]]; then
        local app_name
        app_name=$(basename "$app_path" .app)
        
        if grep -q "^$app_name$" "$approved_apps_file"; then
            echo "✅ Application is in approved list"
        else
            echo "❌ Application not in approved list"
            return 1
        fi
    fi
    
    # Check for enterprise certificates
    local cert_info
    cert_info=$(codesign -dv "$app_path" 2>&1)
    
    if echo "$cert_info" | grep -q "Developer ID\|Mac App Store"; then
        echo "✅ Valid developer certificate"
    else
        echo "âš ī¸  No valid developer certificate"
    fi
    
    return 0
}

Monitoring and Maintenance

Launch Success Monitoring

#!/bin/bash

# Monitor application launch success
monitor_launch_success() {
    local monitoring_log="/var/log/roundfleet_launch_monitoring.log"
    
    echo "=== Launch Success Monitoring ===" | tee -a "$monitoring_log"
    echo "Timestamp: $(date)" | tee -a "$monitoring_log"
    
    # Check each configured LaunchAgent
    for plist_file in "$LAUNCH_AGENTS_DIR"/com.roundfleet.*.plist; do
        if [[ -f "$plist_file" ]]; then
            local label
            local program
            label=$(defaults read "$plist_file" Label 2>/dev/null)
            program=$(defaults read "$plist_file" Program 2>/dev/null)
            
            # Check if application is running
            local app_name
            app_name=$(basename "$program")
            
            if pgrep -f "$app_name" >/dev/null; then
                echo "✅ $label: Running" | tee -a "$monitoring_log"
            else
                echo "❌ $label: Not running" | tee -a "$monitoring_log"
                
                # Try to restart
                launchctl unload "$plist_file" 2>/dev/null
                launchctl load "$plist_file" 2>/dev/null
                echo "🔄 Attempted restart for $label" | tee -a "$monitoring_log"
            fi
        fi
    done
}

Automated Maintenance

#!/bin/bash

# Setup automated maintenance
setup_maintenance_schedule() {
    local maintenance_script="/usr/local/bin/roundfleet_app_maintenance.sh"
    local launchd_plist="/Library/LaunchDaemons/com.roundfleet.app.maintenance.plist"
    
    # Create maintenance script
    cat > "$maintenance_script" << 'EOF'
#!/bin/bash
LOG_FILE="/var/log/roundfleet_app_maintenance.log"
exec > >(tee -a "$LOG_FILE") 2>&1

echo "$(date): Starting application maintenance"

# Validate all apps
/usr/local/bin/roundfleet_app_manager.sh validate

# Monitor launch success
monitor_launch_success

# Cleanup invalid agents
/usr/local/bin/roundfleet_app_manager.sh cleanup

echo "$(date): Application maintenance completed"
EOF

    chmod +x "$maintenance_script"
    
    # Create LaunchDaemon for scheduled maintenance
    cat > "$launchd_plist" << EOF
<?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>com.roundfleet.app.maintenance</string>
    <key>ProgramArguments</key>
    <array>
        <string>$maintenance_script</string>
    </array>
    <key>StartCalendarInterval</key>
    <dict>
        <key>Hour</key>
        <integer>2</integer>
        <key>Minute</key>
        <integer>0</integer>
    </dict>
    <key>RunAtLoad</key>
    <false/>
</dict>
</plist>
EOF

    # Load the LaunchDaemon
    sudo launchctl load "$launchd_plist"
    
    echo "Automated maintenance configured"
    echo "Script: $maintenance_script"
    echo "Schedule: Daily at 2:00 AM"
}

Best Practices

🚀 Performance Optimization

  • Stagger app launches to prevent resource contention
  • Use resource limits to prevent system overload
  • Monitor launch success and implement automatic restart
  • Validate applications before deployment

🔐 Security Guidelines

  • Verify code signatures before allowing automatic launch
  • Maintain approved app lists for enterprise compliance
  • Use secure paths and avoid user-writable locations
  • Regular security audits of configured applications

📋 Management Best Practices

  • Profile-based deployment for different user types
  • Centralized configuration management
  • Regular backup of LaunchAgent configurations
  • Automated monitoring and maintenance

🔍 Troubleshooting Tips

  • Check application paths and executables
  • Verify LaunchAgent syntax using plutil
  • Monitor system logs for launch errors
  • Test configurations before fleet deployment

Important Notes

  • LaunchAgents run per-user while LaunchDaemons run system-wide
  • Applications must be properly signed for enterprise deployment
  • Resource limits help prevent system performance issues
  • Regular validation ensures continued functionality
  • Backup configurations before making changes

Application Uninstall Management for macOS

Implement enterprise-grade application uninstall management across your Roundfleet deployment with automated lifecycle management, security validation, residual file cleanup, and comprehensive fleet-wide application removal. This tutorial provides solutions for maintaining clean system environments while ensuring secure and efficient application lifecycle management.

Understanding macOS Application Uninstall Management

macOS provides several methods for application removal:

  • Manual Drag-to-Trash - Standard user method via Finder
  • rm command - Command-line removal of application bundles
  • Third-party Uninstallers - Specialized tools for complete removal
  • MDM Uninstall Actions - Remote uninstall capabilities
  • Package Manager Tools - Homebrew, MacPorts uninstall commands

Basic Application Uninstall

Simple Application Removal

#!/bin/bash

# Basic app uninstall
sudo rm -rf /Applications/Opera.app

Core Uninstall Command Structure

#!/bin/bash

# Generic app uninstall template
sudo rm -rf /path/to/app/files

The rm command options:

  • -r - Removes the file hierarchy (recursive)
  • -f - Removes files without prompting for confirmation (force)

Enterprise Application Uninstall Management System

Comprehensive Application Lifecycle Tool

#!/bin/bash

# Roundfleet Enterprise Application Uninstall Management Tool
# Advanced application removal and lifecycle management

# Configuration
CONFIG_FILE="/etc/roundfleet/app_uninstall_policy.conf"
LOG_FILE="/var/log/roundfleet_app_uninstall.log"
QUARANTINE_DIR="/Library/Roundfleet/QuarantinedApps"
AUDIT_LOG="/var/log/roundfleet_app_audit.log"

# Create directories
mkdir -p "$(dirname "$CONFIG_FILE")" "$(dirname "$LOG_FILE")" "$QUARANTINE_DIR" "$(dirname "$AUDIT_LOG")"

# Default application uninstall policy
cat > "$CONFIG_FILE" 2>/dev/null << 'EOF' || true
# Roundfleet Enterprise Application Uninstall Management Policy
# Version: 2.0

# Uninstall Policy Enforcement
ENFORCE_UNINSTALL_POLICIES=true
SAFE_UNINSTALL_MODE=true
BACKUP_BEFORE_UNINSTALL=true
VERIFY_APP_SIGNATURES=true
PREVENT_SYSTEM_APP_REMOVAL=true

# Security and Safety
REQUIRE_ADMIN_APPROVAL=false
VALIDATE_APP_DEPENDENCIES=true
CHECK_RUNNING_PROCESSES=true
QUARANTINE_SUSPICIOUS_APPS=true
MALWARE_SCAN_ENABLED=true

# Cleanup and Maintenance
COMPLETE_CLEANUP_ENABLED=true
REMOVE_PREFERENCES=true
REMOVE_SUPPORT_FILES=true
REMOVE_CACHES=true
REMOVE_LOGS=true
CLEAN_LAUNCH_SERVICES=true

# Business Rules
BUSINESS_HOURS_RESTRICTION=true
BUSINESS_HOURS_START="09:00"
BUSINESS_HOURS_END="18:00"
CRITICAL_APP_PROTECTION=true
LICENSED_APP_TRACKING=true

# Notification and Communication
USER_NOTIFICATION_ENABLED=true
ADMIN_NOTIFICATION_ENABLED=true
SLACK_WEBHOOK_URL=""
EMAIL_NOTIFICATION_ENABLED=false

# Compliance and Audit
AUDIT_ALL_UNINSTALLS=true
COMPLIANCE_REPORTING=true
SOFTWARE_INVENTORY_UPDATE=true
LICENSE_TRACKING=true
SECURITY_INCIDENT_REPORTING=true

# Recovery and Rollback
BACKUP_RETENTION_DAYS=30
ROLLBACK_CAPABILITY=true
EMERGENCY_RECOVERY=true
EOF

# Source configuration
source "$CONFIG_FILE" 2>/dev/null || true

# Logging function
log_action() {
    echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" | tee -a "$LOG_FILE"
}

# Audit logging function
audit_log() {
    local action="$1"
    local app_name="$2"
    local result="$3"
    local details="$4"
    echo "$(date '+%Y-%m-%d %H:%M:%S') - ACTION:$action APP:$app_name RESULT:$result DETAILS:$details USER:$(whoami)" >> "$AUDIT_LOG"
}

# Get application information
get_app_info() {
    local app_path="$1"
    
    if [[ ! -d "$app_path" ]]; then
        echo "App not found: $app_path"
        return 1
    fi
    
    local app_name
    app_name=$(basename "$app_path")
    
    local bundle_id=""
    local version=""
    local signature_status=""
    
    # Get bundle identifier
    if [[ -f "$app_path/Contents/Info.plist" ]]; then
        bundle_id=$(defaults read "$app_path/Contents/Info.plist" CFBundleIdentifier 2>/dev/null || echo "unknown")
        version=$(defaults read "$app_path/Contents/Info.plist" CFBundleShortVersionString 2>/dev/null || echo "unknown")
    fi
    
    # Check code signature
    if command -v codesign >/dev/null 2>&1; then
        if codesign -v "$app_path" >/dev/null 2>&1; then
            signature_status="valid"
        else
            signature_status="invalid"
        fi
    else
        signature_status="unknown"
    fi
    
    echo "Name: $app_name"
    echo "Bundle ID: $bundle_id"
    echo "Version: $version"
    echo "Signature: $signature_status"
    echo "Path: $app_path"
}

# Check if application can be safely uninstalled
check_uninstall_safety() {
    local app_path="$1"
    local force="${2:-false}"
    
    echo "=== Validating Application Uninstall Safety ==="
    
    local app_name
    app_name=$(basename "$app_path")
    
    # Check if app exists
    if [[ ! -d "$app_path" ]]; then
        echo "✅ App not found (already uninstalled): $app_name"
        return 0
    fi
    
    # Prevent system app removal
    if [[ "$PREVENT_SYSTEM_APP_REMOVAL" == "true" ]]; then
        local system_apps=(
            "Activity Monitor.app"
            "Console.app"
            "Disk Utility.app"
            "Finder.app"
            "System Preferences.app"
            "Terminal.app"
            "Utilities"
        )
        
        for system_app in "${system_apps[@]}"; do
            if [[ "$app_name" == "$system_app" ]]; then
                echo "❌ Cannot uninstall system application: $app_name"
                audit_log "UNINSTALL_BLOCKED" "$app_name" "SYSTEM_APP" "System app protection active"
                return 1
            fi
        done
    fi
    
    # Check if app is currently running
    if [[ "$CHECK_RUNNING_PROCESSES" == "true" ]]; then
        local app_executable
        app_executable=$(basename "$app_name" .app)
        
        if pgrep -f "$app_executable" >/dev/null 2>&1; then
            echo "âš ī¸  Application is currently running: $app_name"
            
            if [[ "$force" != "true" ]]; then
                echo "❌ Uninstall blocked: Application is running. Use force option to terminate and uninstall."
                audit_log "UNINSTALL_BLOCKED" "$app_name" "RUNNING" "Application is currently running"
                return 1
            else
                echo "🚨 Force uninstall: Will terminate running application"
                pkill -f "$app_executable" 2>/dev/null || true
                sleep 2
            fi
        fi
    fi
    
    # Business hours check
    if [[ "$BUSINESS_HOURS_RESTRICTION" == "true" && "$force" != "true" ]]; then
        local current_hour
        current_hour=$(date +%H)
        local start_hour
        start_hour=$(echo "$BUSINESS_HOURS_START" | cut -d':' -f1)
        local end_hour
        end_hour=$(echo "$BUSINESS_HOURS_END" | cut -d':' -f1)
        
        if [[ $current_hour -ge $start_hour && $current_hour -lt $end_hour ]]; then
            echo "âš ī¸  Business hours restriction active ($BUSINESS_HOURS_START - $BUSINESS_HOURS_END)"
            
            # Check if it's a critical app
            if [[ "$CRITICAL_APP_PROTECTION" == "true" ]]; then
                echo "❌ Uninstall blocked during business hours for safety"
                audit_log "UNINSTALL_BLOCKED" "$app_name" "BUSINESS_HOURS" "Business hours protection active"
                return 1
            fi
        fi
    fi
    
    # Signature verification
    if [[ "$VERIFY_APP_SIGNATURES" == "true" ]]; then
        if ! codesign -v "$app_path" >/dev/null 2>&1; then
            echo "âš ī¸  Warning: Application has invalid or missing signature"
            
            if [[ "$QUARANTINE_SUSPICIOUS_APPS" == "true" ]]; then
                echo "🔒 Quarantining suspicious application before removal"
                quarantine_application "$app_path"
            fi
        fi
    fi
    
    echo "✅ Application uninstall safety validated"
    audit_log "SAFETY_CHECK" "$app_name" "PASSED" "All safety checks passed"
    return 0
}

# Create backup before uninstall
create_app_backup() {
    local app_path="$1"
    local app_name
    app_name=$(basename "$app_path")
    
    if [[ "$BACKUP_BEFORE_UNINSTALL" != "true" ]]; then
        return 0
    fi
    
    echo "=== Creating Application Backup ==="
    
    local backup_dir="/Library/Roundfleet/AppBackups"
    local backup_file="$backup_dir/${app_name%.*}_backup_$(date +%Y%m%d_%H%M%S).tar.gz"
    
    mkdir -p "$backup_dir"
    
    echo "Creating backup of $app_name..."
    if tar -czf "$backup_file" -C "$(dirname "$app_path")" "$(basename "$app_path")" 2>/dev/null; then
        echo "✅ Application backup created: $backup_file"
        log_action "Application backup created: $backup_file"
        
        # Set retention policy
        find "$backup_dir" -name "*_backup_*.tar.gz" -mtime +$BACKUP_RETENTION_DAYS -delete 2>/dev/null || true
        
        return 0
    else
        echo "âš ī¸  Application backup failed"
        log_action "WARNING: Application backup failed for $app_name"
        return 1
    fi
}

# Quarantine suspicious application
quarantine_application() {
    local app_path="$1"
    local app_name
    app_name=$(basename "$app_path")
    
    echo "=== Quarantining Suspicious Application ==="
    
    local quarantine_path="$QUARANTINE_DIR/$(date +%Y%m%d_%H%M%S)_$app_name"
    
    if mv "$app_path" "$quarantine_path" 2>/dev/null; then
        echo "🔒 Application quarantined: $quarantine_path"
        log_action "Application quarantined: $app_name -> $quarantine_path"
        audit_log "QUARANTINE" "$app_name" "SUCCESS" "Suspicious app quarantined"
        
        # Create quarantine record
        cat > "$quarantine_path.info" << EOF
{
  "original_path": "$app_path",
  "quarantine_time": "$(date -u +%Y-%m-%dT%H:%M:%SZ)",
  "reason": "suspicious_signature",
  "quarantined_by": "$(whoami)"
}
EOF
        
        return 0
    else
        echo "❌ Failed to quarantine application"
        return 1
    fi
}

# Find and remove application support files
cleanup_app_support_files() {
    local app_name="$1"
    local bundle_id="$2"
    
    if [[ "$COMPLETE_CLEANUP_ENABLED" != "true" ]]; then
        return 0
    fi
    
    echo "=== Cleaning Application Support Files ==="
    
    local cleanup_paths=()
    local app_base_name
    app_base_name=$(basename "$app_name" .app)
    
    # Common cleanup locations
    local common_locations=(
        "/Library/Application Support"
        "/Library/Caches"
        "/Library/Preferences"
        "/Library/Logs"
        "~/Library/Application Support"
        "~/Library/Caches"
        "~/Library/Preferences"
        "~/Library/Logs"
        "~/Library/Saved Application State"
    )
    
    for location in "${common_locations[@]}"; do
        # Expand tilde
        location="${location/#\~/$HOME}"
        
        if [[ -d "$location" ]]; then
            # Search by app name
            find "$location" -maxdepth 2 -name "*$app_base_name*" -type d 2>/dev/null | while read -r path; do
                if [[ -n "$path" ]]; then
                    cleanup_paths+=("$path")
                fi
            done
            
            # Search by bundle ID if available
            if [[ -n "$bundle_id" && "$bundle_id" != "unknown" ]]; then
                find "$location" -maxdepth 2 -name "*$bundle_id*" -type d 2>/dev/null | while read -r path; do
                    if [[ -n "$path" ]]; then
                        cleanup_paths+=("$path")
                    fi
                done
            fi
        fi
    done
    
    # Remove preference files
    if [[ "$REMOVE_PREFERENCES" == "true" && -n "$bundle_id" && "$bundle_id" != "unknown" ]]; then
        local pref_files=(
            "/Library/Preferences/$bundle_id.plist"
            "$HOME/Library/Preferences/$bundle_id.plist"
            "$HOME/Library/Preferences/ByHost/$bundle_id.*"
        )
        
        for pref_file in "${pref_files[@]}"; do
            if [[ -f "$pref_file" ]]; then
                rm -f "$pref_file" 2>/dev/null || true
                echo "đŸ—‘ī¸  Removed preference file: $pref_file"
            fi
        done
    fi
    
    # Clean up found support files
    local cleaned_count=0
    for path in "${cleanup_paths[@]}"; do
        if [[ -d "$path" ]]; then
            rm -rf "$path" 2>/dev/null || true
            echo "đŸ—‘ī¸  Removed support files: $path"
            ((cleaned_count++))
        fi
    done
    
    # Update Launch Services database
    if [[ "$CLEAN_LAUNCH_SERVICES" == "true" ]]; then
        echo "🔄 Updating Launch Services database..."
        /System/Library/Frameworks/CoreServices.framework/Frameworks/LaunchServices.framework/Support/lsregister -kill -r -domain local -domain system -domain user 2>/dev/null || true
    fi
    
    echo "✅ Cleanup completed: $cleaned_count support file locations removed"
    log_action "Application support files cleanup completed for $app_name ($cleaned_count locations)"
}

# Send uninstall notification
send_uninstall_notification() {
    local app_name="$1"
    local operation="$2"
    local result="$3"
    
    if [[ "$USER_NOTIFICATION_ENABLED" != "true" ]]; then
        return 0
    fi
    
    echo "=== Sending Uninstall Notifications ==="
    
    local notification_title="Roundfleet Application Management"
    local notification_message="Application $operation: $app_name ($result)"
    
    # Display notification to logged-in users
    local logged_users
    logged_users=$(who | awk '{print $1}' | sort -u)
    
    for user in $logged_users; do
        if [[ -n "$user" ]]; then
            sudo -u "$user" osascript -e "display notification \"$notification_message\" with title \"$notification_title\"" 2>/dev/null || true
            echo "📱 Notification sent to user: $user"
        fi
    done
    
    # Slack notification
    if [[ -n "$SLACK_WEBHOOK_URL" ]]; then
        local slack_payload="{\"text\":\"đŸ–Ĩī¸ *$(hostname)*: $notification_title\\n$notification_message\"}"
        curl -s -X POST -H 'Content-type: application/json' --data "$slack_payload" "$SLACK_WEBHOOK_URL" >/dev/null 2>&1 || true
        echo "đŸ“ĸ Slack notification sent"
    fi
    
    log_action "Uninstall notifications sent for $app_name ($operation - $result)"
}

# Enterprise application uninstall
enterprise_uninstall() {
    local app_path="$1"
    local force="${2:-false}"
    local skip_backup="${3:-false}"
    
    echo "=== Enterprise Application Uninstall ==="
    
    if [[ -z "$app_path" ]]; then
        echo "❌ Application path required"
        return 1
    fi
    
    local app_name
    app_name=$(basename "$app_path")
    
    # Get application information
    echo "Analyzing application: $app_name"
    local app_info
    app_info=$(get_app_info "$app_path")
    echo "$app_info"
    
    local bundle_id
    bundle_id=$(echo "$app_info" | grep "Bundle ID:" | cut -d':' -f2 | xargs)
    
    # Safety checks
    if ! check_uninstall_safety "$app_path" "$force"; then
        return 1
    fi
    
    # Create backup if enabled
    if [[ "$skip_backup" != "true" ]]; then
        create_app_backup "$app_path"
    fi
    
    log_action "ENTERPRISE UNINSTALL: Starting uninstall of $app_name"
    audit_log "UNINSTALL" "$app_name" "INITIATED" "Path: $app_path Bundle: $bundle_id Force: $force"
    
    # Perform the uninstall
    echo "đŸ—‘ī¸  Removing application bundle..."
    if sudo rm -rf "$app_path"; then
        echo "✅ Application bundle removed successfully"
        
        # Complete cleanup
        cleanup_app_support_files "$app_name" "$bundle_id"
        
        # Send notifications
        send_uninstall_notification "$app_name" "uninstall" "success"
        
        log_action "Application uninstalled successfully: $app_name"
        audit_log "UNINSTALL" "$app_name" "SUCCESS" "Complete removal including support files"
        
        return 0
    else
        echo "❌ Failed to remove application bundle"
        send_uninstall_notification "$app_name" "uninstall" "failed"
        log_action "FAILED: Could not remove application: $app_name"
        audit_log "UNINSTALL" "$app_name" "FAILED" "Bundle removal failed"
        return 1
    fi
}

# Bulk application uninstall
bulk_uninstall() {
    local app_list_file="$1"
    local force="${2:-false}"
    
    echo "=== Bulk Application Uninstall ==="
    
    if [[ ! -f "$app_list_file" ]]; then
        echo "❌ Application list file not found: $app_list_file"
        return 1
    fi
    
    local success_count=0
    local failure_count=0
    local total_count=0
    
    while IFS= read -r app_path; do
        # Skip empty lines and comments
        if [[ -z "$app_path" || "$app_path" == \#* ]]; then
            continue
        fi
        
        ((total_count++))
        echo "Processing ($total_count): $app_path"
        
        if enterprise_uninstall "$app_path" "$force" "false"; then
            ((success_count++))
        else
            ((failure_count++))
        fi
        
        echo "---"
    done < "$app_list_file"
    
    echo "=== Bulk Uninstall Summary ==="
    echo "Total applications: $total_count"
    echo "Successful uninstalls: $success_count"
    echo "Failed uninstalls: $failure_count"
    
    log_action "Bulk uninstall completed: $success_count/$total_count successful"
    audit_log "BULK_UNINSTALL" "MULTIPLE" "COMPLETED" "Success: $success_count Failed: $failure_count Total: $total_count"
}

# Malware application removal
remove_malware_app() {
    local app_path="$1"
    local threat_level="${2:-medium}"
    
    echo "🚨 MALWARE APPLICATION REMOVAL 🚨"
    
    local app_name
    app_name=$(basename "$app_path")
    
    log_action "MALWARE REMOVAL: Removing malicious application: $app_name (Threat: $threat_level)"
    audit_log "MALWARE_REMOVAL" "$app_name" "INITIATED" "Threat level: $threat_level"
    
    # Quarantine first for analysis
    if [[ "$threat_level" == "high" ]]; then
        echo "🔒 High threat level - quarantining for security analysis"
        quarantine_application "$app_path"
    else
        # Force removal without backup for malware
        echo "đŸ—‘ī¸  Performing emergency malware removal..."
        enterprise_uninstall "$app_path" "true" "true"
    fi
    
    # Security incident reporting
    if [[ "$SECURITY_INCIDENT_REPORTING" == "true" ]]; then
        local incident_file="/var/log/roundfleet_security_incidents.log"
        echo "$(date '+%Y-%m-%d %H:%M:%S') - MALWARE_REMOVAL: $app_name (Threat: $threat_level) User: $(whoami) Device: $(hostname)" >> "$incident_file"
    fi
    
    send_uninstall_notification "$app_name" "malware removal" "completed"
    audit_log "MALWARE_REMOVAL" "$app_name" "COMPLETED" "Emergency removal completed"
}

# List installed applications
list_applications() {
    local filter="$1"
    
    echo "=== Installed Applications ==="
    
    local app_list=()
    
    # Find all .app bundles
    while IFS= read -r -d '' app_path; do
        local app_name
        app_name=$(basename "$app_path")
        
        if [[ -n "$filter" ]]; then
            if [[ "$app_name" == *"$filter"* ]]; then
                app_list+=("$app_path")
            fi
        else
            app_list+=("$app_path")
        fi
    done < <(find /Applications -name "*.app" -type d -print0 2>/dev/null)
    
    # Sort and display
    printf '%s\n' "${app_list[@]}" | sort
    
    echo "Total applications found: ${#app_list[@]}"
}

# Generate uninstall report
generate_uninstall_report() {
    local report_file="/Library/Roundfleet/Reports/app_uninstall_report_$(date +%Y%m%d_%H%M%S).json"
    
    echo "=== Generating Application Uninstall Report ==="
    
    mkdir -p "$(dirname "$report_file")"
    
    # Count recent operations from audit log
    local recent_uninstalls=0
    local recent_quarantines=0
    local recent_malware_removals=0
    
    if [[ -f "$AUDIT_LOG" ]]; then
        recent_uninstalls=$(grep -c "ACTION:UNINSTALL.*RESULT:SUCCESS" "$AUDIT_LOG" 2>/dev/null || echo 0)
        recent_quarantines=$(grep -c "ACTION:QUARANTINE" "$AUDIT_LOG" 2>/dev/null || echo 0)
        recent_malware_removals=$(grep -c "ACTION:MALWARE_REMOVAL" "$AUDIT_LOG" 2>/dev/null || echo 0)
    fi
    
    # Get current application count
    local total_apps
    total_apps=$(find /Applications -name "*.app" -type d 2>/dev/null | wc -l)
    
    # Create JSON report
    cat > "$report_file" << EOF
{
  "report_type": "application_uninstall_management",
  "timestamp": "$(date -u +%Y-%m-%dT%H:%M:%SZ)",
  "device_info": {
    "hostname": "$(hostname)",
    "os_version": "$(sw_vers -productVersion)",
    "serial_number": "$(system_profiler SPHardwareDataType | grep "Serial Number" | awk -F: '{print $2}' | xargs)"
  },
  "application_statistics": {
    "total_installed_applications": $total_apps,
    "recent_uninstalls": $recent_uninstalls,
    "quarantined_applications": $recent_quarantines,
    "malware_removals": $recent_malware_removals
  },
  "policy_configuration": {
    "safe_uninstall_mode": $SAFE_UNINSTALL_MODE,
    "backup_before_uninstall": $BACKUP_BEFORE_UNINSTALL,
    "complete_cleanup_enabled": $COMPLETE_CLEANUP_ENABLED,
    "business_hours_restriction": $BUSINESS_HOURS_RESTRICTION
  },
  "security_status": {
    "signature_verification": $VERIFY_APP_SIGNATURES,
    "quarantine_enabled": $QUARANTINE_SUSPICIOUS_APPS,
    "malware_scan_enabled": $MALWARE_SCAN_ENABLED,
    "security_incident_reporting": $SECURITY_INCIDENT_REPORTING
  }
}
EOF
    
    echo "Application uninstall report saved to: $report_file"
    log_action "Application uninstall management report generated: $report_file"
}

# Main function with argument handling
main() {
    log_action "=== Roundfleet Application Uninstall Management Tool Started ==="
    
    case "${1:-help}" in
        "uninstall")
            enterprise_uninstall "$2" "$3" "$4"
            ;;
        "bulk")
            bulk_uninstall "$2" "$3"
            ;;
        "malware")
            remove_malware_app "$2" "$3"
            ;;
        "list")
            list_applications "$2"
            ;;
        "info")
            get_app_info "$2"
            ;;
        "report")
            generate_uninstall_report
            ;;
        *)
            echo "Roundfleet Enterprise Application Uninstall Management Tool"
            echo "Usage: $0 [command] [options]"
            echo ""
            echo "Commands:"
            echo "  uninstall [app_path] [force] [skip_backup]  - Uninstall application with safety checks"
            echo "  bulk [list_file] [force]                    - Bulk uninstall from file list"
            echo "  malware [app_path] [threat_level]           - Remove malicious application"
            echo "  list [filter]                               - List installed applications"
            echo "  info [app_path]                             - Get application information"
            echo "  report                                      - Generate uninstall management report"
            echo ""
            echo "Examples:"
            echo "  $0 uninstall /Applications/Opera.app       - Safe uninstall with backup"
            echo "  $0 uninstall /Applications/App.app true    - Force uninstall (skip safety checks)"
            echo "  $0 bulk apps_to_remove.txt                 - Bulk uninstall from list"
            echo "  $0 malware /Applications/Malware.app high  - Emergency malware removal"
            echo "  $0 list Safari                             - List apps containing 'Safari'"
            ;;
    esac
    
    log_action "=== Application uninstall management operation completed ==="
}

# Execute main function
main "$@"

Advanced Application Management Features

Application Dependency Analysis

#!/bin/bash

# Check application dependencies before uninstall
check_app_dependencies() {
    local app_path="$1"
    local app_name
    app_name=$(basename "$app_path")
    
    echo "=== Analyzing Application Dependencies ==="
    
    # Check for shared frameworks
    local frameworks_dir="$app_path/Contents/Frameworks"
    if [[ -d "$frameworks_dir" ]]; then
        echo "đŸ“Ļ Found embedded frameworks:"
        ls -la "$frameworks_dir" | grep -v "^total" | awk '{print $9}' | grep -v "^$"
    fi
    
    # Check for plugins and extensions
    local plugins_dir="$app_path/Contents/PlugIns"
    if [[ -d "$plugins_dir" ]]; then
        echo "🔌 Found plugins/extensions:"
        find "$plugins_dir" -name "*.appex" -o -name "*.plugin" | while read -r plugin; do
            echo "  - $(basename "$plugin")"
        done
    fi
    
    # Check for launch agents/daemons
    local plist_locations=(
        "/Library/LaunchAgents"
        "/Library/LaunchDaemons"
        "$HOME/Library/LaunchAgents"
    )
    
    echo "🔄 Checking for launch services:"
    for location in "${plist_locations[@]}"; do
        if [[ -d "$location" ]]; then
            find "$location" -name "*.plist" | while read -r plist; do
                if grep -q "$app_name" "$plist" 2>/dev/null; then
                    echo "  - Found reference in: $(basename "$plist")"
                fi
            done
        fi
    done
}

# Create application removal checklist
create_removal_checklist() {
    local app_path="$1"
    local checklist_file="/tmp/app_removal_checklist_$(date +%Y%m%d_%H%M%S).txt"
    
    cat > "$checklist_file" << EOF
Application Removal Checklist
=============================
Application: $(basename "$app_path")
Date: $(date)
Operator: $(whoami)

Pre-Removal Checks:
[ ] Application is not currently running
[ ] No dependent applications identified
[ ] Backup created (if required)
[ ] User notification sent
[ ] Business hours compliance verified

Removal Steps:
[ ] Main application bundle removed
[ ] Preferences files cleaned
[ ] Support files removed
[ ] Cache files cleared
[ ] Launch services updated
[ ] System integrity verified

Post-Removal Verification:
[ ] Application no longer appears in Applications folder
[ ] No residual files remain
[ ] System stability confirmed
[ ] License tracking updated
[ ] Audit log entry created

Notes:
_________________________________________________
_________________________________________________
_________________________________________________

Operator Signature: ________________________
Date Completed: ____________________________
EOF
    
    echo "Removal checklist created: $checklist_file"
}

Important Configuration Notes

macOS Application Structure Understanding

  • Application Bundles - .app directories containing executable and resources
  • Bundle Identifiers - Unique identifiers for application tracking
  • Code Signatures - Security validation for application authenticity
  • Support Files - Preferences, caches, logs in various Library locations

Enterprise Integration Points

  • Software Asset Management - Integration with SAM platforms
  • License Compliance - Tracking of licensed application removals
  • Security Information and Event Management (SIEM) - Security incident reporting
  • Change Management Systems - Documentation and approval workflows

Best Practices for Enterprise Application Management

  1. Safety and Validation

    • Always verify application signatures before removal
    • Check for running processes and dependencies
    • Implement business hours restrictions for critical applications
    • Maintain comprehensive audit trails
  2. Data Protection

    • Create backups before uninstallation when required
    • Preserve user data and preferences when appropriate
    • Implement quarantine procedures for suspicious applications
    • Follow data retention policies
  3. System Cleanliness

    • Remove all associated support files and preferences
    • Clean up caches and temporary files
    • Update Launch Services database after removal
    • Verify complete removal through system scans
  4. Security and Compliance

    • Track license compliance for removed applications
    • Report security incidents for malware removal
    • Maintain detailed audit logs for compliance
    • Implement role-based access controls

Troubleshooting Common Issues

  • Permission errors - Ensure admin privileges for application removal
  • Apps in use - Terminate running processes before uninstallation
  • Incomplete removal - Use comprehensive cleanup procedures
  • System apps - Implement protection against critical system app removal
  • Dependency conflicts - Analyze dependencies before bulk removals

Remember to test uninstallation procedures thoroughly in a controlled environment before implementing across your entire Roundfleet to ensure system stability and operational continuity.

Application Launch Management for macOS

Implement enterprise-grade application launch management across your Roundfleet deployment with automated app deployment, security validation, remote execution, and comprehensive fleet-wide application lifecycle management. This tutorial provides solutions for maintaining application availability while ensuring secure and efficient application launching.

Understanding macOS Application Launch Management

macOS provides several methods for application launching:

  • open - System command for opening files, directories, and applications
  • open -a - Launch applications by name
  • open -b - Launch applications by bundle identifier
  • Finder - GUI-based application launching
  • Spotlight - Search-based application launching

Basic Application Launch Operations

Simple Application Launch

#!/bin/bash

# Basic app launch
open -a "App name"

Launch by Bundle Identifier

#!/bin/bash

# Launch using bundle ID
open -b com.apple.AppStore

Background Application Launch

#!/bin/bash

# Launch app in background
open -g -a "App Store"

Multiple Instance Launch

#!/bin/bash

# Open new instance
open -n -a "App Store"

Hidden Application Launch

#!/bin/bash

# Launch app hidden
open -j -a "App Store"

Enterprise Application Launch Management System

#!/bin/bash

# Roundfleet Enterprise Application Launch Management Tool
# Advanced application deployment and lifecycle management

# Configuration
CONFIG_FILE="/etc/roundfleet/app_launch_policy.conf"
LOG_FILE="/var/log/roundfleet_app_launch.log"
APP_REGISTRY="/Library/Roundfleet/AppRegistry"
DEPLOYMENT_LOG="/var/log/roundfleet_deployment_audit.log"

# Create directories
mkdir -p "$(dirname "$CONFIG_FILE")" "$(dirname "$LOG_FILE")" "$APP_REGISTRY" "$(dirname "$DEPLOYMENT_LOG")"

# Default application launch management policy
cat > "$CONFIG_FILE" 2>/dev/null << 'EOF' || true
# Roundfleet Enterprise Application Launch Management Policy
# Version: 2.0

# Launch Policy Enforcement
ENFORCE_LAUNCH_POLICIES=true
VALIDATE_APP_SIGNATURES=true
CHECK_APP_PERMISSIONS=true
QUARANTINE_UNKNOWN_APPS=true
BUSINESS_HOURS_ENFORCEMENT=true

# Security and Validation
REQUIRE_ADMIN_APPROVAL=false
WHITELIST_ENFORCEMENT=true
MALWARE_SCANNING=true
SECURITY_ASSESSMENT=true
CERTIFICATE_VALIDATION=true

# Application Management
AUTO_UPDATE_DETECTION=true
LICENSE_VALIDATION=true
DEPENDENCY_CHECKING=true
RESOURCE_MONITORING=true
PERFORMANCE_TRACKING=true

# Deployment Controls
STAGED_DEPLOYMENT=true
ROLLBACK_CAPABILITY=true
A_B_TESTING=false
CANARY_RELEASES=false
EMERGENCY_DEPLOYMENT=true

# User Experience
USER_NOTIFICATION_ENABLED=true
LAUNCH_TIMEOUT=30
RETRY_ATTEMPTS=3
GRACEFUL_FAILURE=true
CONTEXT_AWARENESS=true

# Compliance and Audit
AUDIT_ALL_LAUNCHES=true
COMPLIANCE_REPORTING=true
LAUNCH_ANALYTICS=true
USAGE_TRACKING=true
INCIDENT_LOGGING=true
EOF

# Source configuration
source "$CONFIG_FILE" 2>/dev/null || true

# Logging function
log_action() {
    echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" | tee -a "$LOG_FILE"
}

# Audit logging function
audit_log() {
    local action="$1"
    local app_name="$2"
    local result="$3"
    local details="$4"
    echo "$(date '+%Y-%m-%d %H:%M:%S') - ACTION:$action APP:$app_name RESULT:$result DETAILS:$details USER:$(whoami)" >> "$DEPLOYMENT_LOG"
}

# Validate application before launch
validate_application() {
    local app_identifier="$1"
    local app_path=""
    
    echo "=== Application Validation ==="
    
    # Determine app path
    if [[ "$app_identifier" == *".app" ]]; then
        # Direct app name
        app_path="/Applications/$app_identifier"
    elif [[ "$app_identifier" == com.* ]]; then
        # Bundle identifier
        app_path=$(mdfind "kMDItemCFBundleIdentifier == '$app_identifier'" | head -1)
    else
        # Search for app
        app_path="/Applications/$app_identifier.app"
    fi
    
    if [[ ! -d "$app_path" ]]; then
        echo "❌ Application not found: $app_identifier"
        audit_log "VALIDATION" "$app_identifier" "NOT_FOUND" "Application path not found"
        return 1
    fi
    
    echo "✅ Application found: $app_path"
    
    # Validate code signature
    if [[ "$VALIDATE_APP_SIGNATURES" == "true" ]]; then
        echo "🔐 Validating code signature..."
        if codesign -v "$app_path" 2>/dev/null; then
            echo "✅ Code signature valid"
        else
            echo "❌ Invalid code signature"
            audit_log "VALIDATION" "$app_identifier" "SIGNATURE_INVALID" "Code signature validation failed"
            return 1
        fi
    fi
    
    # Check quarantine status
    if [[ "$QUARANTINE_UNKNOWN_APPS" == "true" ]]; then
        if xattr -l "$app_path" 2>/dev/null | grep -q "com.apple.quarantine"; then
            echo "âš ī¸  Application is quarantined"
            log_action "Quarantined application launch attempt: $app_identifier"
            audit_log "VALIDATION" "$app_identifier" "QUARANTINED" "Application under quarantine"
            return 1
        fi
    fi
    
    # Whitelist validation
    if [[ "$WHITELIST_ENFORCEMENT" == "true" ]]; then
        if ! check_whitelist "$app_identifier"; then
            echo "❌ Application not in whitelist"
            audit_log "VALIDATION" "$app_identifier" "NOT_WHITELISTED" "Application not in approved whitelist"
            return 1
        fi
    fi
    
    audit_log "VALIDATION" "$app_identifier" "PASSED" "All validation checks passed"
    return 0
}

# Check application whitelist
check_whitelist() {
    local app_identifier="$1"
    local whitelist_file="$APP_REGISTRY/whitelist.txt"
    
    if [[ ! -f "$whitelist_file" ]]; then
        # Create default whitelist
        cat > "$whitelist_file" << 'EOF'
# Roundfleet Approved Applications Whitelist
Safari
Google Chrome
Microsoft Word
Microsoft Excel
Microsoft PowerPoint
Slack
Microsoft Teams
Zoom
Finder
System Preferences
Activity Monitor
Terminal
TextEdit
Calculator
Calendar
Contacts
Mail
Notes
Reminders
Maps
App Store
com.apple.Safari
com.google.Chrome
com.microsoft.Word
com.microsoft.Excel
com.microsoft.PowerPoint
com.tinyspeck.slackmacgap
com.microsoft.teams
us.zoom.xos
com.apple.finder
com.apple.systempreferences
EOF
    fi
    
    # Check if app is in whitelist
    if grep -qi "^$app_identifier$" "$whitelist_file" 2>/dev/null; then
        return 0
    fi
    
    return 1
}

# Business hours enforcement
check_business_hours() {
    local app_identifier="$1"
    
    if [[ "$BUSINESS_HOURS_ENFORCEMENT" != "true" ]]; then
        return 0
    fi
    
    local current_hour
    current_hour=$(date +%H)
    local current_day
    current_day=$(date +%u)  # 1=Monday, 7=Sunday
    
    # Business hours: 9 AM to 6 PM, Monday to Friday
    if [[ $current_day -ge 1 && $current_day -le 5 ]]; then
        if [[ $current_hour -ge 9 && $current_hour -lt 18 ]]; then
            # During business hours - check restricted apps
            local restricted_apps=(
                "Steam"
                "Epic Games"
                "Discord"
                "Spotify"
                "Netflix"
                "YouTube"
            )
            
            for restricted_app in "${restricted_apps[@]}"; do
                if [[ "$app_identifier" == *"$restricted_app"* ]]; then
                    echo "âš ī¸  Application restricted during business hours: $app_identifier"
                    audit_log "BUSINESS_HOURS" "$app_identifier" "RESTRICTED" "Application blocked during business hours"
                    return 1
                fi
            done
        fi
    fi
    
    return 0
}

# Check application dependencies
check_dependencies() {
    local app_identifier="$1"
    
    if [[ "$DEPENDENCY_CHECKING" != "true" ]]; then
        return 0
    fi
    
    echo "=== Dependency Check ==="
    
    # Known dependencies
    case "$app_identifier" in
        *"Microsoft"*)
            if ! check_microsoft_office_license; then
                echo "❌ Microsoft Office license required"
                return 1
            fi
            ;;
        *"Adobe"*)
            if ! check_adobe_license; then
                echo "❌ Adobe license required"
                return 1
            fi
            ;;
        *"Xcode"*)
            if ! check_developer_tools; then
                echo "❌ Developer tools required"
                return 1
            fi
            ;;
    esac
    
    return 0
}

# Enterprise application launch with comprehensive management
enterprise_app_launch() {
    local app_identifier="$1"
    local options="${2:-}"
    local deployment_mode="${3:-standard}"
    
    echo "=== Enterprise Application Launch ==="
    
    if [[ -z "$app_identifier" ]]; then
        echo "❌ Application identifier required"
        return 1
    fi
    
    log_action "ENTERPRISE APP LAUNCH: Starting launch of $app_identifier"
    
    # Pre-launch validation
    if ! validate_application "$app_identifier"; then
        log_action "FAILED: Application validation failed for $app_identifier"
        return 1
    fi
    
    # Business hours check
    if ! check_business_hours "$app_identifier"; then
        log_action "BLOCKED: Business hours restriction for $app_identifier"
        return 1
    fi
    
    # Dependency verification
    if ! check_dependencies "$app_identifier"; then
        log_action "FAILED: Dependency check failed for $app_identifier"
        return 1
    fi
    
    # Resource availability check
    check_system_resources
    
    # Launch application based on type
    local launch_command=""
    local launch_result=""
    
    case "$deployment_mode" in
        "background")
            launch_command="open -g"
            ;;
        "hidden")
            launch_command="open -j"
            ;;
        "new-instance")
            launch_command="open -n"
            ;;
        *)
            launch_command="open"
            ;;
    esac
    
    # Determine launch method
    if [[ "$app_identifier" == com.* ]]; then
        # Bundle identifier
        echo "🚀 Launching by bundle identifier: $app_identifier"
        audit_log "LAUNCH" "$app_identifier" "BUNDLE_ID" "Launch by bundle identifier"
        
        timeout "$LAUNCH_TIMEOUT" $launch_command -b "$app_identifier" $options 2>/dev/null
        launch_result=$?
    else
        # Application name
        echo "🚀 Launching by application name: $app_identifier"
        audit_log "LAUNCH" "$app_identifier" "APP_NAME" "Launch by application name"
        
        timeout "$LAUNCH_TIMEOUT" $launch_command -a "$app_identifier" $options 2>/dev/null
        launch_result=$?
    fi
    
    # Handle launch result
    if [[ $launch_result -eq 0 ]]; then
        echo "✅ Application launched successfully: $app_identifier"
        post_launch_monitoring "$app_identifier"
        audit_log "LAUNCH" "$app_identifier" "SUCCESS" "Application launched successfully"
        
        # Update usage statistics
        update_usage_stats "$app_identifier"
        
        log_action "SUCCESS: Application launched successfully: $app_identifier"
        return 0
    else
        echo "❌ Failed to launch application: $app_identifier"
        
        # Retry logic
        if [[ "$RETRY_ATTEMPTS" -gt 0 ]]; then
            echo "🔄 Retrying launch..."
            retry_launch "$app_identifier" "$options" "$deployment_mode"
        fi
        
        audit_log "LAUNCH" "$app_identifier" "FAILED" "Application launch failed"
        log_action "FAILED: Could not launch application: $app_identifier"
        return 1
    fi
}

# Post-launch monitoring
post_launch_monitoring() {
    local app_identifier="$1"
    
    echo "=== Post-Launch Monitoring ==="
    
    sleep 5  # Allow app to fully launch
    
    # Check if application is running
    if pgrep -f "$app_identifier" >/dev/null 2>&1; then
        echo "✅ Application is running: $app_identifier"
        
        # Monitor resource usage
        local pid
        pid=$(pgrep -f "$app_identifier" | head -1)
        
        if [[ -n "$pid" ]]; then
            local cpu_usage
            local mem_usage
            cpu_usage=$(ps -p "$pid" -o pcpu= | xargs)
            mem_usage=$(ps -p "$pid" -o pmem= | xargs)
            
            echo "📊 Resource usage - CPU: ${cpu_usage}%, Memory: ${mem_usage}%"
            log_action "Post-launch monitoring: $app_identifier (PID: $pid, CPU: $cpu_usage%, Mem: $mem_usage%)"
        fi
    else
        echo "âš ī¸  Application not detected as running: $app_identifier"
        log_action "WARNING: Application launch successful but not detected running: $app_identifier"
    fi
}

# Bulk application deployment
bulk_app_deployment() {
    local app_list_file="$1"
    local deployment_mode="${2:-standard}"
    
    echo "=== Bulk Application Deployment ==="
    
    if [[ ! -f "$app_list_file" ]]; then
        echo "❌ Application list file not found: $app_list_file"
        return 1
    fi
    
    local success_count=0
    local failure_count=0
    local total_count=0
    
    while IFS= read -r app_line; do
        # Skip empty lines and comments
        if [[ -z "$app_line" || "$app_line" == \#* ]]; then
            continue
        fi
        
        # Parse app identifier and options
        local app_identifier
        local app_options
        read -r app_identifier app_options <<< "$app_line"
        
        ((total_count++))
        echo "Deploying ($total_count): $app_identifier"
        
        if enterprise_app_launch "$app_identifier" "$app_options" "$deployment_mode"; then
            ((success_count++))
        else
            ((failure_count++))
        fi
        
        echo "---"
        sleep 2  # Brief pause between deployments
    done < "$app_list_file"
    
    echo "=== Bulk Deployment Summary ==="
    echo "Total applications: $total_count"
    echo "Successful launches: $success_count"
    echo "Failed launches: $failure_count"
    
    log_action "Bulk deployment completed: $success_count/$total_count successful"
    audit_log "BULK_DEPLOYMENT" "MULTIPLE" "COMPLETED" "Success: $success_count Failed: $failure_count Total: $total_count"
}

# Application lifecycle management
manage_app_lifecycle() {
    local action="$1"
    local app_identifier="$2"
    
    case "$action" in
        "install")
            install_application "$app_identifier"
            ;;
        "update")
            update_application "$app_identifier"
            ;;
        "remove")
            remove_application "$app_identifier"
            ;;
        "status")
            check_app_status "$app_identifier"
            ;;
        *)
            echo "Invalid lifecycle action: $action"
            return 1
            ;;
    esac
}

# Check system resources before launch
check_system_resources() {
    echo "=== System Resource Check ==="
    
    # Check available memory
    local available_memory
    available_memory=$(vm_stat | grep "Pages free" | awk '{print $3}' | tr -d '.')
    available_memory=$((available_memory * 4096 / 1024 / 1024))  # Convert to MB
    
    echo "Available Memory: ${available_memory}MB"
    
    if [[ $available_memory -lt 512 ]]; then
        echo "âš ī¸  Low memory warning: ${available_memory}MB available"
        log_action "Low memory warning during app launch: ${available_memory}MB"
    fi
    
    # Check CPU load
    local load_average
    load_average=$(uptime | awk -F'load average:' '{print $2}' | awk '{print $1}' | tr -d ',')
    
    echo "System Load: $load_average"
    
    if (( $(echo "$load_average > 5.0" | bc -l) )); then
        echo "âš ī¸  High system load: $load_average"
        log_action "High system load during app launch: $load_average"
    fi
}

# Generate application deployment report
generate_deployment_report() {
    local report_file="/Library/Roundfleet/Reports/app_deployment_report_$(date +%Y%m%d_%H%M%S).json"
    
    echo "=== Generating Application Deployment Report ==="
    
    mkdir -p "$(dirname "$report_file")"
    
    # Count recent deployments from audit log
    local recent_launches=0
    local successful_launches=0
    local failed_launches=0
    
    if [[ -f "$DEPLOYMENT_LOG" ]]; then
        recent_launches=$(grep -c "ACTION:LAUNCH" "$DEPLOYMENT_LOG" 2>/dev/null || echo 0)
        successful_launches=$(grep -c "ACTION:LAUNCH.*RESULT:SUCCESS" "$DEPLOYMENT_LOG" 2>/dev/null || echo 0)
        failed_launches=$(grep -c "ACTION:LAUNCH.*RESULT:FAILED" "$DEPLOYMENT_LOG" 2>/dev/null || echo 0)
    fi
    
    # Get system information
    local total_apps
    total_apps=$(find /Applications -name "*.app" -maxdepth 1 | wc -l)
    
    cat > "$report_file" << EOF
{
  "report_type": "application_deployment",
  "timestamp": "$(date -u +%Y-%m-%dT%H:%M:%SZ)",
  "device_info": {
    "hostname": "$(hostname)",
    "os_version": "$(sw_vers -productVersion)",
    "serial_number": "$(system_profiler SPHardwareDataType | grep "Serial Number" | awk -F: '{print $2}' | xargs)"
  },
  "deployment_statistics": {
    "total_applications": $total_apps,
    "recent_launches": $recent_launches,
    "successful_launches": $successful_launches,
    "failed_launches": $failed_launches,
    "success_rate": "$(echo "scale=2; $successful_launches * 100 / ($successful_launches + $failed_launches + 1)" | bc)%"
  },
  "policy_configuration": {
    "whitelist_enforcement": $WHITELIST_ENFORCEMENT,
    "signature_validation": $VALIDATE_APP_SIGNATURES,
    "business_hours_enforcement": $BUSINESS_HOURS_ENFORCEMENT,
    "dependency_checking": $DEPENDENCY_CHECKING
  },
  "security_status": {
    "quarantine_protection": $QUARANTINE_UNKNOWN_APPS,
    "malware_scanning": $MALWARE_SCANNING,
    "certificate_validation": $CERTIFICATE_VALIDATION,
    "audit_enabled": $AUDIT_ALL_LAUNCHES
  }
}
EOF
    
    echo "Application deployment report saved to: $report_file"
    log_action "Deployment report generated: $report_file"
}

# Main function with argument handling
main() {
    log_action "=== Roundfleet Application Launch Management Tool Started ==="
    
    case "${1:-help}" in
        "launch")
            enterprise_app_launch "$2" "$3" "$4"
            ;;
        "bulk")
            bulk_app_deployment "$2" "$3"
            ;;
        "lifecycle")
            manage_app_lifecycle "$2" "$3"
            ;;
        "report")
            generate_deployment_report
            ;;
        *)
            echo "Roundfleet Enterprise Application Launch Management Tool"
            echo "Usage: $0 [command] [options]"
            echo ""
            echo "Commands:"
            echo "  launch [app_name/bundle_id] [options] [mode]  - Launch application with enterprise controls"
            echo "  bulk [list_file] [mode]                      - Bulk deployment from file list"
            echo "  lifecycle [action] [app_identifier]          - Manage application lifecycle"
            echo "  report                                       - Generate deployment report"
            echo ""
            echo "Launch Modes:"
            echo "  standard      - Normal application launch"
            echo "  background    - Launch in background"
            echo "  hidden        - Launch hidden"
            echo "  new-instance  - Force new instance"
            echo ""
            echo "Examples:"
            echo "  $0 launch \"Safari\"                         - Launch Safari normally"
            echo "  $0 launch com.apple.Safari \"\" background   - Launch Safari in background"
            echo "  $0 bulk essential_apps.txt                  - Deploy apps from list"
            echo "  $0 lifecycle status \"Microsoft Word\"       - Check Word installation status"
            ;;
    esac
    
    log_action "=== Application launch management operation completed ==="
}

# Execute main function
main "$@"

## Advanced Application Management Features

### Smart Application Deployment

```bash
#!/bin/bash

# Intelligent application deployment with machine learning
intelligent_deployment() {
    local app_identifier="$1"
    
    echo "=== Intelligent Application Deployment ==="
    
    # Analyze user patterns
    local usage_pattern
    usage_pattern=$(analyze_usage_patterns "$app_identifier")
    
    # Determine optimal launch strategy
    case "$usage_pattern" in
        "heavy_user")
            # Pre-launch for frequent users
            enterprise_app_launch "$app_identifier" "" "background"
            ;;
        "occasional_user")
            # Standard launch
            enterprise_app_launch "$app_identifier"
            ;;
        "new_user")
            # Guided launch with tutorial
            launch_with_guidance "$app_identifier"
            ;;
    esac
}

# Application health monitoring
monitor_app_health() {
    local app_identifier="$1"
    
    echo "=== Application Health Monitoring ==="
    
    # Check for crashes
    local crash_logs
    crash_logs=$(find ~/Library/Logs/DiagnosticReports -name "*$app_identifier*" -mtime -1 2>/dev/null | wc -l)
    
    if [[ $crash_logs -gt 0 ]]; then
        echo "âš ī¸  Recent crashes detected: $crash_logs"
        log_action "Application health alert: $app_identifier has $crash_logs recent crashes"
    fi
    
    # Performance monitoring
    local pid
    pid=$(pgrep -f "$app_identifier" | head -1)
    
    if [[ -n "$pid" ]]; then
        local memory_pressure
        memory_pressure=$(ps -p "$pid" -o pmem= | xargs)
        
        if (( $(echo "$memory_pressure > 10.0" | bc -l) )); then
            echo "âš ī¸  High memory usage: ${memory_pressure}%"
            log_action "Performance alert: $app_identifier using ${memory_pressure}% memory"
        fi
    fi
}

## Important Configuration Notes

### macOS Application Launch Commands

- **`open -a`** - Launch by application name
- **`open -b`** - Launch by bundle identifier  
- **`open -g`** - Launch in background
- **`open -n`** - Open new instance
- **`open -j`** - Launch hidden

### Enterprise Integration Points

- **Application Catalog Management** - Centralized app repository
- **License Management Systems** - Automated license validation
- **Security Platforms** - Integration with endpoint protection
- **Performance Monitoring** - APM platform integration

### Best Practices for Enterprise App Launch

1. **Security and Validation**
   - Validate code signatures before launching
   - Enforce application whitelists
   - Check for malware and quarantine status
   - Monitor for suspicious behavior

2. **User Experience**
   - Provide clear feedback on launch status
   - Implement intelligent pre-loading
   - Handle failures gracefully
   - Support offline scenarios

3. **Performance and Resources**
   - Monitor system resources before launch
   - Implement load balancing for resource-intensive apps
   - Track application performance metrics
   - Optimize launch sequences

Remember to test application launch procedures thoroughly in a controlled environment before implementing across your entire Roundfleet to ensure system stability and user productivity. 

Application Language Management on macOS

Manage application-specific language settings across your Roundfleet devices using command-line tools. This tutorial covers language discovery, individual app configuration, bulk management, and enterprise-wide language policy enforcement for international deployments.

Understanding macOS Language Management

macOS allows setting different languages for individual applications without changing the system language:

Language Configuration Levels

  • System Language - Overall macOS interface language
  • Application Language - Per-app language override
  • Regional Settings - Date, time, number, currency formats
  • Keyboard Input - Input method and layout preferences

Language Management Tools

  • defaults - Modify application preferences and language settings
  • languagesetup - Display available system languages
  • locale - Show current locale information
  • System Preferences - GUI language management interface

Language Discovery and Analysis

Discover Available Languages

#!/bin/bash

# Display all languages supported by the device
echo "🌍 Discovering available languages on device..."

# Get system supported languages
echo "=== System Supported Languages ==="
languagesetup

echo -e "\n=== Current Locale Information ==="
locale

echo -e "\n=== Available Language Codes ==="
ls /System/Library/CoreServices/SystemUIServer.app/Contents/Resources/*.lproj | \
    sed 's/.*\/\(.*\)\.lproj/\1/' | sort

echo "✅ Language discovery completed successfully"

Get Current System Language

#!/bin/bash

# Display current system and application language settings
echo "🔍 Analyzing current language configuration..."

# System language
echo "System Language: $(defaults read -g AppleLanguages | head -1 | tr -d '[:space:],"()')"

# Regional settings
echo "Region: $(defaults read -g AppleLocale)"

# Current user
CURRENT_USER=$(stat -f%Su /dev/console)
echo "Current User: $CURRENT_USER"

# Input sources
echo -e "\nInput Sources:"
defaults read com.apple.HIToolbox AppleEnabledInputSources | grep -E 'InputSourceKind|KeyboardLayout Name'

echo "✅ Language analysis completed"

Individual Application Language Management

Set Application Language

#!/bin/bash

# Set language for a specific application
APP_NAME="$1"
LANGUAGE_CODE="$2"

if [[ -z "$APP_NAME" || -z "$LANGUAGE_CODE" ]]; then
    echo "❌ Usage: $0 <AppName> <LanguageCode>"
    echo "Example: $0 Calendar de"
    echo "Example: $0 Safari fr"
    exit 1
fi

# Get current user
CURRENT_USER=$(stat -f%Su /dev/console)
echo "🌐 Setting language for $APP_NAME to $LANGUAGE_CODE"

# Validate language code
if ! languagesetup | grep -q "$LANGUAGE_CODE"; then
    echo "âš ī¸ Warning: Language code '$LANGUAGE_CODE' may not be supported"
fi

# Set application language
if sudo su "$CURRENT_USER" -c "defaults write -app '$APP_NAME' AppleLanguages -array '$LANGUAGE_CODE'"; then
    echo "✅ Language set successfully for $APP_NAME"
    echo "â„šī¸ Restart $APP_NAME to see changes"
else
    echo "❌ Failed to set language for $APP_NAME"
    exit 1
fi

Verify Application Language

#!/bin/bash

# Verify current language setting for an application
APP_NAME="$1"

if [[ -z "$APP_NAME" ]]; then
    echo "❌ Usage: $0 <AppName>"
    echo "Example: $0 Calendar"
    exit 1
fi

CURRENT_USER=$(stat -f%Su /dev/console)
echo "🔍 Checking language setting for $APP_NAME..."

# Read current language setting
CURRENT_LANG=$(sudo su "$CURRENT_USER" -c "defaults read -app '$APP_NAME' AppleLanguages 2>/dev/null" | head -1 | tr -d '[:space:],"()')

if [[ -n "$CURRENT_LANG" ]]; then
    echo "Current language for $APP_NAME: $CURRENT_LANG"
else
    echo "No specific language set for $APP_NAME (using system default)"
fi

Reset Application Language

#!/bin/bash

# Reset application language to system default
APP_NAME="$1"

if [[ -z "$APP_NAME" ]]; then
    echo "❌ Usage: $0 <AppName>"
    exit 1
fi

CURRENT_USER=$(stat -f%Su /dev/console)
echo "🔄 Resetting language for $APP_NAME to system default..."

# Delete application-specific language setting
if sudo su "$CURRENT_USER" -c "defaults delete -app '$APP_NAME' AppleLanguages 2>/dev/null"; then
    echo "✅ Language reset successfully for $APP_NAME"
else
    echo "â„šī¸ No custom language setting found for $APP_NAME"
fi

Bulk Language Management

Set Multiple Applications

#!/bin/bash

# Set language for multiple applications
LANGUAGE_CODE="$1"
shift
APPS=("$@")

if [[ -z "$LANGUAGE_CODE" || ${#APPS[@]} -eq 0 ]]; then
    echo "❌ Usage: $0 <LanguageCode> <App1> <App2> <App3>..."
    echo "Example: $0 fr Safari Calendar Mail"
    exit 1
fi

CURRENT_USER=$(stat -f%Su /dev/console)
echo "🌐 Setting language '$LANGUAGE_CODE' for ${#APPS[@]} applications..."

SUCCESS_COUNT=0
FAILED_APPS=()

for app in "${APPS[@]}"; do
    echo "Processing: $app"
    
    if sudo su "$CURRENT_USER" -c "defaults write -app '$app' AppleLanguages -array '$LANGUAGE_CODE'" 2>/dev/null; then
        echo "  ✅ Success: $app"
        ((SUCCESS_COUNT++))
    else
        echo "  ❌ Failed: $app"
        FAILED_APPS+=("$app")
    fi
done

echo -e "\n📊 Summary:"
echo "Successfully configured: $SUCCESS_COUNT applications"
echo "Failed: ${#FAILED_APPS[@]} applications"

if [[ ${#FAILED_APPS[@]} -gt 0 ]]; then
    echo "Failed applications: ${FAILED_APPS[*]}"
fi

Common Applications Language Setup

#!/bin/bash

# Set language for common macOS applications
LANGUAGE_CODE="$1"

if [[ -z "$LANGUAGE_CODE" ]]; then
    echo "❌ Usage: $0 <LanguageCode>"
    echo "Available codes: en, fr, de, es, it, ja, ko, zh-Hans, zh-Hant, etc."
    exit 1
fi

CURRENT_USER=$(stat -f%Su /dev/console)
echo "🌍 Configuring common applications for language: $LANGUAGE_CODE"

# Define common applications
COMMON_APPS=(
    "Safari"
    "Mail"
    "Calendar"
    "Contacts"
    "Notes"
    "Reminders"
    "Pages"
    "Numbers"
    "Keynote"
    "TextEdit"
    "Preview"
    "Finder"
    "System Preferences"
)

SUCCESS_COUNT=0
CONFIGURED_APPS=()

echo "Configuring ${#COMMON_APPS[@]} common applications..."

for app in "${COMMON_APPS[@]}"; do
    echo -n "  $app: "
    
    if sudo su "$CURRENT_USER" -c "defaults write -app '$app' AppleLanguages -array '$LANGUAGE_CODE'" 2>/dev/null; then
        echo "✅"
        CONFIGURED_APPS+=("$app")
        ((SUCCESS_COUNT++))
    else
        echo "❌"
    fi
done

echo -e "\n📊 Configuration Summary:"
echo "Successfully configured: $SUCCESS_COUNT applications"
echo "Applications configured: ${CONFIGURED_APPS[*]}"

Enterprise Language Management Script

#!/bin/bash

# Roundfleet Application Language Management Tool
# Comprehensive language management for enterprise environments

# Configuration
LOG_FILE="/var/log/roundfleet_language.log"
BACKUP_DIR="/var/backups/roundfleet/language"
REPORT_DIR="/var/reports/roundfleet/language"
CONFIG_FILE="/etc/roundfleet/language_policy.conf"

# Default language policy settings
DEFAULT_LANGUAGE="en"
ENFORCE_LANGUAGE_POLICY=false
ALLOWED_LANGUAGES=("en" "fr" "de" "es" "it" "ja" "ko" "zh-Hans" "zh-Hant")
RESTRICTED_APPS=()

# Logging function
log_action() {
    echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" | tee -a "$LOG_FILE"
}

# Setup directories
setup_directories() {
    for dir in "$BACKUP_DIR" "$REPORT_DIR" "$(dirname "$CONFIG_FILE")"; do
        if [[ ! -d "$dir" ]]; then
            sudo mkdir -p "$dir"
            log_action "Created directory: $dir"
        fi
    done
}

# Get current user
get_current_user() {
    stat -f%Su /dev/console
}

# Discover available languages
discover_languages() {
    echo "🌍 Discovering available languages..."
    
    {
        echo "=== System Language Discovery ==="
        echo "Date: $(date)"
        echo "Device: $(hostname)"
        echo ""
        
        echo "=== Available Languages ==="
        languagesetup
        echo ""
        
        echo "=== Current System Settings ==="
        echo "System Language: $(defaults read -g AppleLanguages | head -1 | tr -d '[:space:],"()')"
        echo "Region: $(defaults read -g AppleLocale)"
        echo "Currency: $(defaults read -g AppleCurrencies | head -1 | tr -d '[:space:],"()')"
        echo ""
        
        echo "=== Language Resource Directories ==="
        find /System/Library/CoreServices -name "*.lproj" -type d | head -20
        
    } > "$REPORT_DIR/language_discovery_$(date +%Y%m%d_%H%M%S).txt"
    
    log_action "Language discovery completed"
}

# Backup current language settings
backup_language_settings() {
    local backup_file="$BACKUP_DIR/language_backup_$(date +%Y%m%d_%H%M%S).txt"
    local current_user=$(get_current_user)
    
    echo "💾 Backing up current language settings..."
    
    {
        echo "=== Roundfleet Language Settings Backup ==="
        echo "Date: $(date)"
        echo "User: $current_user"
        echo "Device: $(hostname)"
        echo ""
        
        echo "=== System Language Settings ==="
        echo "AppleLanguages: $(defaults read -g AppleLanguages 2>/dev/null || echo 'Not set')"
        echo "AppleLocale: $(defaults read -g AppleLocale 2>/dev/null || echo 'Not set')"
        echo ""
        
        echo "=== Application-Specific Languages ==="
        
        # Get list of applications with custom language settings
        local apps_with_custom_lang=()
        
        # Check common applications
        local check_apps=(
            "Safari" "Mail" "Calendar" "Contacts" "Notes" "Reminders"
            "Pages" "Numbers" "Keynote" "TextEdit" "Preview" "Finder"
            "System Preferences" "Photos" "Music" "TV" "Books"
        )
        
        for app in "${check_apps[@]}"; do
            local app_lang
            app_lang=$(sudo su "$current_user" -c "defaults read -app '$app' AppleLanguages 2>/dev/null" | head -1 | tr -d '[:space:],"()')
            if [[ -n "$app_lang" ]]; then
                echo "$app: $app_lang"
                apps_with_custom_lang+=("$app")
            fi
        done
        
        if [[ ${#apps_with_custom_lang[@]} -eq 0 ]]; then
            echo "No applications with custom language settings found"
        fi
        
    } > "$backup_file"
    
    echo "✅ Backup saved to: $backup_file"
    log_action "Language settings backed up to: $backup_file"
}

# Generate language audit report
generate_language_report() {
    local report_file="$REPORT_DIR/language_audit_$(date +%Y%m%d_%H%M%S).txt"
    local current_user=$(get_current_user)
    
    echo "📊 Generating language audit report..."
    
    {
        echo "Roundfleet Language Audit Report"
        echo "Generated: $(date)"
        echo "Device: $(hostname)"
        echo "User: $current_user"
        echo "================================="
        echo ""
        
        echo "=== System Language Configuration ==="
        local sys_lang=$(defaults read -g AppleLanguages | head -1 | tr -d '[:space:],"()')
        echo "Primary Language: $sys_lang"
        echo "Region: $(defaults read -g AppleLocale)"
        echo "Currency: $(defaults read -g AppleCurrencies | head -1 | tr -d '[:space:],"()')"
        echo ""
        
        echo "=== Available Languages ==="
        languagesetup | grep -v "Language setup tool" | head -20
        echo ""
        
        echo "=== Application Language Audit ==="
        local total_apps=0
        local custom_lang_apps=0
        
        # Audit common applications
        local audit_apps=(
            "Safari" "Mail" "Calendar" "Contacts" "Notes" "Reminders"
            "Pages" "Numbers" "Keynote" "TextEdit" "Preview" "Finder"
            "System Preferences" "Photos" "Music" "TV" "Books" "Maps"
            "FaceTime" "Messages" "Calculator" "Clock mini" "Dictionary"
        )
        
        for app in "${audit_apps[@]}"; do
            ((total_apps++))
            local app_lang
            app_lang=$(sudo su "$current_user" -c "defaults read -app '$app' AppleLanguages 2>/dev/null" | head -1 | tr -d '[:space:],"()')
            
            if [[ -n "$app_lang" ]]; then
                echo "$app: $app_lang (custom)"
                ((custom_lang_apps++))
            else
                echo "$app: $sys_lang (system default)"
            fi
        done
        
        echo ""
        echo "=== Summary ==="
        echo "Total applications audited: $total_apps"
        echo "Applications with custom language: $custom_lang_apps"
        echo "Applications using system default: $((total_apps - custom_lang_apps))"
        
        # Check for compliance
        if [[ "$ENFORCE_LANGUAGE_POLICY" == "true" ]]; then
            echo ""
            echo "=== Policy Compliance ==="
            echo "Language policy enforcement: ENABLED"
            echo "Default required language: $DEFAULT_LANGUAGE"
            echo "Allowed languages: ${ALLOWED_LANGUAGES[*]}"
            
            local non_compliant_apps=()
            for app in "${audit_apps[@]}"; do
                local app_lang
                app_lang=$(sudo su "$current_user" -c "defaults read -app '$app' AppleLanguages 2>/dev/null" | head -1 | tr -d '[:space:],"()')
                
                if [[ -n "$app_lang" ]]; then
                    # Check if language is in allowed list
                    local is_allowed=false
                    for allowed_lang in "${ALLOWED_LANGUAGES[@]}"; do
                        if [[ "$app_lang" == "$allowed_lang" ]]; then
                            is_allowed=true
                            break
                        fi
                    done
                    
                    if [[ "$is_allowed" == "false" ]]; then
                        non_compliant_apps+=("$app:$app_lang")
                    fi
                fi
            done
            
            if [[ ${#non_compliant_apps[@]} -gt 0 ]]; then
                echo "Non-compliant applications:"
                for app_info in "${non_compliant_apps[@]}"; do
                    echo "  - ${app_info//:/ (language: }")"
                done
            else
                echo "All applications are compliant with language policy"
            fi
        fi
        
    } > "$report_file"
    
    echo "📊 Report saved to: $report_file"
    log_action "Language audit report generated: $report_file"
}

# Enforce language policy
enforce_language_policy() {
    local target_language="${1:-$DEFAULT_LANGUAGE}"
    local current_user=$(get_current_user)
    
    echo "🔒 Enforcing language policy: $target_language"
    log_action "Language policy enforcement started: $target_language"
    
    # Validate target language
    local is_allowed=false
    for allowed_lang in "${ALLOWED_LANGUAGES[@]}"; do
        if [[ "$target_language" == "$allowed_lang" ]]; then
            is_allowed=true
            break
        fi
    done
    
    if [[ "$is_allowed" == "false" ]]; then
        echo "❌ Language '$target_language' is not in the allowed languages list"
        echo "Allowed languages: ${ALLOWED_LANGUAGES[*]}"
        return 1
    fi
    
    # Applications to enforce policy on
    local enforce_apps=(
        "Safari" "Mail" "Calendar" "Contacts" "Notes" "Reminders"
        "Pages" "Numbers" "Keynote" "TextEdit" "Preview"
        "System Preferences" "Photos" "Music" "TV" "Books"
    )
    
    local success_count=0
    local failed_apps=()
    
    for app in "${enforce_apps[@]}"; do
        # Skip restricted apps
        local is_restricted=false
        for restricted_app in "${RESTRICTED_APPS[@]}"; do
            if [[ "$app" == "$restricted_app" ]]; then
                is_restricted=true
                break
            fi
        done
        
        if [[ "$is_restricted" == "true" ]]; then
            echo "  Skipping restricted app: $app"
            continue
        fi
        
        echo -n "  Configuring $app: "
        
        if sudo su "$current_user" -c "defaults write -app '$app' AppleLanguages -array '$target_language'" 2>/dev/null; then
            echo "✅"
            ((success_count++))
        else
            echo "❌"
            failed_apps+=("$app")
        fi
    done
    
    echo -e "\n📊 Policy Enforcement Summary:"
    echo "Successfully configured: $success_count applications"
    echo "Failed: ${#failed_apps[@]} applications"
    
    if [[ ${#failed_apps[@]} -gt 0 ]]; then
        echo "Failed applications: ${failed_apps[*]}"
    fi
    
    log_action "Language policy enforcement completed: $success_count successes, ${#failed_apps[@]} failures"
}

# Restore language settings from backup
restore_language_settings() {
    local backup_file="$1"
    local current_user=$(get_current_user)
    
    if [[ ! -f "$backup_file" ]]; then
        echo "❌ Backup file not found: $backup_file"
        return 1
    fi
    
    echo "🔄 Restoring language settings from backup..."
    log_action "Language settings restoration started from: $backup_file"
    
    # Parse backup file and restore settings
    local in_app_section=false
    local restored_count=0
    
    while IFS= read -r line; do
        if [[ "$line" == "=== Application-Specific Languages ===" ]]; then
            in_app_section=true
            continue
        fi
        
        if [[ "$in_app_section" == "true" && "$line" =~ ^([^:]+):[[:space:]]*(.+)$ ]]; then
            local app_name="${BASH_REMATCH[1]}"
            local app_lang="${BASH_REMATCH[2]}"
            
            if [[ "$app_lang" != "Not set" ]]; then
                echo -n "  Restoring $app_name to $app_lang: "
                
                if sudo su "$current_user" -c "defaults write -app '$app_name' AppleLanguages -array '$app_lang'" 2>/dev/null; then
                    echo "✅"
                    ((restored_count++))
                else
                    echo "❌"
                fi
            fi
        fi
    done < "$backup_file"
    
    echo -e "\n✅ Restoration completed: $restored_count applications restored"
    log_action "Language settings restoration completed: $restored_count applications"
}

# Main execution function
main() {
    local action="${1:-help}"
    local target="${2:-}"
    local apps_or_backup=("${@:3}")
    
    log_action "=== Roundfleet Language Management Started ==="
    
    setup_directories
    
    case "$action" in
        "discover"|"languages")
            discover_languages
            ;;
        "audit"|"report")
            generate_language_report
            ;;
        "backup")
            backup_language_settings
            ;;
        "restore")
            if [[ -n "$target" ]]; then
                restore_language_settings "$target"
            else
                echo "❌ Please specify backup file to restore from"
                echo "Usage: $0 restore <backup_file>"
            fi
            ;;
        "set")
            if [[ -n "$target" && ${#apps_or_backup[@]} -gt 0 ]]; then
                # Set language for specific apps
                local language_code="$target"
                local apps=("${apps_or_backup[@]}")
                local current_user=$(get_current_user)
                
                echo "🌐 Setting language '$language_code' for specified applications..."
                
                local success_count=0
                for app in "${apps[@]}"; do
                    echo -n "  $app: "
                    if sudo su "$current_user" -c "defaults write -app '$app' AppleLanguages -array '$language_code'" 2>/dev/null; then
                        echo "✅"
                        ((success_count++))
                    else
                        echo "❌"
                    fi
                done
                
                echo "✅ Configured $success_count applications"
            else
                echo "❌ Usage: $0 set <language_code> <app1> <app2> ..."
                echo "Example: $0 set fr Safari Mail Calendar"
            fi
            ;;
        "enforce")
            local target_lang="${target:-$DEFAULT_LANGUAGE}"
            enforce_language_policy "$target_lang"
            ;;
        "reset")
            if [[ -n "$target" ]]; then
                local current_user=$(get_current_user)
                echo "🔄 Resetting language for $target to system default..."
                
                if sudo su "$current_user" -c "defaults delete -app '$target' AppleLanguages" 2>/dev/null; then
                    echo "✅ Language reset for $target"
                else
                    echo "â„šī¸ No custom language setting found for $target"
                fi
            else
                echo "❌ Usage: $0 reset <app_name>"
            fi
            ;;
        "check")
            if [[ -n "$target" ]]; then
                local current_user=$(get_current_user)
                local app_lang
                app_lang=$(sudo su "$current_user" -c "defaults read -app '$target' AppleLanguages 2>/dev/null" | head -1 | tr -d '[:space:],"()')
                
                if [[ -n "$app_lang" ]]; then
                    echo "Language for $target: $app_lang"
                else
                    echo "No custom language set for $target (using system default)"
                fi
            else
                echo "❌ Usage: $0 check <app_name>"
            fi
            ;;
        "help"|*)
            echo "Roundfleet Application Language Management Tool"
            echo "Usage: $0 [action] [options]"
            echo ""
            echo "Actions:"
            echo "  discover              - Discover available languages on device"
            echo "  audit                 - Generate language audit report"
            echo "  backup                - Backup current language settings"
            echo "  restore <file>        - Restore language settings from backup"
            echo "  set <lang> <apps...>  - Set language for specific applications"
            echo "  enforce [language]    - Enforce language policy across applications"
            echo "  reset <app>           - Reset application to system default language"
            echo "  check <app>           - Check current language setting for application"
            echo "  help                  - Show this help message"
            echo ""
            echo "Language Codes:"
            echo "  en        - English"
            echo "  fr        - French"
            echo "  de        - German"
            echo "  es        - Spanish"
            echo "  it        - Italian"
            echo "  ja        - Japanese"
            echo "  ko        - Korean"
            echo "  zh-Hans   - Chinese (Simplified)"
            echo "  zh-Hant   - Chinese (Traditional)"
            ;;
    esac
    
    log_action "=== Roundfleet Language Management Completed ==="
}

# Execute main function
main "$@"

Language Code Reference

Common Language Codes

LanguageCodeRegion
EnglishenInternational
FrenchfrFrance
GermandeGermany
SpanishesSpain
ItalianitItaly
PortugueseptPortugal
Portuguese (Brazil)pt-BRBrazil
JapanesejaJapan
KoreankoKorea
Chinese (Simplified)zh-HansChina
Chinese (Traditional)zh-HantTaiwan/Hong Kong
RussianruRussia
ArabicarMiddle East
DutchnlNetherlands
SwedishsvSweden
NorwegiannoNorway
DanishdaDenmark
FinnishfiFinland

Regional Variants

# Common regional language codes
en-US    # English (United States)
en-GB    # English (United Kingdom)
en-CA    # English (Canada)
en-AU    # English (Australia)
fr-FR    # French (France)
fr-CA    # French (Canada)
de-DE    # German (Germany)
de-CH    # German (Switzerland)
es-ES    # Spanish (Spain)
es-MX    # Spanish (Mexico)

Application-Specific Examples

Popular macOS Applications

# Set French for productivity apps
./language_manager.sh set fr "Pages" "Numbers" "Keynote"

# Set German for communication apps
./language_manager.sh set de "Mail" "Messages" "FaceTime"

# Set Japanese for creative apps
./language_manager.sh set ja "Photos" "GarageBand" "iMovie"

# Set Spanish for system apps
./language_manager.sh set es "Calendar" "Contacts" "Reminders"

Enterprise Application Setup

# Configure Microsoft Office
defaults write -app "Microsoft Word" AppleLanguages -array "fr"
defaults write -app "Microsoft Excel" AppleLanguages -array "fr"
defaults write -app "Microsoft PowerPoint" AppleLanguages -array "fr"

# Configure Adobe Creative Suite
defaults write -app "Adobe Photoshop 2024" AppleLanguages -array "de"
defaults write -app "Adobe Illustrator 2024" AppleLanguages -array "de"
defaults write -app "Adobe InDesign 2024" AppleLanguages -array "de"

Language Policy Management

Enterprise Language Enforcement

# Create organization language policy
ORGANIZATION_LANGUAGE="en"
DEPARTMENT_LANGUAGES=("en" "fr" "de")  # Allowed languages

# Enforce across all standard applications
for app in Safari Mail Calendar Contacts Notes; do
    defaults write -app "$app" AppleLanguages -array "$ORGANIZATION_LANGUAGE"
done

Compliance Checking

# Check compliance with language policy
check_language_compliance() {
    local required_lang="$1"
    local non_compliant_apps=()
    
    for app in Safari Mail Calendar Contacts Notes Reminders; do
        local current_lang=$(defaults read -app "$app" AppleLanguages 2>/dev/null | head -1 | tr -d '[:space:],"()')
        
        if [[ -n "$current_lang" && "$current_lang" != "$required_lang" ]]; then
            non_compliant_apps+=("$app:$current_lang")
        fi
    done
    
    if [[ ${#non_compliant_apps[@]} -gt 0 ]]; then
        echo "âš ī¸ Non-compliant applications found:"
        printf '%s\n' "${non_compliant_apps[@]}"
        return 1
    else
        echo "✅ All applications comply with language policy"
        return 0
    fi
}

Troubleshooting

Common Issues

# Check if application exists
app_exists() {
    local app_name="$1"
    if mdfind "kMDItemKind == 'Application'" | grep -q "$app_name.app"; then
        return 0
    else
        echo "❌ Application '$app_name' not found"
        return 1
    fi
}

# Force application restart
restart_application() {
    local app_name="$1"
    echo "🔄 Restarting $app_name..."
    
    # Kill application if running
    pkill -f "$app_name" 2>/dev/null
    
    # Wait and relaunch
    sleep 2
    open -a "$app_name" 2>/dev/null
}

Language Setting Verification

# Verify language change took effect
verify_language_change() {
    local app_name="$1"
    local expected_lang="$2"
    
    local actual_lang=$(defaults read -app "$app_name" AppleLanguages 2>/dev/null | head -1 | tr -d '[:space:],"()')
    
    if [[ "$actual_lang" == "$expected_lang" ]]; then
        echo "✅ $app_name language verified: $expected_lang"
        return 0
    else
        echo "❌ $app_name language mismatch. Expected: $expected_lang, Actual: $actual_lang"
        return 1
    fi
}

Important Notes

  • Application Restart Required - Most applications need to be restarted to apply language changes
  • System vs App Languages - App-specific settings override system language
  • User Context - Language settings apply to the current user only
  • Backup Before Changes - Always backup current settings before bulk modifications
  • Test Individual Apps - Verify language changes work for specific applications
  • Regional Considerations - Some apps may require specific regional language codes