Automatic App Launch Management on macOS
Streamline enterprise productivity by automatically launching essential applications on user login across your MacFleet devices. This tutorial covers LaunchAgent configuration, user-specific app management, security validation, and centralized deployment strategies.
Understanding macOS App Launch Mechanisms
macOS provides several mechanisms for automatic application launching:
- LaunchAgents - User-specific applications that launch at login
- LaunchDaemons - System-wide services that start at boot
- Login Items - User-configured applications in System Preferences
- MDM Configurations - Enterprise-managed launch configurations
Basic Automatic App Launch
Simple App Launch Configuration
#!/bin/bash
# Basic app launch setup for single application
APP_NAME="Messages"
PLIST_NAME="com.${APP_NAME}.plist"
LAUNCH_AGENTS_DIR="/Library/LaunchAgents"
# Create LaunchAgent plist
cat > "${LAUNCH_AGENTS_DIR}/${PLIST_NAME}" << EOF
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>KeepAlive</key>
<false/>
<key>Label</key>
<string>${PLIST_NAME}</string>
<key>Program</key>
<string>/System/Applications/${APP_NAME}.app/Contents/MacOS/${APP_NAME}</string>
<key>RunAtLoad</key>
<true/>
</dict>
</plist>
EOF
echo "LaunchAgent created for ${APP_NAME}"
Enhanced App Launch with Validation
#!/bin/bash
# Enhanced app launch with validation
setup_app_launch() {
local app_name="$1"
local app_path="$2"
local plist_name="com.macfleet.${app_name}.plist"
echo "Setting up automatic launch for: $app_name"
# Validate app exists
if [[ ! -d "$app_path" ]]; then
echo "Error: Application not found at $app_path"
return 1
fi
# Validate executable
local executable_path="${app_path}/Contents/MacOS/${app_name}"
if [[ ! -x "$executable_path" ]]; then
echo "Error: Executable not found or not executable: $executable_path"
return 1
fi
# Create LaunchAgent
cat > "/Library/LaunchAgents/${plist_name}" << EOF
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>KeepAlive</key>
<false/>
<key>Label</key>
<string>${plist_name}</string>
<key>Program</key>
<string>${executable_path}</string>
<key>RunAtLoad</key>
<true/>
<key>StandardErrorPath</key>
<string>/var/log/macfleet_${app_name}.error.log</string>
<key>StandardOutPath</key>
<string>/var/log/macfleet_${app_name}.out.log</string>
</dict>
</plist>
EOF
echo "LaunchAgent configured successfully for $app_name"
return 0
}
# Example usage
setup_app_launch "Messages" "/System/Applications/Messages.app"
Enterprise Application Launch Management
#!/bin/bash
# MacFleet Enterprise Application Launch Management
# Centralized control of automatic app launches across fleet devices
# Configuration
LOG_FILE="/var/log/macfleet_app_launch.log"
CONFIG_DIR="/etc/macfleet/app_launch"
LAUNCH_AGENTS_DIR="/Library/LaunchAgents"
USER_LAUNCH_AGENTS_DIR="~/Library/LaunchAgents"
BACKUP_DIR="/var/backups/launch_agents"
# Application configuration database
declare -A ENTERPRISE_APPS=(
["productivity_suite"]="Slack,Microsoft Teams,Notion,1Password 7 - Password Manager"
["development_tools"]="Xcode,Terminal,Visual Studio Code,Docker Desktop"
["design_suite"]="Adobe Photoshop 2023,Sketch,Figma,Adobe Illustrator 2023"
["communication"]="Messages,Mail,Zoom,Microsoft Outlook"
["security_tools"]="Little Snitch 5,1Password 7 - Password Manager,Malwarebytes Anti-Malware"
)
# User profile configurations
declare -A USER_PROFILES=(
["developer"]="development_tools,communication,security_tools"
["designer"]="design_suite,communication,productivity_suite"
["manager"]="productivity_suite,communication"
["security"]="security_tools,communication,productivity_suite"
["default"]="communication"
)
# Logging function
log_action() {
echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" | tee -a "$LOG_FILE"
}
# Create necessary directories
setup_directories() {
for dir in "$CONFIG_DIR" "$BACKUP_DIR"; do
if [[ ! -d "$dir" ]]; then
mkdir -p "$dir"
log_action "Created directory: $dir"
fi
done
}
# Validate application path and executable
validate_application() {
local app_name="$1"
local app_path=""
log_action "Validating application: $app_name"
# Common application paths to check
local search_paths=(
"/Applications"
"/System/Applications"
"/Applications/Utilities"
"/System/Applications/Utilities"
)
# Find application
for base_path in "${search_paths[@]}"; do
local potential_path="${base_path}/${app_name}.app"
if [[ -d "$potential_path" ]]; then
app_path="$potential_path"
break
fi
done
if [[ -z "$app_path" ]]; then
log_action "❌ Application not found: $app_name"
return 1
fi
# Validate executable
local executable_path="${app_path}/Contents/MacOS/${app_name}"
if [[ ! -x "$executable_path" ]]; then
# Try alternative executable name (some apps use different names)
local info_plist="${app_path}/Contents/Info.plist"
if [[ -f "$info_plist" ]]; then
local bundle_executable
bundle_executable=$(defaults read "$info_plist" CFBundleExecutable 2>/dev/null)
if [[ -n "$bundle_executable" ]]; then
executable_path="${app_path}/Contents/MacOS/${bundle_executable}"
fi
fi
if [[ ! -x "$executable_path" ]]; then
log_action "❌ Executable not found or not executable: $executable_path"
return 1
fi
fi
log_action "✅ Application validated: $app_name at $app_path"
echo "$app_path"
return 0
}
# Create LaunchAgent plist for application
create_launch_agent() {
local app_name="$1"
local app_path="$2"
local user_specific="${3:-false}"
local delay="${4:-0}"
local plist_name="com.macfleet.${app_name// /_}.plist"
local target_dir="$LAUNCH_AGENTS_DIR"
if [[ "$user_specific" == "true" ]]; then
target_dir="$USER_LAUNCH_AGENTS_DIR"
fi
log_action "Creating LaunchAgent for: $app_name"
# Get executable path
local executable_path="${app_path}/Contents/MacOS/${app_name}"
local info_plist="${app_path}/Contents/Info.plist"
if [[ -f "$info_plist" ]]; then
local bundle_executable
bundle_executable=$(defaults read "$info_plist" CFBundleExecutable 2>/dev/null)
if [[ -n "$bundle_executable" ]]; then
executable_path="${app_path}/Contents/MacOS/${bundle_executable}"
fi
fi
# Create plist content
cat > "${target_dir}/${plist_name}" << EOF
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>${plist_name}</string>
<key>Program</key>
<string>${executable_path}</string>
<key>RunAtLoad</key>
<true/>
<key>KeepAlive</key>
<false/>
<key>StandardErrorPath</key>
<string>/var/log/macfleet_$(echo "$app_name" | tr ' ' '_').error.log</string>
<key>StandardOutPath</key>
<string>/var/log/macfleet_$(echo "$app_name" | tr ' ' '_').out.log</string>
EOF
# Add delay if specified
if [[ "$delay" -gt 0 ]]; then
cat >> "${target_dir}/${plist_name}" << EOF
<key>StartInterval</key>
<integer>$delay</integer>
EOF
fi
# Add environment variables for enterprise apps
cat >> "${target_dir}/${plist_name}" << EOF
<key>EnvironmentVariables</key>
<dict>
<key>MACFLEET_MANAGED</key>
<string>true</string>
<key>ENTERPRISE_MODE</key>
<string>enabled</string>
</dict>
</dict>
</plist>
EOF
# Set proper permissions
chmod 644 "${target_dir}/${plist_name}"
log_action "✅ LaunchAgent created: ${plist_name}"
return 0
}
# Remove LaunchAgent for application
remove_launch_agent() {
local app_name="$1"
local user_specific="${2:-false}"
local plist_name="com.macfleet.${app_name// /_}.plist"
local target_dir="$LAUNCH_AGENTS_DIR"
if [[ "$user_specific" == "true" ]]; then
target_dir="$USER_LAUNCH_AGENTS_DIR"
fi
local plist_path="${target_dir}/${plist_name}"
if [[ -f "$plist_path" ]]; then
# Unload if loaded
launchctl unload "$plist_path" 2>/dev/null || true
# Remove file
rm -f "$plist_path"
log_action "✅ LaunchAgent removed: $plist_name"
return 0
else
log_action "⚠️ LaunchAgent not found: $plist_name"
return 1
fi
}
# Deploy applications for user profile
deploy_user_profile() {
local profile_name="$1"
local username="${2:-$(whoami)}"
log_action "Deploying user profile: $profile_name for user: $username"
# Get profile configuration
local profile_config="${USER_PROFILES[$profile_name]}"
if [[ -z "$profile_config" ]]; then
log_action "❌ Unknown user profile: $profile_name"
return 1
fi
# Backup existing configuration
backup_launch_agents
local success_count=0
local total_count=0
local failed_apps=()
# Process each app suite in profile
IFS=',' read -ra SUITES <<< "$profile_config"
for suite in "${SUITES[@]}"; do
local suite_apps="${ENTERPRISE_APPS[$suite]}"
if [[ -z "$suite_apps" ]]; then
log_action "⚠️ Unknown app suite: $suite"
continue
fi
# Process each app in suite
IFS=',' read -ra APPS <<< "$suite_apps"
for app in "${APPS[@]}"; do
total_count=$((total_count + 1))
# Validate and deploy app
local app_path
if app_path=$(validate_application "$app"); then
if create_launch_agent "$app" "$app_path" false 0; then
success_count=$((success_count + 1))
log_action "✅ Deployed: $app"
else
failed_apps+=("$app")
fi
else
failed_apps+=("$app")
fi
done
done
# Generate deployment report
generate_deployment_report "$profile_name" "$username" "$success_count" "$total_count" "${failed_apps[@]}"
log_action "Profile deployment completed: $success_count/$total_count successful"
return $((total_count - success_count))
}
# Backup existing LaunchAgents
backup_launch_agents() {
local backup_timestamp
backup_timestamp=$(date '+%Y%m%d_%H%M%S')
local backup_file="$BACKUP_DIR/launch_agents_backup_$backup_timestamp.tar.gz"
log_action "Creating LaunchAgents backup: $backup_file"
if tar -czf "$backup_file" -C /Library LaunchAgents 2>/dev/null; then
log_action "✅ Backup created: $backup_file"
return 0
else
log_action "❌ Backup failed"
return 1
fi
}
# Generate deployment report
generate_deployment_report() {
local profile_name="$1"
local username="$2"
local success_count="$3"
local total_count="$4"
shift 4
local failed_apps=("$@")
local report_file="$CONFIG_DIR/deployment_report_$(date '+%Y%m%d_%H%M%S').json"
log_action "Generating deployment report: $report_file"
cat > "$report_file" << EOF
{
"deployment_metadata": {
"timestamp": "$(date -Iseconds)",
"profile_name": "$profile_name",
"username": "$username",
"hostname": "$(hostname)",
"generator": "MacFleet App Launch Manager"
},
"deployment_summary": {
"total_applications": $total_count,
"successful_deployments": $success_count,
"failed_deployments": $((total_count - success_count)),
"success_rate": $(awk "BEGIN {printf \"%.2f\", ($success_count/$total_count)*100}")
},
"failed_applications": [
EOF
# Add failed apps
local first=true
for app in "${failed_apps[@]}"; do
if [[ "$first" == true ]]; then
first=false
else
echo "," >> "$report_file"
fi
echo " \"$app\"" >> "$report_file"
done
cat >> "$report_file" << EOF
],
"system_info": {
"os_version": "$(sw_vers -productVersion)",
"build_version": "$(sw_vers -buildVersion)",
"serial_number": "$(system_profiler SPHardwareDataType | grep 'Serial Number' | awk '{print $4}')"
}
}
EOF
log_action "✅ Deployment report generated: $report_file"
echo "$report_file"
}
# List all configured LaunchAgents
list_configured_apps() {
log_action "Listing configured automatic launch applications"
echo "=== MacFleet Managed LaunchAgents ==="
local agent_count=0
for plist_file in "$LAUNCH_AGENTS_DIR"/com.macfleet.*.plist; do
if [[ -f "$plist_file" ]]; then
local label
local program
label=$(defaults read "$plist_file" Label 2>/dev/null || echo "Unknown")
program=$(defaults read "$plist_file" Program 2>/dev/null || echo "Unknown")
echo "Label: $label"
echo "Program: $program"
echo "File: $plist_file"
echo "---"
agent_count=$((agent_count + 1))
fi
done
echo "Total managed LaunchAgents: $agent_count"
}
# Validate all configured apps
validate_all_apps() {
log_action "Validating all configured applications"
local validation_report="$CONFIG_DIR/validation_report_$(date '+%Y%m%d_%H%M%S').json"
local valid_count=0
local invalid_count=0
local invalid_apps=()
cat > "$validation_report" << EOF
{
"validation_timestamp": "$(date -Iseconds)",
"hostname": "$(hostname)",
"validation_results": [
EOF
local first=true
for plist_file in "$LAUNCH_AGENTS_DIR"/com.macfleet.*.plist; do
if [[ -f "$plist_file" ]]; then
if [[ "$first" == true ]]; then
first=false
else
echo "," >> "$validation_report"
fi
local label
local program
local exists="false"
local executable="false"
label=$(defaults read "$plist_file" Label 2>/dev/null || echo "Unknown")
program=$(defaults read "$plist_file" Program 2>/dev/null || echo "Unknown")
if [[ -f "$program" ]]; then
exists="true"
if [[ -x "$program" ]]; then
executable="true"
valid_count=$((valid_count + 1))
else
invalid_count=$((invalid_count + 1))
invalid_apps+=("$label")
fi
else
invalid_count=$((invalid_count + 1))
invalid_apps+=("$label")
fi
cat >> "$validation_report" << EOF
{
"label": "$label",
"program": "$program",
"file_exists": $exists,
"executable": $executable,
"valid": $([ "$exists" = "true" ] && [ "$executable" = "true" ] && echo "true" || echo "false")
}
EOF
fi
done
cat >> "$validation_report" << EOF
],
"validation_summary": {
"total_agents": $((valid_count + invalid_count)),
"valid_agents": $valid_count,
"invalid_agents": $invalid_count
}
}
EOF
log_action "✅ Validation completed: $valid_count valid, $invalid_count invalid"
log_action "Validation report: $validation_report"
if [[ $invalid_count -gt 0 ]]; then
log_action "Invalid applications found: ${invalid_apps[*]}"
fi
echo "$validation_report"
}
# Clean up invalid or orphaned LaunchAgents
cleanup_launch_agents() {
log_action "Cleaning up invalid LaunchAgents"
local cleanup_count=0
local cleanup_report="$CONFIG_DIR/cleanup_report_$(date '+%Y%m%d_%H%M%S').txt"
echo "MacFleet LaunchAgent Cleanup Report" > "$cleanup_report"
echo "Generated: $(date)" >> "$cleanup_report"
echo "======================================" >> "$cleanup_report"
for plist_file in "$LAUNCH_AGENTS_DIR"/com.macfleet.*.plist; do
if [[ -f "$plist_file" ]]; then
local program
program=$(defaults read "$plist_file" Program 2>/dev/null || echo "")
if [[ -n "$program" ]] && [[ ! -x "$program" ]]; then
local label
label=$(defaults read "$plist_file" Label 2>/dev/null || echo "Unknown")
log_action "Removing invalid LaunchAgent: $label"
echo "Removed: $label ($program not found/executable)" >> "$cleanup_report"
# Unload if loaded
launchctl unload "$plist_file" 2>/dev/null || true
# Remove file
rm -f "$plist_file"
cleanup_count=$((cleanup_count + 1))
fi
fi
done
echo "Total cleaned up: $cleanup_count" >> "$cleanup_report"
log_action "✅ Cleanup completed: $cleanup_count agents removed"
echo "$cleanup_report"
}
# Test application launch
test_app_launch() {
local app_name="$1"
local plist_name="com.macfleet.${app_name// /_}.plist"
local plist_path="$LAUNCH_AGENTS_DIR/$plist_name"
if [[ ! -f "$plist_path" ]]; then
log_action "❌ LaunchAgent not found: $plist_name"
return 1
fi
log_action "Testing application launch: $app_name"
# Load the LaunchAgent
if launchctl load "$plist_path" 2>/dev/null; then
log_action "✅ LaunchAgent loaded successfully"
# Wait a moment and check if process is running
sleep 2
if pgrep -f "$app_name" >/dev/null; then
log_action "✅ Application is running: $app_name"
return 0
else
log_action "⚠️ Application may not have started properly"
return 1
fi
else
log_action "❌ Failed to load LaunchAgent"
return 1
fi
}
# Main execution function
main() {
local action="${1:-list}"
local profile_name="$2"
local username="$3"
log_action "=== MacFleet App Launch Management Started ==="
log_action "Action: $action"
log_action "Profile: ${profile_name:-N/A}"
log_action "User: ${username:-$(whoami)}"
# Setup
setup_directories
case "$action" in
"deploy")
if [[ -z "$profile_name" ]]; then
echo "Available profiles:"
for profile in "${!USER_PROFILES[@]}"; do
echo " - $profile: ${USER_PROFILES[$profile]}"
done
echo ""
echo "Usage: $0 deploy <profile_name> [username]"
exit 1
fi
deploy_user_profile "$profile_name" "$username"
;;
"list")
list_configured_apps
;;
"validate")
validate_all_apps
;;
"cleanup")
cleanup_launch_agents
;;
"test")
if [[ -z "$profile_name" ]]; then
echo "Usage: $0 test <app_name>"
exit 1
fi
test_app_launch "$profile_name"
;;
"remove")
if [[ -z "$profile_name" ]]; then
echo "Usage: $0 remove <app_name>"
exit 1
fi
remove_launch_agent "$profile_name"
;;
"backup")
backup_launch_agents
;;
*)
echo "Usage: $0 {deploy|list|validate|cleanup|test|remove|backup}"
echo " deploy - Deploy user profile applications"
echo " list - List configured LaunchAgents"
echo " validate - Validate all configured applications"
echo " cleanup - Remove invalid LaunchAgents"
echo " test - Test specific application launch"
echo " remove - Remove specific LaunchAgent"
echo " backup - Backup current LaunchAgents"
exit 1
;;
esac
log_action "=== App launch management completed ==="
}
# Execute main function
main "$@"
Advanced LaunchAgent Configuration
Conditional App Launch
#!/bin/bash
# Create conditional LaunchAgent based on system state
create_conditional_launch_agent() {
local app_name="$1"
local app_path="$2"
local condition="$3" # network, power, time
local plist_name="com.macfleet.conditional.${app_name// /_}.plist"
cat > "/Library/LaunchAgents/${plist_name}" << EOF
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>${plist_name}</string>
<key>Program</key>
<string>${app_path}/Contents/MacOS/${app_name}</string>
<key>RunAtLoad</key>
<true/>
EOF
case "$condition" in
"network")
cat >> "/Library/LaunchAgents/${plist_name}" << EOF
<key>KeepAlive</key>
<dict>
<key>NetworkState</key>
<true/>
</dict>
EOF
;;
"power")
cat >> "/Library/LaunchAgents/${plist_name}" << EOF
<key>KeepAlive</key>
<dict>
<key>PowerManagement</key>
<true/>
</dict>
EOF
;;
"time")
cat >> "/Library/LaunchAgents/${plist_name}" << EOF
<key>StartCalendarInterval</key>
<dict>
<key>Hour</key>
<integer>9</integer>
<key>Minute</key>
<integer>0</integer>
</dict>
EOF
;;
esac
cat >> "/Library/LaunchAgents/${plist_name}" << EOF
</dict>
</plist>
EOF
echo "Conditional LaunchAgent created: $plist_name"
}
Resource-Aware App Launch
#!/bin/bash
# Create resource-aware LaunchAgent with throttling
create_resource_aware_agent() {
local app_name="$1"
local app_path="$2"
local cpu_limit="$3" # percentage
local memory_limit="$4" # MB
local plist_name="com.macfleet.resource.${app_name// /_}.plist"
cat > "/Library/LaunchAgents/${plist_name}" << EOF
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>${plist_name}</string>
<key>Program</key>
<string>${app_path}/Contents/MacOS/${app_name}</string>
<key>RunAtLoad</key>
<true/>
<key>ThrottleInterval</key>
<integer>60</integer>
<key>SoftResourceLimits</key>
<dict>
<key>CPU</key>
<integer>$cpu_limit</integer>
<key>Mem</key>
<integer>$((memory_limit * 1024 * 1024))</integer>
</dict>
<key>HardResourceLimits</key>
<dict>
<key>CPU</key>
<integer>$((cpu_limit + 10))</integer>
<key>Mem</key>
<integer>$((memory_limit * 1024 * 1024 * 2))</integer>
</dict>
</dict>
</plist>
EOF
echo "Resource-aware LaunchAgent created: $plist_name"
}
User Profile Management
Dynamic Profile Assignment
#!/bin/bash
# Assign profile based on user attributes
assign_user_profile() {
local username="$1"
# Get user information
local user_groups
user_groups=$(groups "$username" 2>/dev/null)
# Determine profile based on group membership
if [[ "$user_groups" =~ developer|engineering ]]; then
echo "developer"
elif [[ "$user_groups" =~ design|creative ]]; then
echo "designer"
elif [[ "$user_groups" =~ manager|executive ]]; then
echo "manager"
elif [[ "$user_groups" =~ security|admin ]]; then
echo "security"
else
echo "default"
fi
}
# Auto-configure user on first login
auto_configure_user() {
local username="$(whoami)"
local assigned_profile
assigned_profile=$(assign_user_profile "$username")
echo "Auto-configuring user: $username"
echo "Assigned profile: $assigned_profile"
# Deploy profile
deploy_user_profile "$assigned_profile" "$username"
}
Profile Templates
#!/bin/bash
# Create custom profile template
create_profile_template() {
local template_name="$1"
local template_file="$CONFIG_DIR/profiles/${template_name}.json"
mkdir -p "$(dirname "$template_file")"
cat > "$template_file" << EOF
{
"profile_name": "$template_name",
"description": "Custom profile template",
"applications": [
{
"name": "Application Name",
"path": "/Applications/App.app",
"required": true,
"delay": 0,
"conditions": []
}
],
"settings": {
"auto_update": true,
"notifications": true,
"logging": true
}
}
EOF
echo "Profile template created: $template_file"
}
Security and Validation
Application Security Verification
#!/bin/bash
# Verify application security before launch
verify_app_security() {
local app_path="$1"
echo "=== Application Security Verification ==="
# Check code signature
if codesign -v "$app_path" 2>/dev/null; then
echo "✅ Code signature valid"
else
echo "❌ Code signature invalid or missing"
return 1
fi
# Check notarization
if spctl -a -v "$app_path" 2>/dev/null | grep -q "accepted"; then
echo "✅ Application notarized"
else
echo "⚠️ Application not notarized"
fi
# Check quarantine attributes
if xattr -l "$app_path" | grep -q "com.apple.quarantine"; then
echo "⚠️ Application has quarantine attribute"
else
echo "✅ No quarantine attributes"
fi
# Check for suspicious characteristics
local info_plist="${app_path}/Contents/Info.plist"
if [[ -f "$info_plist" ]]; then
local bundle_id
bundle_id=$(defaults read "$info_plist" CFBundleIdentifier 2>/dev/null)
echo "Bundle ID: $bundle_id"
# Check for suspicious bundle identifiers
if [[ "$bundle_id" =~ (malware|hack|crack) ]]; then
echo "❌ Suspicious bundle identifier detected"
return 1
fi
fi
echo "✅ Security verification completed"
return 0
}
Enterprise Compliance Checks
#!/bin/bash
# Check enterprise compliance requirements
check_enterprise_compliance() {
local app_path="$1"
echo "=== Enterprise Compliance Check ==="
# Check if app is in approved list
local approved_apps_file="/etc/macfleet/approved_apps.txt"
if [[ -f "$approved_apps_file" ]]; then
local app_name
app_name=$(basename "$app_path" .app)
if grep -q "^$app_name$" "$approved_apps_file"; then
echo "✅ Application is in approved list"
else
echo "❌ Application not in approved list"
return 1
fi
fi
# Check for enterprise certificates
local cert_info
cert_info=$(codesign -dv "$app_path" 2>&1)
if echo "$cert_info" | grep -q "Developer ID\|Mac App Store"; then
echo "✅ Valid developer certificate"
else
echo "⚠️ No valid developer certificate"
fi
return 0
}
Monitoring and Maintenance
Launch Success Monitoring
#!/bin/bash
# Monitor application launch success
monitor_launch_success() {
local monitoring_log="/var/log/macfleet_launch_monitoring.log"
echo "=== Launch Success Monitoring ===" | tee -a "$monitoring_log"
echo "Timestamp: $(date)" | tee -a "$monitoring_log"
# Check each configured LaunchAgent
for plist_file in "$LAUNCH_AGENTS_DIR"/com.macfleet.*.plist; do
if [[ -f "$plist_file" ]]; then
local label
local program
label=$(defaults read "$plist_file" Label 2>/dev/null)
program=$(defaults read "$plist_file" Program 2>/dev/null)
# Check if application is running
local app_name
app_name=$(basename "$program")
if pgrep -f "$app_name" >/dev/null; then
echo "✅ $label: Running" | tee -a "$monitoring_log"
else
echo "❌ $label: Not running" | tee -a "$monitoring_log"
# Try to restart
launchctl unload "$plist_file" 2>/dev/null
launchctl load "$plist_file" 2>/dev/null
echo "🔄 Attempted restart for $label" | tee -a "$monitoring_log"
fi
fi
done
}
Automated Maintenance
#!/bin/bash
# Setup automated maintenance
setup_maintenance_schedule() {
local maintenance_script="/usr/local/bin/macfleet_app_maintenance.sh"
local launchd_plist="/Library/LaunchDaemons/com.macfleet.app.maintenance.plist"
# Create maintenance script
cat > "$maintenance_script" << 'EOF'
#!/bin/bash
LOG_FILE="/var/log/macfleet_app_maintenance.log"
exec > >(tee -a "$LOG_FILE") 2>&1
echo "$(date): Starting application maintenance"
# Validate all apps
/usr/local/bin/macfleet_app_manager.sh validate
# Monitor launch success
monitor_launch_success
# Cleanup invalid agents
/usr/local/bin/macfleet_app_manager.sh cleanup
echo "$(date): Application maintenance completed"
EOF
chmod +x "$maintenance_script"
# Create LaunchDaemon for scheduled maintenance
cat > "$launchd_plist" << EOF
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.macfleet.app.maintenance</string>
<key>ProgramArguments</key>
<array>
<string>$maintenance_script</string>
</array>
<key>StartCalendarInterval</key>
<dict>
<key>Hour</key>
<integer>2</integer>
<key>Minute</key>
<integer>0</integer>
</dict>
<key>RunAtLoad</key>
<false/>
</dict>
</plist>
EOF
# Load the LaunchDaemon
sudo launchctl load "$launchd_plist"
echo "Automated maintenance configured"
echo "Script: $maintenance_script"
echo "Schedule: Daily at 2:00 AM"
}
Best Practices
🚀 Performance Optimization
- Stagger app launches to prevent resource contention
- Use resource limits to prevent system overload
- Monitor launch success and implement automatic restart
- Validate applications before deployment
🔐 Security Guidelines
- Verify code signatures before allowing automatic launch
- Maintain approved app lists for enterprise compliance
- Use secure paths and avoid user-writable locations
- Regular security audits of configured applications
📋 Management Best Practices
- Profile-based deployment for different user types
- Centralized configuration management
- Regular backup of LaunchAgent configurations
- Automated monitoring and maintenance
🔍 Troubleshooting Tips
- Check application paths and executables
- Verify LaunchAgent syntax using plutil
- Monitor system logs for launch errors
- Test configurations before fleet deployment
Important Notes
- LaunchAgents run per-user while LaunchDaemons run system-wide
- Applications must be properly signed for enterprise deployment
- Resource limits help prevent system performance issues
- Regular validation ensures continued functionality
- Backup configurations before making changes