Tutorial

New updates and improvements to Macfleet.

Automatic App Launch Management on macOS

Streamline enterprise productivity by automatically launching essential applications on user login across your MacFleet 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.macfleet.${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/macfleet_${app_name}.error.log</string>
    <key>StandardOutPath</key>
    <string>/var/log/macfleet_${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

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

# Configuration
LOG_FILE="/var/log/macfleet_app_launch.log"
CONFIG_DIR="/etc/macfleet/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.macfleet.${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/macfleet_$(echo "$app_name" | tr ' ' '_').error.log</string>
    <key>StandardOutPath</key>
    <string>/var/log/macfleet_$(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>MACFLEET_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.macfleet.${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": "MacFleet 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 "=== MacFleet Managed LaunchAgents ==="
    
    local agent_count=0
    for plist_file in "$LAUNCH_AGENTS_DIR"/com.macfleet.*.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.macfleet.*.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 "MacFleet LaunchAgent Cleanup Report" > "$cleanup_report"
    echo "Generated: $(date)" >> "$cleanup_report"
    echo "======================================" >> "$cleanup_report"
    
    for plist_file in "$LAUNCH_AGENTS_DIR"/com.macfleet.*.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.macfleet.${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 "=== MacFleet 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.macfleet.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.macfleet.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/macfleet/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/macfleet_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.macfleet.*.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/macfleet_app_maintenance.sh"
    local launchd_plist="/Library/LaunchDaemons/com.macfleet.app.maintenance.plist"
    
    # Create maintenance script
    cat > "$maintenance_script" << 'EOF'
#!/bin/bash
LOG_FILE="/var/log/macfleet_app_maintenance.log"
exec > >(tee -a "$LOG_FILE") 2>&1

echo "$(date): Starting application maintenance"

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

# Monitor launch success
monitor_launch_success

# Cleanup invalid agents
/usr/local/bin/macfleet_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.macfleet.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 MacFleet 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

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

# Configuration
CONFIG_FILE="/etc/macfleet/app_uninstall_policy.conf"
LOG_FILE="/var/log/macfleet_app_uninstall.log"
QUARANTINE_DIR="/Library/MacFleet/QuarantinedApps"
AUDIT_LOG="/var/log/macfleet_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
# MacFleet 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/MacFleet/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="MacFleet 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/macfleet_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/MacFleet/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 "=== MacFleet 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 "MacFleet 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 MacFleet to ensure system stability and operational continuity.

Application Launch Management for macOS

Implement enterprise-grade application launch management across your MacFleet 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

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

# Configuration
CONFIG_FILE="/etc/macfleet/app_launch_policy.conf"
LOG_FILE="/var/log/macfleet_app_launch.log"
APP_REGISTRY="/Library/MacFleet/AppRegistry"
DEPLOYMENT_LOG="/var/log/macfleet_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
# MacFleet 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'
# MacFleet 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/MacFleet/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 "=== MacFleet 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 "MacFleet 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 MacFleet to ensure system stability and user productivity. 

Application Language Management on macOS

Manage application-specific language settings across your MacFleet 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

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

# Configuration
LOG_FILE="/var/log/macfleet_language.log"
BACKUP_DIR="/var/backups/macfleet/language"
REPORT_DIR="/var/reports/macfleet/language"
CONFIG_FILE="/etc/macfleet/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 "=== MacFleet 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 "MacFleet 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 "=== MacFleet 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 "MacFleet 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 "=== MacFleet 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

Application Force Close Management for macOS

Implement enterprise-grade application force close management across your MacFleet deployment with automated process termination, security validation, troubleshooting diagnostics, and comprehensive fleet-wide application control. This tutorial provides solutions for maintaining system stability while ensuring secure and efficient application process management.

Understanding macOS Application Process Management

macOS provides several methods for process termination:

  • killall - Terminate all instances of a named process
  • kill - Terminate specific processes by PID
  • pkill - Pattern-based process termination
  • Activity Monitor - GUI-based process management
  • Force Quit - System-level application termination

Basic Force Close Operations

Simple Force Close

#!/bin/bash

# Basic force close
killall "appname"

Force Close with Verbose Output

#!/bin/bash

# Force close with PID output
killall -v "Notes"

Detailed Process Information

#!/bin/bash

# Get detailed process info without killing
killall -d "appname"

List Available Signals

#!/bin/bash

# List available signals
killall -l "appname"

Force Close with Specific Signal

#!/bin/bash

# Force close with ABRT signal
killall -abrt "Pages"

Enterprise Application Force Close Management System

Comprehensive Process Control Tool

#!/bin/bash

# MacFleet Enterprise Application Force Close Management Tool
# Advanced process termination and application control

# Configuration
CONFIG_FILE="/etc/macfleet/force_close_policy.conf"
LOG_FILE="/var/log/macfleet_force_close.log"
QUARANTINE_DIR="/Library/MacFleet/TerminatedApps"
AUDIT_LOG="/var/log/macfleet_process_audit.log"

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

# Default force close management policy
cat > "$CONFIG_FILE" 2>/dev/null << 'EOF' || true
# MacFleet Enterprise Application Force Close Management Policy
# Version: 2.0

# Force Close Policy Enforcement
ENFORCE_FORCE_CLOSE_POLICIES=true
GRACEFUL_TERMINATION_FIRST=true
ESCALATION_TIMEOUT=10
SAVE_WORK_BEFORE_TERMINATION=true
PREVENT_SYSTEM_PROCESS_TERMINATION=true

# Security and Safety
REQUIRE_ADMIN_APPROVAL=false
VALIDATE_PROCESS_LEGITIMACY=true
CHECK_PROCESS_DEPENDENCIES=true
MALWARE_DETECTION_ENABLED=true
SUSPICIOUS_BEHAVIOR_MONITORING=true

# Business Rules
BUSINESS_HOURS_PROTECTION=true
BUSINESS_HOURS_START="09:00"
BUSINESS_HOURS_END="18:00"
CRITICAL_APP_PROTECTION=true
PRODUCTIVITY_APP_MONITORING=true

# Diagnostic and Troubleshooting
DIAGNOSTIC_LOGGING=true
CRASH_REPORT_COLLECTION=true
PERFORMANCE_MONITORING=true
RESOURCE_USAGE_TRACKING=true
HANG_DETECTION_ENABLED=true

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

# Compliance and Audit
AUDIT_ALL_TERMINATIONS=true
COMPLIANCE_REPORTING=true
INCIDENT_DOCUMENTATION=true
ESCALATION_PROCEDURES=true
AUTOMATED_RECOVERY=true

# Recovery and Restart
AUTO_RESTART_CRITICAL_APPS=true
RESTART_DELAY=5
CRASH_RECOVERY_ENABLED=true
STATE_PRESERVATION=true
USER_SESSION_PROTECTION=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 process_name="$2"
    local result="$3"
    local details="$4"
    echo "$(date '+%Y-%m-%d %H:%M:%S') - ACTION:$action PROCESS:$process_name RESULT:$result DETAILS:$details USER:$(whoami)" >> "$AUDIT_LOG"
}

# Get comprehensive process information
get_process_info() {
    local process_name="$1"
    
    echo "=== Process Information Analysis ==="
    
    # Check if process exists
    if ! pgrep -f "$process_name" >/dev/null 2>&1; then
        echo "Process not found: $process_name"
        return 1
    fi
    
    # Get process details
    echo "Process Name: $process_name"
    
    # Get PIDs
    local pids
    pids=$(pgrep -f "$process_name" | tr '\n' ' ')
    echo "Process IDs: $pids"
    
    # Get CPU and memory usage
    echo "Resource Usage:"
    ps -p $(pgrep -f "$process_name" | head -1) -o pid,pcpu,pmem,time,command 2>/dev/null | tail -1
    
    # Get process tree
    echo "Process Tree:"
    pstree $(pgrep -f "$process_name" | head -1) 2>/dev/null || echo "  Process tree not available"
    
    # Get open files
    echo "Open Files Count:"
    lsof -p $(pgrep -f "$process_name" | head -1) 2>/dev/null | wc -l || echo "  Unable to determine"
    
    # Get network connections
    echo "Network Connections:"
    lsof -i -p $(pgrep -f "$process_name" | head -1) 2>/dev/null | wc -l || echo "  0"
    
    # Check if process is hanging
    local cpu_usage
    cpu_usage=$(ps -p $(pgrep -f "$process_name" | head -1) -o pcpu= 2>/dev/null | xargs)
    if [[ -n "$cpu_usage" ]] && (( $(echo "$cpu_usage < 0.1" | bc -l) )); then
        echo "Status: Potentially hung (very low CPU usage)"
    else
        echo "Status: Active"
    fi
}

# Check if process termination is safe
check_termination_safety() {
    local process_name="$1"
    local force="${2:-false}"
    
    echo "=== Validating Process Termination Safety ==="
    
    # Check if process exists
    if ! pgrep -f "$process_name" >/dev/null 2>&1; then
        echo "✅ Process not running: $process_name"
        return 0
    fi
    
    # Prevent system process termination
    if [[ "$PREVENT_SYSTEM_PROCESS_TERMINATION" == "true" ]]; then
        local system_processes=(
            "kernel"
            "launchd"
            "WindowServer"
            "loginwindow"
            "SystemUIServer"
            "Dock"
            "Finder"
            "cfprefsd"
            "CoreServicesUIAgent"
        )
        
        for system_process in "${system_processes[@]}"; do
            if [[ "$process_name" == "$system_process" ]]; then
                echo "❌ Cannot terminate critical system process: $process_name"
                audit_log "TERMINATION_BLOCKED" "$process_name" "SYSTEM_PROCESS" "System process protection active"
                return 1
            fi
        done
    fi
    
    # Business hours protection for critical apps
    if [[ "$BUSINESS_HOURS_PROTECTION" == "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
            local critical_apps=(
                "Microsoft Word"
                "Microsoft Excel"
                "Microsoft PowerPoint"
                "Slack"
                "Microsoft Teams"
                "Zoom"
                "Safari"
                "Google Chrome"
            )
            
            for critical_app in "${critical_apps[@]}"; do
                if [[ "$process_name" == *"$critical_app"* ]]; then
                    echo "❌ Termination blocked: Critical productivity app during business hours"
                    audit_log "TERMINATION_BLOCKED" "$process_name" "BUSINESS_HOURS" "Critical app protection during business hours"
                    return 1
                fi
            done
        fi
    fi
    
    # Check for unsaved work
    if [[ "$SAVE_WORK_BEFORE_TERMINATION" == "true" ]]; then
        echo "⚠️  Checking for unsaved work..."
        
        # Check for document apps with potential unsaved changes
        local document_apps=(
            "TextEdit"
            "Pages"
            "Numbers"
            "Keynote"
            "Microsoft Word"
            "Microsoft Excel"
            "Microsoft PowerPoint"
        )
        
        for doc_app in "${document_apps[@]}"; do
            if [[ "$process_name" == *"$doc_app"* ]]; then
                echo "📝 Document application detected - attempting to save work"
                try_save_work "$process_name"
                break
            fi
        done
    fi
    
    # Check process dependencies
    if [[ "$CHECK_PROCESS_DEPENDENCIES" == "true" ]]; then
        local child_processes
        child_processes=$(pgrep -P $(pgrep -f "$process_name" | head -1) 2>/dev/null | wc -l)
        
        if [[ $child_processes -gt 0 ]]; then
            echo "⚠️  Process has $child_processes child processes"
            if [[ "$force" != "true" ]]; then
                echo "❌ Termination blocked: Process has dependencies. Use force option to proceed."
                audit_log "TERMINATION_BLOCKED" "$process_name" "DEPENDENCIES" "Process has $child_processes child processes"
                return 1
            fi
        fi
    fi
    
    echo "✅ Process termination safety validated"
    audit_log "SAFETY_CHECK" "$process_name" "PASSED" "All safety checks passed"
    return 0
}

# Try to save work in document applications
try_save_work() {
    local process_name="$1"
    
    echo "=== Attempting to Save Work ==="
    
    # Send save command via AppleScript for common applications
    local save_commands=(
        "osascript -e 'tell application \"System Events\" to keystroke \"s\" using command down'"
        "osascript -e 'tell application \"$process_name\" to save every document'"
    )
    
    for cmd in "${save_commands[@]}"; do
        eval "$cmd" 2>/dev/null || true
        sleep 1
    done
    
    # Wait a moment for save operations to complete
    sleep 3
    
    echo "💾 Save attempt completed"
    log_action "Work save attempt completed for $process_name"
}

# Detect suspicious or malware processes
detect_suspicious_process() {
    local process_name="$1"
    
    if [[ "$MALWARE_DETECTION_ENABLED" != "true" ]]; then
        return 0
    fi
    
    echo "=== Suspicious Process Detection ==="
    
    local suspicious_indicators=(
        "crypto"
        "miner"
        "trojan"
        "virus"
        "malware"
        "ransomware"
        "keylogger"
        "backdoor"
    )
    
    # Check process name for suspicious keywords
    for indicator in "${suspicious_indicators[@]}"; do
        if [[ "$process_name" == *"$indicator"* ]]; then
            echo "🚨 Suspicious process detected: $process_name (matches: $indicator)"
            log_action "SECURITY ALERT: Suspicious process detected: $process_name"
            audit_log "SUSPICIOUS_PROCESS" "$process_name" "DETECTED" "Matches indicator: $indicator"
            
            # Quarantine process information
            quarantine_process_info "$process_name"
            return 1
        fi
    done
    
    # Check for unusual resource consumption
    local cpu_usage
    cpu_usage=$(ps -p $(pgrep -f "$process_name" | head -1) -o pcpu= 2>/dev/null | xargs)
    
    if [[ -n "$cpu_usage" ]] && (( $(echo "$cpu_usage > 80" | bc -l) )); then
        echo "⚠️  High CPU usage detected: ${cpu_usage}%"
        log_action "High CPU usage detected for $process_name: ${cpu_usage}%"
    fi
    
    return 0
}

# Quarantine suspicious process information
quarantine_process_info() {
    local process_name="$1"
    
    echo "=== Quarantining Process Information ==="
    
    local quarantine_file="$QUARANTINE_DIR/suspicious_process_$(date +%Y%m%d_%H%M%S).json"
    
    mkdir -p "$QUARANTINE_DIR"
    
    # Gather comprehensive process information
    local pid
    pid=$(pgrep -f "$process_name" | head -1)
    
    cat > "$quarantine_file" << EOF
{
  "timestamp": "$(date -u +%Y-%m-%dT%H:%M:%SZ)",
  "process_name": "$process_name",
  "pid": "$pid",
  "detection_reason": "suspicious_indicators",
  "system_info": {
    "hostname": "$(hostname)",
    "user": "$(whoami)",
    "os_version": "$(sw_vers -productVersion)"
  },
  "process_details": {
    "command_line": "$(ps -p $pid -o command= 2>/dev/null || echo 'unknown')",
    "cpu_usage": "$(ps -p $pid -o pcpu= 2>/dev/null || echo 'unknown')",
    "memory_usage": "$(ps -p $pid -o pmem= 2>/dev/null || echo 'unknown')",
    "start_time": "$(ps -p $pid -o lstart= 2>/dev/null || echo 'unknown')"
  }
}
EOF
    
    echo "🔒 Process information quarantined: $quarantine_file"
    log_action "Suspicious process information quarantined: $quarantine_file"
}

# Send termination notification
send_termination_notification() {
    local process_name="$1"
    local operation="$2"
    local result="$3"
    local reason="$4"
    
    if [[ "$USER_NOTIFICATION_ENABLED" != "true" ]]; then
        return 0
    fi
    
    echo "=== Sending Termination Notifications ==="
    
    local notification_title="MacFleet Process Management"
    local notification_message="Process $operation: $process_name ($result)"
    
    if [[ -n "$reason" ]]; then
        notification_message="$notification_message - Reason: $reason"
    fi
    
    # 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 "Termination notifications sent for $process_name ($operation - $result)"
}

# Enterprise force close with escalation
enterprise_force_close() {
    local process_name="$1"
    local force="${2:-false}"
    local signal="${3:-TERM}"
    
    echo "=== Enterprise Force Close Initiated ==="
    
    if [[ -z "$process_name" ]]; then
        echo "❌ Process name required"
        return 1
    fi
    
    # Get process information
    echo "Analyzing process: $process_name"
    get_process_info "$process_name"
    
    # Detect suspicious processes
    if detect_suspicious_process "$process_name"; then
        echo "⚠️  Suspicious process detected - proceeding with caution"
    fi
    
    # Safety checks
    if ! check_termination_safety "$process_name" "$force"; then
        return 1
    fi
    
    log_action "ENTERPRISE FORCE CLOSE: Starting termination of $process_name"
    audit_log "FORCE_CLOSE" "$process_name" "INITIATED" "Signal: $signal Force: $force"
    
    # Graceful termination first (if enabled)
    if [[ "$GRACEFUL_TERMINATION_FIRST" == "true" && "$force" != "true" ]]; then
        echo "🔄 Attempting graceful termination first..."
        
        if killall -TERM "$process_name" 2>/dev/null; then
            echo "Graceful termination signal sent, waiting ${ESCALATION_TIMEOUT}s..."
            sleep "$ESCALATION_TIMEOUT"
            
            # Check if process is still running
            if ! pgrep -f "$process_name" >/dev/null 2>&1; then
                echo "✅ Process terminated gracefully"
                send_termination_notification "$process_name" "graceful termination" "success"
                audit_log "FORCE_CLOSE" "$process_name" "SUCCESS" "Graceful termination successful"
                return 0
            else
                echo "⚠️  Graceful termination failed, escalating to force termination"
            fi
        fi
    fi
    
    # Force termination
    echo "🚨 Executing force termination..."
    
    case "$signal" in
        "TERM")
            if killall "$process_name" 2>/dev/null; then
                echo "✅ Process force closed successfully with TERM signal"
                termination_result="success"
            else
                echo "❌ Failed to force close process with TERM signal"
                termination_result="failed"
            fi
            ;;
        "KILL")
            if killall -KILL "$process_name" 2>/dev/null; then
                echo "✅ Process force killed successfully with KILL signal"
                termination_result="success"
            else
                echo "❌ Failed to force kill process with KILL signal"
                termination_result="failed"
            fi
            ;;
        "ABRT")
            if killall -ABRT "$process_name" 2>/dev/null; then
                echo "✅ Process aborted successfully with ABRT signal"
                termination_result="success"
            else
                echo "❌ Failed to abort process with ABRT signal"
                termination_result="failed"
            fi
            ;;
        *)
            if killall -"$signal" "$process_name" 2>/dev/null; then
                echo "✅ Process terminated successfully with $signal signal"
                termination_result="success"
            else
                echo "❌ Failed to terminate process with $signal signal"
                termination_result="failed"
            fi
            ;;
    esac
    
    # Send notifications
    send_termination_notification "$process_name" "force close" "$termination_result" "Signal: $signal"
    
    # Auto-restart critical applications if configured
    if [[ "$AUTO_RESTART_CRITICAL_APPS" == "true" && "$termination_result" == "success" ]]; then
        restart_if_critical "$process_name"
    fi
    
    if [[ "$termination_result" == "success" ]]; then
        log_action "Process force closed successfully: $process_name"
        audit_log "FORCE_CLOSE" "$process_name" "SUCCESS" "Signal: $signal"
        return 0
    else
        log_action "FAILED: Could not force close process: $process_name"
        audit_log "FORCE_CLOSE" "$process_name" "FAILED" "Signal: $signal"
        return 1
    fi
}

# Restart critical applications
restart_if_critical() {
    local process_name="$1"
    
    local critical_apps=(
        "Finder"
        "Dock"
        "SystemUIServer"
        "Spotlight"
    )
    
    for critical_app in "${critical_apps[@]}"; do
        if [[ "$process_name" == *"$critical_app"* ]]; then
            echo "🔄 Restarting critical application: $critical_app"
            log_action "Auto-restarting critical application: $critical_app"
            
            sleep "$RESTART_DELAY"
            
            case "$critical_app" in
                "Finder")
                    open -a Finder &
                    ;;
                "Dock")
                    killall Dock &
                    ;;
                "SystemUIServer")
                    killall SystemUIServer &
                    ;;
                "Spotlight")
                    mdutil -E / &
                    ;;
            esac
            
            break
        fi
    done
}

# Bulk force close operations
bulk_force_close() {
    local process_list_file="$1"
    local force="${2:-false}"
    local signal="${3:-TERM}"
    
    echo "=== Bulk Force Close Operations ==="
    
    if [[ ! -f "$process_list_file" ]]; then
        echo "❌ Process list file not found: $process_list_file"
        return 1
    fi
    
    local success_count=0
    local failure_count=0
    local total_count=0
    
    while IFS= read -r process_name; do
        # Skip empty lines and comments
        if [[ -z "$process_name" || "$process_name" == \#* ]]; then
            continue
        fi
        
        ((total_count++))
        echo "Processing ($total_count): $process_name"
        
        if enterprise_force_close "$process_name" "$force" "$signal"; then
            ((success_count++))
        else
            ((failure_count++))
        fi
        
        echo "---"
        sleep 1  # Brief pause between operations
    done < "$process_list_file"
    
    echo "=== Bulk Force Close Summary ==="
    echo "Total processes: $total_count"
    echo "Successful terminations: $success_count"
    echo "Failed terminations: $failure_count"
    
    log_action "Bulk force close completed: $success_count/$total_count successful"
    audit_log "BULK_FORCE_CLOSE" "MULTIPLE" "COMPLETED" "Success: $success_count Failed: $failure_count Total: $total_count Signal: $signal"
}

# Hang detection and automatic recovery
detect_and_recover_hangs() {
    echo "=== Hang Detection and Recovery ==="
    
    if [[ "$HANG_DETECTION_ENABLED" != "true" ]]; then
        echo "Hang detection is disabled"
        return 0
    fi
    
    local hang_threshold=0.1  # CPU usage below this for extended time indicates hang
    local hang_duration=30    # Seconds of low activity to consider hung
    
    # Find processes with very low CPU usage
    local potentially_hung
    potentially_hung=$(ps -A -o pid,pcpu,time,command | awk -v threshold="$hang_threshold" '$2 < threshold && $2 > 0 {print $1 ":" $4}')
    
    if [[ -n "$potentially_hung" ]]; then
        echo "Potentially hung processes detected:"
        echo "$potentially_hung" | while IFS=':' read -r pid command; do
            echo "  PID $pid: $command"
            
            # Check if it's a user application (not system process)
            if [[ "$command" == *".app"* ]]; then
                local app_name
                app_name=$(basename "$command")
                echo "🔄 Attempting recovery of hung application: $app_name"
                
                log_action "Hang detected and recovery attempted: $app_name (PID: $pid)"
                audit_log "HANG_RECOVERY" "$app_name" "ATTEMPTED" "PID: $pid"
                
                # Try graceful recovery first
                kill -USR1 "$pid" 2>/dev/null || true
                sleep 5
                
                # If still hanging, force close
                if ps -p "$pid" >/dev/null 2>&1; then
                    enterprise_force_close "$app_name" "true" "TERM"
                fi
            fi
        done
    else
        echo "No hung processes detected"
    fi
}

# Generate comprehensive process management report
generate_process_report() {
    local report_file="/Library/MacFleet/Reports/process_management_report_$(date +%Y%m%d_%H%M%S).json"
    
    echo "=== Generating Process Management Report ==="
    
    mkdir -p "$(dirname "$report_file")"
    
    # Count recent operations from audit log
    local recent_terminations=0
    local recent_hangs=0
    local suspicious_processes=0
    
    if [[ -f "$AUDIT_LOG" ]]; then
        recent_terminations=$(grep -c "ACTION:FORCE_CLOSE.*RESULT:SUCCESS" "$AUDIT_LOG" 2>/dev/null || echo 0)
        recent_hangs=$(grep -c "ACTION:HANG_RECOVERY" "$AUDIT_LOG" 2>/dev/null || echo 0)
        suspicious_processes=$(grep -c "ACTION:SUSPICIOUS_PROCESS" "$AUDIT_LOG" 2>/dev/null || echo 0)
    fi
    
    # Get current system load
    local load_average
    load_average=$(uptime | awk -F'load average:' '{print $2}' | awk '{print $1}' | tr -d ',')
    
    # Count running processes
    local total_processes
    total_processes=$(ps -A | wc -l)
    
    # Create JSON report
    cat > "$report_file" << EOF
{
  "report_type": "process_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)"
  },
  "system_status": {
    "load_average": "$load_average",
    "total_processes": $total_processes,
    "recent_terminations": $recent_terminations,
    "hang_recoveries": $recent_hangs,
    "suspicious_processes_detected": $suspicious_processes
  },
  "policy_configuration": {
    "graceful_termination_first": $GRACEFUL_TERMINATION_FIRST,
    "business_hours_protection": $BUSINESS_HOURS_PROTECTION,
    "hang_detection_enabled": $HANG_DETECTION_ENABLED,
    "malware_detection_enabled": $MALWARE_DETECTION_ENABLED
  },
  "security_status": {
    "system_process_protection": $PREVENT_SYSTEM_PROCESS_TERMINATION,
    "suspicious_behavior_monitoring": $SUSPICIOUS_BEHAVIOR_MONITORING,
    "audit_enabled": $AUDIT_ALL_TERMINATIONS
  }
}
EOF
    
    echo "Process management report saved to: $report_file"
    log_action "Process management report generated: $report_file"
}

# Main function with argument handling
main() {
    log_action "=== MacFleet Process Management Tool Started ==="
    
    case "${1:-help}" in
        "close")
            enterprise_force_close "$2" "$3" "$4"
            ;;
        "bulk")
            bulk_force_close "$2" "$3" "$4"
            ;;
        "info")
            get_process_info "$2"
            ;;
        "detect-hangs")
            detect_and_recover_hangs
            ;;
        "report")
            generate_process_report
            ;;
        *)
            echo "MacFleet Enterprise Application Force Close Management Tool"
            echo "Usage: $0 [command] [options]"
            echo ""
            echo "Commands:"
            echo "  close [process_name] [force] [signal]    - Force close application with safety checks"
            echo "  bulk [list_file] [force] [signal]       - Bulk force close from file list"
            echo "  info [process_name]                     - Get detailed process information"
            echo "  detect-hangs                            - Detect and recover hung applications"
            echo "  report                                  - Generate process management report"
            echo ""
            echo "Signals:"
            echo "  TERM (default)  - Graceful termination signal"
            echo "  KILL           - Immediate termination (cannot be ignored)"
            echo "  ABRT           - Abort with core dump generation"
            echo "  HUP            - Hang up signal"
            echo "  INT            - Interrupt signal"
            echo ""
            echo "Examples:"
            echo "  $0 close \"Safari\"                      - Safe force close of Safari"
            echo "  $0 close \"Notes\" true KILL             - Force kill Notes (bypass safety)"
            echo "  $0 bulk hung_processes.txt              - Bulk close from list"
            echo "  $0 info \"Google Chrome\"                - Get Chrome process information"
            echo "  $0 detect-hangs                         - Scan for and recover hung apps"
            ;;
    esac
    
    log_action "=== Process management operation completed ==="
}

# Execute main function
main "$@"

## Advanced Process Management Features

### Intelligent Hang Detection

```bash
#!/bin/bash

# Advanced hang detection with machine learning patterns
detect_application_patterns() {
    local process_name="$1"
    
    echo "=== Application Behavior Pattern Analysis ==="
    
    # Monitor CPU and memory usage over time
    local cpu_samples=()
    local memory_samples=()
    
    for i in {1..10}; do
        local pid
        pid=$(pgrep -f "$process_name" | 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)
            
            cpu_samples+=("$cpu_usage")
            memory_samples+=("$mem_usage")
        fi
        
        sleep 2
    done
    
    # Analyze patterns
    local avg_cpu=0
    local cpu_variance=0
    
    for cpu in "${cpu_samples[@]}"; do
        avg_cpu=$(echo "$avg_cpu + $cpu" | bc -l)
    done
    avg_cpu=$(echo "scale=2; $avg_cpu / ${#cpu_samples[@]}" | bc -l)
    
    echo "Average CPU Usage: ${avg_cpu}%"
    
    # Detect hang patterns
    if (( $(echo "$avg_cpu < 0.5" | bc -l) )); then
        echo "🚨 Pattern indicates potential hang: Very low CPU activity"
        return 1
    elif (( $(echo "$avg_cpu > 90" | bc -l) )); then
        echo "🚨 Pattern indicates potential infinite loop: Sustained high CPU"
        return 1
    else
        echo "✅ Process behavior appears normal"
        return 0
    fi
}

# Resource leak detection
detect_resource_leaks() {
    local process_name="$1"
    
    echo "=== Resource Leak Detection ==="
    
    local pid
    pid=$(pgrep -f "$process_name" | head -1)
    
    if [[ -z "$pid" ]]; then
        echo "Process not found: $process_name"
        return 1
    fi
    
    # Check memory growth
    local initial_memory
    initial_memory=$(ps -p "$pid" -o rss= | xargs)
    
    sleep 60  # Monitor for 1 minute
    
    local final_memory
    final_memory=$(ps -p "$pid" -o rss= | xargs)
    
    local memory_growth
    memory_growth=$((final_memory - initial_memory))
    
    echo "Memory Growth: ${memory_growth} KB in 60 seconds"
    
    if [[ $memory_growth -gt 50000 ]]; then  # More than 50MB growth
        echo "🚨 Potential memory leak detected"
        log_action "Memory leak detected in $process_name: ${memory_growth}KB growth"
        return 1
    fi
    
    # Check file descriptor leaks
    local open_files
    open_files=$(lsof -p "$pid" 2>/dev/null | wc -l)
    
    echo "Open File Descriptors: $open_files"
    
    if [[ $open_files -gt 1000 ]]; then
        echo "🚨 Potential file descriptor leak detected"
        log_action "File descriptor leak detected in $process_name: $open_files open files"
        return 1
    fi
    
    echo "✅ No resource leaks detected"
    return 0
}

## Important Configuration Notes

### macOS Process Control Commands

- **`killall`** - Terminate all processes by name (case-sensitive)
- **`kill`** - Terminate specific process by PID
- **`pkill`** - Pattern-based process termination
- **Signals** - TERM (graceful), KILL (immediate), ABRT (with core dump)

### Enterprise Integration Points

- **Security Information and Event Management (SIEM)** - Process termination logging
- **Application Performance Monitoring** - Integration with APM platforms
- **Incident Management Systems** - Automated ticket creation for hangs
- **Change Management** - Documentation of process interventions

### Best Practices for Enterprise Process Management

1. **Safety and Validation**
   - Always attempt graceful termination before force killing
   - Protect critical system processes from accidental termination
   - Implement business hours restrictions for productivity applications
   - Maintain comprehensive audit trails

2. **User Experience**
   - Attempt to save user work before terminating applications
   - Provide clear notifications about process terminations
   - Auto-restart critical applications when possible
   - Minimize disruption during business hours

3. **Security and Monitoring**
   - Detect and quarantine suspicious processes
   - Monitor for unusual resource consumption patterns
   - Implement hang detection and automatic recovery
   - Track process behavior for security analysis

4. **Troubleshooting and Diagnostics**
   - Collect detailed process information before termination
   - Generate crash reports for analysis
   - Monitor system performance impact
   - Provide comprehensive reporting capabilities

### Troubleshooting Common Issues

- **Process won't terminate** - Escalate through signal hierarchy (TERM → KILL)
- **System stability issues** - Avoid terminating critical system processes
- **Data loss concerns** - Implement work-saving procedures before termination
- **Resource leaks** - Monitor memory and file descriptor usage
- **Hang detection false positives** - Tune detection thresholds based on application behavior

Remember to test process management procedures thoroughly in a controlled environment before implementing across your entire MacFleet to ensure system stability and user productivity.