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 controlreboot
- Alternative reboot commandhalt
- 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.