Tutorial

New updates and improvements to Roundfleet.

Application Force Close Management for macOS

Implement enterprise-grade application force close management across your Roundfleet 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

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

# Configuration
CONFIG_FILE="/etc/roundfleet/force_close_policy.conf"
LOG_FILE="/var/log/roundfleet_force_close.log"
QUARANTINE_DIR="/Library/Roundfleet/TerminatedApps"
AUDIT_LOG="/var/log/roundfleet_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
# Roundfleet 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="Roundfleet 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/Roundfleet/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 "=== Roundfleet 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 "Roundfleet 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 Roundfleet to ensure system stability and user productivity. 

Apple ID Management and Identity Tracking on macOS

Manage Apple ID usage, monitor iCloud services, and implement enterprise identity policies across your Roundfleet devices. This tutorial covers Apple ID discovery, service monitoring, privacy compliance, and comprehensive identity management for enterprise environments.

Understanding Apple ID Integration on macOS

Apple ID integration provides access to various Apple services:

  • iCloud services - Storage, synchronization, and backup
  • Find My network - Device location and security features
  • App Store - Application downloads and updates
  • Apple Pay - Secure payment processing
  • Keychain - Password and credential synchronization

Basic Apple ID Detection

Simple Apple ID Discovery

#!/bin/bash

# Basic Apple ID detection for all users
check_apple_ids() {
    echo "=== Apple ID Detection ==="
    
    for user in $(dscl . list /Users UniqueID | awk '$2 >= 500 {print $1}'); do
        local userHome
        userHome=$(dscl . read /Users/"$user" NFSHomeDirectory | sed 's/NFSHomeDirectory://' | grep "/" | sed 's/^[ \t]*//')
        
        local appleid
        appleid=$(dscl . readpl "${userHome}" dsAttrTypeNative:LinkedIdentity appleid.apple.com:linked\ identities:0:full\ name 2>/dev/null | awk -F'full name: ' '{print $2}')
        
        if [[ "${appleid}" == "" ]]; then
            echo "👤 User: ${user} - No Apple ID signed in"
        else
            echo "🍎 User: ${user} - Apple ID: ${appleid}"
        fi
    done
}

# Usage
check_apple_ids

Enhanced Apple ID Information

#!/bin/bash

# Enhanced Apple ID detection with additional details
get_detailed_apple_id_info() {
    local username="$1"
    
    echo "=== Detailed Apple ID Information for: $username ==="
    
    # Get user home directory
    local userHome
    userHome=$(dscl . read /Users/"$username" NFSHomeDirectory | sed 's/NFSHomeDirectory://' | grep "/" | sed 's/^[ \t]*//')
    
    if [[ -z "$userHome" ]]; then
        echo "❌ User not found: $username"
        return 1
    fi
    
    # Check Apple ID
    local appleid
    appleid=$(dscl . readpl "${userHome}" dsAttrTypeNative:LinkedIdentity appleid.apple.com:linked\ identities:0:full\ name 2>/dev/null | awk -F'full name: ' '{print $2}')
    
    if [[ -n "$appleid" ]]; then
        echo "🍎 Apple ID: $appleid"
        
        # Check iCloud status
        local icloud_status
        if defaults read "${userHome}/Library/Preferences/MobileMeAccounts" Accounts &>/dev/null; then
            echo "☁️  iCloud: Configured"
        else
            echo "☁️  iCloud: Not configured"
        fi
        
        # Check Find My status
        if defaults read "${userHome}/Library/Preferences/com.apple.preferences.account" &>/dev/null; then
            echo "📍 Find My: Available"
        else
            echo "📍 Find My: Not available"
        fi
        
        # Check Keychain status
        if [[ -d "${userHome}/Library/Keychains" ]]; then
            local keychain_count
            keychain_count=$(find "${userHome}/Library/Keychains" -name "*.keychain*" | wc -l)
            echo "🔑 Keychains: $keychain_count found"
        fi
        
    else
        echo "❌ No Apple ID signed in"
    fi
}

# Usage example
# get_detailed_apple_id_info "john.doe"

Enterprise Apple ID Management System

#!/bin/bash

# Roundfleet Enterprise Apple ID Management System
# Comprehensive identity management, compliance tracking, and service monitoring

# Configuration
LOG_FILE="/var/log/roundfleet_apple_id.log"
CONFIG_DIR="/etc/roundfleet/identity"
REPORTS_DIR="$CONFIG_DIR/reports"
POLICIES_DIR="$CONFIG_DIR/policies"
BACKUP_DIR="/var/backups/identity_configs"

# Apple service configurations
declare -A APPLE_SERVICES=(
    ["icloud"]="com.apple.bird,com.apple.iCloudHelper,MobileMeAccounts"
    ["findmy"]="com.apple.icloud.findmydeviced,com.apple.FindMyMacHelper"
    ["appstore"]="com.apple.appstore,com.apple.CommerceKit"
    ["keychain"]="Security,Keychain"
    ["handoff"]="com.apple.coreservices.useractivityd"
)

# Privacy policy templates
declare -A PRIVACY_POLICIES=(
    ["strict"]="no_icloud,no_sync,audit_all"
    ["balanced"]="limited_icloud,controlled_sync,audit_sensitive"
    ["permissive"]="full_icloud,full_sync,audit_minimal"
    ["education"]="edu_icloud,student_sync,audit_compliance"
    ["enterprise"]="corp_icloud,enterprise_sync,audit_comprehensive"
)

# Compliance frameworks
declare -A COMPLIANCE_FRAMEWORKS=(
    ["hipaa"]="healthcare,strict_audit,encrypted_only"
    ["sox"]="financial,comprehensive_audit,controlled_access"
    ["gdpr"]="privacy_first,consent_required,data_minimization"
    ["ferpa"]="education,student_privacy,limited_sharing"
    ["corporate"]="business_use,managed_access,policy_enforcement"
)

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

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

# Comprehensive Apple ID discovery
discover_apple_ids() {
    log_action "Starting comprehensive Apple ID discovery"
    
    local discovery_report="$REPORTS_DIR/apple_id_discovery_$(date '+%Y%m%d_%H%M%S').json"
    
    cat > "$discovery_report" << EOF
{
    "discovery_metadata": {
        "timestamp": "$(date -Iseconds)",
        "hostname": "$(hostname)",
        "os_version": "$(sw_vers -productVersion)",
        "generator": "Roundfleet Apple ID Manager"
    },
    "user_accounts": [
EOF

    local first=true
    local total_users=0
    local signed_in_users=0
    
    # Process each user account
    for user in $(dscl . list /Users UniqueID | awk '$2 >= 500 {print $1}'); do
        total_users=$((total_users + 1))
        
        if [[ "$first" == true ]]; then
            first=false
        else
            echo "," >> "$discovery_report"
        fi
        
        local userHome uid gid realName
        userHome=$(dscl . read /Users/"$user" NFSHomeDirectory | sed 's/NFSHomeDirectory://' | grep "/" | sed 's/^[ \t]*//')
        uid=$(dscl . read /Users/"$user" UniqueID | awk '{print $2}')
        gid=$(dscl . read /Users/"$user" PrimaryGroupID | awk '{print $2}')
        realName=$(dscl . read /Users/"$user" RealName | sed 's/RealName://' | sed 's/^[ \t]*//' || echo "")
        
        # Get Apple ID information
        local appleid=""
        if [[ -n "$userHome" ]]; then
            appleid=$(dscl . readpl "${userHome}" dsAttrTypeNative:LinkedIdentity appleid.apple.com:linked\ identities:0:full\ name 2>/dev/null | awk -F'full name: ' '{print $2}')
        fi
        
        local apple_id_status="not_signed_in"
        if [[ -n "$appleid" ]]; then
            apple_id_status="signed_in"
            signed_in_users=$((signed_in_users + 1))
        fi
        
        # Check Apple services
        local services_status
        services_status=$(check_apple_services "$user" "$userHome")
        
        # Generate user record
        cat >> "$discovery_report" << EOF
        {
            "username": "$user",
            "real_name": "$realName",
            "uid": $uid,
            "gid": $gid,
            "home_directory": "$userHome",
            "apple_id_status": "$apple_id_status",
            "apple_id": "${appleid:-null}",
            "services": $services_status,
            "last_login": "$(last -1 "$user" | head -1 | awk '{print $4, $5, $6, $7}' || echo 'Never')",
            "account_created": "$(stat -f %SB -t %Y-%m-%d "$userHome" 2>/dev/null || echo 'Unknown')"
        }
EOF
        
        log_action "Processed user: $user (Apple ID: ${apple_id_status})"
    done
    
    cat >> "$discovery_report" << EOF
    ],
    "summary": {
        "total_users": $total_users,
        "users_with_apple_id": $signed_in_users,
        "users_without_apple_id": $((total_users - signed_in_users)),
        "apple_id_adoption_rate": $(awk "BEGIN {printf \"%.2f\", ($signed_in_users/$total_users)*100}")
    }
}
EOF

    log_action "✅ Apple ID discovery completed: $discovery_report"
    echo "$discovery_report"
}

# Check Apple services for a user
check_apple_services() {
    local username="$1"
    local userHome="$2"
    
    cat << EOF
{
    "icloud": {
        "enabled": $(check_icloud_status "$userHome"),
        "drive": $(check_icloud_drive "$userHome"),
        "photos": $(check_icloud_photos "$userHome"),
        "mail": $(check_icloud_mail "$userHome")
    },
    "find_my": {
        "enabled": $(check_findmy_status "$userHome"),
        "device_registered": $(check_findmy_device "$userHome")
    },
    "app_store": {
        "signed_in": $(check_appstore_status "$userHome"),
        "automatic_downloads": $(check_auto_downloads "$userHome")
    },
    "keychain": {
        "sync_enabled": $(check_keychain_sync "$userHome"),
        "keychain_count": $(count_keychains "$userHome")
    },
    "handoff": {
        "enabled": $(check_handoff_status "$userHome")
    }
}
EOF
}

# Individual service check functions
check_icloud_status() {
    local userHome="$1"
    if defaults read "${userHome}/Library/Preferences/MobileMeAccounts" Accounts &>/dev/null; then
        echo "true"
    else
        echo "false"
    fi
}

check_icloud_drive() {
    local userHome="$1"
    if [[ -d "${userHome}/Library/Mobile Documents/com~apple~CloudDocs" ]]; then
        echo "true"
    else
        echo "false"
    fi
}

check_icloud_photos() {
    local userHome="$1"
    if defaults read "${userHome}/Library/Preferences/com.apple.photoanalysisd" &>/dev/null; then
        echo "true"
    else
        echo "false"
    fi
}

check_icloud_mail() {
    local userHome="$1"
    if defaults read "${userHome}/Library/Preferences/com.apple.mail" &>/dev/null | grep -q "icloud"; then
        echo "true"
    else
        echo "false"
    fi
}

check_findmy_status() {
    local userHome="$1"
    if defaults read "${userHome}/Library/Preferences/com.apple.preferences.account" &>/dev/null; then
        echo "true"
    else
        echo "false"
    fi
}

check_findmy_device() {
    local userHome="$1"
    if pgrep -f "FindMyMacHelper" >/dev/null; then
        echo "true"
    else
        echo "false"
    fi
}

check_appstore_status() {
    local userHome="$1"
    if defaults read "${userHome}/Library/Preferences/com.apple.appstore" &>/dev/null; then
        echo "true"
    else
        echo "false"
    fi
}

check_auto_downloads() {
    local userHome="$1"
    local auto_downloads
    auto_downloads=$(defaults read "${userHome}/Library/Preferences/com.apple.appstore" AutomaticallyDownloadApps 2>/dev/null || echo "0")
    if [[ "$auto_downloads" == "1" ]]; then
        echo "true"
    else
        echo "false"
    fi
}

check_keychain_sync() {
    local userHome="$1"
    if security list-keychains -d user | grep -q "iCloud"; then
        echo "true"
    else
        echo "false"
    fi
}

count_keychains() {
    local userHome="$1"
    if [[ -d "${userHome}/Library/Keychains" ]]; then
        find "${userHome}/Library/Keychains" -name "*.keychain*" | wc -l | tr -d ' '
    else
        echo "0"
    fi
}

check_handoff_status() {
    local userHome="$1"
    local handoff_enabled
    handoff_enabled=$(defaults read "${userHome}/Library/Preferences/com.apple.coreservices.useractivityd" ActivityAdvertisingAllowed 2>/dev/null || echo "0")
    if [[ "$handoff_enabled" == "1" ]]; then
        echo "true"
    else
        echo "false"
    fi
}

# Monitor Apple ID changes
monitor_apple_id_changes() {
    local monitoring_duration="${1:-3600}"  # 1 hour default
    local check_interval="${2:-300}"        # 5 minutes default
    
    log_action "Starting Apple ID monitoring for ${monitoring_duration} seconds"
    
    local monitoring_report="$REPORTS_DIR/apple_id_monitoring_$(date '+%Y%m%d_%H%M%S').json"
    local baseline_file="/tmp/apple_id_baseline.json"
    
    # Create baseline
    discover_apple_ids > "$baseline_file"
    
    cat > "$monitoring_report" << EOF
{
    "monitoring_metadata": {
        "start_time": "$(date -Iseconds)",
        "duration_seconds": $monitoring_duration,
        "check_interval_seconds": $check_interval,
        "hostname": "$(hostname)"
    },
    "changes_detected": [
EOF

    local start_time end_time
    start_time=$(date +%s)
    end_time=$((start_time + monitoring_duration))
    
    local first=true
    while [[ $(date +%s) -lt $end_time ]]; do
        sleep "$check_interval"
        
        # Check for changes
        local current_state="/tmp/apple_id_current.json"
        discover_apple_ids > "$current_state"
        
        # Compare with baseline (simplified comparison)
        if ! diff "$baseline_file" "$current_state" >/dev/null 2>&1; then
            if [[ "$first" == true ]]; then
                first=false
            else
                echo "," >> "$monitoring_report"
            fi
            
            cat >> "$monitoring_report" << EOF
        {
            "timestamp": "$(date -Iseconds)",
            "change_type": "apple_id_status_change",
            "details": "Changes detected in Apple ID configuration"
        }
EOF
            
            log_action "⚠️  Apple ID configuration changes detected"
            
            # Update baseline
            cp "$current_state" "$baseline_file"
        fi
        
        rm -f "$current_state"
    done
    
    cat >> "$monitoring_report" << EOF
    ],
    "end_time": "$(date -Iseconds)"
}
EOF

    log_action "✅ Apple ID monitoring completed: $monitoring_report"
    rm -f "$baseline_file"
    echo "$monitoring_report"
}

# Apply privacy policies
apply_privacy_policy() {
    local policy_name="$1"
    local target_user="$2"
    
    log_action "Applying privacy policy: $policy_name for user: ${target_user:-all_users}"
    
    local policy_config="${PRIVACY_POLICIES[$policy_name]}"
    if [[ -z "$policy_config" ]]; then
        log_action "❌ Unknown privacy policy: $policy_name"
        return 1
    fi
    
    # Parse policy configuration
    IFS=',' read -ra POLICY_RULES <<< "$policy_config"
    
    for rule in "${POLICY_RULES[@]}"; do
        case "$rule" in
            "no_icloud")
                disable_icloud_services "$target_user"
                ;;
            "limited_icloud")
                configure_limited_icloud "$target_user"
                ;;
            "full_icloud")
                log_action "Full iCloud access permitted"
                ;;
            "no_sync")
                disable_sync_services "$target_user"
                ;;
            "controlled_sync")
                configure_controlled_sync "$target_user"
                ;;
            "audit_all")
                enable_comprehensive_audit "$target_user"
                ;;
            "audit_sensitive")
                enable_sensitive_audit "$target_user"
                ;;
            "audit_minimal")
                enable_minimal_audit "$target_user"
                ;;
        esac
    done
    
    log_action "✅ Privacy policy applied: $policy_name"
    return 0
}

# Disable iCloud services
disable_icloud_services() {
    local target_user="$1"
    
    log_action "Disabling iCloud services for user: ${target_user:-all_users}"
    
    if [[ -n "$target_user" ]]; then
        local userHome
        userHome=$(dscl . read /Users/"$target_user" NFSHomeDirectory | sed 's/NFSHomeDirectory://' | grep "/" | sed 's/^[ \t]*//')
        
        # Disable iCloud Drive
        defaults write "${userHome}/Library/Preferences/com.apple.bird" 'LastDisabledDate' -date "$(date)"
        
        # Disable iCloud Photos
        defaults write "${userHome}/Library/Preferences/com.apple.Photos" 'DisableiCloudPhotos' -bool true
        
        log_action "iCloud services disabled for user: $target_user"
    else
        log_action "Bulk iCloud disable requires individual user processing"
    fi
}

# Configure limited iCloud access
configure_limited_icloud() {
    local target_user="$1"
    
    log_action "Configuring limited iCloud access for user: ${target_user:-all_users}"
    
    # Implementation would involve setting specific iCloud service restrictions
    # This is a placeholder for actual implementation
    log_action "Limited iCloud configuration applied"
}

# Enable comprehensive audit
enable_comprehensive_audit() {
    local target_user="$1"
    
    log_action "Enabling comprehensive audit for user: ${target_user:-all_users}"
    
    # Create audit configuration
    local audit_config="$CONFIG_DIR/audit_comprehensive.conf"
    cat > "$audit_config" << EOF
# Comprehensive Apple ID Audit Configuration
audit_apple_id_changes=true
audit_icloud_access=true
audit_service_usage=true
audit_data_sync=true
log_level=detailed
retention_days=365
EOF

    log_action "Comprehensive audit enabled: $audit_config"
}

# Generate compliance report
generate_compliance_report() {
    local framework="$1"
    local report_type="${2:-summary}"
    
    log_action "Generating compliance report for framework: $framework"
    
    local compliance_report="$REPORTS_DIR/compliance_${framework}_$(date '+%Y%m%d_%H%M%S').json"
    
    # Get current Apple ID discovery data
    local discovery_data
    discovery_data=$(discover_apple_ids)
    
    cat > "$compliance_report" << EOF
{
    "compliance_metadata": {
        "timestamp": "$(date -Iseconds)",
        "framework": "$framework",
        "report_type": "$report_type",
        "hostname": "$(hostname)",
        "generator": "Roundfleet Compliance Manager"
    },
    "compliance_assessment": {
        "framework_requirements": $(get_framework_requirements "$framework"),
        "current_status": $(assess_compliance_status "$framework"),
        "recommendations": $(generate_compliance_recommendations "$framework"),
        "risk_level": "$(calculate_risk_level "$framework")"
    },
    "user_data": $(echo "$discovery_data" | jq '.user_accounts')
}
EOF

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

# Get framework requirements
get_framework_requirements() {
    local framework="$1"
    
    case "$framework" in
        "hipaa")
            echo '{"encryption_required": true, "audit_required": true, "data_minimization": true, "access_controls": true}'
            ;;
        "gdpr")
            echo '{"consent_required": true, "data_portability": true, "right_to_erasure": true, "privacy_by_design": true}'
            ;;
        "sox")
            echo '{"financial_controls": true, "audit_trails": true, "segregation_of_duties": true, "data_integrity": true}'
            ;;
        "ferpa")
            echo '{"student_privacy": true, "parental_consent": true, "educational_purpose": true, "limited_disclosure": true}'
            ;;
        *)
            echo '{"general_security": true, "basic_audit": true}'
            ;;
    esac
}

# Assess compliance status
assess_compliance_status() {
    local framework="$1"
    
    # Simplified compliance assessment
    local compliance_score=0
    local total_checks=0
    
    # Check encryption
    total_checks=$((total_checks + 1))
    if system_profiler SPStorageDataType | grep -q "Encrypted: Yes"; then
        compliance_score=$((compliance_score + 1))
    fi
    
    # Check audit logging
    total_checks=$((total_checks + 1))
    if [[ -f "$LOG_FILE" ]]; then
        compliance_score=$((compliance_score + 1))
    fi
    
    local compliance_percentage
    compliance_percentage=$(awk "BEGIN {printf \"%.0f\", ($compliance_score/$total_checks)*100}")
    
    echo "{\"score\": $compliance_score, \"total_checks\": $total_checks, \"percentage\": $compliance_percentage, \"status\": \"$([ $compliance_percentage -ge 80 ] && echo 'compliant' || echo 'non_compliant')\"}"
}

# Generate compliance recommendations
generate_compliance_recommendations() {
    local framework="$1"
    
    local recommendations=()
    
    # Check for common compliance issues
    if ! system_profiler SPStorageDataType | grep -q "Encrypted: Yes"; then
        recommendations+=("Enable FileVault encryption")
    fi
    
    if [[ ! -f "$LOG_FILE" ]]; then
        recommendations+=("Configure comprehensive audit logging")
    fi
    
    # Framework-specific recommendations
    case "$framework" in
        "hipaa")
            recommendations+=("Implement data access controls" "Configure PHI data handling")
            ;;
        "gdpr")
            recommendations+=("Implement consent management" "Configure data retention policies")
            ;;
    esac
    
    # Convert to JSON array
    local json_recommendations="["
    local first=true
    for rec in "${recommendations[@]}"; do
        if [[ "$first" == true ]]; then
            first=false
        else
            json_recommendations+=","
        fi
        json_recommendations+="\"$rec\""
    done
    json_recommendations+="]"
    
    echo "$json_recommendations"
}

# Calculate risk level
calculate_risk_level() {
    local framework="$1"
    
    local risk_factors=0
    
    # Check for high-risk configurations
    if discover_apple_ids | jq -r '.summary.users_with_apple_id' | awk '$1 > 0 {exit 1}'; then
        risk_factors=$((risk_factors + 1))
    fi
    
    if [[ $risk_factors -ge 3 ]]; then
        echo "high"
    elif [[ $risk_factors -ge 1 ]]; then
        echo "medium"
    else
        echo "low"
    fi
}

# Backup Apple ID configurations
backup_apple_id_configs() {
    local backup_timestamp
    backup_timestamp=$(date '+%Y%m%d_%H%M%S')
    local backup_file="$BACKUP_DIR/apple_id_backup_$backup_timestamp.tar.gz"
    
    log_action "Creating Apple ID configuration backup: $backup_file"
    
    # Create temporary backup directory
    local temp_backup="/tmp/apple_id_backup_$$"
    mkdir -p "$temp_backup"
    
    # Export current discovery data
    discover_apple_ids > "$temp_backup/current_apple_ids.json"
    
    # Export user preferences (if accessible)
    for user in $(dscl . list /Users UniqueID | awk '$2 >= 500 {print $1}'); do
        local userHome
        userHome=$(dscl . read /Users/"$user" NFSHomeDirectory | sed 's/NFSHomeDirectory://' | grep "/" | sed 's/^[ \t]*//')
        
        if [[ -n "$userHome" && -d "$userHome" ]]; then
            mkdir -p "$temp_backup/users/$user"
            
            # Backup relevant preference files (if readable)
            if [[ -f "${userHome}/Library/Preferences/MobileMeAccounts.plist" ]]; then
                cp "${userHome}/Library/Preferences/MobileMeAccounts.plist" "$temp_backup/users/$user/" 2>/dev/null || true
            fi
        fi
    done
    
    # Create compressed backup
    if tar -czf "$backup_file" -C "$(dirname "$temp_backup")" "$(basename "$temp_backup")" 2>/dev/null; then
        log_action "✅ Apple ID backup created: $backup_file"
        rm -rf "$temp_backup"
        echo "$backup_file"
        return 0
    else
        log_action "❌ Apple ID backup failed"
        rm -rf "$temp_backup"
        return 1
    fi
}

# Main execution function
main() {
    local action="${1:-discover}"
    local parameter="$2"
    local additional_param="$3"
    
    log_action "=== Roundfleet Apple ID Management Started ==="
    log_action "Action: $action"
    log_action "Parameter: ${parameter:-N/A}"
    
    # Setup
    setup_directories
    
    case "$action" in
        "discover")
            discover_apple_ids
            ;;
        "monitor")
            monitor_apple_id_changes "$parameter" "$additional_param"
            ;;
        "policy")
            if [[ -z "$parameter" ]]; then
                echo "Available privacy policies:"
                for policy in "${!PRIVACY_POLICIES[@]}"; do
                    echo "  - $policy: ${PRIVACY_POLICIES[$policy]}"
                done
                echo ""
                echo "Usage: $0 policy <policy_name> [username]"
                exit 1
            fi
            apply_privacy_policy "$parameter" "$additional_param"
            ;;
        "compliance")
            if [[ -z "$parameter" ]]; then
                echo "Available compliance frameworks:"
                for framework in "${!COMPLIANCE_FRAMEWORKS[@]}"; do
                    echo "  - $framework: ${COMPLIANCE_FRAMEWORKS[$framework]}"
                done
                echo ""
                echo "Usage: $0 compliance <framework> [report_type]"
                exit 1
            fi
            generate_compliance_report "$parameter" "$additional_param"
            ;;
        "backup")
            backup_apple_id_configs
            ;;
        "user")
            if [[ -z "$parameter" ]]; then
                echo "Usage: $0 user <username>"
                exit 1
            fi
            get_detailed_apple_id_info "$parameter"
            ;;
        *)
            echo "Usage: $0 {discover|monitor|policy|compliance|backup|user}"
            echo "  discover    - Discover Apple IDs across all users"
            echo "  monitor     - Monitor Apple ID changes over time"
            echo "  policy      - Apply privacy policies"
            echo "  compliance  - Generate compliance reports"
            echo "  backup      - Backup Apple ID configurations"
            echo "  user        - Get detailed info for specific user"
            exit 1
            ;;
    esac
    
    log_action "=== Apple ID management completed ==="
}

# Execute main function
main "$@"

Advanced Apple ID Analysis

Service Usage Analytics

#!/bin/bash

# Analyze Apple service usage patterns
analyze_service_usage() {
    echo "=== Apple Service Usage Analytics ==="
    
    local analytics_report="$REPORTS_DIR/service_analytics_$(date '+%Y%m%d_%H%M%S').json"
    
    cat > "$analytics_report" << EOF
{
    "analytics_metadata": {
        "timestamp": "$(date -Iseconds)",
        "hostname": "$(hostname)"
    },
    "service_usage": {
EOF

    # Analyze iCloud usage
    local icloud_users=0
    local total_users=0
    
    for user in $(dscl . list /Users UniqueID | awk '$2 >= 500 {print $1}'); do
        total_users=$((total_users + 1))
        local userHome
        userHome=$(dscl . read /Users/"$user" NFSHomeDirectory | sed 's/NFSHomeDirectory://' | grep "/" | sed 's/^[ \t]*//')
        
        if [[ "$(check_icloud_status "$userHome")" == "true" ]]; then
            icloud_users=$((icloud_users + 1))
        fi
    done
    
    cat >> "$analytics_report" << EOF
        "icloud": {
            "users_enabled": $icloud_users,
            "total_users": $total_users,
            "adoption_rate": $(awk "BEGIN {printf \"%.2f\", ($icloud_users/$total_users)*100}")
        }
    }
}
EOF

    echo "📊 Service usage analytics: $analytics_report"
}

Privacy Impact Assessment

#!/bin/bash

# Conduct privacy impact assessment
privacy_impact_assessment() {
    local assessment_type="${1:-standard}"
    
    echo "=== Privacy Impact Assessment ==="
    log_action "Starting privacy impact assessment: $assessment_type"
    
    local pia_report="$REPORTS_DIR/privacy_assessment_$(date '+%Y%m%d_%H%M%S').json"
    
    cat > "$pia_report" << EOF
{
    "assessment_metadata": {
        "timestamp": "$(date -Iseconds)",
        "assessment_type": "$assessment_type",
        "hostname": "$(hostname)"
    },
    "privacy_risks": [
EOF

    local risks=()
    
    # Check for data synchronization risks
    local sync_users
    sync_users=$(discover_apple_ids | jq -r '.user_accounts[] | select(.services.icloud.enabled == true) | .username' | wc -l)
    
    if [[ $sync_users -gt 0 ]]; then
        risks+=("Data synchronization to iCloud enabled for $sync_users users")
    fi
    
    # Check for location services
    if pgrep -f "locationd" >/dev/null; then
        risks+=("Location services active - potential privacy concern")
    fi
    
    # Add risks to report
    local first=true
    for risk in "${risks[@]}"; do
        if [[ "$first" == true ]]; then
            first=false
        else
            echo "," >> "$pia_report"
        fi
        echo "        \"$risk\"" >> "$pia_report"
    done
    
    cat >> "$pia_report" << EOF
    ],
    "recommendations": [
        "Implement data governance policies",
        "Configure privacy controls",
        "Regular privacy audits"
    ]
}
EOF

    log_action "✅ Privacy impact assessment completed: $pia_report"
    echo "$pia_report"
}

Best Practices

🚀 Identity Management

  • Regular discovery scans to track Apple ID usage across fleet
  • Centralized policy enforcement for consistent privacy controls
  • Automated monitoring for unauthorized Apple ID changes
  • Comprehensive audit trails for compliance and security

🔐 Security Guidelines

  • Privacy policy enforcement based on organizational requirements
  • Data minimization principles for sensitive environments
  • Access controls for Apple service configurations
  • Regular security assessments of identity management practices

📋 Compliance Management

  • Framework-specific policies (HIPAA, GDPR, SOX, FERPA)
  • Regular compliance reporting with automated assessment
  • Risk-based approach to identity management
  • Documentation and audit trails for regulatory requirements

🔍 Monitoring and Maintenance

  • Continuous monitoring of Apple ID status and service usage
  • Change detection with automated alerting
  • Regular backup of identity configurations
  • Performance optimization for large-scale deployments

Important Notes

  • Privacy compliance requires careful balance between functionality and data protection
  • User consent may be required for certain monitoring activities
  • Apple ID management should align with organizational privacy policies
  • Regular updates needed as Apple introduces new services and privacy features
  • Legal considerations vary by jurisdiction and industry sector

App Store Inventory Management on macOS

Efficiently manage and track App Store applications across your Roundfleet devices with comprehensive inventory tools. This tutorial covers app discovery, license compliance, usage analytics, and enterprise-grade reporting for Mac App Store applications.

Understanding App Store App Management

App Store applications on macOS contain unique identifiers and receipts that enable enterprise tracking:

Core Components

  • MAS Receipts - Digital receipts stored in app bundles for verification
  • Bundle Identifiers - Unique app identification across the App Store ecosystem
  • Version Tracking - App version management and update compliance
  • License Management - Enterprise license allocation and compliance monitoring
  • Usage Analytics - Application usage patterns and adoption metrics

Enterprise Benefits

  • Software Asset Management - Complete inventory of App Store applications
  • License Compliance - Track enterprise app licenses and allocations
  • Security Monitoring - Identify unauthorized or non-compliant applications
  • Cost Optimization - Optimize App Store spending and license utilization
  • Policy Enforcement - Ensure compliance with enterprise app policies

Basic App Store App Discovery

Simple App Store App List

#!/bin/bash

# Basic App Store app discovery
echo "📱 Discovering App Store Applications"
echo "===================================="
echo ""

app_store_apps=$(find /Applications -path '*Contents/_MASReceipt/receipt' -maxdepth 4 -print | \
    sed 's#.app/Contents/_MASReceipt/receipt#.app#g; s#/Applications/##')

if [[ -n "$app_store_apps" ]]; then
    echo "App Store Applications Found:"
    echo "$app_store_apps" | sort
    
    local app_count=$(echo "$app_store_apps" | wc -l | xargs)
    echo ""
    echo "Total App Store apps: $app_count"
else
    echo "No App Store applications found in /Applications"
fi

Enhanced App Discovery with Details

#!/bin/bash

# Comprehensive App Store app discovery with metadata
discover_app_store_apps() {
    echo "🔍 Comprehensive App Store App Discovery"
    echo "======================================="
    echo ""
    
    local apps_found=0
    local total_size=0
    
    # Find all App Store apps with receipts
    while IFS= read -r -d '' app_path; do
        if [[ -n "$app_path" ]]; then
            local app_name=$(basename "$app_path" .app)
            local app_bundle_id=""
            local app_version=""
            local app_size=""
            local install_date=""
            
            # Get bundle identifier
            if [[ -f "$app_path/Contents/Info.plist" ]]; then
                app_bundle_id=$(defaults read "$app_path/Contents/Info.plist" CFBundleIdentifier 2>/dev/null || echo "Unknown")
                app_version=$(defaults read "$app_path/Contents/Info.plist" CFBundleShortVersionString 2>/dev/null || echo "Unknown")
            fi
            
            # Get app size
            if [[ -d "$app_path" ]]; then
                app_size=$(du -sh "$app_path" 2>/dev/null | cut -f1 || echo "Unknown")
                # Convert size to bytes for totaling
                local size_bytes=$(du -s "$app_path" 2>/dev/null | cut -f1 || echo "0")
                total_size=$((total_size + size_bytes))
            fi
            
            # Get installation/modification date
            if [[ -f "$app_path/Contents/_MASReceipt/receipt" ]]; then
                install_date=$(stat -f "%Sm" -t "%Y-%m-%d %H:%M:%S" "$app_path/Contents/_MASReceipt/receipt" 2>/dev/null || echo "Unknown")
            fi
            
            echo "App: $app_name"
            echo "  Bundle ID: $app_bundle_id"
            echo "  Version: $app_version"
            echo "  Size: $app_size"
            echo "  Install Date: $install_date"
            echo "  Path: $app_path"
            echo ""
            
            ((apps_found++))
        fi
    done < <(find /Applications -name "*.app" -path '*Contents/_MASReceipt/receipt' -exec dirname {} \; 2>/dev/null | \
             sed 's|/Contents/_MASReceipt||' | sort -u | tr '\n' '\0')
    
    # Summary statistics
    echo "=== Discovery Summary ==="
    echo "Total App Store apps found: $apps_found"
    echo "Total disk space used: $(echo "scale=2; $total_size / 1024 / 1024" | bc 2>/dev/null || echo "Unknown") MB"
    echo "Average app size: $(echo "scale=2; $total_size / $apps_found / 1024 / 1024" | bc 2>/dev/null || echo "Unknown") MB"
    echo "Scan completed: $(date)"
    
    return $apps_found
}

# Execute discovery
discover_app_store_apps

Enterprise App Inventory Management

Comprehensive App Inventory Script

#!/bin/bash

# Enterprise App Store inventory management
generate_app_store_inventory() {
    local output_format="${1:-json}"
    local include_metadata="${2:-true}"
    local export_path="${3:-/tmp}"
    
    echo "📊 Generating Enterprise App Store Inventory"
    echo "==========================================="
    echo "Output format: $output_format"
    echo "Include metadata: $include_metadata"
    echo ""
    
    local timestamp=$(date +"%Y%m%d_%H%M%S")
    local hostname=$(hostname)
    local report_file="$export_path/app_store_inventory_${hostname}_${timestamp}"
    
    # System information
    local device_info=$(system_profiler SPHardwareDataType | grep -E "(Model Name|Serial Number)" | \
                        awk -F': ' '{print $2}' | xargs | tr ' ' '_')
    local macos_version=$(sw_vers -productVersion)
    local current_user=$(stat -f%Su /dev/console 2>/dev/null || echo "$USER")
    
    # Initialize inventory data structure
    local inventory_data=""
    local app_count=0
    local total_size_bytes=0
    
    echo "Scanning applications..."
    
    # Discover all App Store applications
    while IFS= read -r -d '' app_path; do
        if [[ -d "$app_path" && -f "$app_path/Contents/_MASReceipt/receipt" ]]; then
            local app_name=$(basename "$app_path" .app)
            local bundle_id=""
            local version=""
            local build_version=""
            local size_bytes=0
            local size_human=""
            local install_date=""
            local last_modified=""
            local executable_path=""
            local app_category=""
            local developer_name=""
            local app_store_url=""
            
            # Extract app metadata
            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")
                build_version=$(defaults read "$app_path/Contents/Info.plist" CFBundleVersion 2>/dev/null || echo "unknown")
                executable_path=$(defaults read "$app_path/Contents/Info.plist" CFBundleExecutable 2>/dev/null || echo "unknown")
                app_category=$(defaults read "$app_path/Contents/Info.plist" LSApplicationCategoryType 2>/dev/null || echo "unknown")
            fi
            
            # Get app size
            size_bytes=$(du -sk "$app_path" 2>/dev/null | cut -f1 || echo "0")
            size_bytes=$((size_bytes * 1024))  # Convert KB to bytes
            size_human=$(du -sh "$app_path" 2>/dev/null | cut -f1 || echo "unknown")
            total_size_bytes=$((total_size_bytes + size_bytes))
            
            # Get timestamps
            install_date=$(stat -f "%Sm" -t "%Y-%m-%d %H:%M:%S" "$app_path/Contents/_MASReceipt/receipt" 2>/dev/null || echo "unknown")
            last_modified=$(stat -f "%Sm" -t "%Y-%m-%d %H:%M:%S" "$app_path" 2>/dev/null || echo "unknown")
            
            # Try to extract additional metadata if requested
            if [[ "$include_metadata" == "true" ]]; then
                # Look for team identifier
                local team_id=""
                if command -v codesign >/dev/null 2>&1; then
                    team_id=$(codesign -dv "$app_path" 2>&1 | grep "TeamIdentifier" | awk -F'=' '{print $2}' || echo "unknown")
                fi
                
                # Check if app is running
                local is_running="false"
                if pgrep -f "$app_name" >/dev/null 2>&1; then
                    is_running="true"
                fi
                
                # Get app permissions (simplified check)
                local has_camera_permission="unknown"
                local has_microphone_permission="unknown"
                local has_location_permission="unknown"
                
                if [[ -f "$app_path/Contents/Info.plist" ]]; then
                    if defaults read "$app_path/Contents/Info.plist" NSCameraUsageDescription >/dev/null 2>&1; then
                        has_camera_permission="requested"
                    else
                        has_camera_permission="not_requested"
                    fi
                    
                    if defaults read "$app_path/Contents/Info.plist" NSMicrophoneUsageDescription >/dev/null 2>&1; then
                        has_microphone_permission="requested"
                    else
                        has_microphone_permission="not_requested"
                    fi
                    
                    if defaults read "$app_path/Contents/Info.plist" NSLocationUsageDescription >/dev/null 2>&1; then
                        has_location_permission="requested"
                    else
                        has_location_permission="not_requested"
                    fi
                fi
            fi
            
            # Format output based on requested format
            case "$output_format" in
                "json")
                    local app_json="{
                        \"app_name\": \"$app_name\",
                        \"bundle_id\": \"$bundle_id\",
                        \"version\": \"$version\",
                        \"build_version\": \"$build_version\",
                        \"size_bytes\": $size_bytes,
                        \"size_human\": \"$size_human\",
                        \"install_date\": \"$install_date\",
                        \"last_modified\": \"$last_modified\",
                        \"app_path\": \"$app_path\",
                        \"executable_path\": \"$executable_path\",
                        \"category\": \"$app_category\""
                    
                    if [[ "$include_metadata" == "true" ]]; then
                        app_json="$app_json,
                        \"team_id\": \"$team_id\",
                        \"is_running\": $is_running,
                        \"camera_permission\": \"$has_camera_permission\",
                        \"microphone_permission\": \"$has_microphone_permission\",
                        \"location_permission\": \"$has_location_permission\""
                    fi
                    
                    app_json="$app_json}"
                    
                    if [[ $app_count -gt 0 ]]; then
                        inventory_data="$inventory_data,$app_json"
                    else
                        inventory_data="$app_json"
                    fi
                    ;;
                    
                "csv")
                    if [[ $app_count -eq 0 ]]; then
                        # CSV header
                        if [[ "$include_metadata" == "true" ]]; then
                            inventory_data="App Name,Bundle ID,Version,Build Version,Size (Bytes),Size (Human),Install Date,Last Modified,App Path,Category,Team ID,Is Running,Camera Permission,Microphone Permission,Location Permission"
                        else
                            inventory_data="App Name,Bundle ID,Version,Build Version,Size (Bytes),Size (Human),Install Date,Last Modified,App Path,Category"
                        fi
                    fi
                    
                    local csv_line="\"$app_name\",\"$bundle_id\",\"$version\",\"$build_version\",$size_bytes,\"$size_human\",\"$install_date\",\"$last_modified\",\"$app_path\",\"$app_category\""
                    
                    if [[ "$include_metadata" == "true" ]]; then
                        csv_line="$csv_line,\"$team_id\",$is_running,\"$has_camera_permission\",\"$has_microphone_permission\",\"$has_location_permission\""
                    fi
                    
                    inventory_data="$inventory_data\n$csv_line"
                    ;;
                    
                "text"|*)
                    inventory_data="$inventory_data
App: $app_name
  Bundle ID: $bundle_id
  Version: $version ($build_version)
  Size: $size_human ($size_bytes bytes)
  Install Date: $install_date
  Last Modified: $last_modified
  Path: $app_path
  Category: $app_category"
                    
                    if [[ "$include_metadata" == "true" ]]; then
                        inventory_data="$inventory_data
  Team ID: $team_id
  Currently Running: $is_running
  Camera Permission: $has_camera_permission
  Microphone Permission: $has_microphone_permission
  Location Permission: $has_location_permission"
                    fi
                    
                    inventory_data="$inventory_data
"
                    ;;
            esac
            
            ((app_count++))
        fi
    done < <(find /Applications -name "*.app" -type d -print0 2>/dev/null)
    
    # Generate final report
    local total_size_human=$(echo "scale=2; $total_size_bytes / 1024 / 1024 / 1024" | bc 2>/dev/null || echo "unknown")
    
    case "$output_format" in
        "json")
            local final_report="{
                \"report_metadata\": {
                    \"timestamp\": \"$(date -u +"%Y-%m-%dT%H:%M:%SZ")\",
                    \"hostname\": \"$hostname\",
                    \"device_info\": \"$device_info\",
                    \"macos_version\": \"$macos_version\",
                    \"current_user\": \"$current_user\",
                    \"total_apps\": $app_count,
                    \"total_size_bytes\": $total_size_bytes,
                    \"total_size_gb\": \"$total_size_human GB\"
                },
                \"applications\": [$inventory_data]
            }"
            
            echo "$final_report" > "${report_file}.json"
            echo "✅ JSON report saved to: ${report_file}.json"
            ;;
            
        "csv")
            echo -e "$inventory_data" > "${report_file}.csv"
            echo "✅ CSV report saved to: ${report_file}.csv"
            ;;
            
        "text"|*)
            {
                echo "Roundfleet App Store Inventory Report"
                echo "=================================="
                echo "Generated: $(date)"
                echo "Hostname: $hostname"
                echo "Device: $device_info"
                echo "macOS Version: $macos_version"
                echo "Current User: $current_user"
                echo "Total Apps: $app_count"
                echo "Total Size: $total_size_human GB"
                echo ""
                echo "Applications:"
                echo "============"
                echo "$inventory_data"
            } > "${report_file}.txt"
            echo "✅ Text report saved to: ${report_file}.txt"
            ;;
    esac
    
    # Summary output
    echo ""
    echo "=== Inventory Summary ==="
    echo "Apps discovered: $app_count"
    echo "Total size: $total_size_human GB"
    echo "Report format: $output_format"
    echo "Report location: $report_file"
    echo ""
    
    return $app_count
}

# Usage examples
echo "📊 Enterprise App Store Inventory Management"
echo ""
echo "1. Generate JSON inventory with metadata"
generate_app_store_inventory "json" "true" "/tmp"
echo ""

echo "2. Generate CSV inventory (basic)"
generate_app_store_inventory "csv" "false" "/tmp"
echo ""

echo "3. Generate text inventory with metadata"
generate_app_store_inventory "text" "true" "/tmp"

App Compliance and Security Analysis

#!/bin/bash

# App Store app compliance and security analysis
analyze_app_compliance() {
    echo "🔒 App Store Application Compliance Analysis"
    echo "==========================================="
    echo ""
    
    local compliance_issues=0
    local security_concerns=0
    local policy_violations=0
    
    # Define enterprise policy rules
    local blocked_apps=("Games" "Social Media" "Dating")  # Example categories
    local required_apps=("Microsoft Word" "Microsoft Excel" "Slack")  # Example required apps
    local max_app_age_days=365  # Apps older than 1 year flagged
    local min_security_permissions=("Camera" "Microphone" "Location")
    
    echo "Analyzing App Store applications for compliance..."
    echo ""
    
    # Track required apps
    local found_required_apps=()
    local missing_required_apps=()
    
    # Analyze each App Store application
    while IFS= read -r -d '' app_path; do
        if [[ -d "$app_path" && -f "$app_path/Contents/_MASReceipt/receipt" ]]; then
            local app_name=$(basename "$app_path" .app)
            local bundle_id=""
            local version=""
            local category=""
            local install_date=""
            local days_since_install=""
            
            echo "Analyzing: $app_name"
            
            # Get app metadata
            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")
                category=$(defaults read "$app_path/Contents/Info.plist" LSApplicationCategoryType 2>/dev/null || echo "unknown")
            fi
            
            # Get install date and calculate age
            if [[ -f "$app_path/Contents/_MASReceipt/receipt" ]]; then
                install_date=$(stat -f "%Sm" -t "%Y-%m-%d" "$app_path/Contents/_MASReceipt/receipt" 2>/dev/null || echo "unknown")
                if [[ "$install_date" != "unknown" ]]; then
                    local install_epoch=$(date -j -f "%Y-%m-%d" "$install_date" "+%s" 2>/dev/null || echo "0")
                    local current_epoch=$(date "+%s")
                    days_since_install=$(( (current_epoch - install_epoch) / 86400 ))
                fi
            fi
            
            # Check against blocked apps/categories
            local is_blocked=false
            for blocked_category in "${blocked_apps[@]}"; do
                if [[ "$category" =~ "$blocked_category" ]] || [[ "$app_name" =~ "$blocked_category" ]]; then
                    echo "  ❌ POLICY VIOLATION: App category '$category' is blocked"
                    is_blocked=true
                    ((policy_violations++))
                    break
                fi
            done
            
            # Check app age
            if [[ -n "$days_since_install" && "$days_since_install" -gt "$max_app_age_days" ]]; then
                echo "  ⚠️ COMPLIANCE: App is older than $max_app_age_days days ($days_since_install days)"
                ((compliance_issues++))
            fi
            
            # Check for security permissions
            local permission_count=0
            if [[ -f "$app_path/Contents/Info.plist" ]]; then
                if defaults read "$app_path/Contents/Info.plist" NSCameraUsageDescription >/dev/null 2>&1; then
                    echo "  🔒 SECURITY: App requests camera access"
                    ((permission_count++))
                fi
                
                if defaults read "$app_path/Contents/Info.plist" NSMicrophoneUsageDescription >/dev/null 2>&1; then
                    echo "  🔒 SECURITY: App requests microphone access"
                    ((permission_count++))
                fi
                
                if defaults read "$app_path/Contents/Info.plist" NSLocationUsageDescription >/dev/null 2>&1; then
                    echo "  🔒 SECURITY: App requests location access"
                    ((permission_count++))
                fi
                
                if [[ "$permission_count" -gt 2 ]]; then
                    echo "  ⚠️ SECURITY CONCERN: App requests multiple sensitive permissions"
                    ((security_concerns++))
                fi
            fi
            
            # Check against required apps
            for required_app in "${required_apps[@]}"; do
                if [[ "$app_name" =~ "$required_app" ]]; then
                    found_required_apps+=("$required_app")
                fi
            done
            
            # Code signing verification
            if command -v codesign >/dev/null 2>&1; then
                if ! codesign -v "$app_path" >/dev/null 2>&1; then
                    echo "  ❌ SECURITY: Invalid code signature"
                    ((security_concerns++))
                fi
            fi
            
            echo "  ✅ Analysis complete"
            echo ""
        fi
    done < <(find /Applications -name "*.app" -type d -print0 2>/dev/null)
    
    # Check for missing required apps
    for required_app in "${required_apps[@]}"; do
        local found=false
        for found_app in "${found_required_apps[@]}"; do
            if [[ "$found_app" == "$required_app" ]]; then
                found=true
                break
            fi
        done
        
        if [[ "$found" == "false" ]]; then
            missing_required_apps+=("$required_app")
        fi
    done
    
    # Generate compliance report
    echo "=== Compliance Analysis Report ==="
    echo "Policy violations: $policy_violations"
    echo "Compliance issues: $compliance_issues"
    echo "Security concerns: $security_concerns"
    echo ""
    
    if [[ ${#missing_required_apps[@]} -gt 0 ]]; then
        echo "Missing required applications:"
        for missing_app in "${missing_required_apps[@]}"; do
            echo "  - $missing_app"
        done
        echo ""
    fi
    
    if [[ ${#found_required_apps[@]} -gt 0 ]]; then
        echo "Found required applications:"
        for found_app in "${found_required_apps[@]}"; do
            echo "  ✅ $found_app"
        done
        echo ""
    fi
    
    # Overall compliance score
    local total_issues=$((policy_violations + compliance_issues + security_concerns + ${#missing_required_apps[@]}))
    if [[ "$total_issues" -eq 0 ]]; then
        echo "🎉 COMPLIANCE STATUS: FULLY COMPLIANT"
    elif [[ "$total_issues" -le 3 ]]; then
        echo "⚠️ COMPLIANCE STATUS: MINOR ISSUES ($total_issues issues)"
    else
        echo "❌ COMPLIANCE STATUS: MAJOR ISSUES ($total_issues issues)"
    fi
    
    return $total_issues
}

# Execute compliance analysis
analyze_app_compliance

Fleet Management and Reporting

Enterprise Fleet App Management

#!/bin/bash

# Enterprise fleet-wide App Store management
manage_fleet_app_inventory() {
    local operation="${1:-discover}"  # discover, report, compliance, update
    local fleet_config_file="${2:-/etc/roundfleet/app_config.json}"
    local output_dir="${3:-/var/log/roundfleet}"
    
    echo "🚀 Roundfleet Enterprise App Store Management"
    echo "=========================================="
    echo "Operation: $operation"
    echo "Config file: $fleet_config_file"
    echo "Output directory: $output_dir"
    echo ""
    
    # Ensure output directory exists
    mkdir -p "$output_dir"
    
    # Device identification
    local device_id=$(system_profiler SPHardwareDataType | grep "Serial Number" | awk -F': ' '{print $2}' | xargs)
    local device_name=$(hostname)
    local timestamp=$(date +"%Y%m%d_%H%M%S")
    local report_file="$output_dir/fleet_app_report_${device_id}_${timestamp}.json"
    
    case "$operation" in
        "discover")
            echo "🔍 Fleet App Discovery Mode"
            echo "==========================="
            
            # Generate comprehensive app inventory
            local app_data=$(generate_comprehensive_app_data)
            
            # Create fleet report
            local fleet_report="{
                \"device_info\": {
                    \"device_id\": \"$device_id\",
                    \"device_name\": \"$device_name\",
                    \"timestamp\": \"$(date -u +"%Y-%m-%dT%H:%M:%SZ")\",
                    \"macos_version\": \"$(sw_vers -productVersion)\",
                    \"current_user\": \"$(stat -f%Su /dev/console 2>/dev/null || echo "$USER")\"
                },
                \"app_inventory\": $app_data,
                \"operation\": \"fleet_discovery\"
            }"
            
            echo "$fleet_report" > "$report_file"
            echo "✅ Fleet discovery report saved: $report_file"
            ;;
            
        "compliance")
            echo "📋 Fleet Compliance Check"
            echo "========================="
            
            # Run compliance analysis
            local compliance_result=$(analyze_fleet_compliance)
            
            # Create compliance report
            local compliance_report="{
                \"device_info\": {
                    \"device_id\": \"$device_id\",
                    \"device_name\": \"$device_name\",
                    \"timestamp\": \"$(date -u +"%Y-%m-%dT%H:%M:%SZ")\"
                },
                \"compliance_results\": $compliance_result,
                \"operation\": \"compliance_check\"
            }"
            
            echo "$compliance_report" > "$report_file"
            echo "✅ Compliance report saved: $report_file"
            ;;
            
        "report")
            echo "📊 Fleet Reporting Mode"
            echo "======================"
            
            # Generate all report formats
            echo "Generating comprehensive fleet reports..."
            
            generate_app_store_inventory "json" "true" "$output_dir"
            generate_app_store_inventory "csv" "true" "$output_dir"
            generate_app_store_inventory "text" "true" "$output_dir"
            
            echo "✅ All fleet reports generated in: $output_dir"
            ;;
            
        "update")
            echo "🔄 Fleet Update Check"
            echo "===================="
            
            # Check for app updates
            check_app_store_updates
            ;;
            
        *)
            echo "❌ Unknown operation: $operation"
            echo "Available operations: discover, report, compliance, update"
            return 1
            ;;
    esac
    
    return 0
}

# Helper function to generate comprehensive app data
generate_comprehensive_app_data() {
    local apps_json="["
    local first_app=true
    
    while IFS= read -r -d '' app_path; do
        if [[ -d "$app_path" && -f "$app_path/Contents/_MASReceipt/receipt" ]]; then
            local app_name=$(basename "$app_path" .app)
            local bundle_id=$(defaults read "$app_path/Contents/Info.plist" CFBundleIdentifier 2>/dev/null || echo "unknown")
            local version=$(defaults read "$app_path/Contents/Info.plist" CFBundleShortVersionString 2>/dev/null || echo "unknown")
            local size_bytes=$(du -sk "$app_path" 2>/dev/null | cut -f1 || echo "0")
            size_bytes=$((size_bytes * 1024))
            
            if [[ "$first_app" == "false" ]]; then
                apps_json="$apps_json,"
            fi
            
            apps_json="$apps_json{
                \"name\": \"$app_name\",
                \"bundle_id\": \"$bundle_id\",
                \"version\": \"$version\",
                \"size_bytes\": $size_bytes,
                \"path\": \"$app_path\"
            }"
            
            first_app=false
        fi
    done < <(find /Applications -name "*.app" -type d -print0 2>/dev/null)
    
    apps_json="$apps_json]"
    echo "$apps_json"
}

# Check for App Store updates
check_app_store_updates() {
    echo "Checking for available App Store updates..."
    
    # Use softwareupdate to check for available updates
    local updates_available=$(softwareupdate -l 2>/dev/null | grep -i "app store" || echo "")
    
    if [[ -n "$updates_available" ]]; then
        echo "📦 App Store updates available:"
        echo "$updates_available"
    else
        echo "✅ All App Store apps are up to date"
    fi
    
    # Also check Mac App Store directly if available
    if command -v mas >/dev/null 2>&1; then
        echo ""
        echo "Checking with mas-cli..."
        mas outdated 2>/dev/null || echo "mas-cli not available or no updates found"
    fi
}

# Usage examples
echo "Fleet Management Examples:"
echo "========================="
echo ""

echo "1. Discovery mode:"
manage_fleet_app_inventory "discover"
echo ""

echo "2. Compliance check:"
manage_fleet_app_inventory "compliance"
echo ""

echo "3. Generate all reports:"
manage_fleet_app_inventory "report"

App Store Connect Integration

Enterprise App Management with App Store Connect

#!/bin/bash

# Enterprise App Store Connect integration for license management
manage_app_store_licenses() {
    echo "📄 App Store Connect License Management"
    echo "======================================"
    echo ""
    
    # Note: This requires enterprise App Store Connect access
    # and proper API credentials configuration
    
    local license_report_file="/tmp/app_store_licenses_$(date +%Y%m%d_%H%M%S).json"
    
    echo "Analyzing App Store app licensing..."
    echo ""
    
    # Track apps that may require business licenses
    local business_apps=()
    local consumer_apps=()
    local unknown_apps=()
    
    while IFS= read -r -d '' app_path; do
        if [[ -d "$app_path" && -f "$app_path/Contents/_MASReceipt/receipt" ]]; then
            local app_name=$(basename "$app_path" .app)
            local bundle_id=$(defaults read "$app_path/Contents/Info.plist" CFBundleIdentifier 2>/dev/null || echo "unknown")
            
            # Categories that typically require business licenses
            local business_categories=("Developer Tools" "Business" "Productivity" "Graphics & Design")
            local is_business_app=false
            
            # Check if app is business-oriented
            if [[ -f "$app_path/Contents/Info.plist" ]]; then
                local category=$(defaults read "$app_path/Contents/Info.plist" LSApplicationCategoryType 2>/dev/null || echo "unknown")
                
                for biz_cat in "${business_categories[@]}"; do
                    if [[ "$category" =~ "$biz_cat" ]]; then
                        is_business_app=true
                        break
                    fi
                done
                
                # Also check common business app patterns
                if [[ "$app_name" =~ (Microsoft|Adobe|Slack|Zoom|Teams|Office) ]]; then
                    is_business_app=true
                fi
            fi
            
            if [[ "$is_business_app" == "true" ]]; then
                business_apps+=("$app_name ($bundle_id)")
                echo "💼 Business app detected: $app_name"
            else
                # Consumer apps that might be acceptable
                if [[ "$app_name" =~ (Calculator|TextEdit|Safari|Mail|Photos) ]]; then
                    consumer_apps+=("$app_name ($bundle_id)")
                    echo "👤 Consumer app: $app_name"
                else
                    unknown_apps+=("$app_name ($bundle_id)")
                    echo "❓ Unknown category: $app_name"
                fi
            fi
        fi
    done < <(find /Applications -name "*.app" -type d -print0 2>/dev/null)
    
    # Generate license compliance report
    {
        echo "{"
        echo "  \"license_analysis\": {"
        echo "    \"timestamp\": \"$(date -u +"%Y-%m-%dT%H:%M:%SZ")\","
        echo "    \"device_id\": \"$(system_profiler SPHardwareDataType | grep "Serial Number" | awk -F': ' '{print $2}' | xargs)\","
        echo "    \"business_apps\": ["
        
        local first=true
        for app in "${business_apps[@]}"; do
            if [[ "$first" == "false" ]]; then echo ","; fi
            echo "      \"$app\""
            first=false
        done
        
        echo "    ],"
        echo "    \"consumer_apps\": ["
        
        first=true
        for app in "${consumer_apps[@]}"; do
            if [[ "$first" == "false" ]]; then echo ","; fi
            echo "      \"$app\""
            first=false
        done
        
        echo "    ],"
        echo "    \"unknown_apps\": ["
        
        first=true
        for app in "${unknown_apps[@]}"; do
            if [[ "$first" == "false" ]]; then echo ","; fi
            echo "      \"$app\""
            first=false
        done
        
        echo "    ],"
        echo "    \"summary\": {"
        echo "      \"total_business_apps\": ${#business_apps[@]},"
        echo "      \"total_consumer_apps\": ${#consumer_apps[@]},"
        echo "      \"total_unknown_apps\": ${#unknown_apps[@]},"
        echo "      \"requires_license_review\": $([[ ${#business_apps[@]} -gt 0 || ${#unknown_apps[@]} -gt 0 ]] && echo "true" || echo "false")"
        echo "    }"
        echo "  }"
        echo "}"
    } > "$license_report_file"
    
    echo ""
    echo "=== License Analysis Summary ==="
    echo "Business apps found: ${#business_apps[@]}"
    echo "Consumer apps found: ${#consumer_apps[@]}"
    echo "Unknown apps found: ${#unknown_apps[@]}"
    echo ""
    
    if [[ ${#business_apps[@]} -gt 0 || ${#unknown_apps[@]} -gt 0 ]]; then
        echo "⚠️ License review required for business/unknown applications"
        echo "📄 License report saved: $license_report_file"
    else
        echo "✅ No business licensing concerns detected"
    fi
    
    return 0
}

# Execute license management
manage_app_store_licenses

Important Notes

Enterprise Management Features

  • Comprehensive Inventory - Complete App Store application discovery and tracking
  • Compliance Monitoring - Policy enforcement and security analysis
  • License Management - Enterprise App Store Connect integration
  • Fleet Reporting - Multi-format reporting (JSON, CSV, text) with metadata
  • Security Analysis - Permission auditing and code signature verification
  • Update Management - App Store update detection and management

App Store Receipt System

  • MAS Receipts - Digital proof of App Store purchase located in Contents/_MASReceipt/receipt
  • Bundle Identification - Unique app tracking via CFBundleIdentifier
  • Version Tracking - App version and build number management
  • Installation Metadata - Install date and modification tracking
  • License Verification - Enterprise license compliance and allocation

Security and Compliance

  • Permission Auditing - Camera, microphone, location access monitoring
  • Code Signature Verification - Validate app integrity and authenticity
  • Policy Enforcement - Blocked app categories and required app validation
  • Age Analysis - Identify outdated applications requiring updates
  • Team Identifier Tracking - Developer team identification for enterprise policies

Usage Examples

# Basic App Store app discovery
find /Applications -path '*Contents/_MASReceipt/receipt' -maxdepth 4 -print | \
    sed 's#.app/Contents/_MASReceipt/receipt#.app#g; s#/Applications/##'

# Enterprise inventory with JSON output
generate_app_store_inventory "json" "true" "/tmp"

# Compliance analysis
analyze_app_compliance

# Fleet management - discovery mode
manage_fleet_app_inventory "discover"

# License management
manage_app_store_licenses

App Store Auto Updates Management on macOS

Control and manage App Store automatic updates on your Roundfleet devices to optimize bandwidth usage, manage security updates, and maintain system stability. This tutorial covers update policies, enterprise configuration, and comprehensive update management strategies.

Understanding macOS App Store Auto Updates

App Store auto updates on macOS automatically download and install application updates from the Mac App Store. This feature affects:

  • Application Updates - Automatic installation of app updates
  • System Storage - Downloaded updates consume disk space
  • Network Bandwidth - Updates download in the background
  • System Stability - New updates may introduce bugs or compatibility issues

Enterprise Considerations

Managing auto updates is crucial for enterprise environments:

  • Bandwidth Control - Prevent unexpected network usage
  • Security Management - Control when security updates are applied
  • System Stability - Test updates before deployment
  • Storage Management - Prevent storage issues on limited-space devices
  • Compliance Requirements - Some industries require controlled update deployment

Basic App Store Update Control

Disable Auto Updates

#!/bin/bash

# Disable App Store auto updates
sudo defaults write /Library/Preferences/com.apple.commerce.plist AutoUpdate -bool FALSE

echo "App Store auto updates disabled"
exit 0

Enable Auto Updates

#!/bin/bash

# Enable App Store auto updates
sudo defaults write /Library/Preferences/com.apple.commerce.plist AutoUpdate -bool TRUE

echo "App Store auto updates enabled"
exit 0

Check Current Auto Update Status

#!/bin/bash

# Check current auto update setting
auto_update_status=$(defaults read /Library/Preferences/com.apple.commerce.plist AutoUpdate 2>/dev/null || echo "Not Set")

if [[ "$auto_update_status" == "1" ]]; then
    echo "App Store Auto Updates: ENABLED"
elif [[ "$auto_update_status" == "0" ]]; then
    echo "App Store Auto Updates: DISABLED"
else
    echo "App Store Auto Updates: DEFAULT (typically enabled)"
fi

Advanced Update Management

Comprehensive Update Policy Configuration

#!/bin/bash

# Advanced App Store update management with validation
configure_app_store_updates() {
    local policy="$1"
    local schedule="$2"
    local dry_run="${3:-false}"
    
    # Validate admin privileges
    if [[ $EUID -ne 0 ]]; then
        echo "Error: This script requires administrator privileges"
        echo "Please run with sudo: sudo $0"
        exit 1
    fi
    
    echo "=== Configuring App Store Update Policy: $policy ==="
    
    if [[ "$dry_run" == "true" ]]; then
        echo "DRY RUN MODE - No changes will be applied"
        return 0
    fi
    
    case "$policy" in
        "enterprise_controlled")
            echo "Applying enterprise controlled update policy..."
            
            # Disable auto updates for controlled environment
            defaults write /Library/Preferences/com.apple.commerce.plist AutoUpdate -bool FALSE
            
            # Disable automatic download of updates
            defaults write /Library/Preferences/com.apple.SoftwareUpdate.plist AutomaticDownload -bool FALSE
            
            # Disable critical updates installation
            defaults write /Library/Preferences/com.apple.SoftwareUpdate.plist CriticalUpdateInstall -bool FALSE
            
            echo "✓ Enterprise controlled policy applied"
            ;;
        "security_only")
            echo "Applying security-only update policy..."
            
            # Disable general app updates
            defaults write /Library/Preferences/com.apple.commerce.plist AutoUpdate -bool FALSE
            
            # Enable critical security updates only
            defaults write /Library/Preferences/com.apple.SoftwareUpdate.plist CriticalUpdateInstall -bool TRUE
            defaults write /Library/Preferences/com.apple.SoftwareUpdate.plist AutomaticDownload -bool TRUE
            
            echo "✓ Security-only update policy applied"
            ;;
        "scheduled_updates")
            echo "Applying scheduled update policy..."
            
            # Disable immediate updates
            defaults write /Library/Preferences/com.apple.commerce.plist AutoUpdate -bool FALSE
            
            # Configure scheduled update checking
            setup_scheduled_updates "$schedule"
            
            echo "✓ Scheduled update policy applied"
            ;;
        "bandwidth_conscious")
            echo "Applying bandwidth-conscious update policy..."
            
            # Disable automatic downloads
            defaults write /Library/Preferences/com.apple.commerce.plist AutoUpdate -bool FALSE
            defaults write /Library/Preferences/com.apple.SoftwareUpdate.plist AutomaticDownload -bool FALSE
            
            # Enable update checking but not automatic installation
            defaults write /Library/Preferences/com.apple.SoftwareUpdate.plist AutomaticCheckEnabled -bool TRUE
            
            echo "✓ Bandwidth-conscious policy applied"
            ;;
        "full_auto")
            echo "Applying full automatic update policy..."
            
            # Enable all automatic updates
            defaults write /Library/Preferences/com.apple.commerce.plist AutoUpdate -bool TRUE
            defaults write /Library/Preferences/com.apple.SoftwareUpdate.plist AutomaticDownload -bool TRUE
            defaults write /Library/Preferences/com.apple.SoftwareUpdate.plist AutomaticCheckEnabled -bool TRUE
            defaults write /Library/Preferences/com.apple.SoftwareUpdate.plist CriticalUpdateInstall -bool TRUE
            
            echo "✓ Full automatic update policy applied"
            ;;
        "disabled")
            echo "Disabling all automatic updates..."
            
            # Disable all automatic update features
            defaults write /Library/Preferences/com.apple.commerce.plist AutoUpdate -bool FALSE
            defaults write /Library/Preferences/com.apple.SoftwareUpdate.plist AutomaticDownload -bool FALSE
            defaults write /Library/Preferences/com.apple.SoftwareUpdate.plist AutomaticCheckEnabled -bool FALSE
            defaults write /Library/Preferences/com.apple.SoftwareUpdate.plist CriticalUpdateInstall -bool FALSE
            
            echo "✓ All automatic updates disabled"
            ;;
        *)
            echo "Error: Unknown policy '$policy'"
            echo "Available policies: enterprise_controlled, security_only, scheduled_updates, bandwidth_conscious, full_auto, disabled"
            return 1
            ;;
    esac
    
    # Verify configuration
    verify_update_settings
}

# Setup scheduled updates
setup_scheduled_updates() {
    local schedule="$1"
    
    case "$schedule" in
        "weekly")
            # Create weekly update check
            create_update_schedule "weekly" "0 2 * * 1"
            ;;
        "monthly")
            # Create monthly update check
            create_update_schedule "monthly" "0 2 1 * *"
            ;;
        "daily_check")
            # Daily check, manual install
            create_update_schedule "daily_check" "0 8 * * *"
            ;;
        *)
            echo "Default schedule: weekly"
            create_update_schedule "weekly" "0 2 * * 1"
            ;;
    esac
}

# Create scheduled update tasks
create_update_schedule() {
    local schedule_name="$1"
    local cron_schedule="$2"
    
    local plist_path="/Library/LaunchDaemons/com.roundfleet.updatecheck.plist"
    
    cat > "$plist_path" << EOF
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Label</key>
    <string>com.roundfleet.updatecheck</string>
    <key>ProgramArguments</key>
    <array>
        <string>/usr/bin/python3</string>
        <string>/usr/local/bin/roundfleet_update_checker.py</string>
    </array>
    <key>StartCalendarInterval</key>
    <dict>
        <key>Hour</key>
        <integer>2</integer>
        <key>Minute</key>
        <integer>0</integer>
        <key>Weekday</key>
        <integer>1</integer>
    </dict>
    <key>RunAtLoad</key>
    <false/>
</dict>
</plist>
EOF
    
    # Set proper permissions
    chown root:wheel "$plist_path"
    chmod 644 "$plist_path"
    
    echo "✓ Scheduled update check created: $schedule_name"
}

# Verify current update settings
verify_update_settings() {
    echo ""
    echo "=== Current Update Configuration ==="
    
    # Check App Store auto updates
    local app_store_auto=$(defaults read /Library/Preferences/com.apple.commerce.plist AutoUpdate 2>/dev/null || echo "Default")
    echo "App Store Auto Updates: $([ "$app_store_auto" == "1" ] && echo "Enabled" || [ "$app_store_auto" == "0" ] && echo "Disabled" || echo "Default (Enabled)")"
    
    # Check Software Update settings
    local auto_download=$(defaults read /Library/Preferences/com.apple.SoftwareUpdate.plist AutomaticDownload 2>/dev/null || echo "Default")
    echo "Automatic Download: $([ "$auto_download" == "1" ] && echo "Enabled" || [ "$auto_download" == "0" ] && echo "Disabled" || echo "Default")"
    
    local auto_check=$(defaults read /Library/Preferences/com.apple.SoftwareUpdate.plist AutomaticCheckEnabled 2>/dev/null || echo "Default")
    echo "Automatic Check: $([ "$auto_check" == "1" ] && echo "Enabled" || [ "$auto_check" == "0" ] && echo "Disabled" || echo "Default")"
    
    local critical_updates=$(defaults read /Library/Preferences/com.apple.SoftwareUpdate.plist CriticalUpdateInstall 2>/dev/null || echo "Default")
    echo "Critical Updates: $([ "$critical_updates" == "1" ] && echo "Enabled" || [ "$critical_updates" == "0" ] && echo "Disabled" || echo "Default")"
}

# Usage examples
configure_app_store_updates "enterprise_controlled" "weekly"

Update Monitoring and Reporting

#!/bin/bash

# Monitor and report on update status
monitor_update_status() {
    local detailed="${1:-false}"
    
    echo "=== App Store Update Status Monitor ==="
    
    # Check for available updates
    echo "Checking for available updates..."
    local available_updates
    available_updates=$(softwareupdate -l 2>/dev/null | grep -c "recommended" || echo "0")
    
    echo "Available Updates: $available_updates"
    
    # Check last update check time
    local last_check
    last_check=$(defaults read /Library/Preferences/com.apple.SoftwareUpdate.plist LastSuccessfulDate 2>/dev/null || echo "Unknown")
    echo "Last Update Check: $last_check"
    
    # Check update history
    if [[ "$detailed" == "true" ]]; then
        echo ""
        echo "=== Detailed Update Information ==="
        
        # List available updates
        echo "Available Updates:"
        softwareupdate -l 2>/dev/null | grep -A 3 "recommended" || echo "No updates available"
        
        # Check update download cache
        local cache_size
        cache_size=$(du -sh /Library/Updates 2>/dev/null | cut -f1 || echo "0B")
        echo "Update Cache Size: $cache_size"
        
        # Check system version
        echo "Current System Version: $(sw_vers -productVersion)"
        echo "Build Version: $(sw_vers -buildVersion)"
    fi
}

# Generate update compliance report
generate_update_report() {
    local report_type="${1:-standard}"
    local output_file="${2:-/tmp/update_report_$(date +%Y%m%d_%H%M%S).json}"
    
    echo "=== Generating Update Report: $report_type ==="
    
    # Collect update information
    local hostname=$(hostname)
    local system_version=$(sw_vers -productVersion)
    local build_version=$(sw_vers -buildVersion)
    local app_store_auto=$(defaults read /Library/Preferences/com.apple.commerce.plist AutoUpdate 2>/dev/null || echo "default")
    local auto_download=$(defaults read /Library/Preferences/com.apple.SoftwareUpdate.plist AutomaticDownload 2>/dev/null || echo "default")
    local last_check=$(defaults read /Library/Preferences/com.apple.SoftwareUpdate.plist LastSuccessfulDate 2>/dev/null || echo "unknown")
    
    # Get available updates list
    local available_updates
    available_updates=$(softwareupdate -l 2>/dev/null | grep "recommended" | wc -l | tr -d ' ')
    
    cat > "$output_file" << EOF
{
    "update_report": {
        "report_type": "$report_type",
        "timestamp": "$(date -u +%Y-%m-%dT%H:%M:%SZ)",
        "hostname": "$hostname",
        "system_info": {
            "system_version": "$system_version",
            "build_version": "$build_version"
        },
        "update_settings": {
            "app_store_auto_update": "$app_store_auto",
            "automatic_download": "$auto_download",
            "last_update_check": "$last_check"
        },
        "update_status": {
            "available_updates": $available_updates,
            "pending_restarts": false
        }
    }
}
EOF
    
    echo "✓ Update report generated: $output_file"
    echo "$output_file"
}

# Usage
monitor_update_status "true"
generate_update_report "compliance"

Enterprise App Store Update Management System

#!/bin/bash

# Roundfleet App Store Update Management Tool
# Comprehensive update policy management and monitoring for fleet devices

# Configuration
SCRIPT_VERSION="1.0.0"
LOG_FILE="/var/log/roundfleet_appstore_updates.log"
REPORT_DIR="/etc/roundfleet/reports/updates"
CONFIG_DIR="/etc/roundfleet/updates"
POLICY_DIR="/etc/roundfleet/policies/updates"

# Create directories if they don't exist
mkdir -p "$REPORT_DIR" "$CONFIG_DIR" "$POLICY_DIR"

# Update policy templates
declare -A UPDATE_POLICIES=(
    ["enterprise_strict"]="app_updates_disabled,system_updates_manual,security_updates_auto,bandwidth_priority_high"
    ["enterprise_balanced"]="app_updates_scheduled,system_updates_auto,security_updates_immediate,bandwidth_priority_medium"
    ["enterprise_liberal"]="app_updates_auto,system_updates_auto,security_updates_immediate,bandwidth_priority_low"
    ["kiosk_mode"]="app_updates_disabled,system_updates_disabled,security_updates_manual,bandwidth_priority_high"
    ["development"]="app_updates_auto,system_updates_prompt,security_updates_auto,bandwidth_priority_low"
    ["education"]="app_updates_scheduled,system_updates_scheduled,security_updates_auto,bandwidth_priority_medium"
    ["healthcare"]="app_updates_manual,system_updates_manual,security_updates_immediate,bandwidth_priority_high"
    ["financial"]="app_updates_disabled,system_updates_manual,security_updates_immediate,bandwidth_priority_high"
    ["retail"]="app_updates_scheduled,system_updates_auto,security_updates_auto,bandwidth_priority_medium"
    ["remote_work"]="app_updates_auto,system_updates_prompt,security_updates_auto,bandwidth_priority_medium"
)

# Update schedules for different scenarios
declare -A UPDATE_SCHEDULES=(
    ["business_hours"]="weekdays_evening,09:00-17:00_block"
    ["maintenance_window"]="weekend_only,saturday_2am"
    ["off_peak"]="overnight,02:00-05:00"
    ["immediate"]="real_time,no_delay"
    ["weekly_batch"]="sunday_night,sunday_23:00"
    ["monthly_patch"]="first_sunday,monthly_02:00"
)

# Bandwidth management profiles
declare -A BANDWIDTH_PROFILES=(
    ["conservative"]="max_5mbps,off_peak_only,cellular_disabled"
    ["balanced"]="max_20mbps,business_hours_limited,cellular_security_only"
    ["unlimited"]="no_throttle,anytime,cellular_enabled"
    ["emergency_only"]="max_1mbps,security_updates_only,cellular_emergency"
)

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

# Advanced update policy enforcement
enforce_update_policy() {
    local policy_name="$1"
    local environment_type="${2:-enterprise}"
    local bandwidth_profile="${3:-balanced}"
    local dry_run="${4:-false}"
    
    log_action "Enforcing update policy: $policy_name (environment: $environment_type, bandwidth: $bandwidth_profile, dry_run: $dry_run)"
    
    if [[ -z "${UPDATE_POLICIES[$policy_name]}" ]]; then
        log_action "ERROR: Unknown policy '$policy_name'"
        echo "Available policies: ${!UPDATE_POLICIES[*]}"
        return 1
    fi
    
    # Parse policy configuration
    IFS=',' read -ra POLICY_PARTS <<< "${UPDATE_POLICIES[$policy_name]}"
    local app_updates="${POLICY_PARTS[0]}"
    local system_updates="${POLICY_PARTS[1]}"
    local security_updates="${POLICY_PARTS[2]}"
    local bandwidth_priority="${POLICY_PARTS[3]}"
    
    echo "=== Enforcing Update Policy: $policy_name ==="
    echo "App Updates: $app_updates"
    echo "System Updates: $system_updates"
    echo "Security Updates: $security_updates"
    echo "Bandwidth Priority: $bandwidth_priority"
    echo "Environment: $environment_type"
    
    if [[ "$dry_run" == "true" ]]; then
        echo "DRY RUN MODE - No changes will be applied"
        return 0
    fi
    
    # Apply app update settings
    apply_app_update_policy "$app_updates"
    
    # Apply system update settings
    apply_system_update_policy "$system_updates"
    
    # Apply security update settings
    apply_security_update_policy "$security_updates"
    
    # Apply bandwidth management
    apply_bandwidth_management "$bandwidth_profile"
    
    # Configure environment-specific settings
    configure_environment_settings "$environment_type"
    
    # Generate policy compliance report
    local report_file="$REPORT_DIR/policy_enforcement_${policy_name}_$(date +%Y%m%d_%H%M%S).json"
    generate_comprehensive_report "$policy_name" "$report_file"
    
    log_action "Update policy enforcement completed: $report_file"
    echo "$report_file"
}

# Apply app update policy settings
apply_app_update_policy() {
    local policy="$1"
    
    case "$policy" in
        "app_updates_disabled")
            defaults write /Library/Preferences/com.apple.commerce.plist AutoUpdate -bool FALSE
            echo "✓ App Store auto updates disabled"
            ;;
        "app_updates_auto")
            defaults write /Library/Preferences/com.apple.commerce.plist AutoUpdate -bool TRUE
            echo "✓ App Store auto updates enabled"
            ;;
        "app_updates_scheduled")
            defaults write /Library/Preferences/com.apple.commerce.plist AutoUpdate -bool FALSE
            setup_scheduled_app_updates "weekly"
            echo "✓ App Store updates scheduled for weekly maintenance window"
            ;;
        "app_updates_manual")
            defaults write /Library/Preferences/com.apple.commerce.plist AutoUpdate -bool FALSE
            defaults write /Library/Preferences/com.apple.SoftwareUpdate.plist AutomaticCheckEnabled -bool TRUE
            echo "✓ App Store updates set to manual with automatic checking"
            ;;
    esac
}

# Apply system update policy settings
apply_system_update_policy() {
    local policy="$1"
    
    case "$policy" in
        "system_updates_disabled")
            defaults write /Library/Preferences/com.apple.SoftwareUpdate.plist AutomaticCheckEnabled -bool FALSE
            defaults write /Library/Preferences/com.apple.SoftwareUpdate.plist AutomaticDownload -bool FALSE
            echo "✓ System updates completely disabled"
            ;;
        "system_updates_auto")
            defaults write /Library/Preferences/com.apple.SoftwareUpdate.plist AutomaticCheckEnabled -bool TRUE
            defaults write /Library/Preferences/com.apple.SoftwareUpdate.plist AutomaticDownload -bool TRUE
            echo "✓ System updates fully automated"
            ;;
        "system_updates_manual")
            defaults write /Library/Preferences/com.apple.SoftwareUpdate.plist AutomaticCheckEnabled -bool TRUE
            defaults write /Library/Preferences/com.apple.SoftwareUpdate.plist AutomaticDownload -bool FALSE
            echo "✓ System updates set to manual installation"
            ;;
        "system_updates_prompt")
            defaults write /Library/Preferences/com.apple.SoftwareUpdate.plist AutomaticCheckEnabled -bool TRUE
            defaults write /Library/Preferences/com.apple.SoftwareUpdate.plist AutomaticDownload -bool TRUE
            # Configure user prompts for installation
            echo "✓ System updates set to prompt user for installation"
            ;;
        "system_updates_scheduled")
            defaults write /Library/Preferences/com.apple.SoftwareUpdate.plist AutomaticCheckEnabled -bool TRUE
            defaults write /Library/Preferences/com.apple.SoftwareUpdate.plist AutomaticDownload -bool TRUE
            setup_scheduled_system_updates "monthly"
            echo "✓ System updates scheduled for monthly maintenance"
            ;;
    esac
}

# Apply security update policy settings
apply_security_update_policy() {
    local policy="$1"
    
    case "$policy" in
        "security_updates_immediate")
            defaults write /Library/Preferences/com.apple.SoftwareUpdate.plist CriticalUpdateInstall -bool TRUE
            defaults write /Library/Preferences/com.apple.SoftwareUpdate.plist AutomaticCheckEnabled -bool TRUE
            echo "✓ Security updates set to immediate installation"
            ;;
        "security_updates_auto")
            defaults write /Library/Preferences/com.apple.SoftwareUpdate.plist CriticalUpdateInstall -bool TRUE
            echo "✓ Security updates enabled for automatic installation"
            ;;
        "security_updates_manual")
            defaults write /Library/Preferences/com.apple.SoftwareUpdate.plist CriticalUpdateInstall -bool FALSE
            echo "✓ Security updates set to manual installation"
            ;;
    esac
}

# Apply bandwidth management settings
apply_bandwidth_management() {
    local profile="$1"
    
    if [[ -z "${BANDWIDTH_PROFILES[$profile]}" ]]; then
        echo "Warning: Unknown bandwidth profile '$profile', using default"
        profile="balanced"
    fi
    
    # Parse bandwidth configuration
    IFS=',' read -ra BANDWIDTH_PARTS <<< "${BANDWIDTH_PROFILES[$profile]}"
    local max_bandwidth="${BANDWIDTH_PARTS[0]}"
    local time_restrictions="${BANDWIDTH_PARTS[1]}"
    local cellular_policy="${BANDWIDTH_PARTS[2]}"
    
    echo "✓ Bandwidth management applied: $profile"
    echo "  Max Bandwidth: $max_bandwidth"
    echo "  Time Restrictions: $time_restrictions"
    echo "  Cellular Policy: $cellular_policy"
    
    # Configure bandwidth throttling (implementation would depend on network tools)
    configure_bandwidth_throttling "$max_bandwidth" "$time_restrictions"
}

# Configure environment-specific settings
configure_environment_settings() {
    local environment="$1"
    
    case "$environment" in
        "healthcare")
            # HIPAA compliance settings
            configure_hipaa_update_compliance
            echo "✓ Healthcare/HIPAA update compliance configured"
            ;;
        "financial")
            # Financial services compliance
            configure_financial_update_compliance
            echo "✓ Financial services update compliance configured"
            ;;
        "education")
            # Educational institution settings
            configure_education_update_settings
            echo "✓ Educational environment update settings configured"
            ;;
        "kiosk")
            # Kiosk-specific restrictions
            configure_kiosk_update_restrictions
            echo "✓ Kiosk update restrictions configured"
            ;;
        "enterprise")
            # Standard enterprise settings
            configure_enterprise_update_settings
            echo "✓ Enterprise update settings configured"
            ;;
    esac
}

# Setup scheduled app updates
setup_scheduled_app_updates() {
    local frequency="$1"
    
    local script_path="/usr/local/bin/roundfleet_scheduled_app_updates.sh"
    
    cat > "$script_path" << 'EOF'
#!/bin/bash
# Roundfleet Scheduled App Updates
LOG_FILE="/var/log/roundfleet_scheduled_updates.log"

echo "$(date): Starting scheduled app update check" >> "$LOG_FILE"

# Check for app updates
available_updates=$(softwareupdate -l 2>/dev/null | grep -c "recommended" || echo "0")

if [[ "$available_updates" -gt 0 ]]; then
    echo "$(date): Found $available_updates available updates" >> "$LOG_FILE"
    
    # Download updates but don't install (for approval process)
    softwareupdate -d -a >> "$LOG_FILE" 2>&1
    
    # Notify administrators
    echo "$(date): Updates downloaded, awaiting approval" >> "$LOG_FILE"
else
    echo "$(date): No updates available" >> "$LOG_FILE"
fi
EOF
    
    chmod +x "$script_path"
    
    # Create launchd job based on frequency
    create_update_launchd_job "$frequency" "$script_path"
}

# Generate comprehensive update report
generate_comprehensive_report() {
    local policy_name="$1"
    local report_file="$2"
    
    # Collect comprehensive update information
    local hostname=$(hostname)
    local system_version=$(sw_vers -productVersion)
    local build_version=$(sw_vers -buildVersion)
    local uptime=$(uptime | awk '{print $3,$4}' | sed 's/,//')
    
    # Get current settings
    local app_store_auto=$(defaults read /Library/Preferences/com.apple.commerce.plist AutoUpdate 2>/dev/null || echo "default")
    local auto_download=$(defaults read /Library/Preferences/com.apple.SoftwareUpdate.plist AutomaticDownload 2>/dev/null || echo "default")
    local auto_check=$(defaults read /Library/Preferences/com.apple.SoftwareUpdate.plist AutomaticCheckEnabled 2>/dev/null || echo "default")
    local critical_updates=$(defaults read /Library/Preferences/com.apple.SoftwareUpdate.plist CriticalUpdateInstall 2>/dev/null || echo "default")
    
    # Get update status
    local available_updates=$(softwareupdate -l 2>/dev/null | grep -c "recommended" || echo "0")
    local last_check=$(defaults read /Library/Preferences/com.apple.SoftwareUpdate.plist LastSuccessfulDate 2>/dev/null || echo "unknown")
    local cache_size=$(du -sh /Library/Updates 2>/dev/null | cut -f1 || echo "0B")
    
    cat > "$report_file" << EOF
{
    "comprehensive_update_report": {
        "policy_name": "$policy_name",
        "timestamp": "$(date -u +%Y-%m-%dT%H:%M:%SZ)",
        "hostname": "$hostname",
        "script_version": "$SCRIPT_VERSION",
        "system_info": {
            "system_version": "$system_version",
            "build_version": "$build_version",
            "uptime": "$uptime"
        },
        "update_settings": {
            "app_store_auto_update": "$app_store_auto",
            "automatic_download": "$auto_download",
            "automatic_check": "$auto_check",
            "critical_updates": "$critical_updates"
        },
        "update_status": {
            "available_updates": $available_updates,
            "last_check": "$last_check",
            "cache_size": "$cache_size"
        },
        "compliance_status": "compliant",
        "policy_enforcement_date": "$(date -u +%Y-%m-%dT%H:%M:%SZ)"
    }
}
EOF
    
    log_action "Comprehensive update report generated: $report_file"
}

# Monitor update compliance across fleet
monitor_fleet_update_compliance() {
    local compliance_type="${1:-standard}"
    
    echo "=== Fleet Update Compliance Monitor ==="
    
    # Check overall compliance status
    local policy_violations=0
    local total_checks=0
    
    # Verify App Store settings
    local app_store_setting=$(defaults read /Library/Preferences/com.apple.commerce.plist AutoUpdate 2>/dev/null || echo "default")
    ((total_checks++))
    
    # Check for pending updates that violate policy
    local pending_updates=$(softwareupdate -l 2>/dev/null | grep -c "recommended" || echo "0")
    
    if [[ "$pending_updates" -gt 0 && "$compliance_type" == "strict" ]]; then
        ((policy_violations++))
        echo "⚠️ Policy Violation: Pending updates found in strict compliance mode"
    fi
    
    # Calculate compliance score
    local compliance_score=$((100 - (policy_violations * 100 / total_checks)))
    
    echo "Compliance Score: $compliance_score%"
    echo "Policy Violations: $policy_violations"
    echo "Total Checks: $total_checks"
    echo "Pending Updates: $pending_updates"
    
    # Generate compliance summary
    local compliance_file="$REPORT_DIR/fleet_compliance_$(date +%Y%m%d_%H%M%S).json"
    cat > "$compliance_file" << EOF
{
    "fleet_compliance": {
        "timestamp": "$(date -u +%Y-%m-%dT%H:%M:%SZ)",
        "compliance_type": "$compliance_type",
        "compliance_score": $compliance_score,
        "policy_violations": $policy_violations,
        "total_checks": $total_checks,
        "pending_updates": $pending_updates,
        "hostname": "$(hostname)"
    }
}
EOF
    
    echo "✓ Fleet compliance report: $compliance_file"
}

# Main execution function
main() {
    local action="${1:-status}"
    local param1="${2:-}"
    local param2="${3:-}"
    local param3="${4:-}"
    local param4="${5:-}"
    
    log_action "=== Roundfleet App Store Update Management Started ==="
    log_action "Action: $action"
    
    # Ensure required privileges for configuration changes
    if [[ "$action" != "status" && "$action" != "help" && "$action" != "report" && $EUID -ne 0 ]]; then
        echo "Error: This action requires administrator privileges"
        echo "Please run with sudo: sudo $0 $*"
        exit 1
    fi
    
    case "$action" in
        "policy")
            if [[ -z "$param1" ]]; then
                echo "Available policies: ${!UPDATE_POLICIES[*]}"
                exit 1
            fi
            enforce_update_policy "$param1" "$param2" "$param3" "$param4"
            ;;
        "enable")
            defaults write /Library/Preferences/com.apple.commerce.plist AutoUpdate -bool TRUE
            echo "✓ App Store auto updates enabled"
            ;;
        "disable")
            defaults write /Library/Preferences/com.apple.commerce.plist AutoUpdate -bool FALSE
            echo "✓ App Store auto updates disabled"
            ;;
        "check")
            echo "Checking for available updates..."
            softwareupdate -l
            ;;
        "install")
            if [[ -n "$param1" ]]; then
                echo "Installing specific update: $param1"
                softwareupdate -i "$param1"
            else
                echo "Installing all available updates..."
                softwareupdate -i -a
            fi
            ;;
        "status")
            verify_update_settings
            if [[ "$param1" == "detailed" ]]; then
                monitor_update_status "true"
            fi
            ;;
        "report")
            generate_comprehensive_report "${param1:-current}" "${param2:-/tmp/update_report_$(date +%Y%m%d_%H%M%S).json}"
            ;;
        "compliance")
            monitor_fleet_update_compliance "$param1"
            ;;
        "reset")
            echo "Resetting App Store update settings to defaults..."
            defaults delete /Library/Preferences/com.apple.commerce.plist AutoUpdate 2>/dev/null || true
            defaults delete /Library/Preferences/com.apple.SoftwareUpdate.plist AutomaticDownload 2>/dev/null || true
            defaults delete /Library/Preferences/com.apple.SoftwareUpdate.plist AutomaticCheckEnabled 2>/dev/null || true
            defaults delete /Library/Preferences/com.apple.SoftwareUpdate.plist CriticalUpdateInstall 2>/dev/null || true
            echo "✓ Update settings reset to system defaults"
            ;;
        "help")
            echo "Usage: $0 [action] [options...]"
            echo "Actions:"
            echo "  policy <policy_name> [environment] [bandwidth] [dry_run] - Apply update policy"
            echo "  enable - Enable App Store auto updates"
            echo "  disable - Disable App Store auto updates"
            echo "  check - Check for available updates"
            echo "  install [update_name] - Install updates (all or specific)"
            echo "  status [detailed] - Show current update configuration"
            echo "  report [policy_name] [output_file] - Generate update report"
            echo "  compliance [type] - Check fleet compliance"
            echo "  reset - Reset to system defaults"
            echo "  help - Show this help"
            echo ""
            echo "Policies: ${!UPDATE_POLICIES[*]}"
            echo "Schedules: ${!UPDATE_SCHEDULES[*]}"
            echo "Bandwidth Profiles: ${!BANDWIDTH_PROFILES[*]}"
            ;;
        *)
            log_action "ERROR: Unknown action: $action"
            echo "Use '$0 help' for usage information"
            exit 1
            ;;
    esac
    
    log_action "=== App Store update management completed ==="
}

# Execute main function
main "$@"

Update Security and Compliance

Healthcare/HIPAA Compliance

#!/bin/bash

# Configure HIPAA-compliant update management
configure_hipaa_update_compliance() {
    echo "=== Configuring HIPAA Update Compliance ==="
    
    # Disable automatic updates for compliance control
    defaults write /Library/Preferences/com.apple.commerce.plist AutoUpdate -bool FALSE
    defaults write /Library/Preferences/com.apple.SoftwareUpdate.plist AutomaticDownload -bool FALSE
    
    # Enable security updates only
    defaults write /Library/Preferences/com.apple.SoftwareUpdate.plist CriticalUpdateInstall -bool TRUE
    
    # Configure audit logging
    setup_update_audit_logging "hipaa"
    
    echo "✓ HIPAA update compliance configured"
}

# Setup audit logging for compliance
setup_update_audit_logging() {
    local compliance_type="$1"
    local audit_file="/var/log/roundfleet_update_audit.log"
    
    # Create audit script
    cat > "/usr/local/bin/roundfleet_update_audit.sh" << 'EOF'
#!/bin/bash
AUDIT_LOG="/var/log/roundfleet_update_audit.log"

log_update_event() {
    local event_type="$1"
    local details="$2"
    echo "$(date -u +%Y-%m-%dT%H:%M:%SZ) | $event_type | $(whoami) | $details" >> "$AUDIT_LOG"
}

# Monitor for update events
log_update_event "AUDIT_START" "Update audit monitoring started"
EOF
    
    chmod +x "/usr/local/bin/roundfleet_update_audit.sh"
    echo "✓ Update audit logging configured for $compliance_type"
}

configure_hipaa_update_compliance

Financial Services Compliance

#!/bin/bash

# Configure financial services update compliance
configure_financial_update_compliance() {
    echo "=== Configuring Financial Services Update Compliance ==="
    
    # Strict update control for financial compliance
    defaults write /Library/Preferences/com.apple.commerce.plist AutoUpdate -bool FALSE
    defaults write /Library/Preferences/com.apple.SoftwareUpdate.plist AutomaticDownload -bool FALSE
    defaults write /Library/Preferences/com.apple.SoftwareUpdate.plist AutomaticCheckEnabled -bool TRUE
    
    # Security updates only with manual approval
    defaults write /Library/Preferences/com.apple.SoftwareUpdate.plist CriticalUpdateInstall -bool FALSE
    
    # Configure change management integration
    setup_change_management_integration "financial"
    
    echo "✓ Financial services update compliance configured"
}

configure_financial_update_compliance

Troubleshooting and Maintenance

Update System Health Check

#!/bin/bash

# Comprehensive update system health check
perform_update_health_check() {
    echo "=== Update System Health Check ==="
    
    # Check update service status
    local update_service_status
    update_service_status=$(launchctl list | grep -c "com.apple.softwareupdated" || echo "0")
    echo "Software Update Service: $([ "$update_service_status" -gt 0 ] && echo "Running" || echo "Not Running")"
    
    # Check update cache
    local cache_path="/Library/Updates"
    if [[ -d "$cache_path" ]]; then
        local cache_size=$(du -sh "$cache_path" | cut -f1)
        local cache_files=$(find "$cache_path" -type f | wc -l | tr -d ' ')
        echo "Update Cache: $cache_size ($cache_files files)"
    else
        echo "Update Cache: Not present"
    fi
    
    # Check for corrupted preferences
    local commerce_plist="/Library/Preferences/com.apple.commerce.plist"
    local softwareupdate_plist="/Library/Preferences/com.apple.SoftwareUpdate.plist"
    
    if plutil -lint "$commerce_plist" &>/dev/null; then
        echo "Commerce Preferences: Valid"
    else
        echo "⚠️ Commerce Preferences: Corrupted or missing"
    fi
    
    if plutil -lint "$softwareupdate_plist" &>/dev/null; then
        echo "Software Update Preferences: Valid"
    else
        echo "⚠️ Software Update Preferences: Corrupted or missing"
    fi
    
    # Check network connectivity for updates
    if curl -s --connect-timeout 5 "https://swscan.apple.com/" &>/dev/null; then
        echo "Apple Update Servers: Accessible"
    else
        echo "⚠️ Apple Update Servers: Not accessible"
    fi
}

perform_update_health_check

Important Notes

  • Administrator privileges required for update configuration changes
  • Restart requirements - Some settings take effect after restart
  • Network impact - Consider bandwidth usage for automatic updates
  • Security implications - Balance automation with security control
  • Compliance requirements - Some industries require manual update approval
  • Storage considerations - Downloaded updates consume disk space
  • Testing recommendations - Test update policies on staging devices first
  • Monitoring importance - Regular compliance checking prevents policy drift

View Last Opened Time of Apps and Files on macOS

This comprehensive guide demonstrates how to track when applications and files were last accessed on macOS devices, providing essential insights for Mac fleet management and usage monitoring.

Overview

Monitoring app and file access patterns is crucial for:

  • Performance optimization: Identifying resource-intensive applications
  • License management: Tracking software usage for compliance
  • Security auditing: Monitoring file access for security compliance
  • Storage optimization: Finding unused applications and files
  • User behavior analysis: Understanding work patterns and productivity

Basic Last Opened Time Script

Simple App/File Check

Create a basic script to check when an app or file was last opened:

#!/bin/bash

# Basic script to get last opened time of an app or file
# Usage: ./last_opened.sh "/path/to/app/or/file"

if [ $# -eq 0 ]; then
    echo "Usage: $0 <file_path>"
    echo "Example: $0 '/Applications/Safari.app'"
    exit 1
fi

file_path="$1"

# Check if file exists
if [ ! -e "$file_path" ]; then
    echo "Error: File or application not found: $file_path"
    exit 1
fi

# Get last opened time using mdls
datetime=$(mdls "$file_path" -name kMDItemLastUsedDate | awk '{print $3,$4}')

if [ "$datetime" = "(null)" ]; then
    echo "'$file_path' has never been opened or last opened time is not available"
    exit 0
fi

echo "'$file_path' was last opened on (UTC):"
echo "$datetime"
echo "'$file_path' was last opened on (Local Time):"
echo "$(date -jf "%Y-%m-%d %H:%M:%S %z" "$datetime +0000" +"%Y-%m-%d %H:%M:%S")"

Enhanced Script with Error Handling

#!/bin/bash

# Enhanced script with comprehensive error handling and formatting
# Usage: ./enhanced_last_opened.sh "/path/to/app/or/file"

check_last_opened() {
    local file_path="$1"
    local file_name=$(basename "$file_path")
    
    # Validate input
    if [ -z "$file_path" ]; then
        echo "Error: No file path provided"
        return 1
    fi
    
    # Check if file exists
    if [ ! -e "$file_path" ]; then
        echo "Error: File not found: $file_path"
        return 1
    fi
    
    # Get metadata
    local datetime=$(mdls "$file_path" -name kMDItemLastUsedDate 2>/dev/null | awk '{print $3,$4}')
    local creation_date=$(mdls "$file_path" -name kMDItemContentCreationDate 2>/dev/null | awk '{print $3,$4}')
    local modification_date=$(mdls "$file_path" -name kMDItemContentModificationDate 2>/dev/null | awk '{print $3,$4}')
    
    echo "=== File Information ==="
    echo "File: $file_name"
    echo "Path: $file_path"
    echo ""
    
    # Last opened time
    if [ "$datetime" = "(null)" ] || [ -z "$datetime" ]; then
        echo "Last Opened: Never opened or information not available"
    else
        echo "Last Opened (UTC): $datetime"
        local local_time=$(date -jf "%Y-%m-%d %H:%M:%S %z" "$datetime +0000" +"%Y-%m-%d %H:%M:%S" 2>/dev/null)
        if [ $? -eq 0 ]; then
            echo "Last Opened (Local): $local_time"
        else
            echo "Last Opened (Local): Unable to convert time"
        fi
    fi
    
    # Creation date
    if [ "$creation_date" != "(null)" ] && [ -n "$creation_date" ]; then
        echo "Created (UTC): $creation_date"
    fi
    
    # Modification date
    if [ "$modification_date" != "(null)" ] && [ -n "$modification_date" ]; then
        echo "Modified (UTC): $modification_date"
    fi
    
    echo "========================"
    echo ""
}

# Main execution
if [ $# -eq 0 ]; then
    echo "Usage: $0 <file_path>"
    echo "Example: $0 '/Applications/Safari.app'"
    exit 1
fi

check_last_opened "$1"

Advanced Application Monitoring

Bulk Application Scanner

#!/bin/bash

# Bulk application scanner with detailed reporting
# Usage: ./bulk_app_scanner.sh

scan_applications() {
    local output_file="app_usage_report_$(date +%Y%m%d_%H%M%S).txt"
    
    echo "Roundfleet Application Usage Report" > "$output_file"
    echo "Generated: $(date)" >> "$output_file"
    echo "Device: $(scutil --get ComputerName)" >> "$output_file"
    echo "User: $(whoami)" >> "$output_file"
    echo "=======================================" >> "$output_file"
    echo "" >> "$output_file"
    
    # Scan Applications folder
    echo "Scanning /Applications..."
    find /Applications -maxdepth 2 -name "*.app" -type d | while read app_path; do
        app_name=$(basename "$app_path" .app)
        
        # Get last opened time
        datetime=$(mdls "$app_path" -name kMDItemLastUsedDate 2>/dev/null | awk '{print $3,$4}')
        
        if [ "$datetime" = "(null)" ] || [ -z "$datetime" ]; then
            last_opened="Never opened"
        else
            last_opened=$(date -jf "%Y-%m-%d %H:%M:%S %z" "$datetime +0000" +"%Y-%m-%d %H:%M:%S" 2>/dev/null)
            if [ $? -ne 0 ]; then
                last_opened="$datetime (UTC)"
            fi
        fi
        
        # Get app version
        app_version=$(mdls "$app_path" -name kMDItemVersion 2>/dev/null | awk -F'"' '{print $2}')
        if [ "$app_version" = "(null)" ] || [ -z "$app_version" ]; then
            app_version="Unknown"
        fi
        
        # Get app size
        app_size=$(du -sh "$app_path" 2>/dev/null | cut -f1)
        if [ -z "$app_size" ]; then
            app_size="Unknown"
        fi
        
        echo "App: $app_name" >> "$output_file"
        echo "  Version: $app_version" >> "$output_file"
        echo "  Size: $app_size" >> "$output_file"
        echo "  Last Opened: $last_opened" >> "$output_file"
        echo "  Path: $app_path" >> "$output_file"
        echo "" >> "$output_file"
        
        # Progress indicator
        echo "Processed: $app_name"
    done
    
    echo "Report saved to: $output_file"
}

# Execute scan
scan_applications

Recently Used Applications Filter

#!/bin/bash

# Filter applications by recent usage
# Usage: ./recent_apps.sh [days]

filter_recent_apps() {
    local days_threshold=${1:-7}  # Default to 7 days
    local cutoff_date=$(date -v -${days_threshold}d +%Y-%m-%d)
    
    echo "Applications used in the last $days_threshold days:"
    echo "Cutoff date: $cutoff_date"
    echo "=================================="
    
    find /Applications -maxdepth 2 -name "*.app" -type d | while read app_path; do
        app_name=$(basename "$app_path" .app)
        
        # Get last opened time
        datetime=$(mdls "$app_path" -name kMDItemLastUsedDate 2>/dev/null | awk '{print $3,$4}')
        
        if [ "$datetime" != "(null)" ] && [ -n "$datetime" ]; then
            # Convert to comparable format
            app_date=$(echo "$datetime" | cut -d' ' -f1)
            
            # Compare dates
            if [[ "$app_date" > "$cutoff_date" ]]; then
                local_time=$(date -jf "%Y-%m-%d %H:%M:%S %z" "$datetime +0000" +"%Y-%m-%d %H:%M:%S" 2>/dev/null)
                if [ $? -eq 0 ]; then
                    echo "$app_name - Last used: $local_time"
                else
                    echo "$app_name - Last used: $datetime (UTC)"
                fi
            fi
        fi
    done | sort
}

# Main execution
if [ $# -gt 1 ]; then
    echo "Usage: $0 [days]"
    echo "Example: $0 30  # Show apps used in last 30 days"
    exit 1
fi

filter_recent_apps "$1"

Enterprise File Monitoring

Document Access Tracker

#!/bin/bash

# Track document access patterns across common file types
# Usage: ./document_tracker.sh "/path/to/documents"

track_document_access() {
    local base_path=${1:-"$HOME/Documents"}
    local output_file="document_access_$(date +%Y%m%d_%H%M%S).json"
    
    echo "Tracking document access in: $base_path"
    
    # Create JSON report
    cat > "$output_file" << EOF
{
  "report_info": {
    "generated": "$(date -u +%Y-%m-%dT%H:%M:%SZ)",
    "device": "$(scutil --get ComputerName)",
    "user": "$(whoami)",
    "scan_path": "$base_path",
    "roundfleet_version": "1.0"
  },
  "documents": [
EOF
    
    local first_entry=true
    
    # Common document types
    local file_types=("*.pdf" "*.doc" "*.docx" "*.xls" "*.xlsx" "*.ppt" "*.pptx" "*.txt" "*.rtf" "*.pages" "*.numbers" "*.keynote")
    
    for pattern in "${file_types[@]}"; do
        find "$base_path" -name "$pattern" -type f 2>/dev/null | while read file_path; do
            # Get file metadata
            local filename=$(basename "$file_path")
            local extension="${filename##*.}"
            local size=$(stat -f%z "$file_path" 2>/dev/null || echo "0")
            
            # Get timestamps
            local last_used=$(mdls "$file_path" -name kMDItemLastUsedDate 2>/dev/null | awk '{print $3,$4}')
            local created=$(mdls "$file_path" -name kMDItemContentCreationDate 2>/dev/null | awk '{print $3,$4}')
            local modified=$(mdls "$file_path" -name kMDItemContentModificationDate 2>/dev/null | awk '{print $3,$4}')
            
            # Format for JSON
            if [ "$last_used" = "(null)" ] || [ -z "$last_used" ]; then
                last_used="null"
            else
                last_used="\"$last_used\""
            fi
            
            if [ "$created" = "(null)" ] || [ -z "$created" ]; then
                created="null"
            else
                created="\"$created\""
            fi
            
            if [ "$modified" = "(null)" ] || [ -z "$modified" ]; then
                modified="null"
            else
                modified="\"$modified\""
            fi
            
            # Add comma if not first entry
            if [ "$first_entry" = false ]; then
                echo "," >> "$output_file"
            fi
            first_entry=false
            
            # Add document entry
            cat >> "$output_file" << EOF
    {
      "filename": "$filename",
      "extension": "$extension",
      "size_bytes": $size,
      "path": "$file_path",
      "last_used": $last_used,
      "created": $created,
      "modified": $modified
    }EOF
        done
    done
    
    # Close JSON
    cat >> "$output_file" << EOF

  ]
}
EOF
    
    echo "Document access report saved to: $output_file"
}

# Execute tracking
track_document_access "$1"

Multi-User File Access Monitor

#!/bin/bash

# Monitor file access across multiple user accounts
# Usage: ./multi_user_monitor.sh

monitor_multi_user_access() {
    local report_file="multi_user_access_$(date +%Y%m%d_%H%M%S).txt"
    
    echo "Roundfleet Multi-User File Access Report" > "$report_file"
    echo "Generated: $(date)" >> "$report_file"
    echo "Device: $(scutil --get ComputerName)" >> "$report_file"
    echo "=========================================" >> "$report_file"
    echo "" >> "$report_file"
    
    # Get all user home directories
    local users=($(dscl . -list /Users | grep -v "^_" | grep -v "daemon" | grep -v "nobody" | grep -v "root"))
    
    for user in "${users[@]}"; do
        local user_home=$(dscl . -read /Users/$user NFSHomeDirectory | awk '{print $2}')
        
        if [ -d "$user_home" ]; then
            echo "User: $user ($user_home)" >> "$report_file"
            echo "--------------------------------" >> "$report_file"
            
            # Check Documents folder
            if [ -d "$user_home/Documents" ]; then
                echo "Recently accessed documents:" >> "$report_file"
                find "$user_home/Documents" -type f -name "*.pdf" -o -name "*.doc*" -o -name "*.xls*" -o -name "*.ppt*" 2>/dev/null | head -10 | while read file_path; do
                    local filename=$(basename "$file_path")
                    local last_used=$(mdls "$file_path" -name kMDItemLastUsedDate 2>/dev/null | awk '{print $3,$4}')
                    
                    if [ "$last_used" != "(null)" ] && [ -n "$last_used" ]; then
                        echo "  - $filename (Last used: $last_used)" >> "$report_file"
                    fi
                done
            fi
            
            # Check Downloads folder
            if [ -d "$user_home/Downloads" ]; then
                echo "Recent downloads:" >> "$report_file"
                find "$user_home/Downloads" -type f -mtime -7 2>/dev/null | head -5 | while read file_path; do
                    local filename=$(basename "$file_path")
                    local mod_time=$(stat -f "%Sm" -t "%Y-%m-%d %H:%M:%S" "$file_path" 2>/dev/null)
                    echo "  - $filename (Downloaded: $mod_time)" >> "$report_file"
                done
            fi
            
            echo "" >> "$report_file"
        fi
    done
    
    echo "Multi-user access report saved to: $report_file"
}

# Execute monitoring
monitor_multi_user_access

Remote Fleet Management

Centralized Usage Collector

#!/bin/bash

# Collect usage data for remote fleet management
# Usage: ./fleet_collector.sh

collect_fleet_data() {
    local device_id=$(system_profiler SPHardwareDataType | grep "Hardware UUID" | awk '{print $3}')
    local computer_name=$(scutil --get ComputerName)
    local timestamp=$(date -u +%Y-%m-%dT%H:%M:%SZ)
    
    # Create comprehensive report
    local report_file="fleet_usage_${computer_name}_$(date +%Y%m%d_%H%M%S).json"
    
    cat > "$report_file" << EOF
{
  "device_info": {
    "device_id": "$device_id",
    "computer_name": "$computer_name",
    "timestamp": "$timestamp",
    "os_version": "$(sw_vers -productVersion)",
    "uptime": "$(uptime | awk '{print $3,$4}' | sed 's/,//')"
  },
  "application_usage": [
EOF
    
    # Collect top applications
    local first_app=true
    find /Applications -maxdepth 2 -name "*.app" -type d | head -20 | while read app_path; do
        local app_name=$(basename "$app_path" .app)
        local last_used=$(mdls "$app_path" -name kMDItemLastUsedDate 2>/dev/null | awk '{print $3,$4}')
        local version=$(mdls "$app_path" -name kMDItemVersion 2>/dev/null | awk -F'"' '{print $2}')
        
        if [ "$first_app" = false ]; then
            echo "," >> "$report_file"
        fi
        first_app=false
        
        # Format values for JSON
        if [ "$last_used" = "(null)" ] || [ -z "$last_used" ]; then
            last_used="null"
        else
            last_used="\"$last_used\""
        fi
        
        if [ "$version" = "(null)" ] || [ -z "$version" ]; then
            version="null"
        else
            version="\"$version\""
        fi
        
        cat >> "$report_file" << EOF
    {
      "name": "$app_name",
      "version": $version,
      "last_used": $last_used,
      "path": "$app_path"
    }EOF
    done
    
    cat >> "$report_file" << EOF

  ],
  "system_stats": {
    "total_applications": $(find /Applications -maxdepth 2 -name "*.app" -type d | wc -l | tr -d ' '),
    "disk_usage": "$(df -h / | tail -1 | awk '{print $5}')",
    "memory_usage": "$(vm_stat | grep "Pages active" | awk '{print $3}' | sed 's/\.//')"
  }
}
EOF
    
    echo "Fleet data collected in: $report_file"
    
    # Optional: Send to central server
    # curl -X POST -H "Content-Type: application/json" -d @"$report_file" "https://your-fleet-server.com/api/usage"
}

# Execute collection
collect_fleet_data

Automated Usage Monitoring

#!/bin/bash

# Automated usage monitoring with alerts
# Usage: ./usage_monitor.sh

setup_monitoring() {
    local log_file="/var/log/roundfleet_usage.log"
    local config_file="/etc/roundfleet/usage_config.conf"
    
    # Create configuration if it doesn't exist
    if [ ! -f "$config_file" ]; then
        sudo mkdir -p /etc/roundfleet
        sudo cat > "$config_file" << EOF
# Roundfleet Usage Monitoring Configuration
MONITOR_INTERVAL=3600  # Check every hour
ALERT_THRESHOLD=30     # Alert if app unused for 30 days
REPORT_INTERVAL=86400  # Generate report daily
CLEANUP_THRESHOLD=90   # Flag apps unused for 90 days
EOF
    fi
    
    # Source configuration
    source "$config_file"
    
    # Create monitoring script
    cat > "/tmp/roundfleet_monitor.sh" << EOF
#!/bin/bash

# Roundfleet Usage Monitor
log_usage() {
    local timestamp=\$(date -u +%Y-%m-%dT%H:%M:%SZ)
    local computer_name=\$(scutil --get ComputerName)
    
    echo "[\$timestamp] Starting usage check on \$computer_name" >> "$log_file"
    
    # Check for unused applications
    find /Applications -maxdepth 2 -name "*.app" -type d | while read app_path; do
        local app_name=\$(basename "\$app_path" .app)
        local last_used=\$(mdls "\$app_path" -name kMDItemLastUsedDate 2>/dev/null | awk '{print \$3,\$4}')
        
        if [ "\$last_used" != "(null)" ] && [ -n "\$last_used" ]; then
            local days_since=\$(( (\$(date +%s) - \$(date -jf "%Y-%m-%d %H:%M:%S %z" "\$last_used +0000" +%s)) / 86400 ))
            
            if [ \$days_since -gt $ALERT_THRESHOLD ]; then
                echo "[\$timestamp] ALERT: \$app_name unused for \$days_since days" >> "$log_file"
            fi
            
            if [ \$days_since -gt $CLEANUP_THRESHOLD ]; then
                echo "[\$timestamp] CLEANUP: \$app_name flagged for removal (\$days_since days)" >> "$log_file"
            fi
        fi
    done
    
    echo "[\$timestamp] Usage check completed" >> "$log_file"
}

# Run monitoring
log_usage
EOF
    
    chmod +x "/tmp/roundfleet_monitor.sh"
    
    # Set up launchd for automated monitoring
    cat > "/tmp/com.roundfleet.usage.monitor.plist" << EOF
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Label</key>
    <string>com.roundfleet.usage.monitor</string>
    <key>ProgramArguments</key>
    <array>
        <string>/tmp/roundfleet_monitor.sh</string>
    </array>
    <key>StartInterval</key>
    <integer>$MONITOR_INTERVAL</integer>
    <key>RunAtLoad</key>
    <true/>
</dict>
</plist>
EOF
    
    echo "Monitoring setup complete. Use 'sudo launchctl load /tmp/com.roundfleet.usage.monitor.plist' to start."
}

# Execute setup
setup_monitoring

Best Practices for Mac Fleet Management

1. Performance Optimization

  • Monitor resource-intensive applications
  • Track applications that haven't been used recently
  • Identify opportunities for app cleanup
  • Optimize system performance through usage insights

2. Security and Compliance

  • Track file access for security audits
  • Monitor document handling compliance
  • Identify unauthorized file access patterns
  • Maintain access logs for compliance requirements

3. License Management

  • Monitor software usage for license optimization
  • Track application deployment effectiveness
  • Identify unused licenses for cost savings
  • Ensure compliance with software licensing agreements

4. User Experience

  • Understand user behavior patterns
  • Optimize application deployment strategies
  • Improve user productivity through usage insights
  • Customize device configurations based on usage

5. Maintenance and Cleanup

  • Identify unused applications for removal
  • Clean up temporary files and caches
  • Optimize storage usage
  • Schedule regular maintenance based on usage patterns

Troubleshooting Common Issues

1. Permission Errors

# Fix permission issues
sudo chown -R $(whoami) /Users/$(whoami)/Documents
sudo chmod -R 755 /Users/$(whoami)/Documents

2. Metadata Not Available

# Check if Spotlight indexing is enabled
mdutil -s /
# Re-index if necessary
sudo mdutil -i on /
sudo mdutil -E /

3. Script Execution Issues

# Make script executable
chmod +x script_name.sh
# Check bash version
bash --version
# Use full path for commands
/usr/bin/mdls instead of mdls

4. Date Format Issues

# Handle different date formats
date -jf "%Y-%m-%d %H:%M:%S %z" "2024-01-01 12:00:00 +0000" +"%Y-%m-%d %H:%M:%S"

Conclusion

Monitoring application and file usage is essential for effective Mac fleet management. These scripts provide comprehensive insights into user behavior, system performance, and security compliance. Regular monitoring helps optimize resources, improve user experience, and maintain security standards across your Mac fleet.

Remember to test scripts in a controlled environment before deploying them across your fleet, and always follow your organization's security and privacy policies when monitoring user activity.

Configure Alert Sound and Volume on macOS

Learn how to customize system alert sounds and volume levels on Mac devices. Essential for creating consistent audio experiences across enterprise Mac fleets and accommodating different work environments.

Change Alert Sound

Change the default alert sound from "Tink" to other available system sounds:

#!/bin/bash

# Get current user context
CURRENT_USER=$(stat -f "%Su" /dev/console)
CURRENT_USER_UID=$(id -u "$CURRENT_USER")

# Configuration
ALERT_SOUND="Submarine"  # Options: Basso, Funk, Glass, Ping, Pop, Submarine, Tink

echo "Setting alert sound to: $ALERT_SOUND"

# Apply alert sound setting
launchctl asuser $CURRENT_USER_UID sudo -iu "$CURRENT_USER" \
    defaults write .GlobalPreferences com.apple.sound.beep.sound "/System/Library/Sounds/${ALERT_SOUND}.aiff"

echo "✅ Alert sound changed to $ALERT_SOUND"
echo "🔄 Changes take effect immediately"

Change Alert Volume

Adjust the alert volume level (0-100%):

#!/bin/bash

# Get current user context
CURRENT_USER=$(stat -f "%Su" /dev/console)
CURRENT_USER_UID=$(id -u "$CURRENT_USER")

# Configuration
ALERT_VOLUME="75"  # Volume percentage (0-100)

echo "Setting alert volume to: ${ALERT_VOLUME}%"

# Apply alert volume setting
launchctl asuser $CURRENT_USER_UID sudo -iu "$CURRENT_USER" \
    osascript -e "set volume alert volume $ALERT_VOLUME"

echo "✅ Alert volume set to ${ALERT_VOLUME}%"

List Available Alert Sounds

Script to discover all available system alert sounds:

#!/bin/bash

echo "🔊 Available System Alert Sounds:"
echo "=================================="

# List all sound files in system sounds directory
SOUNDS_DIR="/System/Library/Sounds"
if [[ -d "$SOUNDS_DIR" ]]; then
    for sound_file in "$SOUNDS_DIR"/*.aiff; do
        if [[ -f "$sound_file" ]]; then
            sound_name=$(basename "$sound_file" .aiff)
            echo "  📢 $sound_name"
        fi
    done
else
    echo "❌ System sounds directory not found"
fi

echo ""
echo "💡 Use any of these names in the ALERT_SOUND variable"

Complete Alert Configuration

Comprehensive script to configure both sound and volume:

#!/bin/bash

# Function to configure alert settings
configure_alert_settings() {
    local sound_name="$1"
    local volume_level="$2"
    
    # Get current user context
    local current_user=$(stat -f "%Su" /dev/console)
    local current_user_uid=$(id -u "$current_user")
    
    echo "=== Roundfleet Alert Configuration ==="
    echo "👤 User: $current_user"
    echo "🔊 Sound: $sound_name"
    echo "🔊 Volume: ${volume_level}%"
    echo "==================================="
    
    # Validate sound file exists
    local sound_path="/System/Library/Sounds/${sound_name}.aiff"
    if [[ ! -f "$sound_path" ]]; then
        echo "❌ Error: Sound '$sound_name' not found"
        echo "📋 Available sounds:"
        ls /System/Library/Sounds/*.aiff | sed 's|.*/||' | sed 's|\.aiff||' | sed 's/^/  - /'
        return 1
    fi
    
    # Validate volume range
    if [[ $volume_level -lt 0 || $volume_level -gt 100 ]]; then
        echo "❌ Error: Volume must be between 0 and 100"
        return 1
    fi
    
    # Apply alert sound setting
    launchctl asuser $current_user_uid sudo -iu "$current_user" \
        defaults write .GlobalPreferences com.apple.sound.beep.sound "$sound_path"
    
    # Apply alert volume setting
    launchctl asuser $current_user_uid sudo -iu "$current_user" \
        osascript -e "set volume alert volume $volume_level"
    
    echo "✅ Alert settings configured successfully"
    echo "🎵 Sound: $sound_name"
    echo "🔊 Volume: ${volume_level}%"
}

# Enterprise configuration
ALERT_SOUND="Glass"
ALERT_VOLUME="50"

# Apply configuration
configure_alert_settings "$ALERT_SOUND" "$ALERT_VOLUME"

Get Current Alert Settings

Script to display current alert sound and volume configuration:

#!/bin/bash

# Get current user context
CURRENT_USER=$(stat -f "%Su" /dev/console)
CURRENT_USER_UID=$(id -u "$CURRENT_USER")

echo "📊 Current Alert Settings"
echo "========================="

# Get current alert sound
current_sound=$(launchctl asuser $CURRENT_USER_UID sudo -iu "$CURRENT_USER" \
    defaults read .GlobalPreferences com.apple.sound.beep.sound 2>/dev/null)

if [[ -n "$current_sound" ]]; then
    sound_name=$(basename "$current_sound" .aiff)
    echo "🔊 Alert Sound: $sound_name"
else
    echo "🔊 Alert Sound: Tink (default)"
fi

# Get current alert volume using AppleScript
current_volume=$(launchctl asuser $CURRENT_USER_UID sudo -iu "$CURRENT_USER" \
    osascript -e "get volume settings" 2>/dev/null | grep -o 'alert volume:[0-9]*' | cut -d: -f2)

if [[ -n "$current_volume" ]]; then
    echo "🔊 Alert Volume: ${current_volume}%"
else
    echo "🔊 Alert Volume: Unable to determine"
fi

echo "👤 User: $CURRENT_USER"
echo "🖥️  Device: $(hostname)"

Enterprise Alert Policy

Standardized alert configuration for enterprise environments:

#!/bin/bash

# Enterprise alert standardization
COMPANY_NAME="Roundfleet"
ENVIRONMENT_TYPE="office"  # Options: office, quiet, presentation, factory

# Define environment-specific settings
case "$ENVIRONMENT_TYPE" in
    "office")
        ALERT_SOUND="Glass"
        ALERT_VOLUME="50"
        ;;
    "quiet")
        ALERT_SOUND="Tink"
        ALERT_VOLUME="25"
        ;;
    "presentation")
        ALERT_SOUND="Pop"
        ALERT_VOLUME="10"
        ;;
    "factory")
        ALERT_SOUND="Basso"
        ALERT_VOLUME="100"
        ;;
    *)
        ALERT_SOUND="Glass"
        ALERT_VOLUME="50"
        ;;
esac

# Function to apply enterprise alert policy
apply_enterprise_alert_policy() {
    local current_user=$(stat -f "%Su" /dev/console)
    local current_user_uid=$(id -u "$current_user")
    
    echo "🏢 Applying Enterprise Alert Policy"
    echo "==================================="
    echo "Environment: $ENVIRONMENT_TYPE"
    echo "Device: $(hostname)"
    echo "User: $current_user"
    echo "Sound: $ALERT_SOUND"
    echo "Volume: ${ALERT_VOLUME}%"
    echo "Timestamp: $(date)"
    
    # Apply sound setting
    launchctl asuser $current_user_uid sudo -iu "$current_user" \
        defaults write .GlobalPreferences com.apple.sound.beep.sound "/System/Library/Sounds/${ALERT_SOUND}.aiff"
    
    # Apply volume setting
    launchctl asuser $current_user_uid sudo -iu "$current_user" \
        osascript -e "set volume alert volume $ALERT_VOLUME"
    
    echo "✅ Enterprise alert policy applied"
    echo "📊 Configuration complete on $(hostname)"
}

# Execute enterprise policy
apply_enterprise_alert_policy

Reset to Default Settings

Restore alert settings to macOS defaults:

#!/bin/bash

# Get current user context
CURRENT_USER=$(stat -f "%Su" /dev/console)
CURRENT_USER_UID=$(id -u "$CURRENT_USER")

echo "🔄 Resetting alert settings to defaults..."

# Reset alert sound to default (Tink)
launchctl asuser $CURRENT_USER_UID sudo -iu "$CURRENT_USER" \
    defaults delete .GlobalPreferences com.apple.sound.beep.sound 2>/dev/null || true

# Reset alert volume to default (75%)
launchctl asuser $CURRENT_USER_UID sudo -iu "$CURRENT_USER" \
    osascript -e "set volume alert volume 75"

echo "✅ Alert settings reset to defaults"
echo "🔊 Sound: Tink (default)"
echo "🔊 Volume: 75% (default)"

Usage with Roundfleet

  1. Choose appropriate sound and volume for your environment
  2. Test settings on a single device first
  3. Deploy through Roundfleet's remote script execution
  4. Verify settings across device fleet

Available System Sounds

Sound NameDescriptionUse Case
BassoDeep, attention-grabbingHigh-priority alerts
FunkModern, pleasantGeneral notifications
GlassClear, sharpProfessional environments
PingQuick, subtleMinimal distraction
PopShort, crispQuick acknowledgments
SubmarineUnique, distinctiveCreative environments
TinkDefault system soundStandard configuration

Environment Guidelines

EnvironmentRecommended SoundVolume Level
OfficeGlass, Tink25-50%
Quiet zonesPing, Pop10-25%
PresentationsPop, Tink10%
Factory/LoudBasso, Funk75-100%
CreativeSubmarine, Funk50-75%

Troubleshooting

Sound not changing: Verify sound file exists in /System/Library/Sounds/ Volume not applying: Ensure AppleScript execution permissions Permission denied: Verify user context with launchctl asuser

AirDrop Management on macOS

Control AirDrop functionality on your Roundfleet devices to enhance security and prevent unauthorized file transfers. This tutorial covers enabling, disabling, monitoring, and managing AirDrop settings for corporate compliance and data protection.

Understanding AirDrop on macOS

AirDrop is Apple's wireless file sharing technology that allows users to transfer files between nearby Apple devices including:

  • Mac computers running macOS Lion (10.7) or later
  • iOS devices (iPhone, iPad, iPod touch) with iOS 7 or later
  • Apple Watch for supported content types

Security Considerations

In enterprise environments, AirDrop can pose security risks:

  • Data leakage through unauthorized file transfers
  • Malware distribution via infected files
  • Corporate policy violations through uncontrolled sharing
  • Network security bypassing traditional file transfer controls

Basic AirDrop Control Commands

Disable AirDrop Functionality

#!/bin/sh

# Disable AirDrop by shutting down AWDL interface
sudo ifconfig awdl0 down

echo "AirDrop functionality disabled"

Enable AirDrop Functionality

#!/bin/sh

# Enable AirDrop by bringing up AWDL interface
sudo ifconfig awdl0 up

echo "AirDrop functionality enabled"

Check AirDrop Status

#!/bin/bash

# Check current AirDrop/AWDL interface status
check_airdrop_status() {
    local awdl_status
    awdl_status=$(ifconfig awdl0 2>/dev/null | grep "status:" | awk '{print $2}')
    
    if [[ "$awdl_status" == "active" ]]; then
        echo "AirDrop: ENABLED"
        return 0
    elif [[ "$awdl_status" == "inactive" ]]; then
        echo "AirDrop: DISABLED"
        return 1
    else
        echo "AirDrop: STATUS UNKNOWN"
        return 2
    fi
}

check_airdrop_status

Advanced AirDrop Management

Comprehensive AirDrop Control Script

#!/bin/bash

# Advanced AirDrop management with validation and logging
manage_airdrop() {
    local action="$1"
    local force="${2:-false}"
    
    # Validate admin privileges
    if [[ $EUID -ne 0 ]]; then
        echo "Error: This script requires administrator privileges"
        echo "Please run with sudo: sudo $0"
        exit 1
    fi
    
    case "$action" in
        "disable")
            echo "Disabling AirDrop functionality..."
            
            # Check current status
            local current_status
            current_status=$(ifconfig awdl0 2>/dev/null | grep "status:" | awk '{print $2}')
            
            if [[ "$current_status" == "inactive" ]]; then
                echo "AirDrop is already disabled"
                return 0
            fi
            
            # Disable AWDL interface
            if ifconfig awdl0 down 2>/dev/null; then
                echo "✓ AirDrop disabled successfully"
                
                # Verify the change
                sleep 2
                local new_status
                new_status=$(ifconfig awdl0 2>/dev/null | grep "status:" | awk '{print $2}')
                
                if [[ "$new_status" == "inactive" ]]; then
                    echo "✓ AirDrop status verified: DISABLED"
                    return 0
                else
                    echo "⚠ Warning: AirDrop status verification failed"
                    return 1
                fi
            else
                echo "✗ Failed to disable AirDrop"
                return 1
            fi
            ;;
        "enable")
            echo "Enabling AirDrop functionality..."
            
            # Check current status
            local current_status
            current_status=$(ifconfig awdl0 2>/dev/null | grep "status:" | awk '{print $2}')
            
            if [[ "$current_status" == "active" ]]; then
                echo "AirDrop is already enabled"
                return 0
            fi
            
            # Enable AWDL interface
            if ifconfig awdl0 up 2>/dev/null; then
                echo "✓ AirDrop enabled successfully"
                
                # Verify the change
                sleep 2
                local new_status
                new_status=$(ifconfig awdl0 2>/dev/null | grep "status:" | awk '{print $2}')
                
                if [[ "$new_status" == "active" ]]; then
                    echo "✓ AirDrop status verified: ENABLED"
                    return 0
                else
                    echo "⚠ Warning: AirDrop status verification failed"
                    return 1
                fi
            else
                echo "✗ Failed to enable AirDrop"
                return 1
            fi
            ;;
        "status")
            echo "Checking AirDrop status..."
            
            # Get detailed interface information
            if ifconfig awdl0 &>/dev/null; then
                local status_line
                status_line=$(ifconfig awdl0 | grep "status:")
                echo "AWDL Interface: $status_line"
                
                local flags_line
                flags_line=$(ifconfig awdl0 | head -1 | cut -d'<' -f2 | cut -d'>' -f1)
                echo "Interface Flags: $flags_line"
                
                # Check if interface is up and running
                if echo "$flags_line" | grep -q "UP"; then
                    echo "AirDrop Status: ENABLED"
                else
                    echo "AirDrop Status: DISABLED"
                fi
            else
                echo "AWDL Interface: NOT AVAILABLE"
                echo "AirDrop Status: NOT SUPPORTED"
            fi
            ;;
        *)
            echo "Usage: manage_airdrop [disable|enable|status]"
            echo "  disable - Disable AirDrop functionality"
            echo "  enable  - Enable AirDrop functionality"
            echo "  status  - Check current AirDrop status"
            return 1
            ;;
    esac
}

# Execute function with provided arguments
manage_airdrop "$@"

User-Level AirDrop Settings Management

#!/bin/bash

# Manage user-level AirDrop discovery settings
manage_airdrop_discovery() {
    local username="$1"
    local setting="$2"
    
    # Validate inputs
    if [[ -z "$username" || -z "$setting" ]]; then
        echo "Usage: manage_airdrop_discovery <username> <off|contacts|everyone>"
        return 1
    fi
    
    # Check if user exists
    if ! id "$username" &>/dev/null; then
        echo "Error: User '$username' does not exist"
        return 1
    fi
    
    # Map setting to numeric value
    local discovery_value
    case "$setting" in
        "off")
            discovery_value="0"
            ;;
        "contacts")
            discovery_value="1"
            ;;
        "everyone")
            discovery_value="2"
            ;;
        *)
            echo "Error: Invalid setting '$setting'"
            echo "Valid options: off, contacts, everyone"
            return 1
            ;;
    esac
    
    echo "Setting AirDrop discovery to '$setting' for user: $username"
    
    # Set the preference for the user
    if sudo -u "$username" defaults write com.apple.sharingd DiscoverableMode -int "$discovery_value"; then
        echo "✓ AirDrop discovery setting updated"
        
        # Restart sharing daemon to apply changes
        sudo -u "$username" killall sharingd 2>/dev/null
        
        echo "✓ Settings applied successfully"
        return 0
    else
        echo "✗ Failed to update AirDrop discovery setting"
        return 1
    fi
}

# Usage examples
manage_airdrop_discovery "$(whoami)" "contacts"

Enterprise AirDrop Policy Management

#!/bin/bash

# Enterprise AirDrop policy enforcement
apply_airdrop_policy() {
    local policy_type="$1"
    local apply_to_all_users="${2:-false}"
    
    echo "=== Applying AirDrop Policy: $policy_type ==="
    
    case "$policy_type" in
        "corporate_lockdown")
            echo "Applying corporate lockdown policy..."
            
            # Disable AirDrop system-wide
            sudo ifconfig awdl0 down
            
            # Disable for all users
            if [[ "$apply_to_all_users" == "true" ]]; then
                local users
                users=$(dscl . -list /Users | grep -v "^_" | grep -v "daemon\|nobody\|root")
                
                for user in $users; do
                    echo "Disabling AirDrop for user: $user"
                    sudo -u "$user" defaults write com.apple.sharingd DiscoverableMode -int 0
                done
            fi
            
            echo "✓ Corporate lockdown policy applied"
            ;;
        "contacts_only")
            echo "Applying contacts-only policy..."
            
            # Enable AirDrop but restrict to contacts
            sudo ifconfig awdl0 up
            
            if [[ "$apply_to_all_users" == "true" ]]; then
                local users
                users=$(dscl . -list /Users | grep -v "^_" | grep -v "daemon\|nobody\|root")
                
                for user in $users; do
                    echo "Setting contacts-only for user: $user"
                    sudo -u "$user" defaults write com.apple.sharingd DiscoverableMode -int 1
                done
            fi
            
            echo "✓ Contacts-only policy applied"
            ;;
        "unrestricted")
            echo "Applying unrestricted policy..."
            
            # Enable AirDrop with full discovery
            sudo ifconfig awdl0 up
            
            if [[ "$apply_to_all_users" == "true" ]]; then
                local users
                users=$(dscl . -list /Users | grep -v "^_" | grep -v "daemon\|nobody\|root")
                
                for user in $users; do
                    echo "Setting unrestricted for user: $user"
                    sudo -u "$user" defaults write com.apple.sharingd DiscoverableMode -int 2
                done
            fi
            
            echo "✓ Unrestricted policy applied"
            ;;
        *)
            echo "Error: Unknown policy type '$policy_type'"
            echo "Available policies: corporate_lockdown, contacts_only, unrestricted"
            return 1
            ;;
    esac
}

# Usage
apply_airdrop_policy "corporate_lockdown" "true"

Enterprise AirDrop Management System

#!/bin/bash

# Roundfleet AirDrop Management Tool
# Comprehensive AirDrop control and monitoring for fleet devices

# Configuration
SCRIPT_VERSION="1.0.0"
LOG_FILE="/var/log/roundfleet_airdrop.log"
REPORT_DIR="/etc/roundfleet/reports/airdrop"
CONFIG_DIR="/etc/roundfleet/airdrop"
POLICY_DIR="/etc/roundfleet/policies/airdrop"

# Create directories if they don't exist
mkdir -p "$REPORT_DIR" "$CONFIG_DIR" "$POLICY_DIR"

# AirDrop policy templates
declare -A AIRDROP_POLICIES=(
    ["high_security"]="disabled,no_discovery,monitoring_enabled,audit_logging"
    ["medium_security"]="enabled,contacts_only,monitoring_enabled,audit_logging"
    ["low_security"]="enabled,everyone,monitoring_disabled,basic_logging"
    ["development"]="enabled,everyone,monitoring_enabled,debug_logging"
    ["kiosk_mode"]="disabled,no_discovery,monitoring_disabled,no_logging"
    ["guest_network"]="enabled,contacts_only,monitoring_enabled,audit_logging"
    ["executive"]="enabled,contacts_only,monitoring_enabled,executive_reporting"
    ["classroom"]="disabled,no_discovery,monitoring_enabled,educational_logging"
    ["healthcare"]="disabled,no_discovery,monitoring_enabled,hipaa_compliance"
    ["financial"]="disabled,no_discovery,monitoring_enabled,sox_compliance"
)

# Security compliance frameworks
declare -A COMPLIANCE_SETTINGS=(
    ["hipaa"]="airdrop_disabled,audit_all_attempts,data_loss_prevention"
    ["sox"]="airdrop_disabled,financial_data_protection,executive_monitoring"
    ["gdpr"]="privacy_controls,user_consent_required,data_transfer_logging"
    ["pci_dss"]="payment_data_protection,cardholder_isolation,secure_networks"
    ["iso27001"]="information_security,access_controls,incident_management"
)

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

# Advanced AirDrop status monitoring
monitor_airdrop_status() {
    local detailed="${1:-false}"
    
    log_action "Monitoring AirDrop status (detailed: $detailed)"
    
    echo "=== AirDrop Status Monitor ==="
    
    # Check AWDL interface status
    local awdl_status="unknown"
    local awdl_flags=""
    local awdl_ip=""
    
    if ifconfig awdl0 &>/dev/null; then
        awdl_status=$(ifconfig awdl0 | grep "status:" | awk '{print $2}' || echo "unknown")
        awdl_flags=$(ifconfig awdl0 | head -1 | grep -o '<.*>' | tr -d '<>')
        awdl_ip=$(ifconfig awdl0 | grep "inet " | awk '{print $2}' || echo "none")
    fi
    
    echo "AWDL Interface Status: $awdl_status"
    echo "Interface Flags: $awdl_flags"
    echo "AWDL IP Address: $awdl_ip"
    
    # Check system-wide AirDrop enablement
    local system_airdrop_enabled="false"
    if [[ "$awdl_status" == "active" ]] && echo "$awdl_flags" | grep -q "UP"; then
        system_airdrop_enabled="true"
    fi
    
    echo "System AirDrop Status: $([ "$system_airdrop_enabled" == "true" ] && echo "ENABLED" || echo "DISABLED")"
    
    if [[ "$detailed" == "true" ]]; then
        echo ""
        echo "=== Detailed Analysis ==="
        
        # Check user-level settings
        local users
        users=$(dscl . -list /Users | grep -v "^_" | grep -v "daemon\|nobody\|root")
        
        echo "User-Level AirDrop Settings:"
        for user in $users; do
            local user_setting
            user_setting=$(sudo -u "$user" defaults read com.apple.sharingd DiscoverableMode 2>/dev/null || echo "not_set")
            
            local setting_text
            case "$user_setting" in
                "0") setting_text="OFF" ;;
                "1") setting_text="CONTACTS ONLY" ;;
                "2") setting_text="EVERYONE" ;;
                *) setting_text="NOT SET" ;;
            esac
            
            echo "  $user: $setting_text"
        done
        
        # Check network connectivity
        echo ""
        echo "Network Interface Information:"
        echo "Wi-Fi Status: $(networksetup -getairportpower en0 | awk '{print $4}')"
        echo "Bluetooth Status: $(system_profiler SPBluetoothDataType | grep "State:" | awk '{print $2}' | head -1)"
        
        # Check running processes
        echo ""
        echo "Related Processes:"
        ps aux | grep -E "(sharingd|airportd)" | grep -v grep | awk '{print $11}'
    fi
}

# Comprehensive AirDrop policy enforcement
enforce_airdrop_policy() {
    local policy_name="$1"
    local target_users="$2"
    local dry_run="${3:-false}"
    
    log_action "Enforcing AirDrop policy: $policy_name (dry_run: $dry_run)"
    
    if [[ -z "${AIRDROP_POLICIES[$policy_name]}" ]]; then
        log_action "ERROR: Unknown policy '$policy_name'"
        echo "Available policies: ${!AIRDROP_POLICIES[*]}"
        return 1
    fi
    
    # Parse policy configuration
    IFS=',' read -ra POLICY_PARTS <<< "${AIRDROP_POLICIES[$policy_name]}"
    local airdrop_state="${POLICY_PARTS[0]}"
    local discovery_setting="${POLICY_PARTS[1]}"
    local monitoring_level="${POLICY_PARTS[2]}"
    local logging_level="${POLICY_PARTS[3]}"
    
    echo "=== Enforcing Policy: $policy_name ==="
    echo "AirDrop State: $airdrop_state"
    echo "Discovery Setting: $discovery_setting"
    echo "Monitoring Level: $monitoring_level"
    echo "Logging Level: $logging_level"
    
    if [[ "$dry_run" == "true" ]]; then
        echo "DRY RUN MODE - No changes will be applied"
        return 0
    fi
    
    # Apply system-level settings
    case "$airdrop_state" in
        "enabled")
            echo "Enabling AirDrop system-wide..."
            sudo ifconfig awdl0 up
            ;;
        "disabled")
            echo "Disabling AirDrop system-wide..."
            sudo ifconfig awdl0 down
            ;;
    esac
    
    # Apply user-level settings
    if [[ "$target_users" == "all" ]]; then
        local users
        users=$(dscl . -list /Users | grep -v "^_" | grep -v "daemon\|nobody\|root")
    else
        IFS=',' read -ra users <<< "$target_users"
    fi
    
    local discovery_value
    case "$discovery_setting" in
        "no_discovery") discovery_value="0" ;;
        "contacts_only") discovery_value="1" ;;
        "everyone") discovery_value="2" ;;
    esac
    
    for user in "${users[@]}"; do
        if id "$user" &>/dev/null; then
            echo "Applying settings for user: $user"
            sudo -u "$user" defaults write com.apple.sharingd DiscoverableMode -int "$discovery_value"
            
            # Restart sharing daemon
            sudo -u "$user" killall sharingd 2>/dev/null
        fi
    done
    
    # Configure monitoring
    configure_airdrop_monitoring "$monitoring_level" "$logging_level"
    
    # Generate policy compliance report
    local report_file="$REPORT_DIR/policy_enforcement_${policy_name}_$(date +%Y%m%d_%H%M%S).json"
    generate_policy_report "$policy_name" "$report_file"
    
    log_action "Policy enforcement completed: $report_file"
    echo "$report_file"
}

# Configure AirDrop monitoring and logging
configure_airdrop_monitoring() {
    local monitoring_level="$1"
    local logging_level="$2"
    
    echo "Configuring monitoring (level: $monitoring_level, logging: $logging_level)"
    
    case "$monitoring_level" in
        "monitoring_enabled")
            # Create monitoring script
            cat > "/usr/local/bin/roundfleet_airdrop_monitor.sh" << 'EOF'
#!/bin/bash
# AirDrop activity monitor
while true; do
    # Monitor AWDL interface changes
    ifconfig awdl0 | grep "status:" >> /var/log/roundfleet_airdrop_activity.log
    sleep 30
done
EOF
            chmod +x "/usr/local/bin/roundfleet_airdrop_monitor.sh"
            
            # Create LaunchDaemon for monitoring
            cat > "/Library/LaunchDaemons/com.roundfleet.airdrop.monitor.plist" << EOF
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Label</key>
    <string>com.roundfleet.airdrop.monitor</string>
    <key>ProgramArguments</key>
    <array>
        <string>/usr/local/bin/roundfleet_airdrop_monitor.sh</string>
    </array>
    <key>RunAtLoad</key>
    <true/>
    <key>KeepAlive</key>
    <true/>
</dict>
</plist>
EOF
            launchctl load "/Library/LaunchDaemons/com.roundfleet.airdrop.monitor.plist"
            ;;
        "monitoring_disabled")
            # Remove monitoring components
            launchctl unload "/Library/LaunchDaemons/com.roundfleet.airdrop.monitor.plist" 2>/dev/null
            rm -f "/Library/LaunchDaemons/com.roundfleet.airdrop.monitor.plist"
            rm -f "/usr/local/bin/roundfleet_airdrop_monitor.sh"
            ;;
    esac
}

# Generate comprehensive policy compliance report
generate_policy_report() {
    local policy_name="$1"
    local report_file="$2"
    
    # Get current system state
    local awdl_status=$(ifconfig awdl0 2>/dev/null | grep "status:" | awk '{print $2}' || echo "unknown")
    local system_enabled="false"
    [[ "$awdl_status" == "active" ]] && system_enabled="true"
    
    # Get user settings
    local users
    users=$(dscl . -list /Users | grep -v "^_" | grep -v "daemon\|nobody\|root")
    
    cat > "$report_file" << EOF
{
    "policy_report": {
        "policy_name": "$policy_name",
        "timestamp": "$(date -u +%Y-%m-%dT%H:%M:%SZ)",
        "hostname": "$(hostname)",
        "script_version": "$SCRIPT_VERSION",
        "system_status": {
            "awdl_interface": "$awdl_status",
            "system_airdrop_enabled": $system_enabled
        },
        "user_settings": [],
        "compliance_status": "compliant",
        "recommendations": []
    }
}
EOF
    
    # Add user-specific settings
    for user in $users; do
        local user_setting
        user_setting=$(sudo -u "$user" defaults read com.apple.sharingd DiscoverableMode 2>/dev/null || echo "-1")
        
        jq --arg user "$user" \
           --argjson setting "$user_setting" \
           '.policy_report.user_settings += [{
               "username": $user,
               "discovery_mode": $setting,
               "discovery_text": (if $setting == 0 then "OFF" elif $setting == 1 then "CONTACTS_ONLY" elif $setting == 2 then "EVERYONE" else "NOT_SET" end)
           }]' "$report_file" > "${report_file}.tmp" && mv "${report_file}.tmp" "$report_file"
    done
    
    log_action "Policy report generated: $report_file"
}

# Fleet-wide AirDrop audit
audit_fleet_airdrop() {
    local scope="${1:-all}"
    
    echo "=== Fleet AirDrop Audit ==="
    log_action "Starting fleet AirDrop audit (scope: $scope)"
    
    local audit_report="$REPORT_DIR/fleet_airdrop_audit_$(date +%Y%m%d_%H%M%S).json"
    
    cat > "$audit_report" << EOF
{
    "audit_info": {
        "timestamp": "$(date -u +%Y-%m-%dT%H:%M:%SZ)",
        "hostname": "$(hostname)",
        "scope": "$scope",
        "audit_type": "airdrop_security"
    },
    "system_analysis": {},
    "user_analysis": [],
    "security_findings": [],
    "recommendations": []
}
EOF
    
    # System-level analysis
    local awdl_status=$(ifconfig awdl0 2>/dev/null | grep "status:" | awk '{print $2}' || echo "unknown")
    local wifi_status=$(networksetup -getairportpower en0 | awk '{print $4}')
    local bluetooth_status=$(system_profiler SPBluetoothDataType | grep "State:" | awk '{print $2}' | head -1)
    
    jq --arg awdl "$awdl_status" \
       --arg wifi "$wifi_status" \
       --arg bluetooth "$bluetooth_status" \
       '.audit_info.system_analysis = {
           "awdl_interface": $awdl,
           "wifi_enabled": ($wifi == "On"),
           "bluetooth_enabled": ($bluetooth == "On"),
           "airdrop_capable": (($wifi == "On") and ($bluetooth == "On"))
       }' "$audit_report" > "${audit_report}.tmp" && mv "${audit_report}.tmp" "$audit_report"
    
    # User-level analysis
    local users
    users=$(dscl . -list /Users | grep -v "^_" | grep -v "daemon\|nobody\|root")
    
    local security_issues=0
    
    for user in $users; do
        local discovery_mode
        discovery_mode=$(sudo -u "$user" defaults read com.apple.sharingd DiscoverableMode 2>/dev/null || echo "-1")
        
        local home_dir
        home_dir=$(dscl . -read "/Users/$user" NFSHomeDirectory 2>/dev/null | cut -d: -f2 | xargs)
        
        local is_admin="false"
        if dseditgroup -o checkmember -m "$user" admin &>/dev/null; then
            is_admin="true"
        fi
        
        # Check for security concerns
        local security_concern="none"
        if [[ "$discovery_mode" == "2" ]] && [[ "$is_admin" == "true" ]]; then
            security_concern="admin_user_unrestricted_airdrop"
            ((security_issues++))
        elif [[ "$discovery_mode" == "2" ]]; then
            security_concern="unrestricted_airdrop_enabled"
        fi
        
        jq --arg user "$user" \
           --argjson discovery "$discovery_mode" \
           --arg home "$home_dir" \
           --arg admin "$is_admin" \
           --arg concern "$security_concern" \
           '.audit_info.user_analysis += [{
               "username": $user,
               "discovery_mode": $discovery,
               "home_directory": $home,
               "is_admin": ($admin == "true"),
               "security_concern": $concern
           }]' "$audit_report" > "${audit_report}.tmp" && mv "${audit_report}.tmp" "$audit_report"
    done
    
    # Generate security summary
    jq --argjson issues "$security_issues" \
       '.audit_info.security_findings = [
           {
               "total_security_issues": $issues,
               "severity": (if $issues == 0 then "low" elif $issues < 3 then "medium" else "high" end),
               "compliance_status": (if $issues == 0 then "compliant" else "non_compliant" end)
           }
       ]' "$audit_report" > "${audit_report}.tmp" && mv "${audit_report}.tmp" "$audit_report"
    
    echo "Audit completed. Found $security_issues security issues."
    log_action "Fleet audit completed: $audit_report"
    echo "$audit_report"
}

# Main execution function
main() {
    local action="${1:-status}"
    local param1="${2:-}"
    local param2="${3:-}"
    local param3="${4:-}"
    
    log_action "=== Roundfleet AirDrop Management Started ==="
    log_action "Action: $action"
    
    # Ensure required privileges for most operations
    if [[ "$action" != "status" && "$action" != "help" && $EUID -ne 0 ]]; then
        echo "Error: This action requires administrator privileges"
        echo "Please run with sudo: sudo $0 $*"
        exit 1
    fi
    
    case "$action" in
        "disable")
            echo "Disabling AirDrop..."
            sudo ifconfig awdl0 down && echo "✓ AirDrop disabled" || echo "✗ Failed to disable AirDrop"
            ;;
        "enable")
            echo "Enabling AirDrop..."
            sudo ifconfig awdl0 up && echo "✓ AirDrop enabled" || echo "✗ Failed to enable AirDrop"
            ;;
        "status")
            monitor_airdrop_status "$param1"
            ;;
        "policy")
            if [[ -z "$param1" ]]; then
                echo "Available policies: ${!AIRDROP_POLICIES[*]}"
                exit 1
            fi
            enforce_airdrop_policy "$param1" "${param2:-all}" "$param3"
            ;;
        "audit")
            audit_fleet_airdrop "$param1"
            ;;
        "user")
            if [[ -z "$param1" || -z "$param2" ]]; then
                echo "Usage: $0 user <username> <off|contacts|everyone>"
                exit 1
            fi
            manage_airdrop_discovery "$param1" "$param2"
            ;;
        "help")
            echo "Usage: $0 [action] [options...]"
            echo "Actions:"
            echo "  disable - Disable AirDrop system-wide"
            echo "  enable - Enable AirDrop system-wide"
            echo "  status [detailed] - Check AirDrop status"
            echo "  policy <policy_name> [users] [dry_run] - Apply policy"
            echo "  user <username> <setting> - Set user AirDrop setting"
            echo "  audit [scope] - Audit AirDrop security"
            echo "  help - Show this help"
            echo ""
            echo "Policies: ${!AIRDROP_POLICIES[*]}"
            ;;
        *)
            log_action "ERROR: Unknown action: $action"
            echo "Use '$0 help' for usage information"
            exit 1
            ;;
    esac
    
    log_action "=== AirDrop management completed ==="
}

# Execute main function
main "$@"

AirDrop Security Best Practices

Corporate Security Policies

#!/bin/bash

# Implement corporate AirDrop security policies
implement_corporate_security() {
    echo "=== Implementing Corporate AirDrop Security ==="
    
    # 1. Disable AirDrop on shared/public computers
    echo "Disabling AirDrop on shared workstations..."
    sudo ifconfig awdl0 down
    
    # 2. Set restrictive user defaults
    echo "Setting restrictive AirDrop defaults..."
    local users
    users=$(dscl . -list /Users | grep -v "^_" | grep -v "daemon\|nobody\|root")
    
    for user in $users; do
        sudo -u "$user" defaults write com.apple.sharingd DiscoverableMode -int 0
    done
    
    # 3. Create system-wide policy enforcement
    cat > "/Library/Preferences/com.apple.sharingd.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>DiscoverableMode</key>
    <integer>0</integer>
    <key>AirDropEnabled</key>
    <false/>
</dict>
</plist>
EOF
    
    # 4. Set proper permissions
    chmod 644 "/Library/Preferences/com.apple.sharingd.plist"
    chown root:wheel "/Library/Preferences/com.apple.sharingd.plist"
    
    echo "✓ Corporate security policies implemented"
}

implement_corporate_security

Compliance Monitoring

#!/bin/bash

# Monitor AirDrop compliance with security policies
monitor_compliance() {
    local compliance_standard="$1"
    
    echo "=== AirDrop Compliance Monitoring: $compliance_standard ==="
    
    case "$compliance_standard" in
        "hipaa")
            # Healthcare compliance - AirDrop must be disabled
            if ifconfig awdl0 | grep -q "status: active"; then
                echo "⚠ HIPAA VIOLATION: AirDrop is enabled"
                echo "Recommendation: Disable AirDrop to prevent PHI leakage"
                return 1
            else
                echo "✓ HIPAA COMPLIANT: AirDrop is disabled"
            fi
            ;;
        "pci_dss")
            # Payment card industry compliance
            if ifconfig awdl0 | grep -q "status: active"; then
                echo "⚠ PCI DSS VIOLATION: AirDrop creates uncontrolled network path"
                echo "Recommendation: Disable AirDrop in cardholder data environment"
                return 1
            else
                echo "✓ PCI DSS COMPLIANT: AirDrop is disabled"
            fi
            ;;
        "sox")
            # Sarbanes-Oxley compliance for financial data
            echo "Checking SOX compliance for financial data protection..."
            # Implementation specific to financial data handling
            ;;
        *)
            echo "Unknown compliance standard: $compliance_standard"
            return 1
            ;;
    esac
}

# Usage
monitor_compliance "hipaa"

Troubleshooting AirDrop Issues

Network Diagnostics

#!/bin/bash

# Comprehensive AirDrop troubleshooting
troubleshoot_airdrop() {
    echo "=== AirDrop Troubleshooting Diagnostics ==="
    
    echo "1. Checking AWDL Interface..."
    if ifconfig awdl0 &>/dev/null; then
        ifconfig awdl0 | head -10
    else
        echo "AWDL interface not available"
    fi
    
    echo -e "\n2. Checking Wi-Fi Status..."
    networksetup -getairportpower en0
    
    echo -e "\n3. Checking Bluetooth Status..."
    system_profiler SPBluetoothDataType | grep -A 5 "State:"
    
    echo -e "\n4. Checking Firewall Settings..."
    /usr/libexec/ApplicationFirewall/socketfilterfw --getglobalstate
    
    echo -e "\n5. Checking Sharing Preferences..."
    local users
    users=$(dscl . -list /Users | grep -v "^_" | grep -v "daemon\|nobody\|root")
    
    for user in $users; do
        local setting
        setting=$(sudo -u "$user" defaults read com.apple.sharingd DiscoverableMode 2>/dev/null || echo "not set")
        echo "User $user: $setting"
    done
    
    echo -e "\n6. Checking Related Processes..."
    ps aux | grep -E "(sharingd|airportd|bluetoothd)" | grep -v grep
    
    echo -e "\n7. Network Interface Summary..."
    networksetup -listallhardwareports | grep -A 1 "Wi-Fi\|Bluetooth"
}

troubleshoot_airdrop

Reset AirDrop Configuration

#!/bin/bash

# Reset AirDrop to default configuration
reset_airdrop_config() {
    echo "=== Resetting AirDrop Configuration ==="
    
    # Stop sharing daemon
    echo "Stopping sharing daemon..."
    sudo killall sharingd 2>/dev/null
    
    # Reset AWDL interface
    echo "Resetting AWDL interface..."
    sudo ifconfig awdl0 down
    sleep 2
    sudo ifconfig awdl0 up
    
    # Clear user preferences
    echo "Clearing user AirDrop preferences..."
    local users
    users=$(dscl . -list /Users | grep -v "^_" | grep -v "daemon\|nobody\|root")
    
    for user in $users; do
        echo "Resetting preferences for user: $user"
        sudo -u "$user" defaults delete com.apple.sharingd DiscoverableMode 2>/dev/null || true
    done
    
    # Remove system-wide policies
    echo "Removing system-wide AirDrop policies..."
    sudo rm -f "/Library/Preferences/com.apple.sharingd.plist"
    
    # Restart sharing daemon
    echo "Restarting sharing daemon..."
    sudo launchctl kickstart -k system/com.apple.sharingd
    
    echo "✓ AirDrop configuration reset to defaults"
}

reset_airdrop_config

Important Notes

  • AWDL Interface - Apple Wireless Direct Link is the underlying technology for AirDrop
  • Administrative privileges required for system-wide AirDrop control
  • User-level settings can override system policies unless enforced
  • Network dependencies - Requires both Wi-Fi and Bluetooth to be enabled
  • Security implications - Consider corporate policies before enabling
  • Compliance requirements - Some industries require AirDrop to be disabled
  • Test thoroughly - Validate changes on test devices before fleet deployment

Admin Rights Management on macOS

Manage and control administrator privileges across your Roundfleet devices using advanced command-line tools and centralized privilege management policies. This tutorial covers temporary admin rights, privilege escalation control, security governance, and enterprise-grade admin rights management with comprehensive auditing and compliance capabilities.

Understanding macOS Admin Rights Management

macOS provides several tools and methods for managing administrator privileges:

  • dscl - Directory Services Command Line utility for user and group management
  • sudo - Execute commands with elevated privileges
  • launchctl - Launch daemon management for scheduled tasks
  • Groups framework - Built-in admin group membership management
  • Security Framework - Authorization and privilege validation

Enterprise admin rights management requires careful balance between security, productivity, and compliance requirements.

Basic Admin Rights Commands

Grant Admin Rights (Basic)

#!/bin/bash

# Basic admin rights grant
grant_admin_rights_basic() {
    local username="$1"
    
    if [[ -z "$username" ]]; then
        echo "Usage: grant_admin_rights_basic <username>"
        return 1
    fi
    
    # Verify user exists
    if ! dscl . -read /Users/"$username" >/dev/null 2>&1; then
        echo "❌ User '$username' not found"
        return 1
    fi
    
    # Add user to admin group
    dscl . -append /Groups/admin GroupMembership "$username"
    
    if [[ $? -eq 0 ]]; then
        echo "✅ Admin rights granted to user: $username"
        return 0
    else
        echo "❌ Failed to grant admin rights to user: $username"
        return 1
    fi
}

# Example usage
# grant_admin_rights_basic "john.doe"

Revoke Admin Rights (Basic)

#!/bin/bash

# Basic admin rights revocation
revoke_admin_rights_basic() {
    local username="$1"
    
    if [[ -z "$username" ]]; then
        echo "Usage: revoke_admin_rights_basic <username>"
        return 1
    fi
    
    # Verify user exists
    if ! dscl . -read /Users/"$username" >/dev/null 2>&1; then
        echo "❌ User '$username' not found"
        return 1
    fi
    
    # Remove user from admin group
    dscl . -delete /Groups/admin GroupMembership "$username"
    
    if [[ $? -eq 0 ]]; then
        echo "✅ Admin rights revoked from user: $username"
        return 0
    else
        echo "❌ Failed to revoke admin rights from user: $username"
        return 1
    fi
}

# Example usage
# revoke_admin_rights_basic "john.doe"

Check Admin Status

#!/bin/bash

# Check if user has admin privileges
check_admin_status() {
    local username="$1"
    
    if [[ -z "$username" ]]; then
        echo "Usage: check_admin_status <username>"
        return 1
    fi
    
    # Check if user is in admin group
    local admin_members
    admin_members=$(dscl . -read /Groups/admin GroupMembership 2>/dev/null | grep -o "$username")
    
    if [[ -n "$admin_members" ]]; then
        echo "✅ User '$username' has admin privileges"
        return 0
    else
        echo "❌ User '$username' does not have admin privileges"
        return 1
    fi
}

# List all admin users
list_admin_users() {
    echo "=== Current Admin Users ==="
    echo ""
    
    local admin_users
    admin_users=$(dscl . -read /Groups/admin GroupMembership 2>/dev/null | cut -d: -f2 | tr ' ' '\n' | grep -v '^$' | sort)
    
    if [[ -n "$admin_users" ]]; then
        echo "Administrator accounts:"
        while IFS= read -r user; do
            # Get user real name if available
            local real_name
            real_name=$(dscl . -read /Users/"$user" RealName 2>/dev/null | cut -d: -f2 | sed 's/^ *//')
            
            if [[ -n "$real_name" && "$real_name" != "$user" ]]; then
                echo "  • $user ($real_name)"
            else
                echo "  • $user"
            fi
        done <<< "$admin_users"
    else
        echo "No admin users found"
    fi
    echo ""
}

# Example usage
# check_admin_status "john.doe"
# list_admin_users

Advanced Admin Rights Management

Temporary Admin Rights

#!/bin/bash

# Enhanced temporary admin rights
grant_temporary_admin_rights() {
    local username="$1"
    local duration_minutes="${2:-30}"
    local reason="${3:-Administrative task}"
    local require_confirmation="${4:-true}"
    
    if [[ -z "$username" ]]; then
        echo "Usage: grant_temporary_admin_rights <username> [duration_minutes] [reason] [require_confirmation]"
        return 1
    fi
    
    # Verify user exists
    if ! dscl . -read /Users/"$username" >/dev/null 2>&1; then
        echo "❌ User '$username' not found"
        return 1
    fi
    
    # Check if user already has admin rights
    if check_admin_status "$username" >/dev/null; then
        echo "⚠️  User '$username' already has admin privileges"
        read -p "Continue with temporary admin setup? (y/N): " -n 1 -r
        echo
        if [[ ! $REPLY =~ ^[Yy]$ ]]; then
            return 1
        fi
    fi
    
    # Display confirmation dialog if required
    if [[ "$require_confirmation" == "true" ]]; then
        osascript -e "display dialog \"You have been granted administrator rights for $duration_minutes minutes.\\n\\nReason: $reason\\n\\nPlease do not misuse this privilege.\" buttons {\"Accept Admin Rights\"} default button 1 with title \"Roundfleet Admin Rights Grant\""
        
        if [[ $? -ne 0 ]]; then
            echo "❌ User declined admin rights grant"
            return 1
        fi
    fi
    
    # Create tracking directory
    local tracking_dir="/private/var/roundfleet_admin_tracking"
    sudo mkdir -p "$tracking_dir"
    
    # Create user tracking file with metadata
    local tracking_file="$tracking_dir/${username}_admin.json"
    cat > "$tracking_file" <<EOF
{
    "username": "$username",
    "granted_at": "$(date -u +%Y-%m-%dT%H:%M:%SZ)",
    "duration_minutes": $duration_minutes,
    "reason": "$reason",
    "granted_by": "$(whoami)",
    "hostname": "$(hostname)",
    "pid": $$,
    "expires_at": "$(date -u -v+${duration_minutes}M +%Y-%m-%dT%H:%M:%SZ)"
}
EOF
    
    # Grant admin rights
    dscl . -append /Groups/admin GroupMembership "$username"
    
    if [[ $? -eq 0 ]]; then
        echo "✅ Temporary admin rights granted to '$username' for $duration_minutes minutes"
        
        # Create removal script
        create_admin_removal_script "$username" "$duration_minutes"
        
        # Schedule removal
        schedule_admin_removal "$username" "$duration_minutes"
        
        return 0
    else
        echo "❌ Failed to grant admin rights to '$username'"
        rm -f "$tracking_file"
        return 1
    fi
}

# Create admin removal script
create_admin_removal_script() {
    local username="$1"
    local duration_minutes="$2"
    
    local script_path="/Library/Application Support/Roundfleet/remove_admin_${username}.sh"
    mkdir -p "$(dirname "$script_path")"
    
    cat > "$script_path" <<'EOF'
#!/bin/bash

USERNAME="{{USERNAME}}"
TRACKING_DIR="/private/var/roundfleet_admin_tracking"
TRACKING_FILE="$TRACKING_DIR/${USERNAME}_admin.json"
LOG_FILE="/var/log/roundfleet_admin_rights.log"

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

log_action "Starting admin rights removal for user: $USERNAME"

# Check if user still has admin rights
if dscl . -read /Groups/admin GroupMembership 2>/dev/null | grep -q "$USERNAME"; then
    # Remove admin rights
    dscl . -delete /Groups/admin GroupMembership "$USERNAME"
    
    if [[ $? -eq 0 ]]; then
        log_action "✅ Admin rights successfully removed from user: $USERNAME"
        
        # Notify user if they're logged in
        if pgrep -u "$USERNAME" >/dev/null; then
            sudo -u "$USERNAME" osascript -e 'display notification "Your temporary administrator privileges have expired." with title "Roundfleet Admin Rights"' 2>/dev/null
        fi
    else
        log_action "❌ Failed to remove admin rights from user: $USERNAME"
    fi
else
    log_action "⚠️  User $USERNAME did not have admin rights (already removed or never granted)"
fi

# Clean up tracking file
if [[ -f "$TRACKING_FILE" ]]; then
    # Archive the tracking data
    ARCHIVE_DIR="/var/log/roundfleet_admin_archive"
    mkdir -p "$ARCHIVE_DIR"
    mv "$TRACKING_FILE" "$ARCHIVE_DIR/${USERNAME}_admin_$(date +%Y%m%d_%H%M%S).json"
    log_action "Admin rights tracking data archived for user: $USERNAME"
fi

# Remove launch daemon
PLIST_PATH="/Library/LaunchDaemons/com.roundfleet.remove_admin_${USERNAME}.plist"
if [[ -f "$PLIST_PATH" ]]; then
    launchctl unload "$PLIST_PATH" 2>/dev/null
    rm -f "$PLIST_PATH"
    log_action "Launch daemon removed for user: $USERNAME"
fi

# Remove this script
rm -f "$0"

log_action "Admin rights removal process completed for user: $USERNAME"
exit 0
EOF
    
    # Replace placeholder with actual username
    sed -i '' "s/{{USERNAME}}/$username/g" "$script_path"
    
    # Set permissions
    chmod 755 "$script_path"
    chown root:wheel "$script_path"
}

# Schedule admin removal using launchd
schedule_admin_removal() {
    local username="$1"
    local duration_minutes="$2"
    
    local plist_path="/Library/LaunchDaemons/com.roundfleet.remove_admin_${username}.plist"
    local script_path="/Library/Application Support/Roundfleet/remove_admin_${username}.sh"
    
    # Calculate execution time
    local start_time
    start_time=$(date -u -v+${duration_minutes}M +%Y-%m-%dT%H:%M:%SZ)
    
    # Create launch daemon plist
    cat > "$plist_path" <<EOF
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Label</key>
    <string>com.roundfleet.remove_admin_${username}</string>
    <key>ProgramArguments</key>
    <array>
        <string>/bin/bash</string>
        <string>${script_path}</string>
    </array>
    <key>StartCalendarInterval</key>
    <dict>
        <key>Year</key>
        <integer>$(date -u -v+${duration_minutes}M +%Y)</integer>
        <key>Month</key>
        <integer>$(date -u -v+${duration_minutes}M +%m)</integer>
        <key>Day</key>
        <integer>$(date -u -v+${duration_minutes}M +%d)</integer>
        <key>Hour</key>
        <integer>$(date -u -v+${duration_minutes}M +%H)</integer>
        <key>Minute</key>
        <integer>$(date -u -v+${duration_minutes}M +%M)</integer>
    </dict>
    <key>RunAtLoad</key>
    <false/>
</dict>
</plist>
EOF
    
    # Set permissions
    chown root:wheel "$plist_path"
    chmod 644 "$plist_path"
    
    # Load the daemon
    launchctl load "$plist_path"
    
    echo "⏰ Admin rights removal scheduled for $start_time"
}

# Example usage
# grant_temporary_admin_rights "john.doe" 30 "Software installation" true

Enterprise Admin Rights Management System

#!/bin/bash

# Roundfleet Enterprise Admin Rights Management System
# Comprehensive privilege management, security governance, and compliance monitoring

# Configuration
LOG_FILE="/var/log/roundfleet_admin_rights.log"
CONFIG_FILE="/etc/roundfleet/admin_rights_config.conf"
AUDIT_DIR="/var/log/roundfleet_admin_audit"
POLICY_DIR="/etc/roundfleet/admin_policies"
TRACKING_DIR="/private/var/roundfleet_admin_tracking"

# Create directory structure
setup_directories() {
    mkdir -p "$(dirname "$LOG_FILE")" "$AUDIT_DIR" "$POLICY_DIR" "$TRACKING_DIR" "$(dirname "$CONFIG_FILE")"
    touch "$LOG_FILE"
    
    # Set appropriate permissions
    chmod 755 "$AUDIT_DIR" "$POLICY_DIR"
    chmod 700 "$TRACKING_DIR"  # Restrict access to tracking data
}

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

# Load configuration
load_config() {
    if [[ -f "$CONFIG_FILE" ]]; then
        source "$CONFIG_FILE"
    else
        # Set defaults
        MAX_ADMIN_DURATION="${MAX_ADMIN_DURATION:-480}"  # 8 hours max
        DEFAULT_ADMIN_DURATION="${DEFAULT_ADMIN_DURATION:-30}"  # 30 minutes default
        REQUIRE_JUSTIFICATION="${REQUIRE_JUSTIFICATION:-true}"
        ENABLE_NOTIFICATIONS="${ENABLE_NOTIFICATIONS:-true}"
        AUDIT_ALL_CHANGES="${AUDIT_ALL_CHANGES:-true}"
        PROTECTED_ACCOUNTS="${PROTECTED_ACCOUNTS:-root,admin,roundfleet}"
    fi
}

# Enterprise admin rights grant with policy enforcement
enterprise_grant_admin() {
    local username="$1"
    local duration_minutes="$2"
    local reason="$3"
    local approved_by="$4"
    
    load_config
    
    if [[ -z "$username" ]]; then
        log_action "ERROR: Username required for admin rights grant"
        return 1
    fi
    
    # Set default duration if not provided
    if [[ -z "$duration_minutes" ]]; then
        duration_minutes="$DEFAULT_ADMIN_DURATION"
    fi
    
    # Validate duration against policy
    if [[ "$duration_minutes" -gt "$MAX_ADMIN_DURATION" ]]; then
        log_action "ERROR: Requested duration ($duration_minutes min) exceeds maximum allowed ($MAX_ADMIN_DURATION min)"
        return 1
    fi
    
    # Require justification if policy enabled
    if [[ "$REQUIRE_JUSTIFICATION" == "true" && -z "$reason" ]]; then
        log_action "ERROR: Justification required for admin rights grant"
        return 1
    fi
    
    # Check if user exists
    if ! dscl . -read /Users/"$username" >/dev/null 2>&1; then
        log_action "ERROR: User '$username' not found"
        return 1
    fi
    
    # Check for protected accounts
    if echo "$PROTECTED_ACCOUNTS" | grep -q "$username"; then
        log_action "ERROR: Cannot modify admin rights for protected account: $username"
        return 1
    fi
    
    # Check for existing admin rights
    local current_admin_status
    if check_admin_status "$username" >/dev/null; then
        current_admin_status="already_admin"
    else
        current_admin_status="standard_user"
    fi
    
    # Create audit entry
    local audit_id
    audit_id=$(create_audit_entry "grant" "$username" "$duration_minutes" "$reason" "$approved_by" "$current_admin_status")
    
    # Grant admin rights
    if [[ "$current_admin_status" == "standard_user" ]]; then
        dscl . -append /Groups/admin GroupMembership "$username"
        
        if [[ $? -ne 0 ]]; then
            log_action "ERROR: Failed to grant admin rights to '$username'"
            update_audit_entry "$audit_id" "failed" "Failed to modify admin group"
            return 1
        fi
    fi
    
    # Create tracking entry
    create_tracking_entry "$username" "$duration_minutes" "$reason" "$approved_by" "$audit_id"
    
    # Schedule removal if temporary
    if [[ "$duration_minutes" -gt 0 ]]; then
        schedule_enterprise_admin_removal "$username" "$duration_minutes" "$audit_id"
    fi
    
    # Send notifications
    if [[ "$ENABLE_NOTIFICATIONS" == "true" ]]; then
        send_admin_notification "$username" "granted" "$duration_minutes" "$reason"
    fi
    
    log_action "✅ Admin rights granted to '$username' for $duration_minutes minutes (Audit ID: $audit_id)"
    update_audit_entry "$audit_id" "success" "Admin rights granted successfully"
    
    return 0
}

# Enterprise admin rights revocation
enterprise_revoke_admin() {
    local username="$1"
    local reason="$2"
    local revoked_by="$3"
    
    load_config
    
    if [[ -z "$username" ]]; then
        log_action "ERROR: Username required for admin rights revocation"
        return 1
    fi
    
    # Check if user exists
    if ! dscl . -read /Users/"$username" >/dev/null 2>&1; then
        log_action "ERROR: User '$username' not found"
        return 1
    fi
    
    # Check for protected accounts
    if echo "$PROTECTED_ACCOUNTS" | grep -q "$username"; then
        log_action "ERROR: Cannot modify admin rights for protected account: $username"
        return 1
    fi
    
    # Check current admin status
    if ! check_admin_status "$username" >/dev/null; then
        log_action "WARNING: User '$username' does not have admin privileges"
        return 0
    fi
    
    # Create audit entry
    local audit_id
    audit_id=$(create_audit_entry "revoke" "$username" "0" "$reason" "$revoked_by" "admin_user")
    
    # Remove admin rights
    dscl . -delete /Groups/admin GroupMembership "$username"
    
    if [[ $? -eq 0 ]]; then
        log_action "✅ Admin rights revoked from '$username' (Audit ID: $audit_id)"
        
        # Clean up tracking
        cleanup_user_tracking "$username"
        
        # Cancel scheduled removal if exists
        cancel_scheduled_removal "$username"
        
        # Send notifications
        if [[ "$ENABLE_NOTIFICATIONS" == "true" ]]; then
            send_admin_notification "$username" "revoked" "0" "$reason"
        fi
        
        update_audit_entry "$audit_id" "success" "Admin rights revoked successfully"
        return 0
    else
        log_action "ERROR: Failed to revoke admin rights from '$username'"
        update_audit_entry "$audit_id" "failed" "Failed to modify admin group"
        return 1
    fi
}

# Create audit entry
create_audit_entry() {
    local action="$1"
    local username="$2"
    local duration="$3"
    local reason="$4"
    local operator="$5"
    local previous_status="$6"
    
    local audit_id="$(date +%s)_${username}_${action}"
    local audit_file="$AUDIT_DIR/${audit_id}.json"
    
    cat > "$audit_file" <<EOF
{
    "audit_id": "$audit_id",
    "action": "$action",
    "username": "$username",
    "duration_minutes": $duration,
    "reason": "$reason",
    "operator": "$operator",
    "previous_status": "$previous_status",
    "timestamp": "$(date -u +%Y-%m-%dT%H:%M:%SZ)",
    "hostname": "$(hostname)",
    "system_info": {
        "macos_version": "$(sw_vers -productVersion)",
        "build_version": "$(sw_vers -buildVersion)"
    },
    "status": "pending",
    "completion_time": null,
    "result_message": null
}
EOF
    
    echo "$audit_id"
}

# Update audit entry
update_audit_entry() {
    local audit_id="$1"
    local status="$2"
    local message="$3"
    
    local audit_file="$AUDIT_DIR/${audit_id}.json"
    
    if [[ -f "$audit_file" ]]; then
        # Update status and completion time
        local temp_file=$(mktemp)
        jq --arg status "$status" --arg time "$(date -u +%Y-%m-%dT%H:%M:%SZ)" --arg msg "$message" \
           '.status = $status | .completion_time = $time | .result_message = $msg' \
           "$audit_file" > "$temp_file" && mv "$temp_file" "$audit_file"
    fi
}

# Create tracking entry
create_tracking_entry() {
    local username="$1"
    local duration="$2"
    local reason="$3"
    local operator="$4"
    local audit_id="$5"
    
    local tracking_file="$TRACKING_DIR/${username}_admin.json"
    
    cat > "$tracking_file" <<EOF
{
    "username": "$username",
    "granted_at": "$(date -u +%Y-%m-%dT%H:%M:%SZ)",
    "duration_minutes": $duration,
    "expires_at": "$(date -u -v+${duration}M +%Y-%m-%dT%H:%M:%SZ)",
    "reason": "$reason",
    "granted_by": "$operator",
    "audit_id": "$audit_id",
    "hostname": "$(hostname)",
    "pid": $$,
    "status": "active"
}
EOF
}

# Schedule enterprise admin removal
schedule_enterprise_admin_removal() {
    local username="$1"
    local duration_minutes="$2"
    local audit_id="$3"
    
    local script_path="/Library/Application Support/Roundfleet/enterprise_remove_admin_${username}.sh"
    local plist_path="/Library/LaunchDaemons/com.roundfleet.enterprise_remove_admin_${username}.plist"
    
    # Create enhanced removal script
    mkdir -p "$(dirname "$script_path")"
    
    cat > "$script_path" <<EOF
#!/bin/bash

# Roundfleet Enterprise Admin Rights Removal
USERNAME="$username"
AUDIT_ID="$audit_id"
LOG_FILE="$LOG_FILE"
TRACKING_DIR="$TRACKING_DIR"
AUDIT_DIR="$AUDIT_DIR"

# Source the main script functions
source /usr/local/bin/roundfleet_admin_management.sh

log_action "Starting scheduled admin rights removal for user: \$USERNAME (Audit ID: \$AUDIT_ID)"

# Remove admin rights
enterprise_revoke_admin "\$USERNAME" "Automatic expiration" "system"

# Clean up launch daemon
launchctl unload "$plist_path" 2>/dev/null
rm -f "$plist_path"
rm -f "\$0"

log_action "Scheduled admin rights removal completed for user: \$USERNAME"
exit 0
EOF
    
    chmod 755 "$script_path"
    chown root:wheel "$script_path"
    
    # Create launch daemon
    create_removal_launch_daemon "$username" "$duration_minutes" "$script_path" "$plist_path"
}

# Send admin notifications
send_admin_notification() {
    local username="$1"
    local action="$2"
    local duration="$3"
    local reason="$4"
    
    local message
    case "$action" in
        "granted")
            if [[ "$duration" -gt 0 ]]; then
                message="Administrator privileges granted for $duration minutes. Reason: $reason"
            else
                message="Administrator privileges granted permanently. Reason: $reason"
            fi
            ;;
        "revoked")
            message="Administrator privileges have been revoked. Reason: $reason"
            ;;
        "expired")
            message="Temporary administrator privileges have expired."
            ;;
    esac
    
    # Send notification to user if logged in
    if pgrep -u "$username" >/dev/null; then
        sudo -u "$username" osascript -e "display notification \"$message\" with title \"Roundfleet Admin Rights\"" 2>/dev/null
    fi
    
    # Log notification
    log_action "Notification sent to '$username': $message"
}

# Admin rights security audit
perform_admin_audit() {
    local audit_file="$AUDIT_DIR/security_audit_$(date +%Y%m%d_%H%M%S).json"
    
    log_action "Performing admin rights security audit: $audit_file"
    
    {
        echo "{"
        echo "  \"audit_type\": \"admin_rights_security\","
        echo "  \"timestamp\": \"$(date -u +%Y-%m-%dT%H:%M:%SZ)\","
        echo "  \"hostname\": \"$(hostname)\","
        echo "  \"auditor\": \"$(whoami)\","
        
        # Current admin users analysis
        echo "  \"current_admin_users\": ["
        local admin_users
        admin_users=$(dscl . -read /Groups/admin GroupMembership 2>/dev/null | cut -d: -f2 | tr ' ' '\n' | grep -v '^$' | sort)
        
        local first_user=true
        while IFS= read -r user; do
            if [[ -n "$user" ]]; then
                if [[ "$first_user" == "false" ]]; then
                    echo ","
                fi
                first_user=false
                
                local real_name uid last_login
                real_name=$(dscl . -read /Users/"$user" RealName 2>/dev/null | cut -d: -f2 | sed 's/^ *//')
                uid=$(dscl . -read /Users/"$user" UniqueID 2>/dev/null | awk '{print $2}')
                last_login=$(last -1 "$user" 2>/dev/null | head -1 | awk '{print $4, $5, $6, $7}')
                
                echo "    {"
                echo "      \"username\": \"$user\","
                echo "      \"real_name\": \"${real_name:-Unknown}\","
                echo "      \"uid\": \"${uid:-Unknown}\","
                echo "      \"last_login\": \"${last_login:-Never}\","
                
                # Check if user has active tracking
                local tracking_file="$TRACKING_DIR/${user}_admin.json"
                if [[ -f "$tracking_file" ]]; then
                    local expires_at reason
                    expires_at=$(jq -r '.expires_at' "$tracking_file" 2>/dev/null)
                    reason=$(jq -r '.reason' "$tracking_file" 2>/dev/null)
                    
                    echo "      \"temporary_admin\": true,"
                    echo "      \"expires_at\": \"$expires_at\","
                    echo "      \"reason\": \"$reason\""
                else
                    echo "      \"temporary_admin\": false,"
                    echo "      \"expires_at\": null,"
                    echo "      \"reason\": null"
                fi
                echo -n "    }"
            fi
        done <<< "$admin_users"
        echo ""
        echo "  ],"
        
        # Active tracking entries
        echo "  \"active_temporary_admin\": ["
        local first_tracking=true
        for tracking_file in "$TRACKING_DIR"/*_admin.json; do
            if [[ -f "$tracking_file" ]]; then
                if [[ "$first_tracking" == "false" ]]; then
                    echo ","
                fi
                first_tracking=false
                cat "$tracking_file"
            fi
        done
        echo ""
        echo "  ],"
        
        # Recent audit entries (last 24 hours)
        echo "  \"recent_admin_changes\": ["
        local cutoff_time
        cutoff_time=$(date -u -v-1d +%s)
        local first_audit=true
        
        for audit_file in "$AUDIT_DIR"/*.json; do
            if [[ -f "$audit_file" ]]; then
                local audit_timestamp
                audit_timestamp=$(jq -r '.timestamp' "$audit_file" 2>/dev/null)
                local audit_epoch
                audit_epoch=$(date -jf "%Y-%m-%dT%H:%M:%SZ" "$audit_timestamp" +%s 2>/dev/null)
                
                if [[ "$audit_epoch" -gt "$cutoff_time" ]]; then
                    if [[ "$first_audit" == "false" ]]; then
                        echo ","
                    fi
                    first_audit=false
                    cat "$audit_file"
                fi
            fi
        done
        echo ""
        echo "  ]"
        echo "}"
    } > "$audit_file"
    
    log_action "Admin rights security audit completed: $audit_file"
    echo "$audit_file"
}

# Main management function
main() {
    local action="${1:-status}"
    local parameter1="$2"
    local parameter2="$3"
    local parameter3="$4"
    local parameter4="$5"
    
    setup_directories
    log_action "Roundfleet Admin Rights Management started with action: $action"
    
    case "$action" in
        "grant")
            enterprise_grant_admin "$parameter1" "$parameter2" "$parameter3" "$parameter4"
            ;;
        "revoke")
            enterprise_revoke_admin "$parameter1" "$parameter2" "$parameter3"
            ;;
        "temp"|"temporary")
            grant_temporary_admin_rights "$parameter1" "$parameter2" "$parameter3" "$parameter4"
            ;;
        "check")
            check_admin_status "$parameter1"
            ;;
        "list")
            list_admin_users
            ;;
        "audit")
            perform_admin_audit
            ;;
        "status"|*)
            list_admin_users
            ;;
    esac
    
    log_action "Roundfleet Admin Rights Management completed with action: $action"
}

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

Admin Rights Policy Templates

Corporate Admin Rights Policy

# /etc/roundfleet/admin_rights_config.conf
# Roundfleet Corporate Admin Rights Configuration

# Duration limits (in minutes)
MAX_ADMIN_DURATION="480"        # 8 hours maximum
DEFAULT_ADMIN_DURATION="30"     # 30 minutes default
WARNING_BEFORE_EXPIRY="5"       # 5 minutes warning

# Security requirements
REQUIRE_JUSTIFICATION="true"
REQUIRE_APPROVAL="true"
MINIMUM_JUSTIFICATION_LENGTH="10"

# Notification settings
ENABLE_NOTIFICATIONS="true"
NOTIFY_SECURITY_TEAM="true"
SECURITY_TEAM_EMAIL="[email protected]"

# Audit settings
AUDIT_ALL_CHANGES="true"
RETAIN_AUDIT_LOGS="90"          # 90 days
ENABLE_REALTIME_MONITORING="true"

# Protected accounts (cannot be modified)
PROTECTED_ACCOUNTS="root,admin,roundfleet,security"

# Approval workflow
REQUIRE_MANAGER_APPROVAL="true"
ENABLE_EMERGENCY_BYPASS="false"
EMERGENCY_BYPASS_ACCOUNTS="security,ciso"

High Security Environment Policy

# /etc/roundfleet/admin_policies/high_security.policy
# Roundfleet High Security Admin Rights Policy

# Strict duration limits
MAX_ADMIN_DURATION="60"         # 1 hour maximum
DEFAULT_ADMIN_DURATION="15"     # 15 minutes default
AUTO_REVOKE_IDLE="true"         # Revoke if user idle
IDLE_TIMEOUT_MINUTES="10"       # 10 minutes idle timeout

# Enhanced security
REQUIRE_JUSTIFICATION="true"
REQUIRE_TWO_PERSON_APPROVAL="true"
ENABLE_SESSION_RECORDING="true"
BLOCK_ADMIN_OUTSIDE_HOURS="true"
ALLOWED_HOURS="09-17"           # 9 AM to 5 PM
ALLOWED_DAYS="1-5"              # Monday to Friday

# Monitoring
ENABLE_REALTIME_ALERTS="true"
ALERT_ON_ADMIN_GRANT="true"
ALERT_ON_SUSPICIOUS_ACTIVITY="true"
LOG_ALL_ADMIN_COMMANDS="true"

Security and Compliance Functions

Admin Rights Compliance Check

#!/bin/bash

# Comprehensive admin rights compliance check
check_admin_compliance() {
    echo "🔍 Admin Rights Compliance Check"
    echo "==============================="
    echo ""
    
    local compliance_issues=()
    local compliance_warnings=()
    
    # Check for unauthorized permanent admin accounts
    echo "1. UNAUTHORIZED PERMANENT ADMIN ACCOUNTS:"
    echo "----------------------------------------"
    
    local admin_users
    admin_users=$(dscl . -read /Groups/admin GroupMembership 2>/dev/null | cut -d: -f2 | tr ' ' '\n' | grep -v '^$')
    
    while IFS= read -r user; do
        if [[ -n "$user" ]]; then
            local tracking_file="$TRACKING_DIR/${user}_admin.json"
            
            # Skip protected accounts
            if echo "$PROTECTED_ACCOUNTS" | grep -q "$user"; then
                echo "  ✅ $user (Protected account)"
                continue
            fi
            
            # Check if user has temporary admin tracking
            if [[ ! -f "$tracking_file" ]]; then
                # No tracking = permanent admin (potential violation)
                compliance_issues+=("Permanent admin account without tracking: $user")
                echo "  ❌ $user (No temporary admin tracking found)"
            else
                # Check if temporary admin has expired
                local expires_at
                expires_at=$(jq -r '.expires_at' "$tracking_file" 2>/dev/null)
                local current_time
                current_time=$(date -u +%Y-%m-%dT%H:%M:%SZ)
                
                if [[ "$expires_at" < "$current_time" ]]; then
                    compliance_issues+=("Expired temporary admin still active: $user")
                    echo "  ⚠️  $user (Temporary admin expired but still active)"
                else
                    local reason
                    reason=$(jq -r '.reason' "$tracking_file" 2>/dev/null)
                    echo "  ✅ $user (Temporary admin, expires: $expires_at, reason: $reason)"
                fi
            fi
        fi
    done <<< "$admin_users"
    echo ""
    
    # Check for stale tracking files
    echo "2. STALE TRACKING FILES:"
    echo "-----------------------"
    
    for tracking_file in "$TRACKING_DIR"/*_admin.json; do
        if [[ -f "$tracking_file" ]]; then
            local username
            username=$(basename "$tracking_file" _admin.json)
            
            # Check if user still has admin rights
            if ! check_admin_status "$username" >/dev/null 2>&1; then
                compliance_warnings+=("Stale tracking file for non-admin user: $username")
                echo "  ⚠️  Stale tracking file: $tracking_file"
            fi
        fi
    done
    echo ""
    
    # Check audit log integrity
    echo "3. AUDIT LOG INTEGRITY:"
    echo "----------------------"
    
    local recent_changes
    recent_changes=$(find "$AUDIT_DIR" -name "*.json" -mtime -1 | wc -l | tr -d ' ')
    
    if [[ "$recent_changes" -eq 0 ]]; then
        compliance_warnings+=("No admin rights changes in last 24 hours")
        echo "  ℹ️  No admin rights changes recorded in last 24 hours"
    else
        echo "  ✅ $recent_changes admin rights changes recorded in last 24 hours"
    fi
    echo ""
    
    # Generate compliance summary
    echo "4. COMPLIANCE SUMMARY:"
    echo "---------------------"
    
    if [[ ${#compliance_issues[@]} -eq 0 ]]; then
        echo "  ✅ No critical compliance issues found"
    else
        echo "  ❌ Critical compliance issues found:"
        for issue in "${compliance_issues[@]}"; do
            echo "    - $issue"
        done
    fi
    
    if [[ ${#compliance_warnings[@]} -gt 0 ]]; then
        echo "  ⚠️  Warnings:"
        for warning in "${compliance_warnings[@]}"; do
            echo "    - $warning"
        done
    fi
    
    echo ""
    echo "Recommendations:"
    echo "• Review and remediate any unauthorized permanent admin accounts"
    echo "• Implement regular compliance checks (daily/weekly)"
    echo "• Enable real-time monitoring for admin rights changes"
    echo "• Establish clear admin rights governance policies"
    echo "• Regular audit of admin activities and justifications"
    
    # Return appropriate exit code
    if [[ ${#compliance_issues[@]} -gt 0 ]]; then
        return 1
    else
        return 0
    fi
}

check_admin_compliance

Important Technical Notes

DSCL Command Reference

  • dscl . -append /Groups/admin GroupMembership <user>: Add user to admin group
  • dscl . -delete /Groups/admin GroupMembership <user>: Remove user from admin group
  • dscl . -read /Groups/admin GroupMembership: List all admin group members
  • dscl . -read /Users/<user>: Get detailed user information

Security Considerations

  1. Principle of Least Privilege: Grant minimum necessary privileges for minimum time
  2. Audit Trail: Maintain comprehensive logs of all admin rights changes
  3. Approval Workflow: Implement approval processes for admin rights grants
  4. Time Limits: Always use temporary admin rights with automatic expiration
  5. Monitoring: Real-time monitoring of admin activities and suspicious behavior

Compliance Requirements

  1. Documentation: Maintain detailed records of admin rights grants and revocations
  2. Justification: Require business justification for all privilege escalations
  3. Regular Audits: Perform regular compliance checks and reviews
  4. Protected Accounts: Safeguard critical system accounts from modification
  5. Retention Policies: Implement appropriate log retention and archival

Enterprise Use Cases

  1. Software Installation: Temporary admin rights for application installations
  2. System Maintenance: Scheduled admin access for maintenance windows
  3. Emergency Response: Rapid privilege escalation for incident response
  4. Compliance Auditing: Regular reviews of admin rights and activities
  5. Zero Trust Security: Continuous verification and minimal privilege access

Remember to test all scripts on individual devices before deploying across your Roundfleet environment, and ensure compliance with corporate security policies and regulatory requirements when implementing enterprise admin rights management systems.

Configuring a GitHub Actions Runner on a Mac Mini (Apple Silicon)

GitHub Actions runner

GitHub Actions is a powerful CI/CD platform that allows you to automate your software development workflows. While GitHub offers hosted runners, self-hosted runners provide increased control and customization for your CI/CD setup. This tutorial guides you through setting up, configuring, and connecting a self-hosted runner on a Mac Mini to execute macOS pipelines.

Prerequisites

Before you begin, ensure you have:

  • A Mac Mini (register on Roundfleet)
  • A GitHub repository with administrator rights
  • A package manager installed (preferably Homebrew)
  • Git installed on your system

Step 1: Create a Dedicated User Account

First, create a dedicated user account for the GitHub Actions runner:

# Create the 'gh-runner' user account
sudo dscl . -create /Users/gh-runner
sudo dscl . -create /Users/gh-runner UserShell /bin/bash
sudo dscl . -create /Users/gh-runner RealName "GitHub runner"
sudo dscl . -create /Users/gh-runner UniqueID "1001"
sudo dscl . -create /Users/gh-runner PrimaryGroupID 20
sudo dscl . -create /Users/gh-runner NFSHomeDirectory /Users/gh-runner

# Set the password for the user
sudo dscl . -passwd /Users/gh-runner your_password

# Add 'gh-runner' to the 'admin' group
sudo dscl . -append /Groups/admin GroupMembership gh-runner

Switch to the new user account:

su gh-runner

Step 2: Install Required Software

Install Git and Rosetta 2 (if using Apple Silicon):

# Install Git if not already installed
brew install git

# Install Rosetta 2 for Apple Silicon Macs
softwareupdate --install-rosetta

Step 3: Configure the GitHub Actions Runner

  1. Go to your GitHub repository
  2. Navigate to Settings > Actions > Runners

GitHub Actions runner

  1. Click "New self-hosted runner" (https://github.com/<username>/<repository>/settings/actions/runners/new)
  2. Select macOS as the runner image and ARM64 as the architecture
  3. Follow the provided commands to download and configure the runner

GitHub Actions runner

Create a .env file in the runner's _work directory:

# _work/.env file
ImageOS=macos15
XCODE_15_DEVELOPER_DIR=/Applications/Xcode.app/Contents/Developer
  1. Execute the run.sh script in your runner directory to complete the setup.
  2. Verify that the runner is up and listening for jobs in the terminal and check the GitHub repository settings for the runner's association and Idle status.

GitHub Actions runner

Step 4: Configure Sudoers (Optional)

If your actions require root privileges, configure the sudoers file:

sudo visudo

Add the following line:

gh-runner ALL=(ALL) NOPASSWD: ALL

Step 5: Using the Runner in Workflows

Configure your GitHub Actions workflow to use the self-hosted runner:

name: Sample workflow

on:
  workflow_dispatch:

jobs:
  build:
    runs-on: [self-hosted, macOS, ARM64]
    steps:
      - name: Install NodeJS
        run: brew install node

The runner is authenticated to your repository and labeled with self-hosted, macOS, and ARM64. Use it in your workflows by specifying these labels in the runs-on field:

runs-on: [self-hosted, macOS, ARM64]

Best Practices

  • Keep your runner software up to date
  • Regularly monitor runner logs for issues
  • Use specific labels for different types of runners
  • Implement proper security measures
  • Consider using multiple runners for load balancing

Troubleshooting

Common issues and solutions:

  1. Runner not connecting:

    • Check network connectivity
    • Verify GitHub token validity
    • Ensure proper permissions
  2. Build failures:

    • Check Xcode installation
    • Verify required dependencies
    • Review workflow logs
  3. Permission issues:

    • Verify user permissions
    • Check sudoers configuration
    • Review file system permissions

Conclusion

You now have a self-hosted GitHub Actions runner configured on your Mac Mini. This setup provides you with more control over your CI/CD environment and allows you to run macOS-specific workflows efficiently.

Remember to regularly maintain your runner and keep it updated with the latest security patches and software versions.

Native App

Roundfleet native app

Roundfleet Installation Guide

Roundfleet is a powerful fleet management solution designed specifically for cloud-hosted Mac Mini environments. As a Mac Mini cloud hosting provider, you can use Roundfleet to monitor, manage, and optimize your entire fleet of virtualized Mac instances.

This installation guide will walk you through setting up Roundfleet monitoring across macOS, Windows, and Linux systems to ensure comprehensive oversight of your cloud infrastructure.

🍎 macOS

  • Download the .dmg file for Mac here
  • Double-click the downloaded .dmg file
  • Drag the Roundfleet app to the Applications folder
  • Eject the .dmg file
  • Open System Preferences > Security & Privacy
    • Privacy tab > Accessibility
    • Check Roundfleet to allow monitoring
  • Launch Roundfleet from Applications
  • Tracking starts automatically

🪟 Windows

  • Download the .exe file for Windows here
  • Right-click the .exe file > "Run as administrator"
  • Follow the installation wizard
  • Accept terms and conditions
  • Allow in Windows Defender if prompted
  • Grant application monitoring permissions
  • Launch Roundfleet from Start Menu
  • The application begins tracking automatically

🐧 Linux

  • Download the .deb package (Ubuntu/Debian) or .rpm (CentOS/RHEL) here
  • Install using your package manager
    • Ubuntu/Debian: sudo dpkg -i Roundfleet-linux.deb
    • CentOS/RHEL: sudo rpm -ivh Roundfleet-linux.rpm
  • Allow X11 access permissions if prompted
  • Add user to appropriate groups if necessary
  • Launch Roundfleet from Applications menu
  • The application begins tracking automatically

Note: After installation on all systems, log in with your Roundfleet credentials to sync data with your dashboard.