Tutorial

New updates and improvements to Macfleet.

Sleep and Power Management for macOS

Implement enterprise-grade sleep and power management across your MacFleet deployment with automated power policies, energy optimization, compliance monitoring, and comprehensive fleet-wide management. This tutorial provides solutions for maintaining optimal power efficiency while ensuring security and operational requirements are met.

Understanding macOS Power Management

macOS provides several power management tools and mechanisms:

  • pmset - Primary power management settings tool
  • caffeinate - Prevent system sleep for specific operations
  • systemsetup - System-wide power configuration
  • Energy Saver - GUI power management interface
  • Power Assertions - Application-level sleep prevention

Basic Power Management Operations

Configure System Sleep Timer

#!/bin/bash

# Set system sleep timer to 15 minutes
sudo pmset sleep 15

Configure Display Sleep Timer

#!/bin/bash

# Set display sleep timer to 15 minutes
sudo pmset displaysleep 15

Schedule Wake Events

#!/bin/bash

# Schedule wake every day at 9:00 AM
sudo pmset repeat wakeorpoweron MTWRFSU 9:00:00

Prevent Sleep for Specific Period

#!/bin/bash

# Prevent system sleep for 300 seconds
caffeinate -u -t 300

Check System Sleep Settings

#!/bin/bash

# Check current sleep idle time
sudo systemsetup -getcomputersleep

Disable System Sleep

#!/bin/bash

# Turn off system sleep
sudo systemsetup -setcomputersleep Never

Enable Restart on Freeze

#!/bin/bash

# Restart automatically on system freeze
systemsetup -setrestartfreeze on

Enterprise Power Management System

Comprehensive Power Management Tool

#!/bin/bash

# MacFleet Enterprise Sleep and Power Management Tool
# Advanced power policies and energy optimization

# Configuration
CONFIG_FILE="/etc/macfleet/power_policy.conf"
LOG_FILE="/var/log/macfleet_power.log"
POLICIES_DIR="/Library/MacFleet/PowerPolicies"
AUDIT_LOG="/var/log/macfleet_power_audit.log"

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

# Default power management policy
cat > "$CONFIG_FILE" 2>/dev/null << 'EOF' || true
# MacFleet Enterprise Power Management Policy
# Version: 2.0

# Power Policy Enforcement
ENFORCE_POWER_POLICIES=true
AUTO_APPLY_POLICIES=true
POWER_PROFILE="corporate_standard"
ENERGY_OPTIMIZATION=true
COMPLIANCE_MONITORING=true

# Sleep Settings (minutes)
SYSTEM_SLEEP_AC=30
SYSTEM_SLEEP_BATTERY=15
DISPLAY_SLEEP_AC=15
DISPLAY_SLEEP_BATTERY=5
DISK_SLEEP_AC=10
DISK_SLEEP_BATTERY=5

# Wake and Power Events
WAKE_ON_LAN=true
WAKE_ON_ADMINISTRATIVE_ACCESS=true
AUTOMATIC_RESTART_ON_POWER_LOSS=true
AUTOMATIC_RESTART_ON_FREEZE=true
SCHEDULED_WAKE_ENABLED=true
SCHEDULED_SLEEP_ENABLED=true

# Business Hours Configuration
BUSINESS_HOURS_START="09:00"
BUSINESS_HOURS_END="18:00"
BUSINESS_DAYS="MTWRF"
WEEKEND_POWER_PROFILE="energy_saver"
AFTER_HOURS_POWER_PROFILE="security_focused"

# Security and Maintenance
SECURE_VIRTUAL_MEMORY=true
DESTROY_FILEVAULT_KEYS_ON_STANDBY=true
HIBERNATE_MODE=3
STANDBY_DELAY=10800
AUTOPOWEROFF_ENABLED=true
AUTOPOWEROFF_DELAY=14400

# Energy and Performance
PROCESSOR_SPEED_REDUCTION=false
REDUCE_BRIGHTNESS_BATTERY=true
DISABLE_POWER_BUTTON_SLEEP=false
PREVENT_SLEEP_DURING_PRESENTATIONS=true
THERMAL_MANAGEMENT=true

# Monitoring and Reporting
POWER_EVENT_LOGGING=true
ENERGY_USAGE_MONITORING=true
BATTERY_HEALTH_MONITORING=true
POWER_ASSERTION_TRACKING=true
AUTOMATED_REPORTING=true

# Compliance Settings
REGULATORY_COMPLIANCE="ENERGY_STAR"
CARBON_FOOTPRINT_TRACKING=true
SUSTAINABILITY_REPORTING=true
POWER_AUDIT_TRAILS=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 result="$2"
    local details="$3"
    echo "$(date '+%Y-%m-%d %H:%M:%S') - ACTION:$action RESULT:$result DETAILS:$details USER:$(whoami)" >> "$AUDIT_LOG"
}

# Get current power settings
get_power_status() {
    echo "=== Current Power Management Status ==="
    
    # System-wide power settings
    echo "System Power Settings:"
    pmset -g 2>/dev/null || echo "  Power settings unavailable"
    
    echo -e "\nCurrent Power Source:"
    pmset -g ps 2>/dev/null | head -1
    
    echo -e "\nSleep Timers:"
    echo "  System Sleep (AC): $(pmset -g | grep -E '^\s*sleep\s' | awk '{print $2}') minutes"
    echo "  Display Sleep (AC): $(pmset -g | grep -E '^\s*displaysleep\s' | awk '{print $2}') minutes"
    echo "  Disk Sleep (AC): $(pmset -g | grep -E '^\s*disksleep\s' | awk '{print $2}') minutes"
    
    echo -e "\nPower Assertions:"
    pmset -g assertions 2>/dev/null | grep -E "(PreventUserIdleSystemSleep|PreventUserIdleDisplaySleep)" | head -5
    
    echo -e "\nThermal State:"
    pmset -g thermstate 2>/dev/null | head -3
    
    echo -e "\nBattery Information:"
    if system_profiler SPPowerDataType 2>/dev/null | grep -q "Battery Information"; then
        system_profiler SPPowerDataType | grep -A 10 "Battery Information" | head -10
    else
        echo "  No battery information available (Desktop Mac)"
    fi
    
    return 0
}

# Apply enterprise power profile
apply_power_profile() {
    local profile="${1:-$POWER_PROFILE}"
    
    echo "=== Applying Enterprise Power Profile: $profile ==="
    
    case "$profile" in
        "corporate_standard")
            apply_corporate_standard_profile
            ;;
        "energy_saver")
            apply_energy_saver_profile
            ;;
        "high_performance")
            apply_high_performance_profile
            ;;
        "security_focused")
            apply_security_focused_profile
            ;;
        "presentation_mode")
            apply_presentation_mode_profile
            ;;
        "kiosk_mode")
            apply_kiosk_mode_profile
            ;;
        *)
            echo "Unknown power profile: $profile"
            echo "Using corporate_standard profile as fallback"
            apply_corporate_standard_profile
            ;;
    esac
    
    # Apply common security settings
    apply_security_settings
    
    # Configure scheduled events
    configure_scheduled_events
    
    echo "✅ Power profile '$profile' applied successfully"
    log_action "Power profile applied: $profile"
    audit_log "POWER_PROFILE" "APPLIED" "Profile: $profile"
    
    return 0
}

# Corporate standard power profile
apply_corporate_standard_profile() {
    echo "=== Configuring Corporate Standard Profile ==="
    
    # AC Power settings
    sudo pmset -c sleep "$SYSTEM_SLEEP_AC" 2>/dev/null
    sudo pmset -c displaysleep "$DISPLAY_SLEEP_AC" 2>/dev/null
    sudo pmset -c disksleep "$DISK_SLEEP_AC" 2>/dev/null
    
    # Battery settings (if applicable)
    sudo pmset -b sleep "$SYSTEM_SLEEP_BATTERY" 2>/dev/null
    sudo pmset -b displaysleep "$DISPLAY_SLEEP_BATTERY" 2>/dev/null
    sudo pmset -b disksleep "$DISK_SLEEP_BATTERY" 2>/dev/null
    
    # Wake settings
    if [[ "$WAKE_ON_LAN" == "true" ]]; then
        sudo pmset -a womp 1 2>/dev/null
    fi
    
    if [[ "$WAKE_ON_ADMINISTRATIVE_ACCESS" == "true" ]]; then
        sudo pmset -a acwake 1 2>/dev/null
    fi
    
    # Restart settings
    if [[ "$AUTOMATIC_RESTART_ON_POWER_LOSS" == "true" ]]; then
        sudo pmset -a autorestart 1 2>/dev/null
    fi
    
    if [[ "$AUTOMATIC_RESTART_ON_FREEZE" == "true" ]]; then
        sudo systemsetup -setrestartfreeze on 2>/dev/null
    fi
    
    echo "Corporate standard profile configured"
    log_action "Corporate standard power profile applied"
}

# Energy saver profile
apply_energy_saver_profile() {
    echo "=== Configuring Energy Saver Profile ==="
    
    # Aggressive power saving
    sudo pmset -c sleep 10 2>/dev/null
    sudo pmset -c displaysleep 5 2>/dev/null
    sudo pmset -c disksleep 5 2>/dev/null
    
    sudo pmset -b sleep 5 2>/dev/null
    sudo pmset -b displaysleep 2 2>/dev/null
    sudo pmset -b disksleep 3 2>/dev/null
    
    # Enable power-saving features
    sudo pmset -a reducebright 1 2>/dev/null
    sudo pmset -a lessbright 1 2>/dev/null
    
    echo "Energy saver profile configured"
    log_action "Energy saver power profile applied"
}

# High performance profile
apply_high_performance_profile() {
    echo "=== Configuring High Performance Profile ==="
    
    # Minimal sleep settings
    sudo pmset -c sleep 60 2>/dev/null
    sudo pmset -c displaysleep 30 2>/dev/null
    sudo pmset -c disksleep 30 2>/dev/null
    
    sudo pmset -b sleep 30 2>/dev/null
    sudo pmset -b displaysleep 15 2>/dev/null
    sudo pmset -b disksleep 15 2>/dev/null
    
    # Disable power-saving features
    sudo pmset -a reducebright 0 2>/dev/null
    sudo pmset -a lessbright 0 2>/dev/null
    
    echo "High performance profile configured"
    log_action "High performance power profile applied"
}

# Security focused profile
apply_security_focused_profile() {
    echo "=== Configuring Security Focused Profile ==="
    
    # Short sleep timers for security
    sudo pmset -c sleep 5 2>/dev/null
    sudo pmset -c displaysleep 3 2>/dev/null
    sudo pmset -c disksleep 5 2>/dev/null
    
    sudo pmset -b sleep 3 2>/dev/null
    sudo pmset -b displaysleep 1 2>/dev/null
    sudo pmset -b disksleep 3 2>/dev/null
    
    # Enhanced security settings
    sudo pmset -a destroyfvkeyonstandby 1 2>/dev/null
    sudo pmset -a hibernatemode 25 2>/dev/null
    
    echo "Security focused profile configured"
    log_action "Security focused power profile applied"
}

# Presentation mode profile
apply_presentation_mode_profile() {
    echo "=== Configuring Presentation Mode Profile ==="
    
    # Prevent sleep during presentations
    sudo pmset -c sleep 0 2>/dev/null
    sudo pmset -c displaysleep 0 2>/dev/null
    
    # Keep system active
    sudo pmset -a lidwake 1 2>/dev/null
    sudo pmset -a acwake 1 2>/dev/null
    
    echo "Presentation mode profile configured"
    log_action "Presentation mode power profile applied"
}

# Kiosk mode profile
apply_kiosk_mode_profile() {
    echo "=== Configuring Kiosk Mode Profile ==="
    
    # Never sleep settings for kiosk devices
    sudo pmset -c sleep 0 2>/dev/null
    sudo pmset -c displaysleep 0 2>/dev/null
    sudo pmset -c disksleep 0 2>/dev/null
    
    # Ensure system stays active
    sudo pmset -a womp 1 2>/dev/null
    sudo pmset -a autorestart 1 2>/dev/null
    
    echo "Kiosk mode profile configured"
    log_action "Kiosk mode power profile applied"
}

# Apply security-specific power settings
apply_security_settings() {
    echo "=== Applying Security Power Settings ==="
    
    if [[ "$SECURE_VIRTUAL_MEMORY" == "true" ]]; then
        sudo pmset -a securevm 1 2>/dev/null
        echo "✅ Secure virtual memory enabled"
    fi
    
    if [[ "$DESTROY_FILEVAULT_KEYS_ON_STANDBY" == "true" ]]; then
        sudo pmset -a destroyfvkeyonstandby 1 2>/dev/null
        echo "✅ FileVault key destruction on standby enabled"
    fi
    
    # Configure hibernation mode
    sudo pmset -a hibernatemode "$HIBERNATE_MODE" 2>/dev/null
    echo "✅ Hibernation mode set to $HIBERNATE_MODE"
    
    # Configure standby and autopoweroff
    sudo pmset -a standbydelay "$STANDBY_DELAY" 2>/dev/null
    
    if [[ "$AUTOPOWEROFF_ENABLED" == "true" ]]; then
        sudo pmset -a autopoweroff 1 2>/dev/null
        sudo pmset -a autopoweroffdelay "$AUTOPOWEROFF_DELAY" 2>/dev/null
        echo "✅ Auto power off enabled"
    fi
    
    log_action "Security power settings applied"
}

# Configure scheduled wake/sleep events
configure_scheduled_events() {
    echo "=== Configuring Scheduled Power Events ==="
    
    # Clear existing scheduled events
    sudo pmset repeat cancel 2>/dev/null
    
    if [[ "$SCHEDULED_WAKE_ENABLED" == "true" ]]; then
        # Schedule wake for business hours
        sudo pmset repeat wakeorpoweron "$BUSINESS_DAYS" "$BUSINESS_HOURS_START:00" 2>/dev/null
        echo "✅ Scheduled wake configured for business hours"
        log_action "Scheduled wake configured: $BUSINESS_DAYS at $BUSINESS_HOURS_START"
    fi
    
    if [[ "$SCHEDULED_SLEEP_ENABLED" == "true" ]]; then
        # Schedule sleep after business hours
        local sleep_time="${BUSINESS_HOURS_END}:30:00"
        sudo pmset repeat sleep "$BUSINESS_DAYS" "$sleep_time" 2>/dev/null
        echo "✅ Scheduled sleep configured for after hours"
        log_action "Scheduled sleep configured: $BUSINESS_DAYS at $sleep_time"
    fi
}

# Monitor power events and assertions
monitor_power_events() {
    echo "=== Starting Power Event Monitoring ==="
    
    local monitor_duration="${1:-3600}"  # Default 1 hour
    local end_time=$(($(date +%s) + monitor_duration))
    
    echo "Monitoring power events for $((monitor_duration/60)) minutes..."
    echo "Press Ctrl+C to stop monitoring"
    
    while [[ $(date +%s) -lt $end_time ]]; do
        # Check power assertions
        local assertion_count
        assertion_count=$(pmset -g assertions 2>/dev/null | grep -c "PreventUserIdleSystemSleep\|PreventUserIdleDisplaySleep" || echo 0)
        
        if [[ $assertion_count -gt 0 ]]; then
            echo "$(date '+%H:%M:%S') - Active power assertions: $assertion_count"
            pmset -g assertions 2>/dev/null | grep -E "(PreventUserIdleSystemSleep|PreventUserIdleDisplaySleep)" | head -3
        fi
        
        # Check thermal state
        local thermal_state
        thermal_state=$(pmset -g thermstate 2>/dev/null | grep -o "Normal\|Fair\|Serious\|Critical" | head -1)
        
        if [[ "$thermal_state" != "Normal" && -n "$thermal_state" ]]; then
            echo "$(date '+%H:%M:%S') - ⚠️  Thermal state: $thermal_state"
            log_action "Thermal warning: $thermal_state"
        fi
        
        # Check power source changes
        local current_power_source
        current_power_source=$(pmset -g ps 2>/dev/null | head -1)
        
        if [[ -f "/tmp/macfleet_last_power_source" ]]; then
            local last_power_source
            last_power_source=$(cat "/tmp/macfleet_last_power_source")
            
            if [[ "$current_power_source" != "$last_power_source" ]]; then
                echo "$(date '+%H:%M:%S') - 🔌 Power source changed: $current_power_source"
                log_action "Power source change: $current_power_source"
                audit_log "POWER_SOURCE_CHANGE" "DETECTED" "$current_power_source"
                
                # Auto-adjust power profile based on power source
                auto_adjust_power_profile
            fi
        fi
        
        echo "$current_power_source" > "/tmp/macfleet_last_power_source"
        
        sleep 30
    done
    
    echo "Power monitoring completed"
}

# Auto-adjust power profile based on conditions
auto_adjust_power_profile() {
    local current_hour
    current_hour=$(date +%H)
    
    local current_power_source
    current_power_source=$(pmset -g ps 2>/dev/null | head -1)
    
    echo "=== Auto-adjusting Power Profile ==="
    
    # Determine appropriate profile
    local new_profile=""
    
    if echo "$current_power_source" | grep -q "Battery Power"; then
        new_profile="energy_saver"
        echo "On battery power - switching to energy saver profile"
    elif [[ $current_hour -ge 18 || $current_hour -lt 9 ]]; then
        new_profile="$AFTER_HOURS_POWER_PROFILE"
        echo "After hours - switching to $new_profile profile"
    else
        new_profile="$POWER_PROFILE"
        echo "Business hours - switching to $new_profile profile"
    fi
    
    if [[ -n "$new_profile" ]]; then
        apply_power_profile "$new_profile"
        log_action "Auto-adjusted power profile to: $new_profile"
    fi
}

# Check power management compliance
check_power_compliance() {
    echo "=== Power Management Compliance Check ==="
    
    local compliance_issues=()
    local compliance_score=100
    
    # Check if power management is properly configured
    local current_settings
    current_settings=$(pmset -g 2>/dev/null)
    
    if [[ -z "$current_settings" ]]; then
        compliance_issues+=("Unable to read power management settings")
        compliance_score=$((compliance_score - 50))
    fi
    
    # Check sleep timers
    local system_sleep
    system_sleep=$(echo "$current_settings" | grep -E '^\s*sleep\s' | awk '{print $2}')
    
    if [[ "$system_sleep" == "0" ]] && [[ "$POWER_PROFILE" != "kiosk_mode" ]] && [[ "$POWER_PROFILE" != "presentation_mode" ]]; then
        compliance_issues+=("System sleep disabled (security risk)")
        compliance_score=$((compliance_score - 20))
    fi
    
    # Check display sleep
    local display_sleep
    display_sleep=$(echo "$current_settings" | grep -E '^\s*displaysleep\s' | awk '{print $2}')
    
    if [[ "$display_sleep" == "0" ]] && [[ "$POWER_PROFILE" != "kiosk_mode" ]] && [[ "$POWER_PROFILE" != "presentation_mode" ]]; then
        compliance_issues+=("Display sleep disabled (energy waste)")
        compliance_score=$((compliance_score - 15))
    fi
    
    # Check security settings
    local hibernatemode
    hibernatemode=$(echo "$current_settings" | grep -E '^\s*hibernatemode\s' | awk '{print $2}')
    
    if [[ "$hibernatemode" == "0" ]] && [[ "$DESTROY_FILEVAULT_KEYS_ON_STANDBY" == "true" ]]; then
        compliance_issues+=("Hibernation disabled but FileVault key destruction enabled")
        compliance_score=$((compliance_score - 10))
    fi
    
    # Check thermal management
    local thermal_state
    thermal_state=$(pmset -g thermstate 2>/dev/null | grep -o "Normal\|Fair\|Serious\|Critical" | head -1)
    
    if [[ "$thermal_state" == "Serious" || "$thermal_state" == "Critical" ]]; then
        compliance_issues+=("Thermal management issue: $thermal_state")
        compliance_score=$((compliance_score - 25))
    fi
    
    # Report compliance status
    echo "Compliance Score: $compliance_score/100"
    
    if [[ ${#compliance_issues[@]} -eq 0 ]]; then
        echo "✅ Power management configuration is compliant"
        audit_log "COMPLIANCE_CHECK" "PASSED" "Score: $compliance_score/100"
        return 0
    else
        echo "❌ Compliance issues found:"
        printf '  - %s\n' "${compliance_issues[@]}"
        audit_log "COMPLIANCE_CHECK" "FAILED" "Issues: ${#compliance_issues[@]} Score: $compliance_score/100"
        
        # Auto-remediation if enabled
        if [[ "$AUTO_APPLY_POLICIES" == "true" ]]; then
            echo "🔧 Auto-remediation enabled, applying correct power profile..."
            apply_power_profile "$POWER_PROFILE"
        fi
        
        return 1
    fi
}

# Generate power management report
generate_power_report() {
    local report_file="$POLICIES_DIR/power_report_$(date +%Y%m%d_%H%M%S).json"
    
    echo "=== Generating Power Management Report ==="
    
    # Get current power information
    local power_source=""
    local battery_percentage=""
    local thermal_state=""
    local power_assertions=""
    
    if command -v pmset >/dev/null; then
        power_source=$(pmset -g ps 2>/dev/null | head -1 | sed 's/.*from //' | sed 's/;.*//')
        battery_percentage=$(pmset -g ps 2>/dev/null | grep -o '[0-9]*%' | head -1 | sed 's/%//')
        thermal_state=$(pmset -g thermstate 2>/dev/null | grep -o "Normal\|Fair\|Serious\|Critical" | head -1)
        power_assertions=$(pmset -g assertions 2>/dev/null | grep -c "PreventUserIdleSystemSleep\|PreventUserIdleDisplaySleep" || echo 0)
    fi
    
    # Get energy usage data
    local uptime_seconds
    uptime_seconds=$(uptime | awk '{print $3}' | cut -d',' -f1 | cut -d':' -f2)
    
    # Create JSON report
    cat > "$report_file" << EOF
{
  "report_type": "power_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)",
    "model": "$(system_profiler SPHardwareDataType | grep "Model Name" | awk -F: '{print $2}' | xargs)"
  },
  "power_status": {
    "power_source": "$power_source",
    "battery_percentage": $([ -n "$battery_percentage" ] && echo "$battery_percentage" || echo "null"),
    "thermal_state": "${thermal_state:-Normal}",
    "active_power_assertions": $power_assertions
  },
  "power_settings": {
    "current_profile": "$POWER_PROFILE",
    "system_sleep_ac": "$SYSTEM_SLEEP_AC",
    "display_sleep_ac": "$DISPLAY_SLEEP_AC",
    "wake_on_lan": $WAKE_ON_LAN,
    "auto_restart_on_power_loss": $AUTOMATIC_RESTART_ON_POWER_LOSS
  },
  "energy_optimization": {
    "energy_optimization_enabled": $ENERGY_OPTIMIZATION,
    "reduce_brightness_battery": $REDUCE_BRIGHTNESS_BATTERY,
    "thermal_management": $THERMAL_MANAGEMENT
  },
  "compliance_status": {
    "policy_compliant": $(check_power_compliance >/dev/null 2>&1 && echo true || echo false),
    "auto_apply_policies": $AUTO_APPLY_POLICIES,
    "regulatory_compliance": "$REGULATORY_COMPLIANCE"
  },
  "sustainability": {
    "carbon_footprint_tracking": $CARBON_FOOTPRINT_TRACKING,
    "energy_star_compliant": $([ "$REGULATORY_COMPLIANCE" == "ENERGY_STAR" ] && echo true || echo false)
  }
}
EOF
    
    echo "Power management report saved to: $report_file"
    log_action "Power management report generated: $report_file"
}

# Prevent system sleep for critical operations
prevent_sleep_for_operation() {
    local operation_name="$1"
    local duration_seconds="$2"
    local prevent_display="${3:-false}"
    
    echo "=== Preventing Sleep for Operation: $operation_name ==="
    
    local caffeinate_options="-i"
    
    if [[ "$prevent_display" == "true" ]]; then
        caffeinate_options="$caffeinate_options -d"
    fi
    
    if [[ -n "$duration_seconds" ]]; then
        caffeinate_options="$caffeinate_options -t $duration_seconds"
    fi
    
    echo "Preventing system sleep for $operation_name..."
    log_action "Sleep prevention started for operation: $operation_name (duration: ${duration_seconds:-indefinite}s)"
    
    # Run caffeinate in background and return PID
    caffeinate $caffeinate_options &
    local caffeinate_pid=$!
    
    echo "Sleep prevention active (PID: $caffeinate_pid)"
    echo "$caffeinate_pid" > "/tmp/macfleet_caffeinate_$operation_name.pid"
    
    audit_log "SLEEP_PREVENTION" "STARTED" "Operation: $operation_name PID: $caffeinate_pid"
    
    return 0
}

# Stop sleep prevention for operation
stop_sleep_prevention() {
    local operation_name="$1"
    local pid_file="/tmp/macfleet_caffeinate_$operation_name.pid"
    
    if [[ -f "$pid_file" ]]; then
        local caffeinate_pid
        caffeinate_pid=$(cat "$pid_file")
        
        if kill -0 "$caffeinate_pid" 2>/dev/null; then
            kill "$caffeinate_pid"
            echo "Sleep prevention stopped for $operation_name (PID: $caffeinate_pid)"
            log_action "Sleep prevention stopped for operation: $operation_name"
            audit_log "SLEEP_PREVENTION" "STOPPED" "Operation: $operation_name PID: $caffeinate_pid"
        else
            echo "Sleep prevention process not found for $operation_name"
        fi
        
        rm -f "$pid_file"
    else
        echo "No active sleep prevention found for $operation_name"
    fi
}

# Main function with argument handling
main() {
    log_action "=== MacFleet Power Management Tool Started ==="
    
    case "${1:-status}" in
        "status")
            get_power_status
            ;;
        "profile")
            apply_power_profile "$2"
            ;;
        "monitor")
            monitor_power_events "$2"
            ;;
        "compliance")
            check_power_compliance
            ;;
        "report")
            generate_power_report
            ;;
        "prevent-sleep")
            prevent_sleep_for_operation "$2" "$3" "$4"
            ;;
        "allow-sleep")
            stop_sleep_prevention "$2"
            ;;
        "auto-adjust")
            auto_adjust_power_profile
            ;;
        "schedule")
            configure_scheduled_events
            ;;
        *)
            echo "MacFleet Enterprise Power Management Tool"
            echo "Usage: $0 [command] [options]"
            echo ""
            echo "Commands:"
            echo "  status                        - Show current power management status"
            echo "  profile [name]                - Apply specific power profile"
            echo "  monitor [duration]            - Monitor power events (duration in seconds)"
            echo "  compliance                    - Check power management compliance"
            echo "  report                        - Generate power management report"
            echo "  prevent-sleep [name] [duration] [display] - Prevent sleep for operation"
            echo "  allow-sleep [name]            - Stop sleep prevention for operation"
            echo "  auto-adjust                   - Auto-adjust power profile based on conditions"
            echo "  schedule                      - Configure scheduled power events"
            echo ""
            echo "Power Profiles:"
            echo "  corporate_standard            - Standard corporate power management (default)"
            echo "  energy_saver                  - Maximum energy efficiency"
            echo "  high_performance              - Performance-focused settings"
            echo "  security_focused              - Security-optimized power management"
            echo "  presentation_mode             - Prevent sleep during presentations"
            echo "  kiosk_mode                    - Always-on for kiosk devices"
            ;;
    esac
    
    log_action "=== Power management operation completed ==="
}

# Execute main function
main "$@"

## Advanced Power Management Features

### Business Hours Power Automation

```bash
#!/bin/bash

# Automated business hours power management
setup_business_hours_automation() {
    echo "=== Setting Up Business Hours Power Automation ==="
    
    # Create business hours power management script
    local automation_script="/Library/MacFleet/Scripts/business_hours_power.sh"
    mkdir -p "$(dirname "$automation_script")"
    
    cat > "$automation_script" << 'EOF'
#!/bin/bash

# Determine current time and apply appropriate power profile
current_hour=$(date +%H)
current_day=$(date +%u)  # 1=Monday, 7=Sunday

# Business hours: Monday-Friday 9AM-6PM
if [[ $current_day -le 5 ]] && [[ $current_hour -ge 9 ]] && [[ $current_hour -lt 18 ]]; then
    # Business hours
    /Library/MacFleet/Scripts/power_management.sh profile corporate_standard
elif [[ $current_day -gt 5 ]]; then
    # Weekend
    /Library/MacFleet/Scripts/power_management.sh profile energy_saver
else
    # After hours
    /Library/MacFleet/Scripts/power_management.sh profile security_focused
fi
EOF
    
    chmod +x "$automation_script"
    
    # Create launch daemon for automation
    local launch_daemon="/Library/LaunchDaemons/com.macfleet.power.automation.plist"
    
    cat > "$launch_daemon" << EOF
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Label</key>
    <string>com.macfleet.power.automation</string>
    <key>ProgramArguments</key>
    <array>
        <string>$automation_script</string>
    </array>
    <key>StartCalendarInterval</key>
    <array>
        <dict>
            <key>Hour</key>
            <integer>9</integer>
            <key>Minute</key>
            <integer>0</integer>
        </dict>
        <dict>
            <key>Hour</key>
            <integer>18</integer>
            <key>Minute</key>
            <integer>0</integer>
        </dict>
    </array>
    <key>RunAtLoad</key>
    <true/>
</dict>
</plist>
EOF
    
    # Load the launch daemon
    sudo launchctl load "$launch_daemon" 2>/dev/null
    
    echo "✅ Business hours power automation configured"
    log_action "Business hours power automation setup completed"
}

# Battery optimization for laptops
optimize_battery_performance() {
    echo "=== Optimizing Battery Performance ==="
    
    # Check if device has a battery
    if ! system_profiler SPPowerDataType 2>/dev/null | grep -q "Battery Information"; then
        echo "No battery detected - skipping battery optimization"
        return 0
    fi
    
    # Get current battery information
    local battery_condition
    battery_condition=$(system_profiler SPPowerDataType | grep "Condition" | awk -F: '{print $2}' | xargs)
    
    local cycle_count
    cycle_count=$(system_profiler SPPowerDataType | grep "Cycle Count" | awk -F: '{print $2}' | xargs)
    
    echo "Battery Condition: $battery_condition"
    echo "Cycle Count: $cycle_count"
    
    # Apply battery-specific optimizations
    if [[ "$battery_condition" == "Replace Soon" || "$battery_condition" == "Replace Now" ]]; then
        echo "⚠️  Battery needs replacement - applying conservative settings"
        sudo pmset -b sleep 5 2>/dev/null
        sudo pmset -b displaysleep 2 2>/dev/null
        sudo pmset -b reducebright 1 2>/dev/null
        
        log_action "BATTERY WARNING: $battery_condition - Conservative settings applied"
        audit_log "BATTERY_WARNING" "DETECTED" "Condition: $battery_condition Cycles: $cycle_count"
    else
        echo "✅ Battery condition normal - applying standard optimization"
        sudo pmset -b sleep "$SYSTEM_SLEEP_BATTERY" 2>/dev/null
        sudo pmset -b displaysleep "$DISPLAY_SLEEP_BATTERY" 2>/dev/null
    fi
    
    # Enable optimized battery charging
    sudo pmset -a optimizedcharging 1 2>/dev/null
    
    echo "Battery optimization completed"
    log_action "Battery performance optimization applied"
}

# Thermal management
monitor_thermal_state() {
    echo "=== Thermal State Monitoring ==="
    
    local thermal_log="/var/log/macfleet_thermal.log"
    local monitoring_duration="${1:-300}"  # Default 5 minutes
    
    echo "Monitoring thermal state for $((monitoring_duration/60)) minutes..."
    
    local end_time=$(($(date +%s) + monitoring_duration))
    
    while [[ $(date +%s) -lt $end_time ]]; do
        local thermal_state
        thermal_state=$(pmset -g thermstate 2>/dev/null | grep -o "Normal\|Fair\|Serious\|Critical" | head -1)
        
        local cpu_temp=""
        if command -v powermetrics >/dev/null; then
            cpu_temp=$(sudo powermetrics -n 1 -s cpu_power 2>/dev/null | grep "CPU die temperature" | awk '{print $4}' | head -1)
        fi
        
        local timestamp
        timestamp=$(date '+%Y-%m-%d %H:%M:%S')
        
        echo "$timestamp - Thermal: $thermal_state CPU: ${cpu_temp:-N/A}°C" | tee -a "$thermal_log"
        
        case "$thermal_state" in
            "Serious"|"Critical")
                echo "🚨 THERMAL ALERT: $thermal_state - Taking protective action"
                # Reduce performance to cool down
                sudo pmset -a reducebright 1 2>/dev/null
                # Log critical thermal event
                log_action "THERMAL ALERT: $thermal_state detected - protective measures activated"
                audit_log "THERMAL_ALERT" "CRITICAL" "State: $thermal_state CPU: ${cpu_temp:-N/A}°C"
                ;;
            "Fair")
                echo "⚠️  Thermal warning: $thermal_state"
                log_action "Thermal warning: $thermal_state"
                ;;
        esac
        
        sleep 10
    done
    
    echo "Thermal monitoring completed"
}

## Important Configuration Notes

### macOS Power Management Architecture

- **Power Management Unit (PMU)** - Hardware-level power control
- **IOPMrootDomain** - Kernel power management
- **PowerManagement.framework** - User-space power APIs
- **pmset** - Command-line power management tool
- **Energy Saver** - System Preferences power interface

### Enterprise Integration Points

- **MDM Configuration Profiles** - Deploy power policies centrally
- **Energy Monitoring Systems** - Integration with facility management
- **Carbon Footprint Tracking** - Environmental compliance reporting
- **Business Intelligence** - Power usage analytics and optimization

### Best Practices for Enterprise Power Management

1. **Energy Efficiency Strategy**
   - Implement tiered power profiles based on usage patterns
   - Monitor and optimize energy consumption across the fleet
   - Align with corporate sustainability initiatives
   - Track cost savings from power management policies

2. **Security Considerations**
   - Enable FileVault key destruction on standby for sensitive data
   - Configure appropriate hibernation modes for security
   - Implement secure sleep modes for unattended devices
   - Balance security requirements with operational needs

3. **Performance Optimization**
   - Use high-performance profiles for resource-intensive tasks
   - Implement presentation modes for meeting scenarios
   - Configure thermal management for sustained workloads
   - Monitor battery health and optimize charging patterns

4. **Compliance and Reporting**
   - Generate energy usage reports for regulatory compliance
   - Track power management policy adherence
   - Document power optimization initiatives
   - Monitor environmental impact metrics

Remember to test power management configurations thoroughly in your environment before fleet-wide deployment to ensure they meet your organization's operational, security, and energy efficiency requirements. 

Shutdown and Reboot Management for macOS

Implement enterprise-grade shutdown and reboot management across your MacFleet deployment with automated maintenance scheduling, graceful shutdown procedures, security validation, and comprehensive fleet-wide power management. This tutorial provides solutions for maintaining operational continuity while ensuring secure and efficient system power operations.

Understanding macOS Shutdown and Reboot Management

macOS provides several power control mechanisms and tools:

  • shutdown - Primary command-line tool for system power control
  • reboot - Alternative reboot command
  • halt - System halt without power off
  • Apple Menu - GUI shutdown interface
  • Power Button - Hardware-level power control

Basic Shutdown Operations

Instant Shutdown

#!/bin/bash

# Shutdown Mac instantly
sudo shutdown -h now

Scheduled Reboot

#!/bin/bash

# Reboot Mac in 5 minutes
sudo shutdown -r +5

Shutdown at Specific Time

#!/bin/bash

# Shutdown at specific time: October 18, 16:11:00 2022
sudo shutdown -h 2210181611

Reboot with Warning Message

#!/bin/bash

# Reboot with warning message
sudo shutdown -r +2 "the system will restart in 2 minutes"

Display Sleep and Lock

#!/bin/bash

# Lock device and turn off display
sudo shutdown -s

Enterprise Shutdown and Reboot Management System

Comprehensive Power Management Tool

#!/bin/bash

# MacFleet Enterprise Shutdown and Reboot Management Tool
# Advanced power control and maintenance scheduling

# Configuration
CONFIG_FILE="/etc/macfleet/shutdown_policy.conf"
LOG_FILE="/var/log/macfleet_shutdown.log"
SCHEDULES_DIR="/Library/MacFleet/ShutdownSchedules"
AUDIT_LOG="/var/log/macfleet_shutdown_audit.log"

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

# Default shutdown management policy
cat > "$CONFIG_FILE" 2>/dev/null << 'EOF' || true
# MacFleet Enterprise Shutdown and Reboot Management Policy
# Version: 2.0

# Shutdown Policy Enforcement
ENFORCE_SHUTDOWN_POLICIES=true
GRACEFUL_SHUTDOWN_ENABLED=true
SAVE_WORK_BEFORE_SHUTDOWN=true
FORCE_SHUTDOWN_TIMEOUT=300
WARNING_NOTIFICATION_TIME=300

# Security and Safety
REQUIRE_ADMIN_APPROVAL=false
VALIDATE_USER_SESSIONS=true
CHECK_RUNNING_PROCESSES=true
BACKUP_BEFORE_SHUTDOWN=false
ENCRYPTION_KEY_PROTECTION=true

# Maintenance Windows
MAINTENANCE_WINDOW_ENABLED=true
MAINTENANCE_START_TIME="02:00"
MAINTENANCE_END_TIME="06:00"
MAINTENANCE_DAYS="MTWRF"
WEEKEND_MAINTENANCE_ENABLED=true
HOLIDAY_MAINTENANCE_DISABLED=true

# Business Hours Protection
BUSINESS_HOURS_START="09:00"
BUSINESS_HOURS_END="18:00"
PREVENT_SHUTDOWN_BUSINESS_HOURS=true
EMERGENCY_SHUTDOWN_OVERRIDE=true
CRITICAL_SYSTEM_PROTECTION=true

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

# Automatic Scheduling
AUTO_REBOOT_ENABLED=true
AUTO_REBOOT_FREQUENCY="weekly"
AUTO_REBOOT_DAY="sunday"
AUTO_REBOOT_TIME="03:00"
PATCH_REBOOT_REQUIRED=true

# Compliance and Audit
AUDIT_ALL_POWER_OPERATIONS=true
COMPLIANCE_REPORTING=true
UPTIME_TRACKING=true
MAINTENANCE_DOCUMENTATION=true
CHANGE_MANAGEMENT_INTEGRATION=true

# Recovery and Failsafe
AUTOMATIC_RECOVERY_ENABLED=true
BOOT_VALIDATION_REQUIRED=true
ROLLBACK_ON_FAILURE=true
EMERGENCY_CONTACT_INFO="IT Support: +1-555-0123"
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 result="$2"
    local details="$3"
    echo "$(date '+%Y-%m-%d %H:%M:%S') - ACTION:$action RESULT:$result DETAILS:$details USER:$(whoami)" >> "$AUDIT_LOG"
}

# Check if shutdown is allowed
check_shutdown_allowed() {
    local operation="$1"
    local force="${2:-false}"
    
    echo "=== Validating Shutdown Authorization ==="
    
    # Check business hours protection
    if [[ "$PREVENT_SHUTDOWN_BUSINESS_HOURS" == "true" && "$force" != "true" ]]; then
        local current_hour
        current_hour=$(date +%H)
        local start_hour
        start_hour=$(echo "$BUSINESS_HOURS_START" | cut -d':' -f1)
        local end_hour
        end_hour=$(echo "$BUSINESS_HOURS_END" | cut -d':' -f1)
        
        if [[ $current_hour -ge $start_hour && $current_hour -lt $end_hour ]]; then
            echo "❌ Shutdown blocked: Currently in business hours ($BUSINESS_HOURS_START - $BUSINESS_HOURS_END)"
            log_action "SHUTDOWN BLOCKED: Business hours protection active"
            audit_log "SHUTDOWN_BLOCKED" "BUSINESS_HOURS" "Operation: $operation Time: $(date '+%H:%M')"
            return 1
        fi
    fi
    
    # Check for active user sessions
    if [[ "$VALIDATE_USER_SESSIONS" == "true" ]]; then
        local active_users
        active_users=$(who | wc -l)
        
        if [[ $active_users -gt 0 && "$force" != "true" ]]; then
            echo "⚠️  Warning: $active_users active user session(s) detected"
            log_action "WARNING: Active user sessions during $operation"
            
            if [[ "$GRACEFUL_SHUTDOWN_ENABLED" != "true" ]]; then
                echo "❌ Shutdown blocked: Active users and graceful shutdown disabled"
                audit_log "SHUTDOWN_BLOCKED" "ACTIVE_USERS" "Users: $active_users Operation: $operation"
                return 1
            fi
        fi
    fi
    
    # Check for critical running processes
    if [[ "$CHECK_RUNNING_PROCESSES" == "true" ]]; then
        local critical_processes=(
            "backupd"
            "softwareupdate"
            "installer"
            "diskutil"
            "fsck"
        )
        
        for process in "${critical_processes[@]}"; do
            if pgrep -f "$process" >/dev/null 2>&1; then
                echo "⚠️  Critical process running: $process"
                
                if [[ "$force" != "true" ]]; then
                    echo "❌ Shutdown blocked: Critical process $process is running"
                    log_action "SHUTDOWN BLOCKED: Critical process $process running"
                    audit_log "SHUTDOWN_BLOCKED" "CRITICAL_PROCESS" "Process: $process Operation: $operation"
                    return 1
                else
                    echo "🚨 Force shutdown: Will terminate critical process $process"
                    log_action "FORCE SHUTDOWN: Terminating critical process $process"
                fi
            fi
        done
    fi
    
    # Admin approval check
    if [[ "$REQUIRE_ADMIN_APPROVAL" == "true" && "$force" != "true" ]]; then
        echo "❌ Shutdown blocked: Admin approval required"
        log_action "SHUTDOWN BLOCKED: Admin approval required"
        audit_log "SHUTDOWN_BLOCKED" "ADMIN_APPROVAL" "Operation: $operation"
        return 1
    fi
    
    echo "✅ Shutdown authorization validated"
    audit_log "SHUTDOWN_AUTHORIZED" "APPROVED" "Operation: $operation"
    return 0
}

# Send notification before shutdown
send_shutdown_notification() {
    local operation="$1"
    local delay_minutes="$2"
    local message="$3"
    
    echo "=== Sending Shutdown Notifications ==="
    
    local notification_title="MacFleet System $operation Notification"
    local notification_message="${message:-System $operation scheduled in $delay_minutes minutes}"
    
    # User notification
    if [[ "$USER_NOTIFICATION_ENABLED" == "true" ]]; then
        # Display notification to all 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
        
        # Terminal notification
        wall "$notification_title: $notification_message" 2>/dev/null || true
    fi
    
    # Admin notification
    if [[ "$ADMIN_NOTIFICATION_ENABLED" == "true" ]]; then
        log_action "ADMIN NOTIFICATION: $notification_title - $notification_message"
    fi
    
    # 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 "Shutdown notifications sent for $operation (delay: $delay_minutes minutes)"
}

# Graceful shutdown with user session handling
graceful_shutdown() {
    local operation="$1"
    local delay_minutes="$2"
    local message="$3"
    
    echo "=== Initiating Graceful $operation ==="
    
    # Send initial notification
    send_shutdown_notification "$operation" "$delay_minutes" "$message"
    
    # Save user work if enabled
    if [[ "$SAVE_WORK_BEFORE_SHUTDOWN" == "true" ]]; then
        echo "💾 Attempting to save user work..."
        
        # Try to save work in common applications
        local save_commands=(
            "osascript -e 'tell application \"System Events\" to keystroke \"s\" using command down'"
            "pkill -USR1 TextEdit"  # Signal TextEdit to save
        )
        
        for cmd in "${save_commands[@]}"; do
            eval "$cmd" 2>/dev/null || true
        done
        
        log_action "User work save attempted before $operation"
    fi
    
    # Create backup if enabled
    if [[ "$BACKUP_BEFORE_SHUTDOWN" == "true" ]]; then
        echo "💾 Creating system backup before $operation..."
        create_pre_shutdown_backup
    fi
    
    # FileVault key protection
    if [[ "$ENCRYPTION_KEY_PROTECTION" == "true" ]]; then
        echo "🔐 Ensuring FileVault key security..."
        sudo pmset -a destroyfvkeyonstandby 1 2>/dev/null || true
        log_action "FileVault key protection enabled before $operation"
    fi
    
    # Wait for delay period with countdown
    if [[ $delay_minutes -gt 0 ]]; then
        echo "⏱️  Waiting $delay_minutes minutes before $operation..."
        
        local remaining_seconds=$((delay_minutes * 60))
        local notification_intervals=(300 120 60 30 10)  # 5min, 2min, 1min, 30s, 10s
        
        while [[ $remaining_seconds -gt 0 ]]; do
            # Send reminder notifications at specific intervals
            for interval in "${notification_intervals[@]}"; do
                if [[ $remaining_seconds -eq $interval ]]; then
                    local remaining_minutes=$((remaining_seconds / 60))
                    if [[ $remaining_minutes -gt 0 ]]; then
                        send_shutdown_notification "$operation" "$remaining_minutes" "Final warning: System $operation in $remaining_minutes minute(s)"
                    else
                        send_shutdown_notification "$operation" "0" "Final warning: System $operation in $remaining_seconds seconds"
                    fi
                    break
                fi
            done
            
            sleep 1
            remaining_seconds=$((remaining_seconds - 1))
        done
    fi
    
    echo "✅ Graceful $operation preparation completed"
    log_action "Graceful $operation preparation completed"
}

# Create pre-shutdown backup
create_pre_shutdown_backup() {
    echo "=== Creating Pre-Shutdown Backup ==="
    
    local backup_dir="/Library/MacFleet/Backups"
    local backup_file="$backup_dir/pre_shutdown_backup_$(date +%Y%m%d_%H%M%S).tar.gz"
    
    mkdir -p "$backup_dir"
    
    # Backup critical system configurations
    local backup_paths=(
        "/etc"
        "/Library/Preferences"
        "/System/Library/LaunchDaemons"
        "/Library/LaunchDaemons"
        "/usr/local/etc"
    )
    
    echo "Creating backup of critical system files..."
    tar -czf "$backup_file" "${backup_paths[@]}" 2>/dev/null || true
    
    if [[ -f "$backup_file" ]]; then
        echo "✅ Pre-shutdown backup created: $backup_file"
        log_action "Pre-shutdown backup created: $backup_file"
    else
        echo "⚠️  Pre-shutdown backup creation failed"
        log_action "WARNING: Pre-shutdown backup creation failed"
    fi
}

# Enterprise shutdown with comprehensive validation
enterprise_shutdown() {
    local delay="${1:-now}"
    local message="$2"
    local force="${3:-false}"
    
    echo "=== Enterprise Shutdown Initiated ==="
    
    # Validate shutdown authorization
    if ! check_shutdown_allowed "shutdown" "$force"; then
        return 1
    fi
    
    # Parse delay
    local delay_minutes=0
    if [[ "$delay" != "now" ]]; then
        if [[ "$delay" =~ ^\+([0-9]+)$ ]]; then
            delay_minutes="${BASH_REMATCH[1]}"
        else
            echo "❌ Invalid delay format. Use 'now' or '+minutes'"
            return 1
        fi
    fi
    
    # Graceful shutdown if enabled
    if [[ "$GRACEFUL_SHUTDOWN_ENABLED" == "true" ]]; then
        graceful_shutdown "shutdown" "$delay_minutes" "$message"
    fi
    
    # Log shutdown action
    log_action "ENTERPRISE SHUTDOWN: Executing shutdown with delay: $delay"
    audit_log "SHUTDOWN" "INITIATED" "Delay: $delay Message: ${message:-None} Force: $force"
    
    # Execute shutdown
    if [[ "$delay" == "now" ]]; then
        echo "🔌 Executing immediate shutdown..."
        sudo shutdown -h now "$message"
    else
        echo "🔌 Scheduling shutdown in $delay_minutes minutes..."
        sudo shutdown -h +"$delay_minutes" "$message"
    fi
    
    audit_log "SHUTDOWN" "EXECUTED" "Command completed successfully"
    return 0
}

# Enterprise reboot with comprehensive validation
enterprise_reboot() {
    local delay="${1:-now}"
    local message="$2"
    local force="${3:-false}"
    
    echo "=== Enterprise Reboot Initiated ==="
    
    # Validate reboot authorization
    if ! check_shutdown_allowed "reboot" "$force"; then
        return 1
    fi
    
    # Parse delay
    local delay_minutes=0
    if [[ "$delay" != "now" ]]; then
        if [[ "$delay" =~ ^\+([0-9]+)$ ]]; then
            delay_minutes="${BASH_REMATCH[1]}"
        else
            echo "❌ Invalid delay format. Use 'now' or '+minutes'"
            return 1
        fi
    fi
    
    # Graceful reboot if enabled
    if [[ "$GRACEFUL_SHUTDOWN_ENABLED" == "true" ]]; then
        graceful_shutdown "reboot" "$delay_minutes" "$message"
    fi
    
    # Log reboot action
    log_action "ENTERPRISE REBOOT: Executing reboot with delay: $delay"
    audit_log "REBOOT" "INITIATED" "Delay: $delay Message: ${message:-None} Force: $force"
    
    # Execute reboot
    if [[ "$delay" == "now" ]]; then
        echo "🔄 Executing immediate reboot..."
        sudo shutdown -r now "$message"
    else
        echo "🔄 Scheduling reboot in $delay_minutes minutes..."
        sudo shutdown -r +"$delay_minutes" "$message"
    fi
    
    audit_log "REBOOT" "EXECUTED" "Command completed successfully"
    return 0
}

# Schedule maintenance reboot
schedule_maintenance_reboot() {
    local schedule_time="$1"
    local reason="$2"
    
    echo "=== Scheduling Maintenance Reboot ==="
    
    if [[ -z "$schedule_time" ]]; then
        echo "❌ Schedule time required (format: YYMMDDHHMM)"
        return 1
    fi
    
    # Validate schedule time format
    if [[ ! "$schedule_time" =~ ^[0-9]{10}$ ]]; then
        echo "❌ Invalid schedule time format. Use YYMMDDHHMM"
        return 1
    fi
    
    # Check if scheduled time is in maintenance window
    if [[ "$MAINTENANCE_WINDOW_ENABLED" == "true" ]]; then
        local schedule_hour
        schedule_hour=$(echo "$schedule_time" | cut -c 7-8)
        local maintenance_start_hour
        maintenance_start_hour=$(echo "$MAINTENANCE_START_TIME" | cut -d':' -f1)
        local maintenance_end_hour
        maintenance_end_hour=$(echo "$MAINTENANCE_END_TIME" | cut -d':' -f1)
        
        if [[ $schedule_hour -lt $maintenance_start_hour || $schedule_hour -ge $maintenance_end_hour ]]; then
            echo "⚠️  Warning: Scheduled time outside maintenance window ($MAINTENANCE_START_TIME - $MAINTENANCE_END_TIME)"
        fi
    fi
    
    # Schedule the reboot
    local message="Scheduled maintenance reboot: ${reason:-System maintenance}"
    
    log_action "MAINTENANCE REBOOT SCHEDULED: Time: $schedule_time Reason: ${reason:-System maintenance}"
    audit_log "MAINTENANCE_SCHEDULED" "CREATED" "Time: $schedule_time Reason: ${reason:-System maintenance}"
    
    echo "🗓️  Scheduling maintenance reboot..."
    sudo shutdown -r "$schedule_time" "$message"
    
    echo "✅ Maintenance reboot scheduled for $(date -j -f "%Y%m%d%H%M" "20$schedule_time" "+%Y-%m-%d %H:%M")"
    
    # Create maintenance record
    local maintenance_file="$SCHEDULES_DIR/maintenance_$(date +%Y%m%d_%H%M%S).json"
    cat > "$maintenance_file" << EOF
{
  "type": "maintenance_reboot",
  "scheduled_time": "$schedule_time",
  "reason": "${reason:-System maintenance}",
  "created_by": "$(whoami)",
  "created_at": "$(date -u +%Y-%m-%dT%H:%M:%SZ)",
  "device": "$(hostname)"
}
EOF
    
    log_action "Maintenance record created: $maintenance_file"
    return 0
}

# Cancel scheduled shutdown/reboot
cancel_scheduled_operation() {
    echo "=== Cancelling Scheduled Operations ==="
    
    # Get list of scheduled operations
    local scheduled_ops
    scheduled_ops=$(ps aux | grep "shutdown" | grep -v grep | wc -l)
    
    if [[ $scheduled_ops -eq 0 ]]; then
        echo "ℹ️  No scheduled shutdown/reboot operations found"
        return 0
    fi
    
    # Cancel shutdown operations
    if sudo pkill -f "shutdown"; then
        echo "✅ Scheduled shutdown/reboot operations cancelled"
        log_action "Scheduled shutdown/reboot operations cancelled"
        audit_log "SCHEDULE_CANCELLED" "SUCCESS" "Operations cancelled by $(whoami)"
        
        # Notify users of cancellation
        send_shutdown_notification "cancellation" "0" "Scheduled system operation has been cancelled"
    else
        echo "❌ Failed to cancel scheduled operations"
        log_action "FAILED: Could not cancel scheduled operations"
        audit_log "SCHEDULE_CANCELLED" "FAILED" "Cancellation attempt by $(whoami)"
        return 1
    fi
    
    return 0
}

# Emergency shutdown (bypasses all checks)
emergency_shutdown() {
    local reason="$1"
    
    echo "🚨 EMERGENCY SHUTDOWN INITIATED 🚨"
    
    if [[ -z "$reason" ]]; then
        echo "❌ Emergency reason required"
        return 1
    fi
    
    log_action "EMERGENCY SHUTDOWN: Reason: $reason"
    audit_log "EMERGENCY_SHUTDOWN" "INITIATED" "Reason: $reason User: $(whoami)"
    
    # Send emergency notification
    send_shutdown_notification "EMERGENCY SHUTDOWN" "0" "EMERGENCY: System shutdown initiated - $reason"
    
    # Emergency contact notification
    if [[ -n "$EMERGENCY_CONTACT_INFO" ]]; then
        echo "📞 Emergency contact: $EMERGENCY_CONTACT_INFO"
        log_action "Emergency contact info: $EMERGENCY_CONTACT_INFO"
    fi
    
    # Force immediate shutdown
    echo "🔌 Executing emergency shutdown (force)..."
    sudo shutdown -h now "EMERGENCY SHUTDOWN: $reason"
    
    audit_log "EMERGENCY_SHUTDOWN" "EXECUTED" "Immediate shutdown completed"
}

# Check system status for shutdown readiness
check_system_status() {
    echo "=== System Status Check ==="
    
    local status_issues=()
    local status_warnings=()
    
    # Check uptime
    local uptime_seconds
    uptime_seconds=$(uptime | awk '{print $3}' | cut -d',' -f1)
    echo "System Uptime: $uptime_seconds"
    
    # Check load average
    local load_average
    load_average=$(uptime | awk -F'load average:' '{print $2}' | awk '{print $1}' | tr -d ',')
    if (( $(echo "$load_average > 5.0" | bc -l) )); then
        status_warnings+=("High system load: $load_average")
    fi
    
    # Check disk space
    local disk_usage
    disk_usage=$(df / | tail -1 | awk '{print $5}' | sed 's/%//')
    if [[ $disk_usage -gt 90 ]]; then
        status_warnings+=("Low disk space: ${disk_usage}% used")
    fi
    
    # Check memory usage
    local memory_pressure
    memory_pressure=$(memory_pressure 2>/dev/null | grep "System-wide memory free percentage" | awk '{print $5}' | sed 's/%//' || echo "unknown")
    if [[ "$memory_pressure" != "unknown" && $memory_pressure -lt 10 ]]; then
        status_warnings+=("Low memory: ${memory_pressure}% free")
    fi
    
    # Check for pending updates
    if softwareupdate -l 2>/dev/null | grep -q "Software Update found"; then
        status_warnings+=("Pending software updates available")
    fi
    
    # Check network connectivity
    if ! ping -c 1 8.8.8.8 >/dev/null 2>&1; then
        status_warnings+=("Network connectivity issue detected")
    fi
    
    # Report status
    if [[ ${#status_issues[@]} -eq 0 && ${#status_warnings[@]} -eq 0 ]]; then
        echo "✅ System status: Ready for shutdown/reboot"
        return 0
    else
        if [[ ${#status_issues[@]} -gt 0 ]]; then
            echo "❌ System status issues:"
            printf '  - %s\n' "${status_issues[@]}"
        fi
        
        if [[ ${#status_warnings[@]} -gt 0 ]]; then
            echo "⚠️  System status warnings:"
            printf '  - %s\n' "${status_warnings[@]}"
        fi
        
        return 1
    fi
}

# Generate shutdown management report
generate_shutdown_report() {
    local report_file="$SCHEDULES_DIR/shutdown_report_$(date +%Y%m%d_%H%M%S).json"
    
    echo "=== Generating Shutdown Management Report ==="
    
    # Get system information
    local last_boot
    last_boot=$(who -b | awk '{print $3 " " $4}')
    
    local uptime_info
    uptime_info=$(uptime | awk -F'up ' '{print $2}' | awk -F',' '{print $1}')
    
    # Count recent operations from audit log
    local recent_shutdowns=0
    local recent_reboots=0
    local recent_cancellations=0
    
    if [[ -f "$AUDIT_LOG" ]]; then
        recent_shutdowns=$(grep -c "ACTION:SHUTDOWN" "$AUDIT_LOG" 2>/dev/null || echo 0)
        recent_reboots=$(grep -c "ACTION:REBOOT" "$AUDIT_LOG" 2>/dev/null || echo 0)
        recent_cancellations=$(grep -c "ACTION:SCHEDULE_CANCELLED" "$AUDIT_LOG" 2>/dev/null || echo 0)
    fi
    
    # Check for scheduled operations
    local scheduled_operations=0
    scheduled_operations=$(ps aux | grep -c "shutdown" | grep -v grep || echo 0)
    
    # Create JSON report
    cat > "$report_file" << EOF
{
  "report_type": "shutdown_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": {
    "last_boot": "$last_boot",
    "uptime": "$uptime_info",
    "scheduled_operations": $scheduled_operations,
    "system_ready": $(check_system_status >/dev/null 2>&1 && echo true || echo false)
  },
  "operation_history": {
    "total_shutdowns": $recent_shutdowns,
    "total_reboots": $recent_reboots,
    "cancelled_operations": $recent_cancellations
  },
  "policy_configuration": {
    "graceful_shutdown_enabled": $GRACEFUL_SHUTDOWN_ENABLED,
    "business_hours_protection": $PREVENT_SHUTDOWN_BUSINESS_HOURS,
    "maintenance_window_enabled": $MAINTENANCE_WINDOW_ENABLED,
    "auto_reboot_enabled": $AUTO_REBOOT_ENABLED
  },
  "compliance_status": {
    "audit_enabled": $AUDIT_ALL_POWER_OPERATIONS,
    "user_notification_enabled": $USER_NOTIFICATION_ENABLED,
    "backup_before_shutdown": $BACKUP_BEFORE_SHUTDOWN
  }
}
EOF
    
    echo "Shutdown management report saved to: $report_file"
    log_action "Shutdown management report generated: $report_file"
}

# Main function with argument handling
main() {
    log_action "=== MacFleet Shutdown Management Tool Started ==="
    
    case "${1:-status}" in
        "shutdown")
            enterprise_shutdown "$2" "$3" "$4"
            ;;
        "reboot")
            enterprise_reboot "$2" "$3" "$4"
            ;;
        "schedule")
            schedule_maintenance_reboot "$2" "$3"
            ;;
        "cancel")
            cancel_scheduled_operation
            ;;
        "emergency")
            emergency_shutdown "$2"
            ;;
        "status")
            check_system_status
            ;;
        "report")
            generate_shutdown_report
            ;;
        *)
            echo "MacFleet Enterprise Shutdown and Reboot Management Tool"
            echo "Usage: $0 [command] [options]"
            echo ""
            echo "Commands:"
            echo "  shutdown [delay] [message] [force]  - Shutdown system with optional delay"
            echo "  reboot [delay] [message] [force]    - Reboot system with optional delay"
            echo "  schedule [time] [reason]            - Schedule maintenance reboot (YYMMDDHHMM)"
            echo "  cancel                              - Cancel scheduled operations"
            echo "  emergency [reason]                  - Emergency shutdown (bypasses checks)"
            echo "  status                              - Check system status for shutdown readiness"
            echo "  report                              - Generate shutdown management report"
            echo ""
            echo "Delay Formats:"
            echo "  now                                 - Immediate operation"
            echo "  +minutes                            - Delay in minutes (e.g., +5)"
            echo ""
            echo "Examples:"
            echo "  $0 shutdown now                     - Immediate shutdown"
            echo "  $0 reboot +10 \"System maintenance\" - Reboot in 10 minutes with message"
            echo "  $0 schedule 2501020300 \"Patch Tuesday\" - Schedule reboot Jan 2, 3:00 AM"
            echo "  $0 emergency \"Security incident\"   - Emergency shutdown"
            ;;
    esac
    
    log_action "=== Shutdown management operation completed ==="
}

# Execute main function
main "$@"

## Advanced Shutdown Management Features

### Automated Maintenance Scheduling

```bash
#!/bin/bash

# Automated maintenance window management
setup_maintenance_automation() {
    echo "=== Setting Up Maintenance Automation ==="
    
    # Create maintenance automation script
    local automation_script="/Library/MacFleet/Scripts/maintenance_automation.sh"
    mkdir -p "$(dirname "$automation_script")"
    
    cat > "$automation_script" << 'EOF'
#!/bin/bash

# Check if we're in maintenance window
current_time=$(date +%H%M)
current_day=$(date +%u)  # 1=Monday, 7=Sunday

maintenance_start=$(echo "$MAINTENANCE_START_TIME" | tr -d ':')
maintenance_end=$(echo "$MAINTENANCE_END_TIME" | tr -d ':')

# Check if current time is in maintenance window
if [[ $current_time -ge $maintenance_start && $current_time -le $maintenance_end ]]; then
    # Check if it's a maintenance day
    if echo "$MAINTENANCE_DAYS" | grep -q "$(date +%a | cut -c1)"; then
        # Check if reboot is needed
        if [[ "$AUTO_REBOOT_ENABLED" == "true" ]]; then
            # Check uptime - reboot if system has been up more than 7 days
            uptime_days=$(uptime | awk '{print $3}' | cut -d',' -f1)
            if [[ $uptime_days -gt 7 ]]; then
                echo "System uptime exceeds 7 days - initiating maintenance reboot"
                /Library/MacFleet/Scripts/shutdown_management.sh reboot +5 "Automated maintenance reboot"
            fi
        fi
    fi
fi
EOF
    
    chmod +x "$automation_script"
    
    # Create launch daemon for maintenance automation
    local launch_daemon="/Library/LaunchDaemons/com.macfleet.maintenance.plist"
    
    cat > "$launch_daemon" << EOF
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Label</key>
    <string>com.macfleet.maintenance</string>
    <key>ProgramArguments</key>
    <array>
        <string>$automation_script</string>
    </array>
    <key>StartCalendarInterval</key>
    <dict>
        <key>Hour</key>
        <integer>2</integer>
        <key>Minute</key>
        <integer>0</integer>
    </dict>
    <key>RunAtLoad</key>
    <false/>
</dict>
</plist>
EOF
    
    # Load the launch daemon
    sudo launchctl load "$launch_daemon" 2>/dev/null
    
    echo "✅ Maintenance automation configured"
    log_action "Maintenance automation setup completed"
}

# Patch management integration
check_patch_reboot_required() {
    echo "=== Checking Patch Reboot Requirements ==="
    
    # Check for pending updates requiring reboot
    local pending_updates
    pending_updates=$(softwareupdate -l 2>/dev/null | grep -i "restart\|reboot" | wc -l)
    
    if [[ $pending_updates -gt 0 ]]; then
        echo "⚠️  $pending_updates update(s) require system reboot"
        log_action "Patch reboot required: $pending_updates updates pending"
        
        if [[ "$PATCH_REBOOT_REQUIRED" == "true" ]]; then
            echo "🔄 Scheduling patch reboot for next maintenance window"
            
            # Calculate next maintenance window
            local next_maintenance
            next_maintenance=$(date -v+1d "+%y%m%d${MAINTENANCE_START_TIME/:/}")
            
            schedule_maintenance_reboot "$next_maintenance" "Patch installation reboot"
        fi
        
        return 1
    else
        echo "✅ No patches requiring reboot"
        return 0
    fi
}

# Disaster recovery shutdown
disaster_recovery_shutdown() {
    local disaster_type="$1"
    local severity="$2"
    
    echo "🚨 DISASTER RECOVERY SHUTDOWN 🚨"
    echo "Disaster Type: $disaster_type"
    echo "Severity: $severity"
    
    log_action "DISASTER RECOVERY: Type: $disaster_type Severity: $severity"
    audit_log "DISASTER_RECOVERY" "INITIATED" "Type: $disaster_type Severity: $severity"
    
    # Send emergency notifications
    send_shutdown_notification "DISASTER RECOVERY SHUTDOWN" "0" "Emergency shutdown due to $disaster_type ($severity)"
    
    # Create disaster recovery record
    local disaster_file="$SCHEDULES_DIR/disaster_recovery_$(date +%Y%m%d_%H%M%S).json"
    cat > "$disaster_file" << EOF
{
  "type": "disaster_recovery",
  "disaster_type": "$disaster_type",
  "severity": "$severity",
  "initiated_by": "$(whoami)",
  "timestamp": "$(date -u +%Y-%m-%dT%H:%M:%SZ)",
  "device": "$(hostname)",
  "emergency_contact": "$EMERGENCY_CONTACT_INFO"
}
EOF
    
    # Execute immediate shutdown
    sudo shutdown -h now "DISASTER RECOVERY: $disaster_type ($severity)"
}

## Important Configuration Notes

### macOS Shutdown Command Options

- **`-h`** - Halt the system (shutdown)
- **`-r`** - Restart the system (reboot)
- **`-s`** - Sleep the system (display off + lock)
- **Time formats** - `now`, `+minutes`, `YYMMDDHHMM`
- **Warning messages** - Additional text displayed to users

### Enterprise Integration Points

- **Change Management Systems** - Integration with ITSM platforms
- **Monitoring Systems** - Real-time shutdown event tracking
- **Backup Solutions** - Pre-shutdown backup automation
- **Security Frameworks** - Compliance with shutdown policies

### Best Practices for Enterprise Shutdown Management

1. **Operational Continuity**
   - Implement graceful shutdown procedures with user notifications
   - Validate system readiness before shutdown operations
   - Maintain emergency override capabilities for critical situations
   - Schedule maintenance operations during designated windows

2. **Security and Compliance**
   - Enable comprehensive audit logging for all power operations
   - Implement FileVault key protection during shutdown
   - Validate user sessions and running processes before shutdown
   - Maintain compliance with regulatory shutdown requirements

3. **Change Management**
   - Require approval for non-scheduled shutdown operations
   - Document all maintenance-related shutdowns
   - Integrate with ITSM platforms for change tracking
   - Maintain emergency contact information for critical situations

4. **User Experience**
   - Provide adequate warning before shutdown operations
   - Attempt to save user work before system shutdown
   - Send notifications through multiple channels (GUI, email, Slack)
   - Allow cancellation of scheduled operations when appropriate

### Troubleshooting Common Issues

- **Permission errors** - Ensure admin privileges for shutdown commands
- **Scheduled operation conflicts** - Check for existing scheduled shutdowns
- **Network notification failures** - Verify webhook URLs and network connectivity
- **Backup failures** - Check disk space and backup destination availability
- **Maintenance window violations** - Review business hours and maintenance schedules

Remember to test shutdown procedures thoroughly in a controlled environment before implementing across your entire MacFleet to ensure business continuity and data protection. 

Sharing User Management on macOS

Manage sharing-only user accounts across your MacFleet devices using advanced dscl commands. This tutorial covers user creation, security policies, bulk deployment, and enterprise user lifecycle management.

Understanding macOS User Management

macOS uses Directory Service command line utility (dscl) for user management:

  • dscl - Directory Service command line utility
  • Local Directory - /var/db/dslocal/nodes/Default
  • User Records - Stored in /Users/ path
  • Sharing-only Users - Limited access accounts for file sharing

Basic Sharing User Creation

Simple Sharing User

#!/bin/bash

# Create a basic sharing-only user account
USERNAME="SharingUser"
DISPLAY_NAME="Sharing Account"
PASSWORD="SecurePass123"
USER_ID="550"

# Create the user
sudo dscl . create /Users/"$USERNAME"

# Set display name
sudo dscl . create /Users/"$USERNAME" RealName "$DISPLAY_NAME"

# Set password
sudo dscl . passwd /Users/"$USERNAME" "$PASSWORD"

# Set unique ID
sudo dscl . create /Users/"$USERNAME" UniqueID "$USER_ID"

# Set group ID (staff group)
sudo dscl . create /Users/"$USERNAME" PrimaryGroupID 20

# Deny shell access
sudo dscl . create /Users/"$USERNAME" UserShell /usr/bin/false

# No home directory
sudo dscl . create /Users/"$USERNAME" NFSHomeDirectory /dev/null

echo "Sharing user '$USERNAME' created successfully"

Enhanced Sharing User with Options

#!/bin/bash

# Enhanced sharing user creation with additional options
create_sharing_user() {
    local username="$1"
    local display_name="$2"
    local password="$3"
    local hint="$4"
    local picture_path="$5"
    local user_id="$6"
    
    echo "Creating sharing user: $username"
    
    # Create user
    sudo dscl . create /Users/"$username"
    
    # Set display name
    sudo dscl . create /Users/"$username" RealName "$display_name"
    
    # Set password
    sudo dscl . passwd /Users/"$username" "$password"
    
    # Set password hint (optional)
    if [[ -n "$hint" ]]; then
        sudo dscl . create /Users/"$username" hint "$hint"
    fi
    
    # Set profile picture (optional)
    if [[ -n "$picture_path" && -f "$picture_path" ]]; then
        sudo dscl . create /Users/"$username" picture "$picture_path"
    fi
    
    # Set unique ID
    sudo dscl . create /Users/"$username" UniqueID "$user_id"
    
    # Set group ID
    sudo dscl . create /Users/"$username" PrimaryGroupID 20
    
    # Deny shell access
    sudo dscl . create /Users/"$username" UserShell /usr/bin/false
    
    # No home directory
    sudo dscl . create /Users/"$username" NFSHomeDirectory /dev/null
    
    echo "✅ Sharing user '$username' created successfully"
    return 0
}

# Usage examples
create_sharing_user "FileShare" "File Sharing Account" "FilePass123" "File access only" "" "551"
create_sharing_user "GuestAccess" "Guest User" "GuestPass456" "Temporary access" "/System/Library/User Pictures/Animals/Butterfly.tif" "552"

Enterprise User Categories

User Type Classifications

#!/bin/bash

# Enterprise user categories with specific configurations
declare -A USER_CATEGORIES=(
    ["sharing_standard"]="Standard file sharing access"
    ["sharing_secure"]="High-security sharing with restrictions"
    ["guest_temporary"]="Temporary guest access with expiration"
    ["service_account"]="Service accounts for applications"
    ["departmental_shared"]="Department-specific shared accounts"
    ["external_partner"]="External partner limited access"
    ["kiosk_public"]="Public kiosk access accounts"
)

# Security policies for each category
declare -A SECURITY_POLICIES=(
    ["sharing_standard"]="password_policy:standard,audit_level:basic,session_timeout:8h"
    ["sharing_secure"]="password_policy:strong,audit_level:comprehensive,session_timeout:2h,mfa_required:true"
    ["guest_temporary"]="password_policy:basic,audit_level:full,session_timeout:1h,auto_expire:24h"
    ["service_account"]="password_policy:service,audit_level:system,no_interactive:true"
    ["departmental_shared"]="password_policy:department,audit_level:department,group_restrictions:true"
    ["external_partner"]="password_policy:external,audit_level:full,network_restrictions:true"
    ["kiosk_public"]="password_policy:public,audit_level:minimal,session_timeout:30m,reset_on_logout:true"
)

# Access control definitions
declare -A ACCESS_CONTROLS=(
    ["sharing_standard"]="file_sharing:read_write,print_access:yes,network_access:local"
    ["sharing_secure"]="file_sharing:read_only,print_access:restricted,network_access:vpn_only"
    ["guest_temporary"]="file_sharing:guest_folder,print_access:no,network_access:guest_wifi"
    ["service_account"]="file_sharing:service_dirs,print_access:no,network_access:service_ports"
    ["departmental_shared"]="file_sharing:department_dirs,print_access:department,network_access:department_vlan"
    ["external_partner"]="file_sharing:partner_dirs,print_access:no,network_access:partner_dmz"
    ["kiosk_public"]="file_sharing:public_docs,print_access:public,network_access:public_wifi"
)

print_user_categories() {
    echo "=== Available User Categories ==="
    for category in "${!USER_CATEGORIES[@]}"; do
        echo "Category: $category"
        echo "  Description: ${USER_CATEGORIES[$category]}"
        echo "  Security: ${SECURITY_POLICIES[$category]}"
        echo "  Access: ${ACCESS_CONTROLS[$category]}"
        echo ""
    done
}

# Display available categories
print_user_categories

User Management Policies

Password Policy Engine

#!/bin/bash

# Password policy definitions for different user types
generate_password_policy() {
    local policy_type="$1"
    
    case "$policy_type" in
        "standard")
            echo "min_length:8,complexity:medium,expiry:90d,history:5"
            ;;
        "strong")
            echo "min_length:12,complexity:high,expiry:60d,history:10,special_chars:required"
            ;;
        "basic")
            echo "min_length:6,complexity:low,expiry:never,history:3"
            ;;
        "service")
            echo "min_length:16,complexity:high,expiry:180d,history:20,machine_generated:true"
            ;;
        "department")
            echo "min_length:10,complexity:medium,expiry:120d,history:8,department_prefix:required"
            ;;
        "external")
            echo "min_length:14,complexity:high,expiry:30d,history:15,external_validation:required"
            ;;
        "public")
            echo "min_length:4,complexity:none,expiry:daily,history:1,auto_reset:true"
            ;;
        *)
            echo "min_length:8,complexity:medium,expiry:90d,history:5"
            ;;
    esac
}

# Generate secure password based on policy
generate_secure_password() {
    local policy="$1"
    local length
    local complexity
    
    # Parse policy
    length=$(echo "$policy" | grep -o 'min_length:[0-9]*' | cut -d: -f2)
    complexity=$(echo "$policy" | grep -o 'complexity:[a-z]*' | cut -d: -f2)
    
    case "$complexity" in
        "high")
            # High complexity: uppercase, lowercase, numbers, special characters
            openssl rand -base64 $((length * 2)) | tr -d "=+/" | cut -c1-"$length" | sed 's/./&@1A/4'
            ;;
        "medium")
            # Medium complexity: uppercase, lowercase, numbers
            openssl rand -base64 "$length" | tr -d "=+/" | cut -c1-"$length"
            ;;
        "low")
            # Low complexity: alphanumeric
            openssl rand -hex "$((length/2))" | cut -c1-"$length"
            ;;
        *)
            # Default medium complexity
            openssl rand -base64 "$length" | tr -d "=+/" | cut -c1-"$length"
            ;;
    esac
}

# Validate password against policy
validate_password() {
    local password="$1"
    local policy="$2"
    local min_length complexity
    
    min_length=$(echo "$policy" | grep -o 'min_length:[0-9]*' | cut -d: -f2)
    complexity=$(echo "$policy" | grep -o 'complexity:[a-z]*' | cut -d: -f2)
    
    # Check length
    if [[ ${#password} -lt $min_length ]]; then
        echo "❌ Password too short (minimum $min_length characters)"
        return 1
    fi
    
    # Check complexity
    case "$complexity" in
        "high")
            if ! [[ "$password" =~ [A-Z] && "$password" =~ [a-z] && "$password" =~ [0-9] && "$password" =~ [^A-Za-z0-9] ]]; then
                echo "❌ Password must contain uppercase, lowercase, numbers, and special characters"
                return 1
            fi
            ;;
        "medium")
            if ! [[ "$password" =~ [A-Z] && "$password" =~ [a-z] && "$password" =~ [0-9] ]]; then
                echo "❌ Password must contain uppercase, lowercase, and numbers"
                return 1
            fi
            ;;
    esac
    
    echo "✅ Password meets policy requirements"
    return 0
}

Enterprise User Deployment Profiles

Deployment Configuration Templates

#!/bin/bash

# Enterprise deployment profiles for different organizational needs
declare -A DEPLOYMENT_PROFILES=(
    ["corporate_standard"]="Standard corporate deployment with basic security"
    ["high_security_finance"]="High-security deployment for financial departments"
    ["guest_access_lobby"]="Guest access deployment for lobby/public areas"
    ["partner_collaboration"]="External partner collaboration deployment"
    ["kiosk_public_library"]="Public kiosk deployment for libraries/public spaces"
    ["research_development"]="Research and development team deployment"
    ["executive_secure"]="Executive-level secure deployment"
)

# Profile-specific configurations
get_deployment_config() {
    local profile="$1"
    
    case "$profile" in
        "corporate_standard")
            cat << EOF
{
    "user_category": "sharing_standard",
    "password_policy": "standard",
    "access_level": "department_files",
    "session_timeout": "8h",
    "audit_level": "basic",
    "group_membership": ["staff", "file_sharing"],
    "restrictions": {
        "shell_access": false,
        "home_directory": false,
        "admin_privileges": false
    },
    "monitoring": {
        "login_tracking": true,
        "file_access_log": true,
        "failed_attempts": 5
    }
}
EOF
            ;;
        "high_security_finance")
            cat << EOF
{
    "user_category": "sharing_secure",
    "password_policy": "strong",
    "access_level": "finance_restricted",
    "session_timeout": "2h",
    "audit_level": "comprehensive",
    "group_membership": ["finance", "secure_sharing"],
    "restrictions": {
        "shell_access": false,
        "home_directory": false,
        "admin_privileges": false,
        "network_access": "finance_vlan_only",
        "time_restrictions": "business_hours"
    },
    "security": {
        "mfa_required": true,
        "encryption": "aes256",
        "key_rotation": "monthly"
    },
    "monitoring": {
        "real_time_alerts": true,
        "login_tracking": true,
        "file_access_log": true,
        "failed_attempts": 3,
        "compliance_reporting": "sox_hipaa"
    }
}
EOF
            ;;
        "guest_access_lobby")
            cat << EOF
{
    "user_category": "guest_temporary",
    "password_policy": "basic",
    "access_level": "guest_resources",
    "session_timeout": "1h",
    "audit_level": "full",
    "group_membership": ["guest", "public_access"],
    "restrictions": {
        "shell_access": false,
        "home_directory": false,
        "admin_privileges": false,
        "internet_access": "guest_wifi_only",
        "file_upload": false
    },
    "automation": {
        "auto_expire": "24h",
        "auto_cleanup": true,
        "reset_on_logout": true
    },
    "monitoring": {
        "session_recording": true,
        "login_tracking": true,
        "activity_log": true,
        "failed_attempts": 3
    }
}
EOF
            ;;
        *)
            echo "Unknown deployment profile: $profile"
            return 1
            ;;
    esac
}

# Apply deployment profile
apply_deployment_profile() {
    local profile="$1"
    local config_file="/tmp/deployment_config.json"
    
    echo "Applying deployment profile: $profile"
    
    # Get configuration
    get_deployment_config "$profile" > "$config_file"
    
    if [[ ! -f "$config_file" ]]; then
        echo "❌ Failed to generate configuration for profile: $profile"
        return 1
    fi
    
    echo "✅ Deployment configuration ready"
    echo "Configuration saved to: $config_file"
    
    # Parse and display key settings
    echo "=== Profile Summary ==="
    echo "User Category: $(jq -r '.user_category' "$config_file")"
    echo "Password Policy: $(jq -r '.password_policy' "$config_file")"
    echo "Access Level: $(jq -r '.access_level' "$config_file")"
    echo "Session Timeout: $(jq -r '.session_timeout' "$config_file")"
    echo "Audit Level: $(jq -r '.audit_level' "$config_file")"
    
    return 0
}

Enterprise User Management System

#!/bin/bash

# MacFleet Enterprise User Management System
# Comprehensive sharing user creation and management

# Configuration
CONFIG_DIR="/etc/macfleet/users"
LOG_FILE="/var/log/macfleet_user_management.log"
BACKUP_DIR="/var/backups/macfleet/users"
REPORTS_DIR="/var/reports/macfleet/users"
AUDIT_LOG="/var/log/macfleet_user_audit.log"

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

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

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

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

# User ID management
get_next_user_id() {
    local start_id="$1"
    local current_id="$start_id"
    
    while dscl . list /Users UniqueID | awk '{print $2}' | grep -q "^${current_id}$"; do
        ((current_id++))
    done
    
    echo "$current_id"
}

# Comprehensive user creation function
create_enterprise_user() {
    local username="$1"
    local display_name="$2"
    local user_category="$3"
    local deployment_profile="$4"
    local department="$5"
    local expiry_date="$6"
    
    log_action "Starting user creation: $username (Category: $user_category, Profile: $deployment_profile)"
    
    # Validate inputs
    if [[ -z "$username" || -z "$display_name" || -z "$user_category" ]]; then
        log_error "Missing required parameters for user creation"
        return 1
    fi
    
    # Check if user already exists
    if dscl . read /Users/"$username" &>/dev/null; then
        log_error "User $username already exists"
        return 1
    fi
    
    # Get deployment configuration
    local config_file="/tmp/user_config_${username}.json"
    get_deployment_config "$deployment_profile" > "$config_file"
    
    # Parse configuration
    local password_policy
    password_policy=$(jq -r '.password_policy' "$config_file")
    
    # Get next available user ID
    local user_id
    user_id=$(get_next_user_id 550)
    
    # Generate secure password
    local policy_details
    policy_details=$(generate_password_policy "$password_policy")
    local password
    password=$(generate_secure_password "$policy_details")
    
    # Create user metadata
    local metadata_file="$CONFIG_DIR/${username}_metadata.json"
    cat > "$metadata_file" << EOF
{
    "username": "$username",
    "display_name": "$display_name",
    "user_category": "$user_category",
    "deployment_profile": "$deployment_profile",
    "department": "$department",
    "user_id": $user_id,
    "created_date": "$(date -Iseconds)",
    "created_by": "$(whoami)",
    "expiry_date": "$expiry_date",
    "password_policy": "$password_policy",
    "status": "active"
}
EOF
    
    # Create the user
    log_action "Creating user record for $username"
    sudo dscl . create /Users/"$username" || {
        log_error "Failed to create user record for $username"
        return 1
    }
    
    # Set basic properties
    sudo dscl . create /Users/"$username" RealName "$display_name"
    sudo dscl . passwd /Users/"$username" "$password"
    sudo dscl . create /Users/"$username" UniqueID "$user_id"
    sudo dscl . create /Users/"$username" PrimaryGroupID 20
    sudo dscl . create /Users/"$username" UserShell /usr/bin/false
    sudo dscl . create /Users/"$username" NFSHomeDirectory /dev/null
    
    # Add custom attributes
    sudo dscl . create /Users/"$username" Comment "MacFleet managed user - $user_category"
    sudo dscl . create /Users/"$username" Keywords "macfleet,$user_category,$deployment_profile,$department"
    
    # Set expiry date if provided
    if [[ -n "$expiry_date" ]]; then
        sudo dscl . create /Users/"$username" ExpiryDate "$expiry_date"
    fi
    
    # Apply group memberships
    local groups
    groups=$(jq -r '.group_membership[]' "$config_file" 2>/dev/null)
    while IFS= read -r group; do
        if [[ -n "$group" && "$group" != "null" ]]; then
            sudo dseditgroup -o edit -a "$username" -t user "$group" 2>/dev/null || {
                log_action "Group $group does not exist, skipping"
            }
        fi
    done <<< "$groups"
    
    # Store secure password (encrypted)
    echo "$password" | openssl enc -aes-256-cbc -pbkdf2 -k "macfleet_$(hostname)" -out "$CONFIG_DIR/${username}_password.enc"
    
    # Create backup
    create_user_backup "$username"
    
    # Audit logging
    audit_log "User created: $username (UID: $user_id, Category: $user_category, Profile: $deployment_profile)"
    
    log_action "✅ User $username created successfully (UID: $user_id)"
    
    # Return password for initial communication (in production, use secure delivery)
    echo "CREATED_USER_INFO:$username:$password:$user_id"
    
    return 0
}

# Bulk user creation
bulk_create_users() {
    local csv_file="$1"
    local created_count=0
    local failed_count=0
    
    if [[ ! -f "$csv_file" ]]; then
        log_error "CSV file not found: $csv_file"
        return 1
    fi
    
    log_action "Starting bulk user creation from: $csv_file"
    
    # Process CSV file (skip header)
    tail -n +2 "$csv_file" | while IFS=',' read -r username display_name category profile department expiry; do
        if create_enterprise_user "$username" "$display_name" "$category" "$profile" "$department" "$expiry"; then
            ((created_count++))
        else
            ((failed_count++))
        fi
    done
    
    log_action "Bulk creation completed. Created: $created_count, Failed: $failed_count"
    
    # Generate report
    generate_user_report "bulk_creation_$(date +%Y%m%d_%H%M%S)"
}

# User management functions
list_enterprise_users() {
    echo "=== MacFleet Managed Users ==="
    echo "Username | Display Name | Category | Status | Created"
    echo "---------|--------------|----------|--------|--------"
    
    for metadata_file in "$CONFIG_DIR"/*_metadata.json; do
        if [[ -f "$metadata_file" ]]; then
            local username display_name category status created_date
            username=$(jq -r '.username' "$metadata_file")
            display_name=$(jq -r '.display_name' "$metadata_file")
            category=$(jq -r '.user_category' "$metadata_file")
            status=$(jq -r '.status' "$metadata_file")
            created_date=$(jq -r '.created_date' "$metadata_file" | cut -d'T' -f1)
            
            printf "%-8s | %-12s | %-8s | %-6s | %s\n" "$username" "$display_name" "$category" "$status" "$created_date"
        fi
    done
}

# User removal with cleanup
remove_enterprise_user() {
    local username="$1"
    local backup_before_removal="$2"
    
    log_action "Starting removal of user: $username"
    
    # Check if user exists
    if ! dscl . read /Users/"$username" &>/dev/null; then
        log_error "User $username does not exist"
        return 1
    fi
    
    # Create backup before removal
    if [[ "$backup_before_removal" == "true" ]]; then
        create_user_backup "$username"
    fi
    
    # Remove user from system
    sudo dscl . delete /Users/"$username" || {
        log_error "Failed to remove user $username from system"
        return 1
    }
    
    # Update metadata
    local metadata_file="$CONFIG_DIR/${username}_metadata.json"
    if [[ -f "$metadata_file" ]]; then
        jq '.status = "deleted" | .deleted_date = now | .deleted_by = "'"$(whoami)"'"' "$metadata_file" > "${metadata_file}.tmp" && mv "${metadata_file}.tmp" "$metadata_file"
    fi
    
    # Audit logging
    audit_log "User removed: $username by $(whoami)"
    
    log_action "✅ User $username removed successfully"
    return 0
}

# User backup and restore
create_user_backup() {
    local username="$1"
    local backup_file="$BACKUP_DIR/${username}_backup_$(date +%Y%m%d_%H%M%S).plist"
    
    log_action "Creating backup for user: $username"
    
    # Export user record
    sudo dscl . read /Users/"$username" > "$backup_file"
    
    # Backup metadata
    local metadata_file="$CONFIG_DIR/${username}_metadata.json"
    if [[ -f "$metadata_file" ]]; then
        cp "$metadata_file" "$BACKUP_DIR/${username}_metadata_$(date +%Y%m%d_%H%M%S).json"
    fi
    
    log_action "✅ User backup created: $backup_file"
}

# System health monitoring
monitor_user_system() {
    echo "=== User System Health Check ==="
    
    # Check for expired users
    local expired_users=0
    for metadata_file in "$CONFIG_DIR"/*_metadata.json; do
        if [[ -f "$metadata_file" ]]; then
            local expiry_date username
            expiry_date=$(jq -r '.expiry_date' "$metadata_file")
            username=$(jq -r '.username' "$metadata_file")
            
            if [[ "$expiry_date" != "null" && "$expiry_date" != "" ]]; then
                if [[ $(date -d "$expiry_date" +%s 2>/dev/null) -lt $(date +%s) ]]; then
                    echo "⚠️  Expired user: $username (expired: $expiry_date)"
                    ((expired_users++))
                fi
            fi
        fi
    done
    
    # Check for orphaned user records
    local system_users
    system_users=$(dscl . list /Users | grep -E "^(Sharing|Guest|Service|External)" || true)
    local orphaned_users=0
    
    while IFS= read -r user; do
        if [[ -n "$user" && ! -f "$CONFIG_DIR/${user}_metadata.json" ]]; then
            echo "⚠️  Orphaned user (no metadata): $user"
            ((orphaned_users++))
        fi
    done <<< "$system_users"
    
    # Summary
    echo ""
    echo "Health Summary:"
    echo "  Expired users: $expired_users"
    echo "  Orphaned users: $orphaned_users"
    
    if [[ $expired_users -eq 0 && $orphaned_users -eq 0 ]]; then
        echo "✅ User system is healthy"
    else
        echo "⚠️  User system requires attention"
    fi
}

# Generate comprehensive reports
generate_user_report() {
    local report_name="$1"
    local report_file="$REPORTS_DIR/${report_name}.json"
    
    log_action "Generating user report: $report_name"
    
    # Collect user statistics
    local total_users active_users inactive_users
    total_users=$(find "$CONFIG_DIR" -name "*_metadata.json" | wc -l)
    active_users=$(grep -l '"status": "active"' "$CONFIG_DIR"/*_metadata.json 2>/dev/null | wc -l)
    inactive_users=$((total_users - active_users))
    
    # Category breakdown
    local categories
    categories=$(jq -r '.user_category' "$CONFIG_DIR"/*_metadata.json 2>/dev/null | sort | uniq -c | awk '{print "{\"category\": \"" $2 "\", \"count\": " $1 "}"}' | jq -s '.')
    
    # Generate report
    cat > "$report_file" << EOF
{
    "report_name": "$report_name",
    "generated_date": "$(date -Iseconds)",
    "generated_by": "$(whoami)",
    "hostname": "$(hostname)",
    "statistics": {
        "total_users": $total_users,
        "active_users": $active_users,
        "inactive_users": $inactive_users
    },
    "category_breakdown": $categories,
    "system_info": {
        "macfleet_version": "2025.07.07",
        "os_version": "$(sw_vers -productVersion)",
        "hostname": "$(hostname)"
    }
}
EOF
    
    log_action "✅ Report generated: $report_file"
    echo "Report saved to: $report_file"
}

# Fleet deployment functions
deploy_to_fleet() {
    local fleet_config="$1"
    local user_config="$2"
    
    log_action "Starting fleet deployment"
    
    if [[ ! -f "$fleet_config" ]]; then
        log_error "Fleet configuration file not found: $fleet_config"
        return 1
    fi
    
    if [[ ! -f "$user_config" ]]; then
        log_error "User configuration file not found: $user_config"
        return 1
    fi
    
    # Read fleet configuration
    local hosts
    hosts=$(jq -r '.hosts[]' "$fleet_config")
    
    # Deploy to each host
    while IFS= read -r host; do
        if [[ -n "$host" ]]; then
            log_action "Deploying to host: $host"
            
            # Copy user management script and configuration
            scp "$0" "$user_config" "root@${host}:/tmp/" || {
                log_error "Failed to copy files to $host"
                continue
            }
            
            # Execute deployment on remote host
            ssh "root@${host}" "chmod +x /tmp/$(basename "$0") && /tmp/$(basename "$0") deploy_from_config /tmp/$(basename "$user_config")" || {
                log_error "Failed to execute deployment on $host"
                continue
            }
            
            log_action "✅ Deployment completed on: $host"
        fi
    done <<< "$hosts"
    
    log_action "Fleet deployment completed"
}

# Main function with command routing
main() {
    local command="$1"
    shift
    
    # Initialize
    create_directories
    
    case "$command" in
        "create")
            create_enterprise_user "$@"
            ;;
        "bulk_create")
            bulk_create_users "$@"
            ;;
        "list")
            list_enterprise_users
            ;;
        "remove")
            remove_enterprise_user "$@"
            ;;
        "backup")
            create_user_backup "$@"
            ;;
        "monitor")
            monitor_user_system
            ;;
        "report")
            generate_user_report "$@"
            ;;
        "deploy_fleet")
            deploy_to_fleet "$@"
            ;;
        "show_categories")
            print_user_categories
            ;;
        "show_policies")
            for policy in standard strong basic service department external public; do
                echo "Policy: $policy"
                echo "  $(generate_password_policy "$policy")"
                echo ""
            done
            ;;
        *)
            echo "MacFleet Enterprise User Management System"
            echo "Usage: $0 <command> [options]"
            echo ""
            echo "Commands:"
            echo "  create <username> <display_name> <category> <profile> [department] [expiry]"
            echo "  bulk_create <csv_file>"
            echo "  list"
            echo "  remove <username> [backup_before_removal]"
            echo "  backup <username>"
            echo "  monitor"
            echo "  report <report_name>"
            echo "  deploy_fleet <fleet_config> <user_config>"
            echo "  show_categories"
            echo "  show_policies"
            echo ""
            echo "Examples:"
            echo "  $0 create FileShare 'File Sharing Account' sharing_standard corporate_standard IT"
            echo "  $0 bulk_create users.csv"
            echo "  $0 list"
            echo "  $0 monitor"
            echo "  $0 report monthly_audit"
            ;;
    esac
}

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

Fleet Deployment Example

CSV Template for Bulk Creation

username,display_name,category,profile,department,expiry
FileShare01,File Sharing Account 1,sharing_standard,corporate_standard,IT,
GuestLobby,Guest Lobby Access,guest_temporary,guest_access_lobby,Reception,2025-12-31
PartnerExt,External Partner Access,sharing_secure,partner_collaboration,Legal,2025-09-30
KioskLib,Library Kiosk Account,kiosk_public,kiosk_public_library,Public,
FinanceShare,Finance Shared Account,sharing_secure,high_security_finance,Finance,
DevTeam,Development Team Share,sharing_standard,research_development,Engineering,

Fleet Configuration Example

{
    "fleet_name": "MacFleet Corporate",
    "deployment_date": "2025-07-07",
    "hosts": [
        "mac-office-01.company.com",
        "mac-office-02.company.com",
        "mac-conference-01.company.com"
    ],
    "deployment_profile": "corporate_standard",
    "security_policy": "enterprise_standard",
    "monitoring": {
        "enabled": true,
        "reporting_interval": "daily",
        "alert_threshold": "high"
    }
}

Security Considerations

User Account Security

  • No Shell Access - Sharing users cannot access command line
  • No Home Directory - Prevents file storage in user directories
  • Limited Group Membership - Restricts system access
  • Password Policies - Enforces strong password requirements
  • Audit Logging - Tracks all user management activities

Enterprise Compliance

  • SOX Compliance - Financial user access controls
  • HIPAA Compliance - Healthcare data protection
  • NIST Framework - Security control implementation
  • ISO 27001 - Information security management

Troubleshooting Guide

Common Issues

User Creation Fails

  • Check if user ID is already in use
  • Verify administrative privileges
  • Ensure directory services are running

Authentication Problems

  • Verify password policy compliance
  • Check user account status
  • Review audit logs for failed attempts

Permission Errors

  • Confirm group memberships
  • Check file sharing permissions
  • Verify security policy application

Diagnostic Commands

# Check user existence
dscl . read /Users/username

# List all users
dscl . list /Users

# Check user groups
groups username

# View user properties
id username

Important Notes

  • Test thoroughly before fleet deployment
  • Backup user data before making changes
  • Monitor audit logs for security events
  • Update policies based on security requirements
  • Document changes for compliance auditing
  • Use secure password delivery methods in production

Run Setup Assistant on macOS Devices at Next Reboot

This comprehensive guide demonstrates how to trigger macOS Setup Assistant on the next device reboot, enabling device reconfiguration, user onboarding, and enterprise deployment workflows.

Overview

The Setup Assistant is macOS's built-in configuration wizard that guides users through initial device setup. It can be triggered manually for various enterprise scenarios:

  • Device reconfiguration: Reset devices to factory-like state while preserving data
  • User onboarding: Streamline new employee device setup
  • Mass deployment: Standardize device configuration across organizations
  • Troubleshooting: Reset system configurations without full device wipe
  • Compliance: Ensure devices meet organizational setup requirements

Basic Setup Assistant Trigger

Simple Setup Assistant Script

Create a basic script to trigger Setup Assistant on next reboot:

#!/bin/bash

# Basic Setup Assistant trigger script
# Usage: ./trigger_setup_assistant.sh

trigger_setup_assistant() {
    # Check if running as root
    if [ "$(id -u)" != "0" ]; then
        echo "Error: This script must be run as root"
        exit 1
    fi
    
    # Check if .AppleSetupDone file exists
    if [ ! -f "/private/var/db/.AppleSetupDone" ]; then
        echo "Setup Assistant marker file not found. Setup Assistant may already be scheduled to run."
        exit 0
    fi
    
    # Remove .AppleSetupDone file
    sudo rm /private/var/db/.AppleSetupDone
    
    if [ $? -eq 0 ]; then
        echo "Setup Assistant will run on the next reboot."
        echo "Please restart the device to begin Setup Assistant."
    else
        echo "Error: Failed to remove Setup Assistant marker file."
        exit 1
    fi
}

# Execute function
trigger_setup_assistant

Enhanced Setup Assistant with Validation

#!/bin/bash

# Enhanced Setup Assistant trigger with validation and logging
# Usage: ./enhanced_setup_assistant.sh

enhanced_setup_assistant() {
    local log_file="/var/log/macfleet_setup_assistant.log"
    local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
    local setup_done_file="/private/var/db/.AppleSetupDone"
    local computer_name=$(scutil --get ComputerName)
    
    # Check if running as root
    if [ "$EUID" -ne 0 ]; then
        echo "Error: This script must be run as root"
        exit 1
    fi
    
    # Create log directory if it doesn't exist
    mkdir -p /var/log
    
    # Log the operation start
    echo "[$timestamp] Starting Setup Assistant trigger on $computer_name" >> "$log_file"
    
    # Check macOS version compatibility
    local os_version=$(sw_vers -productVersion)
    local major_version=$(echo "$os_version" | cut -d. -f1)
    
    if [ "$major_version" -ge 14 ]; then
        echo "[$timestamp] WARNING: macOS $os_version detected. Setup Assistant trigger may not work on macOS 14+" >> "$log_file"
        echo "Warning: This script is supported on macOS versions below 14. Current version: $os_version"
        read -p "Do you want to continue anyway? (y/N): " continue_anyway
        if [ "$continue_anyway" != "y" ] && [ "$continue_anyway" != "Y" ]; then
            echo "[$timestamp] Operation cancelled by user due to version compatibility" >> "$log_file"
            echo "Operation cancelled."
            exit 0
        fi
    fi
    
    # Check if Setup Assistant marker file exists
    if [ ! -f "$setup_done_file" ]; then
        echo "[$timestamp] Setup Assistant marker file not found at $setup_done_file" >> "$log_file"
        echo "Setup Assistant marker file not found. Setup Assistant may already be scheduled to run."
        echo "File location: $setup_done_file"
        exit 0
    fi
    
    # Get file information before removal
    local file_info=$(ls -la "$setup_done_file" 2>/dev/null)
    echo "[$timestamp] Current marker file info: $file_info" >> "$log_file"
    
    # Create backup of marker file
    local backup_dir="/var/backups/macfleet"
    mkdir -p "$backup_dir"
    cp "$setup_done_file" "$backup_dir/.AppleSetupDone.backup.$(date +%Y%m%d_%H%M%S)" 2>/dev/null
    
    # Remove .AppleSetupDone file
    rm "$setup_done_file"
    
    # Verify removal
    if [ ! -f "$setup_done_file" ]; then
        echo "[$timestamp] Setup Assistant marker file removed successfully" >> "$log_file"
        echo "Setup Assistant has been configured to run on the next reboot."
        echo ""
        echo "Device Information:"
        echo "  Computer Name: $computer_name"
        echo "  macOS Version: $os_version"
        echo "  Timestamp: $timestamp"
        echo ""
        echo "Next Steps:"
        echo "  1. Restart the device to begin Setup Assistant"
        echo "  2. Follow the on-screen prompts to configure the device"
        echo "  3. Setup Assistant will guide through language, region, accounts, and other settings"
        echo ""
        echo "Note: All existing user data and applications will remain intact."
    else
        echo "[$timestamp] ERROR: Failed to remove Setup Assistant marker file" >> "$log_file"
        echo "Error: Failed to remove Setup Assistant marker file."
        echo "Please check permissions and try again."
        exit 1
    fi
}

# Execute enhanced setup
enhanced_setup_assistant

Advanced Setup Assistant Management

Conditional Setup Assistant Trigger

#!/bin/bash

# Conditional Setup Assistant trigger with multiple scenarios
# Usage: ./conditional_setup_assistant.sh [scenario]

conditional_setup_assistant() {
    local scenario=${1:-"default"}
    local log_file="/var/log/macfleet_setup_assistant.log"
    local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
    
    # Check if running as root
    if [ "$EUID" -ne 0 ]; then
        echo "Error: This script must be run as root"
        exit 1
    fi
    
    echo "[$timestamp] Conditional Setup Assistant trigger - Scenario: $scenario" >> "$log_file"
    
    case $scenario in
        "new_employee")
            trigger_new_employee_setup
            ;;
        "device_refresh")
            trigger_device_refresh_setup
            ;;
        "compliance_reset")
            trigger_compliance_reset
            ;;
        "troubleshooting")
            trigger_troubleshooting_setup
            ;;
        "mass_deployment")
            trigger_mass_deployment_setup
            ;;
        "default")
            trigger_default_setup
            ;;
        *)
            echo "Unknown scenario: $scenario"
            echo "Available scenarios: new_employee, device_refresh, compliance_reset, troubleshooting, mass_deployment, default"
            exit 1
            ;;
    esac
}

trigger_new_employee_setup() {
    echo "Configuring Setup Assistant for new employee onboarding..."
    
    # Remove Setup Assistant marker
    rm -f /private/var/db/.AppleSetupDone
    
    # Clear previous user data (optional)
    echo "[$timestamp] New employee setup - Setup Assistant configured" >> "$log_file"
    
    cat << 'EOF'
Setup Assistant configured for new employee onboarding.

The following will be presented to the user:
• Language and region selection
• Wi-Fi network configuration
• Apple ID sign-in
• User account creation
• Privacy and security settings
• Touch ID setup (if available)
• Desktop appearance preferences

Please restart the device and provide to the new employee.
EOF
}

trigger_device_refresh_setup() {
    echo "Configuring Setup Assistant for device refresh..."
    
    # Check if user data should be preserved
    local user_dirs=$(ls /Users | grep -v "Shared" | grep -v "Guest" | head -5)
    if [ -n "$user_dirs" ]; then
        echo "Existing user accounts detected:"
        echo "$user_dirs"
        echo ""
        read -p "Preserve existing user data? (Y/n): " preserve_data
        
        if [ "$preserve_data" = "n" ] || [ "$preserve_data" = "N" ]; then
            echo "Warning: This will remove user data during refresh."
            read -p "Are you sure? (y/N): " confirm
            if [ "$confirm" != "y" ] && [ "$confirm" != "Y" ]; then
                echo "Operation cancelled."
                return 1
            fi
        fi
    fi
    
    rm -f /private/var/db/.AppleSetupDone
    echo "[$timestamp] Device refresh setup - Setup Assistant configured" >> "$log_file"
    
    echo "Setup Assistant configured for device refresh."
    echo "Restart the device to begin reconfiguration process."
}

trigger_compliance_reset() {
    echo "Configuring Setup Assistant for compliance reset..."
    
    # Log compliance reset
    echo "[$timestamp] Compliance reset initiated - Setup Assistant triggered" >> "$log_file"
    
    # Remove Setup Assistant marker
    rm -f /private/var/db/.AppleSetupDone
    
    # Additional compliance-related cleanup (customize as needed)
    # rm -f /Library/Preferences/com.apple.loginwindow.plist
    
    cat << 'EOF'
Setup Assistant configured for compliance reset.

This will ensure the device meets organizational compliance requirements:
• Force re-acceptance of terms and policies
• Verify user account configurations
• Confirm security settings
• Update privacy preferences
• Validate organizational settings

Restart the device to begin compliance verification.
EOF
}

trigger_troubleshooting_setup() {
    echo "Configuring Setup Assistant for troubleshooting..."
    
    # Create troubleshooting report
    local troubleshoot_report="/tmp/troubleshoot_report_$(date +%Y%m%d_%H%M%S).txt"
    
    cat > "$troubleshoot_report" << EOF
MacFleet Troubleshooting Report
Generated: $(date)
Device: $(scutil --get ComputerName)
macOS Version: $(sw_vers -productVersion)

Issues that Setup Assistant may resolve:
• User account configuration problems
• System preference corruption
• Network configuration issues
• Apple ID authentication problems
• Privacy setting inconsistencies

Setup Assistant will be triggered on next reboot.
EOF
    
    rm -f /private/var/db/.AppleSetupDone
    echo "[$timestamp] Troubleshooting setup - Setup Assistant configured" >> "$log_file"
    
    echo "Setup Assistant configured for troubleshooting."
    echo "Troubleshooting report saved to: $troubleshoot_report"
    echo "Restart the device to begin setup process."
}

trigger_mass_deployment_setup() {
    echo "Configuring Setup Assistant for mass deployment..."
    
    # Get device serial number for tracking
    local serial_number=$(system_profiler SPHardwareDataType | grep "Serial Number" | awk '{print $4}')
    
    # Log deployment
    echo "[$timestamp] Mass deployment setup - Device: $serial_number" >> "$log_file"
    
    rm -f /private/var/db/.AppleSetupDone
    
    cat << EOF
Setup Assistant configured for mass deployment.

Device Serial: $serial_number
Deployment Date: $(date)

Standardized setup will include:
• Language: English (US)
• Region: United States
• Network: Enterprise Wi-Fi
• Account: Standard user account
• Security: Corporate security policies
• Applications: Standard corporate apps

Device is ready for deployment. Restart to begin setup.
EOF
}

trigger_default_setup() {
    echo "Configuring Setup Assistant with default settings..."
    
    rm -f /private/var/db/.AppleSetupDone
    echo "[$timestamp] Default setup - Setup Assistant configured" >> "$log_file"
    
    echo "Setup Assistant configured with default settings."
    echo "Restart the device to begin setup process."
}

# Main execution
if [ $# -eq 0 ]; then
    echo "Usage: $0 [scenario]"
    echo "Available scenarios:"
    echo "  new_employee    - Configure for new employee onboarding"
    echo "  device_refresh  - Configure for device refresh/reconfiguration"
    echo "  compliance_reset - Configure for compliance verification"
    echo "  troubleshooting - Configure for troubleshooting purposes"
    echo "  mass_deployment - Configure for mass deployment"
    echo "  default         - Configure with default settings"
    echo ""
    conditional_setup_assistant "default"
else
    conditional_setup_assistant "$1"
fi

Enterprise Setup Assistant Manager

#!/bin/bash

# Enterprise Setup Assistant Manager with configuration profiles
# Usage: ./enterprise_setup_manager.sh

enterprise_setup_manager() {
    local config_file="/etc/macfleet/setup_assistant_config.conf"
    local log_file="/var/log/macfleet_setup_assistant.log"
    local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
    
    # Check if running as root
    if [ "$EUID" -ne 0 ]; then
        echo "Error: This script must be run as root"
        exit 1
    fi
    
    # Create configuration directory
    mkdir -p /etc/macfleet
    
    # Load or create configuration
    if [ -f "$config_file" ]; then
        source "$config_file"
    else
        create_enterprise_config
        source "$config_file"
    fi
    
    echo "[$timestamp] Enterprise Setup Assistant Manager started" >> "$log_file"
    
    # Display configuration menu
    display_enterprise_menu
}

create_enterprise_config() {
    cat > "/etc/macfleet/setup_assistant_config.conf" << 'EOF'
# MacFleet Enterprise Setup Assistant Configuration

# Organization Information
ORGANIZATION_NAME="MacFleet Organization"
IT_CONTACT_EMAIL="support@macfleet.com"
IT_CONTACT_PHONE="1-800-MACFLEET"

# Default Configuration
DEFAULT_LANGUAGE="English"
DEFAULT_REGION="United States"
REQUIRE_APPLE_ID="false"
ENABLE_LOCATION_SERVICES="false"
ENABLE_SIRI="false"
REQUIRE_TERMS_ACCEPTANCE="true"

# Security Settings
REQUIRE_STRONG_PASSWORD="true"
ENABLE_FILEVAULT="true"
REQUIRE_TOUCH_ID="true"

# Deployment Settings
DEPLOYMENT_MODE="enterprise"
SKIP_OPTIONAL_STEPS="true"
AUTO_CONFIGURE_NETWORK="true"
EOF
    
    echo "configuration created at /etc/macfleet/setup_assistant_config.conf"
}

display_enterprise_menu() {
    while true; do
        clear
        echo "======================================="
        echo "MacFleet Enterprise Setup Assistant"
        echo "======================================="
        echo ""
        echo "Organization: $ORGANIZATION_NAME"
        echo "Contact: $IT_CONTACT_EMAIL"
        echo ""
        echo "Available Actions:"
        echo "1. Trigger Setup Assistant (Single Device)"
        echo "2. Prepare Mass Deployment"
        echo "3. Configure Setup Assistant Options"
        echo "4. View Setup Assistant Status"
        echo "5. Generate Deployment Report"
        echo "6. Backup/Restore Setup State"
        echo "7. View Configuration"
        echo "8. Exit"
        echo ""
        read -p "Select an option (1-8): " choice
        
        case $choice in
            1)
                trigger_single_device_setup
                ;;
            2)
                prepare_mass_deployment
                ;;
            3)
                configure_setup_options
                ;;
            4)
                view_setup_status
                ;;
            5)
                generate_deployment_report
                ;;
            6)
                backup_restore_setup
                ;;
            7)
                view_configuration
                ;;
            8)
                echo "Exiting Enterprise Setup Assistant Manager."
                exit 0
                ;;
            *)
                echo "Invalid option. Please try again."
                ;;
        esac
        
        echo ""
        read -p "Press Enter to continue..."
    done
}

trigger_single_device_setup() {
    echo "======================================="
    echo "Trigger Setup Assistant - Single Device"
    echo "======================================="
    
    local device_name=$(scutil --get ComputerName)
    local serial_number=$(system_profiler SPHardwareDataType | grep "Serial Number" | awk '{print $4}')
    
    echo "Device: $device_name"
    echo "Serial: $serial_number"
    echo ""
    
    read -p "Confirm triggering Setup Assistant on this device? (y/N): " confirm
    if [ "$confirm" = "y" ] || [ "$confirm" = "Y" ]; then
        # Remove Setup Assistant marker
        if rm -f /private/var/db/.AppleSetupDone; then
            echo "[$timestamp] Single device setup triggered - $device_name ($serial_number)" >> "$log_file"
            echo "Setup Assistant configured successfully."
            echo "Please restart the device to begin setup."
        else
            echo "Error: Failed to configure Setup Assistant."
        fi
    else
        echo "Operation cancelled."
    fi
}

prepare_mass_deployment() {
    echo "======================================="
    echo "Prepare Mass Deployment"
    echo "======================================="
    
    read -p "Enter number of devices for deployment: " device_count
    read -p "Enter deployment batch name: " batch_name
    
    local deployment_dir="/var/macfleet/deployments/$batch_name"
    mkdir -p "$deployment_dir"
    
    # Create deployment package
    cat > "$deployment_dir/deploy_setup_assistant.sh" << 'EOF'
#!/bin/bash
# MacFleet Mass Deployment Setup Assistant Trigger
# Auto-generated deployment script

# Check if running as root
if [ "$EUID" -ne 0 ]; then
    echo "Error: This script must be run as root"
    exit 1
fi

# Remove Setup Assistant marker
rm -f /private/var/db/.AppleSetupDone

# Log deployment
echo "$(date '+%Y-%m-%d %H:%M:%S') - Mass deployment setup triggered on $(scutil --get ComputerName)" >> /var/log/macfleet_mass_deployment.log

echo "Setup Assistant configured for mass deployment."
echo "Restart device to begin setup process."
EOF
    
    chmod +x "$deployment_dir/deploy_setup_assistant.sh"
    
    # Create deployment manifest
    cat > "$deployment_dir/deployment_manifest.txt" << EOF
MacFleet Mass Deployment Manifest
Batch Name: $batch_name
Device Count: $device_count
Created: $(date)
Organization: $ORGANIZATION_NAME

Deployment Instructions:
1. Copy deploy_setup_assistant.sh to each device
2. Run script as root on each device
3. Restart devices to begin Setup Assistant
4. Follow standard setup procedures

Contact: $IT_CONTACT_EMAIL
EOF
    
    echo "Mass deployment package created at: $deployment_dir"
    echo "Deployment script: $deployment_dir/deploy_setup_assistant.sh"
    echo "Manifest: $deployment_dir/deployment_manifest.txt"
}

configure_setup_options() {
    echo "======================================="
    echo "Configure Setup Assistant Options"
    echo "======================================="
    
    echo "Current Configuration:"
    echo "  Language: $DEFAULT_LANGUAGE"
    echo "  Region: $DEFAULT_REGION"
    echo "  Require Apple ID: $REQUIRE_APPLE_ID"
    echo "  Enable Location Services: $ENABLE_LOCATION_SERVICES"
    echo "  Enable Siri: $ENABLE_SIRI"
    echo ""
    
    read -p "Modify configuration? (y/N): " modify
    if [ "$modify" = "y" ] || [ "$modify" = "Y" ]; then
        echo "Configuration modification would require additional setup..."
        echo "Please edit: /etc/macfleet/setup_assistant_config.conf"
    fi
}

view_setup_status() {
    echo "======================================="
    echo "Setup Assistant Status"
    echo "======================================="
    
    local setup_done_file="/private/var/db/.AppleSetupDone"
    local device_name=$(scutil --get ComputerName)
    local os_version=$(sw_vers -productVersion)
    
    echo "Device: $device_name"
    echo "macOS Version: $os_version"
    echo "Timestamp: $(date)"
    echo ""
    
    if [ -f "$setup_done_file" ]; then
        echo "Status: Setup Assistant COMPLETED"
        echo "File: $setup_done_file exists"
        echo "Modified: $(stat -f "%Sm" "$setup_done_file")"
        echo ""
        echo "Setup Assistant will NOT run on next reboot."
    else
        echo "Status: Setup Assistant SCHEDULED"
        echo "File: $setup_done_file does not exist"
        echo ""
        echo "Setup Assistant WILL run on next reboot."
    fi
}

generate_deployment_report() {
    echo "======================================="
    echo "Generate Deployment Report"
    echo "======================================="
    
    local report_file="/tmp/macfleet_setup_report_$(date +%Y%m%d_%H%M%S).txt"
    
    cat > "$report_file" << EOF
MacFleet Setup Assistant Deployment Report
Generated: $(date)
Organization: $ORGANIZATION_NAME

Device Information:
  Computer Name: $(scutil --get ComputerName)
  Serial Number: $(system_profiler SPHardwareDataType | grep "Serial Number" | awk '{print $4}')
  macOS Version: $(sw_vers -productVersion)
  Hardware Model: $(system_profiler SPHardwareDataType | grep "Model Name" | cut -d: -f2 | xargs)

Setup Assistant Status:
EOF
    
    if [ -f "/private/var/db/.AppleSetupDone" ]; then
        echo "  Status: Completed" >> "$report_file"
        echo "  Last Run: $(stat -f "%Sm" "/private/var/db/.AppleSetupDone")" >> "$report_file"
    else
        echo "  Status: Scheduled for next reboot" >> "$report_file"
    fi
    
    cat >> "$report_file" << EOF

Configuration:
  Default Language: $DEFAULT_LANGUAGE
  Default Region: $DEFAULT_REGION
  Deployment Mode: $DEPLOYMENT_MODE
  Contact: $IT_CONTACT_EMAIL

Recent Log Entries:
EOF
    
    if [ -f "/var/log/macfleet_setup_assistant.log" ]; then
        tail -10 "/var/log/macfleet_setup_assistant.log" >> "$report_file"
    else
        echo "  No log entries found" >> "$report_file"
    fi
    
    echo "Deployment report generated: $report_file"
}

backup_restore_setup() {
    echo "======================================="
    echo "Backup/Restore Setup State"
    echo "======================================="
    
    echo "1. Backup current Setup Assistant state"
    echo "2. Restore Setup Assistant state"
    echo ""
    read -p "Select option (1-2): " backup_option
    
    case $backup_option in
        1)
            backup_setup_state
            ;;
        2)
            restore_setup_state
            ;;
        *)
            echo "Invalid option."
            ;;
    esac
}

backup_setup_state() {
    local backup_dir="/var/backups/macfleet"
    local timestamp=$(date +%Y%m%d_%H%M%S)
    
    mkdir -p "$backup_dir"
    
    if [ -f "/private/var/db/.AppleSetupDone" ]; then
        cp "/private/var/db/.AppleSetupDone" "$backup_dir/.AppleSetupDone.backup.$timestamp"
        echo "Setup Assistant state backed up to: $backup_dir/.AppleSetupDone.backup.$timestamp"
    else
        echo "No Setup Assistant state to backup (file does not exist)."
    fi
}

restore_setup_state() {
    local backup_dir="/var/backups/macfleet"
    
    if [ -d "$backup_dir" ]; then
        echo "Available backups:"
        ls -la "$backup_dir"/.AppleSetupDone.backup.* 2>/dev/null || echo "No backups found."
        echo ""
        read -p "Enter backup filename to restore: " backup_file
        
        if [ -f "$backup_dir/$backup_file" ]; then
            cp "$backup_dir/$backup_file" "/private/var/db/.AppleSetupDone"
            echo "Setup Assistant state restored from: $backup_file"
        else
            echo "Backup file not found."
        fi
    else
        echo "No backup directory found."
    fi
}

view_configuration() {
    echo "======================================="
    echo "Current Configuration"
    echo "======================================="
    
    if [ -f "/etc/macfleet/setup_assistant_config.conf" ]; then
        cat "/etc/macfleet/setup_assistant_config.conf"
    else
        echo "No configuration file found."
    fi
}

# Execute enterprise manager
enterprise_setup_manager

Setup Assistant Automation and Monitoring

Automated Setup Assistant Deployment

#!/bin/bash

# Automated Setup Assistant deployment with scheduling
# Usage: ./automated_setup_deployment.sh

automated_setup_deployment() {
    local config_file="/etc/macfleet/automated_deployment.conf"
    local log_file="/var/log/macfleet_automated_setup.log"
    local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
    
    # Check if running as root
    if [ "$EUID" -ne 0 ]; then
        echo "Error: This script must be run as root"
        exit 1
    fi
    
    # Create configuration if it doesn't exist
    if [ ! -f "$config_file" ]; then
        create_automation_config
    fi
    
    source "$config_file"
    
    echo "[$timestamp] Automated Setup Assistant deployment started" >> "$log_file"
    
    # Check deployment conditions
    check_deployment_conditions
    
    # Execute deployment based on configuration
    execute_automated_deployment
}

create_automation_config() {
    mkdir -p /etc/macfleet
    
    cat > "/etc/macfleet/automated_deployment.conf" << 'EOF'
# MacFleet Automated Setup Assistant Deployment Configuration

# Deployment Schedule
ENABLE_SCHEDULED_DEPLOYMENT="false"
DEPLOYMENT_TIME="02:00"  # 24-hour format
DEPLOYMENT_DAYS="Mon,Wed,Fri"

# Deployment Conditions
CHECK_USER_ACTIVITY="true"
IDLE_TIME_THRESHOLD="3600"  # seconds
REQUIRE_AC_POWER="true"
MIN_BATTERY_LEVEL="50"

# Notification Settings
NOTIFY_USERS="true"
NOTIFICATION_LEAD_TIME="300"  # 5 minutes
ALLOW_USER_POSTPONE="true"
MAX_POSTPONE_COUNT="3"

# Deployment Scope
TARGET_DEVICES="all"  # all, specific_models, specific_serials
EXCLUDE_CRITICAL_HOURS="true"
BUSINESS_HOURS_START="09:00"
BUSINESS_HOURS_END="17:00"

# Rollback Settings
ENABLE_AUTOMATIC_ROLLBACK="true"
ROLLBACK_ON_ERROR="true"
BACKUP_BEFORE_DEPLOYMENT="true"
EOF
    
    echo "Automation configuration created at /etc/macfleet/automated_deployment.conf"
}

check_deployment_conditions() {
    local current_time=$(date +%H:%M)
    local current_day=$(date +%a)
    local battery_level=$(pmset -g batt | grep -o '[0-9]*%' | sed 's/%//')
    local ac_power=$(pmset -g batt | grep -c "AC Power")
    
    echo "[$timestamp] Checking deployment conditions" >> "$log_file"
    
    # Check if deployment is enabled
    if [ "$ENABLE_SCHEDULED_DEPLOYMENT" != "true" ]; then
        echo "[$timestamp] Scheduled deployment is disabled" >> "$log_file"
        echo "Scheduled deployment is disabled."
        return 1
    fi
    
    # Check deployment time
    if [ "$current_time" != "$DEPLOYMENT_TIME" ]; then
        echo "[$timestamp] Not deployment time (current: $current_time, scheduled: $DEPLOYMENT_TIME)" >> "$log_file"
        return 1
    fi
    
    # Check deployment day
    if [[ "$DEPLOYMENT_DAYS" != *"$current_day"* ]]; then
        echo "[$timestamp] Not deployment day (current: $current_day, scheduled: $DEPLOYMENT_DAYS)" >> "$log_file"
        return 1
    fi
    
    # Check business hours
    if [ "$EXCLUDE_CRITICAL_HOURS" = "true" ]; then
        if [[ "$current_time" > "$BUSINESS_HOURS_START" && "$current_time" < "$BUSINESS_HOURS_END" ]]; then
            echo "[$timestamp] Deployment blocked during business hours" >> "$log_file"
            return 1
        fi
    fi
    
    # Check power requirements
    if [ "$REQUIRE_AC_POWER" = "true" ] && [ "$ac_power" -eq 0 ]; then
        echo "[$timestamp] AC power required but not available" >> "$log_file"
        return 1
    fi
    
    # Check battery level
    if [ -n "$battery_level" ] && [ "$battery_level" -lt "$MIN_BATTERY_LEVEL" ]; then
        echo "[$timestamp] Battery level too low ($battery_level% < $MIN_BATTERY_LEVEL%)" >> "$log_file"
        return 1
    fi
    
    # Check user activity
    if [ "$CHECK_USER_ACTIVITY" = "true" ]; then
        local idle_time=$(ioreg -c IOHIDSystem | awk '/HIDIdleTime/ {print $3/1000000000; exit}')
        if [ "$(echo "$idle_time < $IDLE_TIME_THRESHOLD" | bc)" -eq 1 ]; then
            echo "[$timestamp] User activity detected (idle: ${idle_time}s < ${IDLE_TIME_THRESHOLD}s)" >> "$log_file"
            return 1
        fi
    fi
    
    echo "[$timestamp] All deployment conditions met" >> "$log_file"
    return 0
}

execute_automated_deployment() {
    echo "[$timestamp] Executing automated Setup Assistant deployment" >> "$log_file"
    
    # Send user notification if enabled
    if [ "$NOTIFY_USERS" = "true" ]; then
        send_user_notification
    fi
    
    # Create backup if enabled
    if [ "$BACKUP_BEFORE_DEPLOYMENT" = "true" ]; then
        create_deployment_backup
    fi
    
    # Trigger Setup Assistant
    if rm -f /private/var/db/.AppleSetupDone; then
        echo "[$timestamp] Setup Assistant triggered successfully via automation" >> "$log_file"
        
        # Schedule automatic reboot if configured
        if [ -n "$AUTO_REBOOT_DELAY" ]; then
            echo "[$timestamp] Scheduling automatic reboot in $AUTO_REBOOT_DELAY minutes" >> "$log_file"
            at "now + $AUTO_REBOOT_DELAY minutes" << 'EOF'
/sbin/reboot
EOF
        fi
        
        # Send completion notification
        send_completion_notification
        
    else
        echo "[$timestamp] ERROR: Failed to trigger Setup Assistant" >> "$log_file"
        
        # Execute rollback if enabled
        if [ "$ROLLBACK_ON_ERROR" = "true" ]; then
            execute_rollback
        fi
    fi
}

send_user_notification() {
    local notification_title="MacFleet Setup Assistant"
    local notification_message="Setup Assistant will be triggered in $NOTIFICATION_LEAD_TIME seconds. Please save your work."
    
    # Use osascript to display notification
    osascript -e "display notification \"$notification_message\" with title \"$notification_title\" sound name \"Glass\""
    
    # Wait for lead time
    sleep "$NOTIFICATION_LEAD_TIME"
}

create_deployment_backup() {
    local backup_dir="/var/backups/macfleet/automated"
    local backup_timestamp=$(date +%Y%m%d_%H%M%S)
    
    mkdir -p "$backup_dir"
    
    if [ -f "/private/var/db/.AppleSetupDone" ]; then
        cp "/private/var/db/.AppleSetupDone" "$backup_dir/.AppleSetupDone.auto_backup.$backup_timestamp"
        echo "[$timestamp] Backup created: .AppleSetupDone.auto_backup.$backup_timestamp" >> "$log_file"
    fi
}

send_completion_notification() {
    local notification_title="MacFleet Setup Assistant"
    local notification_message="Setup Assistant has been configured. Device will restart shortly."
    
    osascript -e "display notification \"$notification_message\" with title \"$notification_title\" sound name \"Glass\""
}

execute_rollback() {
    echo "[$timestamp] Executing rollback due to deployment error" >> "$log_file"
    
    local latest_backup=$(ls -t /var/backups/macfleet/automated/.AppleSetupDone.auto_backup.* 2>/dev/null | head -1)
    
    if [ -n "$latest_backup" ]; then
        cp "$latest_backup" "/private/var/db/.AppleSetupDone"
        echo "[$timestamp] Rollback completed using backup: $(basename "$latest_backup")" >> "$log_file"
    else
        echo "[$timestamp] No backup available for rollback" >> "$log_file"
    fi
}

# Execute automated deployment
automated_setup_deployment

Troubleshooting and Best Practices

Common Issues and Solutions

1. macOS Version Compatibility

# Check macOS version before execution
os_version=$(sw_vers -productVersion)
major_version=$(echo "$os_version" | cut -d. -f1)

if [ "$major_version" -ge 14 ]; then
    echo "Warning: This script may not work on macOS 14 or later"
    echo "Current version: $os_version"
fi

2. Permission Issues

# Ensure script runs with proper privileges
if [ "$EUID" -ne 0 ]; then
    echo "Error: This script must be run as root"
    echo "Please use: sudo $0"
    exit 1
fi

3. File System Protection

# Check if System Integrity Protection affects operation
csrutil status | grep -q "enabled"
if [ $? -eq 0 ]; then
    echo "Note: SIP is enabled. This may affect script operation."
fi

Best Practices for Setup Assistant Management

  1. Version Compatibility: Always check macOS version compatibility before deployment
  2. User Communication: Notify users before triggering Setup Assistant
  3. Data Backup: Create backups before major configuration changes
  4. Testing: Test scripts in controlled environments before mass deployment
  5. Logging: Maintain detailed logs of all Setup Assistant operations
  6. Rollback Plans: Prepare rollback procedures for deployment failures

Enterprise Deployment Considerations

  • Scheduling: Plan deployments during maintenance windows
  • User Impact: Consider user workflows and minimize disruption
  • Network Requirements: Ensure adequate network connectivity for Apple services
  • Security: Implement appropriate security measures for automated deployments
  • Compliance: Ensure deployments meet organizational compliance requirements

Conclusion

Setup Assistant management is a powerful tool for macOS device administration. These scripts provide comprehensive solutions for triggering, managing, and automating Setup Assistant across Mac fleets. From simple single-device triggers to complex enterprise automation, these tools enable efficient device management while maintaining user experience and organizational compliance.

Remember to test all scripts thoroughly in controlled environments before production deployment, and always maintain proper backups of system configurations. Regular monitoring and logging ensure successful Setup Assistant deployments and help identify potential issues before they impact users.

Set Screen Saver on macOS

Learn how to configure and deploy screen savers on Mac devices using scripts. This allows you to set custom slideshow styles, idle times, and photo sources across your Mac fleet.

Basic Screen Saver Setup

Configure a slideshow screen saver with custom settings:

#!/bin/bash

# Screen saver configuration
STYLE="Ken Burns"
IDLE_TIME=300  # 5 minutes in seconds
SHUFFLE_PHOTOS=true
PHOTOS_PATH="/System/Library/Screen Savers/Default Collections/1-National Geographic"

# Set screen saver style
defaults -currentHost write com.apple.screensaver moduleDict -dict moduleName "$STYLE"

# Set idle time before activation
defaults -currentHost write com.apple.screensaver idleTime -int $IDLE_TIME

# Configure photo shuffle
defaults -currentHost write com.apple.screensaver ShufflePhotos -bool $SHUFFLE_PHOTOS

# Set photos folder path
defaults -currentHost write com.apple.screensaver PhotosFolderPath "$PHOTOS_PATH"

echo "Screen saver configured: Style=$STYLE, IdleTime=${IDLE_TIME}s"

Available Screen Saver Styles

Choose from Apple's built-in slideshow styles:

#!/bin/bash

# Available screen saver styles
STYLES=(
    "Floating"
    "Flip-up"
    "Reflections"
    "Origami"
    "Shifting Tiles"
    "Sliding Panels"
    "Photo Mobile"
    "Holiday Mobile"
    "Photo Wall"
    "Vintage Prints"
    "Ken Burns"
    "Classic"
)

# Function to set screen saver style
set_screen_saver_style() {
    local style="$1"
    local idle_time="${2:-600}"  # Default 10 minutes
    local photos_path="${3:-/System/Library/Screen Savers/Default Collections}"
    
    echo "Setting screen saver: $style"
    
    # Configure screen saver
    defaults -currentHost write com.apple.screensaver moduleDict -dict moduleName "$style"
    defaults -currentHost write com.apple.screensaver idleTime -int $idle_time
    defaults -currentHost write com.apple.screensaver PhotosFolderPath "$photos_path"
    
    echo "Screen saver configured successfully"
}

# Example: Set Ken Burns style with 5-minute idle time
set_screen_saver_style "Ken Burns" 300 "/Users/Shared/ScreenSaver Photos"

Interactive Screen Saver Manager

Script with user-friendly interface for configuration:

#!/bin/bash

# Function to display available styles
show_styles() {
    echo "Available Screen Saver Styles:"
    echo "1. Floating"
    echo "2. Flip-up"
    echo "3. Reflections"
    echo "4. Origami"
    echo "5. Shifting Tiles"
    echo "6. Sliding Panels"
    echo "7. Photo Mobile"
    echo "8. Holiday Mobile"
    echo "9. Photo Wall"
    echo "10. Vintage Prints"
    echo "11. Ken Burns"
    echo "12. Classic"
}

# Function to configure screen saver
configure_screen_saver() {
    local style="$1"
    local idle_minutes="$2"
    local shuffle="$3"
    local photos_folder="$4"
    
    local idle_seconds=$((idle_minutes * 60))
    
    # Set all configuration options
    defaults -currentHost write com.apple.screensaver moduleDict -dict moduleName "$style"
    defaults -currentHost write com.apple.screensaver idleTime -int $idle_seconds
    defaults -currentHost write com.apple.screensaver ShufflePhotos -bool $shuffle
    defaults -currentHost write com.apple.screensaver PhotosFolderPath "$photos_folder"
    
    # Kill System Preferences to force refresh
    killall "System Preferences" 2>/dev/null || true
    
    echo "✓ Screen saver configured:"
    echo "  Style: $style"
    echo "  Idle time: $idle_minutes minutes"
    echo "  Shuffle photos: $shuffle"
    echo "  Photos folder: $photos_folder"
}

# Default configuration
STYLE="Ken Burns"
IDLE_MINUTES=10
SHUFFLE_PHOTOS=true
PHOTOS_FOLDER="/System/Library/Screen Savers/Default Collections/1-National Geographic"

# Configure with defaults
configure_screen_saver "$STYLE" "$IDLE_MINUTES" "$SHUFFLE_PHOTOS" "$PHOTOS_FOLDER"

Enterprise Screen Saver Deployment

Deploy standardized screen saver settings across multiple devices:

#!/bin/bash

# Corporate screen saver configuration
CORPORATE_CONFIG() {
    # Company branding configuration
    local style="Classic"
    local idle_time=600  # 10 minutes
    local photos_path="/Library/Desktop Pictures/Corporate"
    local shuffle=false
    
    echo "Deploying corporate screen saver settings..."
    
    # Create corporate photos directory if it doesn't exist
    if [[ ! -d "$photos_path" ]]; then
        sudo mkdir -p "$photos_path"
        echo "Created corporate photos directory: $photos_path"
    fi
    
    # Apply settings
    defaults -currentHost write com.apple.screensaver moduleDict -dict moduleName "$style"
    defaults -currentHost write com.apple.screensaver idleTime -int $idle_time
    defaults -currentHost write com.apple.screensaver ShufflePhotos -bool $shuffle
    defaults -currentHost write com.apple.screensaver PhotosFolderPath "$photos_path"
    
    # Disable screen saver password requirement for corporate environment
    defaults write com.apple.screensaver askForPassword -int 0
    
    echo "Corporate screen saver configuration applied"
    echo "Style: $style | Idle: ${idle_time}s | Shuffle: $shuffle"
}

# Apply corporate configuration
CORPORATE_CONFIG

Screen Saver Status and Management

Check current screen saver settings and manage configuration:

#!/bin/bash

# Function to display current screen saver settings
show_current_settings() {
    echo "=== Current Screen Saver Settings ==="
    
    # Get current style
    local current_style=$(defaults -currentHost read com.apple.screensaver moduleDict 2>/dev/null | grep moduleName | cut -d'"' -f4)
    
    # Get idle time
    local idle_time=$(defaults -currentHost read com.apple.screensaver idleTime 2>/dev/null)
    
    # Get shuffle setting
    local shuffle=$(defaults -currentHost read com.apple.screensaver ShufflePhotos 2>/dev/null)
    
    # Get photos path
    local photos_path=$(defaults -currentHost read com.apple.screensaver PhotosFolderPath 2>/dev/null)
    
    echo "Style: ${current_style:-Not set}"
    echo "Idle time: ${idle_time:-Not set} seconds"
    echo "Shuffle photos: ${shuffle:-Not set}"
    echo "Photos folder: ${photos_path:-Not set}"
}

# Function to disable screen saver
disable_screen_saver() {
    defaults -currentHost write com.apple.screensaver idleTime -int 0
    echo "Screen saver disabled (idle time set to 0)"
}

# Function to enable screen saver with default settings
enable_screen_saver() {
    defaults -currentHost write com.apple.screensaver idleTime -int 600
    defaults -currentHost write com.apple.screensaver moduleDict -dict moduleName "Ken Burns"
    echo "Screen saver enabled with default settings"
}

# Show current settings
show_current_settings

Usage with MacFleet

  1. Choose your preferred screen saver style from the available options
  2. Set idle time in seconds (0 disables screen saver)
  3. Configure photo shuffle and source folder path
  4. Deploy through MacFleet's remote script execution
  5. Monitor deployment in action history

Common Photo Paths

LocationPath
Default Collections/System/Library/Screen Savers/Default Collections
Desktop Pictures/Library/Desktop Pictures
User Pictures/Users/username/Pictures
Shared Folder/Users/Shared/ScreenSaver Photos

Troubleshooting

Settings not applied: Kill System Preferences and restart to refresh settings Photos not displaying: Verify folder path exists and contains image files Screen saver not activating: Check idle time setting and system sleep preferences


Note: Changes take effect immediately but may require restarting System Preferences to see in the GUI. Test configuration before mass deployment.