Tutorial

New updates and improvements to Macfleet.

File Protection on macOS

Protect critical files and applications across your MacFleet devices using advanced file protection techniques, immutable flags, and enterprise security policies. This tutorial provides comprehensive tools for implementing organizational file security standards.

Understanding macOS File Protection Methods

macOS offers several file protection mechanisms:

  • Immutable Flags - System-level protection preventing modification or deletion
  • File Permissions - User and group-based access controls
  • Extended Attributes - Additional metadata for security enforcement
  • System Integrity Protection (SIP) - Built-in protection for system files

Basic File Protection Commands

Lock Single File

#!/bin/bash

# Lock a file using immutable flag
FILE_PATH="/Applications/WhatsApp.app"

chflags schg "$FILE_PATH"
echo "File locked: $FILE_PATH"

Unlock Single File

#!/bin/bash

# Unlock a file by removing immutable flag
FILE_PATH="/Applications/WhatsApp.app"

chflags noschg "$FILE_PATH"
echo "File unlocked: $FILE_PATH"

Check File Protection Status

#!/bin/bash

# Check if file is protected
FILE_PATH="/Applications/WhatsApp.app"

if ls -lO "$FILE_PATH" | grep -q "schg"; then
    echo "File is protected: $FILE_PATH"
else
    echo "File is not protected: $FILE_PATH"
fi

Enterprise File Protection System

#!/bin/bash

# MacFleet Enterprise File Protection System
# Comprehensive file security and protection management

# Configuration
MACFLEET_DIR="/etc/macfleet"
POLICIES_DIR="$MACFLEET_DIR/file_policies"
REPORTS_DIR="$MACFLEET_DIR/reports"
COMPLIANCE_DIR="$MACFLEET_DIR/compliance"
AUDIT_DIR="$MACFLEET_DIR/audit"
LOG_FILE="/var/log/macfleet_file_protection.log"
BACKUP_DIR="$MACFLEET_DIR/backups"

# Create directory structure
create_directories() {
    local dirs=("$MACFLEET_DIR" "$POLICIES_DIR" "$REPORTS_DIR" "$COMPLIANCE_DIR" "$AUDIT_DIR" "$BACKUP_DIR")
    for dir in "${dirs[@]}"; do
        [[ ! -d "$dir" ]] && mkdir -p "$dir"
    done
}

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

# File Categories for Enterprise Protection
declare -A FILE_CATEGORIES=(
    ["critical_apps"]="/Applications/System Preferences.app,/Applications/Terminal.app,/Applications/Utilities"
    ["business_apps"]="/Applications/Microsoft Office,/Applications/Slack.app,/Applications/Zoom.app"
    ["system_configs"]="/etc/hosts,/etc/sudoers,/etc/ssh/sshd_config"
    ["security_tools"]="/Applications/1Password.app,/Applications/Keychain Access.app"
    ["development_tools"]="/Applications/Xcode.app,/Applications/Visual Studio Code.app"
    ["admin_utilities"]="/Applications/Activity Monitor.app,/Applications/Console.app"
)

# Protection Levels
declare -A PROTECTION_LEVELS=(
    ["maximum"]="schg,uappnd,uchg"        # System immutable, user append-only, user immutable
    ["high"]="schg,uchg"                  # System immutable, user immutable
    ["moderate"]="uchg"                   # User immutable only
    ["minimal"]="uappnd"                  # User append-only
    ["readonly"]="ro"                     # Read-only access
)

# Security Policies
declare -A SECURITY_POLICIES=(
    ["enterprise_lockdown"]="critical_apps:maximum,business_apps:high,system_configs:maximum,security_tools:high"
    ["standard_protection"]="critical_apps:high,system_configs:high,security_tools:moderate"
    ["development_safe"]="critical_apps:moderate,system_configs:high,development_tools:minimal"
    ["minimal_security"]="system_configs:moderate,security_tools:minimal"
    ["maintenance_mode"]="system_configs:readonly"
)

# Apply protection to file or directory
protect_file() {
    local file_path="$1"
    local protection_level="$2"
    local policy="$3"
    
    if [[ ! -e "$file_path" ]]; then
        log_action "ERROR: File not found: $file_path"
        return 1
    fi
    
    # Backup current flags
    local current_flags=$(ls -lO "$file_path" 2>/dev/null | awk '{print $5}' || echo "none")
    echo "$file_path:$current_flags:$(date)" >> "$BACKUP_DIR/file_flags_backup.log"
    
    # Apply protection based on level
    local flags="${PROTECTION_LEVELS[$protection_level]}"
    if [[ -z "$flags" ]]; then
        log_action "ERROR: Unknown protection level: $protection_level"
        return 1
    fi
    
    # Split flags and apply each one
    IFS=',' read -ra flag_array <<< "$flags"
    for flag in "${flag_array[@]}"; do
        if chflags "$flag" "$file_path" 2>/dev/null; then
            log_action "Applied protection flag '$flag' to: $file_path (Policy: $policy)"
        else
            log_action "ERROR: Failed to apply flag '$flag' to: $file_path"
        fi
    done
    
    # Set restrictive permissions if needed
    if [[ "$protection_level" == "maximum" || "$protection_level" == "high" ]]; then
        chmod 644 "$file_path" 2>/dev/null
        log_action "Set restrictive permissions for: $file_path"
    fi
    
    # Save protection metadata
    echo "file=$file_path,protection=$protection_level,policy=$policy,timestamp=$(date),user=$(whoami)" >> "$POLICIES_DIR/applied_protections.log"
}

# Remove protection from file
unprotect_file() {
    local file_path="$1"
    local reason="$2"
    
    if [[ ! -e "$file_path" ]]; then
        log_action "ERROR: File not found: $file_path"
        return 1
    fi
    
    # Remove all common protection flags
    local flags_to_remove=("schg" "uchg" "uappnd" "ro")
    
    for flag in "${flags_to_remove[@]}"; do
        if chflags "no$flag" "$file_path" 2>/dev/null; then
            log_action "Removed protection flag '$flag' from: $file_path (Reason: $reason)"
        fi
    done
    
    # Restore standard permissions
    if [[ -f "$file_path" ]]; then
        chmod 644 "$file_path" 2>/dev/null
    elif [[ -d "$file_path" ]]; then
        chmod 755 "$file_path" 2>/dev/null
    fi
    
    log_action "File unprotected: $file_path (Reason: $reason)"
}

# Apply protection to file category
protect_category() {
    local category="$1"
    local protection_level="$2"
    local policy="$3"
    
    if [[ -z "${FILE_CATEGORIES[$category]}" ]]; then
        log_action "ERROR: Unknown file category: $category"
        return 1
    fi
    
    log_action "Protecting category: $category with level: $protection_level (Policy: $policy)"
    
    # Split comma-separated file paths
    IFS=',' read -ra files <<< "${FILE_CATEGORIES[$category]}"
    
    for file_path in "${files[@]}"; do
        # Handle wildcard patterns
        if [[ "$file_path" == *"*"* ]]; then
            # Use find for pattern matching
            find "${file_path%/*}" -name "${file_path##*/}" 2>/dev/null | while read -r found_file; do
                protect_file "$found_file" "$protection_level" "$policy"
            done
        else
            protect_file "$file_path" "$protection_level" "$policy"
        fi
    done
}

# Apply comprehensive security policy
apply_security_policy() {
    local policy="$1"
    
    if [[ -z "${SECURITY_POLICIES[$policy]}" ]]; then
        log_action "ERROR: Unknown security policy: $policy"
        return 1
    fi
    
    log_action "Applying security policy: $policy"
    
    # Parse policy string: "category:level,category:level"
    IFS=',' read -ra policy_items <<< "${SECURITY_POLICIES[$policy]}"
    
    for item in "${policy_items[@]}"; do
        IFS=':' read -ra parts <<< "$item"
        local category="${parts[0]}"
        local protection_level="${parts[1]}"
        
        protect_category "$category" "$protection_level" "$policy"
    done
    
    log_action "Security policy '$policy' applied successfully"
    
    # Generate compliance report
    generate_compliance_report "$policy"
}

# Bulk file protection operations
bulk_protect_files() {
    local file_list="$1"
    local protection_level="$2"
    local policy="$3"
    
    if [[ ! -f "$file_list" ]]; then
        log_action "ERROR: File list not found: $file_list"
        return 1
    fi
    
    log_action "Starting bulk protection operation from list: $file_list"
    local protected_count=0
    local failed_count=0
    
    while IFS= read -r file_path; do
        [[ -z "$file_path" || "$file_path" =~ ^#.*$ ]] && continue
        
        if protect_file "$file_path" "$protection_level" "$policy"; then
            ((protected_count++))
        else
            ((failed_count++))
        fi
    done < "$file_list"
    
    log_action "Bulk protection completed: $protected_count protected, $failed_count failed"
}

# Critical system file protection
protect_system_files() {
    local protection_mode="$1"
    
    log_action "Applying system file protection: $protection_mode"
    
    # Define critical system files
    local critical_files=(
        "/etc/hosts"
        "/etc/sudoers"
        "/etc/ssh/sshd_config"
        "/etc/passwd"
        "/etc/group"
        "/System/Library/LaunchDaemons"
        "/Library/LaunchDaemons"
        "/usr/bin/sudo"
        "/bin/sh"
        "/bin/bash"
    )
    
    case "$protection_mode" in
        "lockdown")
            for file in "${critical_files[@]}"; do
                if [[ -e "$file" ]]; then
                    protect_file "$file" "maximum" "system_lockdown"
                fi
            done
            ;;
        "standard")
            for file in "${critical_files[@]}"; do
                if [[ -e "$file" ]]; then
                    protect_file "$file" "high" "system_standard"
                fi
            done
            ;;
        "minimal")
            for file in "${critical_files[@]}"; do
                if [[ -e "$file" ]]; then
                    protect_file "$file" "moderate" "system_minimal"
                fi
            done
            ;;
    esac
    
    log_action "System file protection applied: $protection_mode"
}

# File integrity monitoring
monitor_file_integrity() {
    local monitoring_mode="$1"
    local monitor_file="$POLICIES_DIR/integrity_monitor.log"
    
    log_action "Starting file integrity monitoring: $monitoring_mode"
    
    # Get list of protected files
    local protected_files=()
    if [[ -f "$POLICIES_DIR/applied_protections.log" ]]; then
        while IFS=',' read -r entry; do
            if [[ "$entry" =~ file=([^,]+) ]]; then
                protected_files+=("${BASH_REMATCH[1]}")
            fi
        done < "$POLICIES_DIR/applied_protections.log"
    fi
    
    # Monitor files for changes
    for file in "${protected_files[@]}"; do
        if [[ -e "$file" ]]; then
            local current_hash=$(shasum -a 256 "$file" 2>/dev/null | cut -d' ' -f1)
            local current_flags=$(ls -lO "$file" 2>/dev/null | awk '{print $5}' || echo "none")
            local timestamp=$(date -u +%Y-%m-%dT%H:%M:%SZ)
            
            echo "$timestamp:$file:$current_hash:$current_flags" >> "$monitor_file"
        fi
    done
    
    log_action "File integrity monitoring completed: $monitoring_mode"
}

# Emergency unlock procedures
emergency_unlock() {
    local reason="$1"
    local unlock_scope="$2"
    
    log_action "EMERGENCY UNLOCK INITIATED - Reason: $reason, Scope: $unlock_scope"
    
    case "$unlock_scope" in
        "all")
            # Unlock all protected files
            if [[ -f "$POLICIES_DIR/applied_protections.log" ]]; then
                while IFS=',' read -r entry; do
                    if [[ "$entry" =~ file=([^,]+) ]]; then
                        unprotect_file "${BASH_REMATCH[1]}" "emergency_unlock"
                    fi
                done < "$POLICIES_DIR/applied_protections.log"
            fi
            ;;
        "system")
            # Unlock only system files
            local system_files=("/etc/hosts" "/etc/sudoers" "/etc/ssh/sshd_config")
            for file in "${system_files[@]}"; do
                if [[ -e "$file" ]]; then
                    unprotect_file "$file" "emergency_system_unlock"
                fi
            done
            ;;
        "applications")
            # Unlock application files
            find /Applications -name "*.app" -exec chflags noschg {} \; 2>/dev/null
            log_action "Emergency unlock completed for applications"
            ;;
    esac
    
    # Create emergency unlock record
    echo "emergency_unlock:$reason:$unlock_scope:$(date):$(whoami)" >> "$AUDIT_DIR/emergency_operations.log"
    log_action "Emergency unlock completed: $unlock_scope"
}

# Generate comprehensive compliance report
generate_compliance_report() {
    local policy="$1"
    local report_file="$REPORTS_DIR/file_protection_compliance_$(date +%Y%m%d_%H%M%S).json"
    
    local protected_files_count=0
    local total_files_checked=0
    
    # Count protected files
    if [[ -f "$POLICIES_DIR/applied_protections.log" ]]; then
        protected_files_count=$(wc -l < "$POLICIES_DIR/applied_protections.log")
    fi
    
    # Count total files in categories
    for category in "${!FILE_CATEGORIES[@]}"; do
        IFS=',' read -ra files <<< "${FILE_CATEGORIES[$category]}"
        total_files_checked=$((total_files_checked + ${#files[@]}))
    done
    
    cat > "$report_file" << EOF
{
  "report_metadata": {
    "timestamp": "$(date -u +%Y-%m-%dT%H:%M:%SZ)",
    "hostname": "$(hostname)",
    "policy_applied": "$policy",
    "report_version": "1.0"
  },
  "file_protection_status": {
    "protected_files_count": $protected_files_count,
    "total_files_checked": $total_files_checked,
    "protection_coverage": $(echo "scale=2; $protected_files_count * 100 / $total_files_checked" | bc -l 2>/dev/null || echo "0"),
    "emergency_unlocks_recorded": $([ -f "$AUDIT_DIR/emergency_operations.log" ] && wc -l < "$AUDIT_DIR/emergency_operations.log" || echo "0")
  },
  "security_policy": {
    "name": "$policy",
    "categories_protected": $(echo "${!FILE_CATEGORIES[@]}" | wc -w),
    "compliance_frameworks": ["SOX", "HIPAA", "NIST", "ISO27001", "PCI-DSS"]
  },
  "system_status": {
    "sip_enabled": $(csrutil status | grep -q "enabled" && echo "true" || echo "false"),
    "gatekeeper_enabled": $(spctl --status | grep -q "enabled" && echo "true" || echo "false"),
    "filevault_enabled": $(fdesetup status | grep -q "On" && echo "true" || echo "false"),
    "backup_available": $([ -f "$BACKUP_DIR/file_flags_backup.log" ] && echo "true" || echo "false")
  },
  "integrity_monitoring": {
    "active": $([ -f "$POLICIES_DIR/integrity_monitor.log" ] && echo "true" || echo "false"),
    "last_check": "$(date -u +%Y-%m-%dT%H:%M:%SZ)",
    "monitored_files": $([ -f "$POLICIES_DIR/integrity_monitor.log" ] && wc -l < "$POLICIES_DIR/integrity_monitor.log" || echo "0")
  }
}
EOF
    
    log_action "Compliance report generated: $report_file"
    echo "Report saved to: $report_file"
}

# Health check and validation
perform_health_check() {
    echo "=== MacFleet File Protection Health Check ==="
    
    # Check system integrity protection
    local sip_status=$(csrutil status 2>/dev/null || echo "Unknown")
    echo "✓ System Integrity Protection: $sip_status"
    
    # Check protected files
    local protected_count=0
    if [[ -f "$POLICIES_DIR/applied_protections.log" ]]; then
        protected_count=$(wc -l < "$POLICIES_DIR/applied_protections.log")
    fi
    echo "✓ Protected files: $protected_count"
    
    # Check critical system files
    local critical_protected=0
    local critical_files=("/etc/hosts" "/etc/sudoers" "/etc/ssh/sshd_config")
    for file in "${critical_files[@]}"; do
        if [[ -e "$file" ]] && ls -lO "$file" | grep -q "schg"; then
            ((critical_protected++))
        fi
    done
    echo "✓ Critical system files protected: $critical_protected/${#critical_files[@]}"
    
    # Check backup availability
    if [[ -f "$BACKUP_DIR/file_flags_backup.log" ]]; then
        local backup_entries=$(wc -l < "$BACKUP_DIR/file_flags_backup.log")
        echo "✓ Backup entries: $backup_entries"
    else
        echo "○ No backup records found"
    fi
    
    # Check integrity monitoring
    if [[ -f "$POLICIES_DIR/integrity_monitor.log" ]]; then
        local monitor_entries=$(wc -l < "$POLICIES_DIR/integrity_monitor.log")
        echo "✓ Integrity monitoring entries: $monitor_entries"
    else
        echo "○ No integrity monitoring active"
    fi
    
    # Check for emergency operations
    if [[ -f "$AUDIT_DIR/emergency_operations.log" ]]; then
        local emergency_count=$(wc -l < "$AUDIT_DIR/emergency_operations.log")
        echo "⚠️  Emergency operations recorded: $emergency_count"
    else
        echo "✓ No emergency operations recorded"
    fi
}

# Fleet deployment function
deploy_to_fleet() {
    local policy="$1"
    local fleet_file="$2"
    
    if [[ ! -f "$fleet_file" ]]; then
        log_action "ERROR: Fleet file not found: $fleet_file"
        return 1
    fi
    
    log_action "Starting fleet deployment of policy: $policy"
    
    while IFS= read -r host; do
        [[ -z "$host" || "$host" =~ ^#.*$ ]] && continue
        
        echo "Deploying to: $host"
        
        # Copy this script to remote host and execute
        ssh "$host" "bash -s" << EOF
#!/bin/bash
# Remote deployment of file protection policy: $policy

# Create directories
mkdir -p /etc/macfleet/{file_policies,reports,compliance,audit,backups}

# Apply the policy (simplified for remote execution)
$(declare -p FILE_CATEGORIES)
$(declare -p PROTECTION_LEVELS)
$(declare -p SECURITY_POLICIES)
$(type apply_security_policy | sed '1d')

apply_security_policy "$policy"
EOF
        
        if [[ $? -eq 0 ]]; then
            log_action "Successfully deployed to: $host"
        else
            log_action "Failed to deploy to: $host"
        fi
        
    done < "$fleet_file"
    
    log_action "Fleet deployment completed"
}

# Main execution function
main() {
    create_directories
    
    case "${1:-}" in
        "apply_policy")
            apply_security_policy "$2"
            ;;
        "protect_file")
            protect_file "$2" "${3:-moderate}" "manual"
            ;;
        "unprotect_file")
            unprotect_file "$2" "${3:-manual_unlock}"
            ;;
        "protect_category")
            protect_category "$2" "${3:-moderate}" "manual"
            ;;
        "bulk_protect")
            bulk_protect_files "$2" "${3:-moderate}" "bulk_operation"
            ;;
        "protect_system")
            protect_system_files "${2:-standard}"
            ;;
        "monitor_integrity")
            monitor_file_integrity "${2:-standard}"
            ;;
        "emergency_unlock")
            emergency_unlock "${2:-manual}" "${3:-all}"
            ;;
        "health_check")
            perform_health_check
            ;;
        "report")
            generate_compliance_report "${2:-manual}"
            ;;
        "deploy")
            deploy_to_fleet "$2" "$3"
            ;;
        "help"|*)
            echo "MacFleet Enterprise File Protection System"
            echo ""
            echo "Usage: $0 <command> [options]"
            echo ""
            echo "Commands:"
            echo "  apply_policy <policy>           - Apply security policy (enterprise_lockdown|standard_protection|development_safe|minimal_security|maintenance_mode)"
            echo "  protect_file <path> [level]     - Protect single file (maximum|high|moderate|minimal|readonly)"
            echo "  unprotect_file <path> [reason]  - Remove protection from file"
            echo "  protect_category <category> [level] - Protect file category (critical_apps|business_apps|system_configs|security_tools|development_tools|admin_utilities)"
            echo "  bulk_protect <file_list> [level] - Protect files from list"
            echo "  protect_system [mode]           - Protect system files (lockdown|standard|minimal)"
            echo "  monitor_integrity [mode]        - Monitor file integrity (standard|strict)"
            echo "  emergency_unlock <reason> [scope] - Emergency unlock (all|system|applications)"
            echo "  health_check                    - Perform system health check"
            echo "  report [policy]                 - Generate compliance report"
            echo "  deploy <policy> <fleet_file>    - Deploy policy to fleet"
            echo ""
            echo "Examples:"
            echo "  $0 apply_policy enterprise_lockdown"
            echo "  $0 protect_file /Applications/Terminal.app maximum"
            echo "  $0 protect_system lockdown"
            echo "  $0 emergency_unlock 'maintenance required' system"
            echo "  $0 health_check"
            ;;
    esac
}

# Execute main function
main "$@"

Protection Levels Explained

LevelDescriptionFlags AppliedUse Case
MaximumComplete system protectionschg, uappnd, uchgCritical system files
HighStrong user protectionschg, uchgImportant applications
ModerateStandard user protectionuchgBusiness applications
MinimalBasic append protectionuappndLog files, databases
Read-onlyPrevent modificationsroConfiguration templates

File Protection Use Cases

Protect Critical Applications

# Protect system utilities from modification
./file_protection.sh protect_category critical_apps maximum

# Protect business applications
./file_protection.sh protect_category business_apps high

System Configuration Protection

# Lock down system configuration files
./file_protection.sh protect_system lockdown

# Standard system protection
./file_protection.sh protect_system standard

Development Environment Safety

# Apply development-safe policy
./file_protection.sh apply_policy development_safe

# Protect development tools with minimal restrictions
./file_protection.sh protect_category development_tools minimal

Emergency Procedures

Complete System Unlock

# Emergency unlock all files
./file_protection.sh emergency_unlock "critical_maintenance" all

# Unlock only system files
./file_protection.sh emergency_unlock "system_update" system

File Recovery

# Check protection status
ls -lO /Applications/Terminal.app

# Remove specific protection
./file_protection.sh unprotect_file /Applications/Terminal.app "maintenance"

Important Security Considerations

  • System Integrity Protection (SIP) provides additional layer beyond file flags
  • Root privileges required for system immutable flags (schg)
  • Backup protection state before making changes
  • Emergency procedures should be tested and documented
  • File integrity monitoring helps detect unauthorized changes

Compliance and Auditing

The enterprise system provides comprehensive audit trails for:

  • SOX Compliance - Financial data protection requirements
  • HIPAA Requirements - Healthcare information security
  • PCI-DSS Standards - Payment card industry data security
  • NIST Framework - Cybersecurity standards compliance
  • ISO 27001 - Information security management

Testing and Validation

Before enterprise deployment:

  1. Test protection levels on non-critical files first
  2. Verify emergency unlock procedures work correctly
  3. Confirm business applications remain functional
  4. Test integrity monitoring accuracy
  5. Validate compliance reporting completeness

This comprehensive system transforms basic file locking into an enterprise-grade protection platform with advanced security policies, compliance monitoring, and fleet management capabilities.

File Ownership Management on macOS

Master file and folder ownership operations on your MacFleet devices using powerful command-line tools. This tutorial covers ownership changes, permission management, group assignments, and advanced ownership policies for secure file system administration.

Understanding macOS File Ownership

macOS file ownership system consists of several key concepts:

  • Owner (User) - The user who owns the file/folder and has primary control
  • Group - A collection of users who share specific permissions
  • Others - All other users on the system
  • Permissions - Read (r), Write (w), Execute (x) permissions for each category

Basic File Ownership Operations

Change File Owner

#!/bin/bash

# Change ownership of a specific file
USERNAME="Daniel"
FILE_PATH="/Users/Alex/Desktop/Dustin"

chown "$USERNAME" "$FILE_PATH"

echo "File ownership changed to $USERNAME successfully"

Change Folder Owner

#!/bin/bash

# Change ownership of a folder
USERNAME="Daniel"
FOLDER_PATH="/Users/Alex/Desktop/ProjectFolder"

chown "$USERNAME" "$FOLDER_PATH"

echo "Folder ownership changed to $USERNAME successfully"

Recursive Ownership Change

#!/bin/bash

# Change ownership recursively for all files and subfolders
USERNAME="Daniel"
FOLDER_PATH="/Users/Alex/Desktop/ProjectFolder"

chown -R "$USERNAME" "$FOLDER_PATH"

echo "Recursive ownership change completed for $USERNAME"

Advanced Ownership Management

Change Owner and Group

#!/bin/bash

# Change both owner and group
USERNAME="Daniel"
GROUPNAME="developers"
FILE_PATH="/Users/Alex/Desktop/project.txt"

chown "$USERNAME:$GROUPNAME" "$FILE_PATH"

echo "Ownership changed to $USERNAME:$GROUPNAME"

Ownership with Permission Verification

#!/bin/bash

# Change ownership and verify permissions
change_ownership_safe() {
    local username="$1"
    local file_path="$2"
    
    # Verify file exists
    if [[ ! -e "$file_path" ]]; then
        echo "Error: File or folder not found: $file_path"
        return 1
    fi
    
    # Verify user exists
    if ! id "$username" &>/dev/null; then
        echo "Error: User '$username' does not exist"
        return 1
    fi
    
    # Get current ownership
    local current_owner=$(stat -f "%Su" "$file_path")
    echo "Current owner: $current_owner"
    
    # Change ownership
    if chown "$username" "$file_path"; then
        echo "Ownership successfully changed from $current_owner to $username"
        
        # Display new permissions
        echo "New permissions:"
        ls -la "$file_path"
        return 0
    else
        echo "Error: Failed to change ownership"
        return 1
    fi
}

# Usage example
change_ownership_safe "Daniel" "/Users/Alex/Desktop/document.txt"

Bulk Ownership Management

#!/bin/bash

# Change ownership for multiple files/folders
bulk_ownership_change() {
    local username="$1"
    shift
    local paths=("$@")
    
    echo "Starting bulk ownership change to user: $username"
    
    for path in "${paths[@]}"; do
        if [[ -e "$path" ]]; then
            if chown "$username" "$path"; then
                echo "✓ Changed ownership: $path"
            else
                echo "✗ Failed to change ownership: $path"
            fi
        else
            echo "✗ File not found: $path"
        fi
    done
    
    echo "Bulk ownership change completed"
}

# Usage example
bulk_ownership_change "Daniel" "/Users/Alex/Desktop/file1.txt" "/Users/Alex/Desktop/file2.txt" "/Users/Alex/Desktop/folder1"

Permission Management

Set Specific Permissions

#!/bin/bash

# Change ownership and set specific permissions
set_ownership_and_permissions() {
    local username="$1"
    local file_path="$2"
    local permissions="$3"
    
    echo "Setting ownership and permissions for: $file_path"
    
    # Change ownership
    chown "$username" "$file_path"
    
    # Set permissions
    chmod "$permissions" "$file_path"
    
    echo "Ownership: $username, Permissions: $permissions"
    ls -la "$file_path"
}

# Usage examples
set_ownership_and_permissions "Daniel" "/Users/Alex/Desktop/script.sh" "755"
set_ownership_and_permissions "Daniel" "/Users/Alex/Desktop/document.txt" "644"

Permission Analysis

#!/bin/bash

# Analyze current permissions and ownership
analyze_permissions() {
    local file_path="$1"
    
    if [[ ! -e "$file_path" ]]; then
        echo "File or folder not found: $file_path"
        return 1
    fi
    
    echo "=== Permission Analysis for: $file_path ==="
    
    # Get detailed information
    local owner=$(stat -f "%Su" "$file_path")
    local group=$(stat -f "%Sg" "$file_path")
    local permissions=$(stat -f "%Sp" "$file_path")
    local octal_permissions=$(stat -f "%A" "$file_path")
    local size=$(stat -f "%z" "$file_path")
    local modified=$(stat -f "%Sm" "$file_path")
    
    echo "Owner: $owner"
    echo "Group: $group"
    echo "Permissions: $permissions"
    echo "Octal: $octal_permissions"
    echo "Size: $size bytes"
    echo "Modified: $modified"
    
    # Check if writable by others
    if [[ "$permissions" =~ .*w.*w.*w.* ]]; then
        echo "⚠️  WARNING: File is world-writable"
    fi
    
    # Check if executable
    if [[ "$permissions" =~ .*x.* ]]; then
        echo "ℹ️  File is executable"
    fi
}

# Usage
analyze_permissions "/Users/Alex/Desktop/document.txt"

Enterprise Ownership Management System

#!/bin/bash

# MacFleet File Ownership Management Tool
# Comprehensive ownership and permission management for fleet devices

# Configuration
SCRIPT_VERSION="1.0.0"
LOG_FILE="/var/log/macfleet_ownership.log"
REPORT_DIR="/etc/macfleet/reports/ownership"
CONFIG_DIR="/etc/macfleet/ownership"
POLICY_DIR="$CONFIG_DIR/policies"

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

# Ownership categories for different file types
declare -A OWNERSHIP_CATEGORIES=(
    ["system_files"]="root:wheel"
    ["application_data"]="root:admin"
    ["user_documents"]="user:staff"
    ["shared_resources"]="shared:staff"
    ["development_files"]="developer:developer"
    ["web_content"]="www:www"
    ["log_files"]="root:wheel"
    ["configuration_files"]="root:wheel"
    ["temporary_files"]="user:staff"
    ["backup_files"]="backup:backup"
)

# Ownership policies for different security levels
declare -A OWNERSHIP_POLICIES=(
    ["public_access"]="644,755,user:staff,world_readable"
    ["restricted_access"]="600,700,user:staff,owner_only"
    ["shared_collaboration"]="664,775,user:staff,group_writable"
    ["system_secure"]="644,755,root:wheel,admin_managed"
    ["development_team"]="664,775,developer:developer,team_access"
    ["confidential_data"]="600,700,secure:secure,encrypted_required"
)

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

# User and group validation
validate_user_group() {
    local user="$1"
    local group="$2"
    
    # Check if user exists
    if ! id "$user" &>/dev/null; then
        log_action "ERROR: User '$user' does not exist"
        return 1
    fi
    
    # Check if group exists (if specified)
    if [[ -n "$group" ]] && ! dscl . -read /Groups/"$group" &>/dev/null; then
        log_action "ERROR: Group '$group' does not exist"
        return 1
    fi
    
    return 0
}

# Advanced ownership change with backup and rollback
change_ownership_advanced() {
    local target_path="$1"
    local new_owner="$2"
    local new_group="${3:-}"
    local recursive="${4:-false}"
    local backup_metadata="${5:-true}"
    
    log_action "Starting advanced ownership change: $target_path -> $new_owner:$new_group"
    
    if [[ ! -e "$target_path" ]]; then
        log_action "ERROR: Target path does not exist: $target_path"
        return 1
    fi
    
    # Validate user and group
    if ! validate_user_group "$new_owner" "$new_group"; then
        return 1
    fi
    
    # Create backup of current metadata
    local backup_file=""
    if [[ "$backup_metadata" == "true" ]]; then
        backup_file="$REPORT_DIR/ownership_backup_$(date +%Y%m%d_%H%M%S).json"
        create_ownership_backup "$target_path" "$backup_file" "$recursive"
    fi
    
    # Construct chown command
    local chown_target="$new_owner"
    if [[ -n "$new_group" ]]; then
        chown_target="$new_owner:$new_group"
    fi
    
    local chown_cmd="chown"
    if [[ "$recursive" == "true" ]]; then
        chown_cmd="chown -R"
    fi
    
    # Execute ownership change
    if $chown_cmd "$chown_target" "$target_path"; then
        log_action "SUCCESS: Ownership changed to $chown_target for $target_path"
        
        # Create post-change report
        local report_file="$REPORT_DIR/ownership_change_$(date +%Y%m%d_%H%M%S).json"
        create_ownership_report "$target_path" "$report_file" "$recursive"
        
        echo "$report_file"
        return 0
    else
        log_action "ERROR: Failed to change ownership for $target_path"
        return 1
    fi
}

# Create ownership backup
create_ownership_backup() {
    local target_path="$1"
    local backup_file="$2"
    local recursive="$3"
    
    cat > "$backup_file" << EOF
{
    "backup_info": {
        "target_path": "$target_path",
        "timestamp": "$(date -u +%Y-%m-%dT%H:%M:%SZ)",
        "hostname": "$(hostname)",
        "recursive": $recursive
    },
    "original_ownership": []
}
EOF
    
    if [[ "$recursive" == "true" ]]; then
        # Recursive backup
        find "$target_path" -exec stat -f '{"path":"%N","owner":"%Su","group":"%Sg","permissions":"%Sp","octal":"%A"}' {} \; | \
        jq -s '.' | \
        jq --slurpfile backup "$backup_file" '.backup_info = $backup[0].backup_info | .original_ownership = .' > "${backup_file}.tmp" && \
        mv "${backup_file}.tmp" "$backup_file"
    else
        # Single file backup
        local owner=$(stat -f "%Su" "$target_path")
        local group=$(stat -f "%Sg" "$target_path")
        local permissions=$(stat -f "%Sp" "$target_path")
        local octal=$(stat -f "%A" "$target_path")
        
        jq --arg path "$target_path" \
           --arg owner "$owner" \
           --arg group "$group" \
           --arg permissions "$permissions" \
           --arg octal "$octal" \
           '.original_ownership = [{"path": $path, "owner": $owner, "group": $group, "permissions": $permissions, "octal": $octal}]' \
           "$backup_file" > "${backup_file}.tmp" && mv "${backup_file}.tmp" "$backup_file"
    fi
    
    log_action "Ownership backup created: $backup_file"
}

# Create ownership report
create_ownership_report() {
    local target_path="$1"
    local report_file="$2"
    local recursive="$3"
    
    cat > "$report_file" << EOF
{
    "report_info": {
        "target_path": "$target_path",
        "timestamp": "$(date -u +%Y-%m-%dT%H:%M:%SZ)",
        "hostname": "$(hostname)",
        "recursive": $recursive,
        "script_version": "$SCRIPT_VERSION"
    },
    "current_ownership": [],
    "security_analysis": {},
    "recommendations": []
}
EOF
    
    # Get current ownership information
    if [[ "$recursive" == "true" ]]; then
        find "$target_path" -exec stat -f '{"path":"%N","owner":"%Su","group":"%Sg","permissions":"%Sp","octal":"%A","size":%z,"modified":"%Sm"}' {} \; | \
        jq -s '.' | \
        jq --slurpfile report "$report_file" '.report_info = $report[0].report_info | .current_ownership = .' > "${report_file}.tmp" && \
        mv "${report_file}.tmp" "$report_file"
    else
        local owner=$(stat -f "%Su" "$target_path")
        local group=$(stat -f "%Sg" "$target_path")
        local permissions=$(stat -f "%Sp" "$target_path")
        local octal=$(stat -f "%A" "$target_path")
        local size=$(stat -f "%z" "$target_path")
        local modified=$(stat -f "%Sm" "$target_path")
        
        jq --arg path "$target_path" \
           --arg owner "$owner" \
           --arg group "$group" \
           --arg permissions "$permissions" \
           --arg octal "$octal" \
           --arg size "$size" \
           --arg modified "$modified" \
           '.current_ownership = [{"path": $path, "owner": $owner, "group": $group, "permissions": $permissions, "octal": $octal, "size": $size, "modified": $modified}]' \
           "$report_file" > "${report_file}.tmp" && mv "${report_file}.tmp" "$report_file"
    fi
    
    # Perform security analysis
    perform_security_analysis "$target_path" "$report_file" "$recursive"
    
    log_action "Ownership report created: $report_file"
}

# Security analysis
perform_security_analysis() {
    local target_path="$1"
    local report_file="$2"
    local recursive="$3"
    
    local world_writable_count=0
    local world_readable_count=0
    local executable_count=0
    local setuid_count=0
    local security_issues=()
    
    if [[ "$recursive" == "true" ]]; then
        world_writable_count=$(find "$target_path" -type f -perm -002 2>/dev/null | wc -l)
        world_readable_count=$(find "$target_path" -type f -perm -004 2>/dev/null | wc -l)
        executable_count=$(find "$target_path" -type f -perm -111 2>/dev/null | wc -l)
        setuid_count=$(find "$target_path" -type f -perm -4000 2>/dev/null | wc -l)
    else
        local perms=$(stat -f "%A" "$target_path")
        [[ $((perms & 002)) -ne 0 ]] && world_writable_count=1
        [[ $((perms & 004)) -ne 0 ]] && world_readable_count=1
        [[ $((perms & 111)) -ne 0 ]] && executable_count=1
        [[ $((perms & 4000)) -ne 0 ]] && setuid_count=1
    fi
    
    # Identify security issues
    [[ $world_writable_count -gt 0 ]] && security_issues+=("World-writable files detected")
    [[ $setuid_count -gt 0 ]] && security_issues+=("SETUID files detected")
    
    # Update report with security analysis
    jq --argjson world_writable "$world_writable_count" \
       --argjson world_readable "$world_readable_count" \
       --argjson executable "$executable_count" \
       --argjson setuid "$setuid_count" \
       --argjson issues "$(printf '%s\n' "${security_issues[@]}" | jq -R . | jq -s .)" \
       '.security_analysis = {
           "world_writable_files": $world_writable,
           "world_readable_files": $world_readable,
           "executable_files": $executable,
           "setuid_files": $setuid,
           "security_issues": $issues
       }' "$report_file" > "${report_file}.tmp" && mv "${report_file}.tmp" "$report_file"
}

# Apply ownership policy
apply_ownership_policy() {
    local target_path="$1"
    local policy_name="$2"
    local recursive="${3:-false}"
    
    log_action "Applying ownership policy '$policy_name' to $target_path"
    
    if [[ -z "${OWNERSHIP_POLICIES[$policy_name]}" ]]; then
        log_action "ERROR: Unknown ownership policy: $policy_name"
        return 1
    fi
    
    # Parse policy
    IFS=',' read -ra POLICY_PARTS <<< "${OWNERSHIP_POLICIES[$policy_name]}"
    local file_perms="${POLICY_PARTS[0]}"
    local dir_perms="${POLICY_PARTS[1]}"
    local ownership="${POLICY_PARTS[2]}"
    local access_level="${POLICY_PARTS[3]}"
    
    # Extract user and group
    IFS=':' read -ra OWNER_PARTS <<< "$ownership"
    local user="${OWNER_PARTS[0]}"
    local group="${OWNER_PARTS[1]:-}"
    
    # Apply ownership
    change_ownership_advanced "$target_path" "$user" "$group" "$recursive" "true"
    
    # Apply permissions
    if [[ -d "$target_path" ]]; then
        chmod "$dir_perms" "$target_path"
    else
        chmod "$file_perms" "$target_path"
    fi
    
    if [[ "$recursive" == "true" ]]; then
        find "$target_path" -type f -exec chmod "$file_perms" {} \;
        find "$target_path" -type d -exec chmod "$dir_perms" {} \;
    fi
    
    log_action "Policy '$policy_name' applied successfully"
}

# Fleet ownership management
manage_fleet_ownership() {
    local action="$1"
    local target_pattern="$2"
    local ownership_spec="$3"
    
    log_action "Fleet ownership management: $action on $target_pattern"
    
    case "$action" in
        "audit")
            audit_fleet_ownership "$target_pattern"
            ;;
        "standardize")
            standardize_fleet_ownership "$target_pattern" "$ownership_spec"
            ;;
        "policy-apply")
            apply_fleet_policy "$target_pattern" "$ownership_spec"
            ;;
        "report")
            generate_fleet_ownership_report
            ;;
    esac
}

# Audit fleet ownership
audit_fleet_ownership() {
    local target_pattern="$1"
    
    echo "Auditing fleet ownership for pattern: $target_pattern"
    
    # Find files matching pattern
    local files=($(find / -path "$target_pattern" 2>/dev/null | head -100))
    
    local audit_report="$REPORT_DIR/fleet_ownership_audit_$(date +%Y%m%d_%H%M%S).json"
    
    cat > "$audit_report" << EOF
{
    "audit_info": {
        "pattern": "$target_pattern",
        "timestamp": "$(date -u +%Y-%m-%dT%H:%M:%SZ)",
        "hostname": "$(hostname)",
        "files_found": ${#files[@]}
    },
    "ownership_summary": {},
    "security_findings": [],
    "recommendations": []
}
EOF
    
    # Analyze ownership patterns
    local owners=()
    local groups=()
    local permissions=()
    
    for file in "${files[@]}"; do
        if [[ -e "$file" ]]; then
            owners+=($(stat -f "%Su" "$file"))
            groups+=($(stat -f "%Sg" "$file"))
            permissions+=($(stat -f "%A" "$file"))
        fi
    done
    
    # Generate summary
    local unique_owners=($(printf '%s\n' "${owners[@]}" | sort -u))
    local unique_groups=($(printf '%s\n' "${groups[@]}" | sort -u))
    
    jq --argjson owners "$(printf '%s\n' "${unique_owners[@]}" | jq -R . | jq -s .)" \
       --argjson groups "$(printf '%s\n' "${unique_groups[@]}" | jq -R . | jq -s .)" \
       '.ownership_summary = {
           "unique_owners": $owners,
           "unique_groups": $groups,
           "total_files": '${#files[@]}'
       }' "$audit_report" > "${audit_report}.tmp" && mv "${audit_report}.tmp" "$audit_report"
    
    log_action "Fleet ownership audit completed: $audit_report"
    echo "$audit_report"
}

# Main execution function
main() {
    local action="${1:-change}"
    local target="${2:-}"
    local owner="${3:-}"
    local group="${4:-}"
    local options="${5:-}"
    
    log_action "=== MacFleet Ownership Management Started ==="
    log_action "Action: $action, Target: $target, Owner: $owner, Group: $group"
    
    case "$action" in
        "change")
            if [[ -z "$target" || -z "$owner" ]]; then
                echo "Usage: $0 change <target_path> <owner> [group] [recursive]"
                exit 1
            fi
            change_ownership_advanced "$target" "$owner" "$group" "$options"
            ;;
        "policy")
            if [[ -z "$target" || -z "$owner" ]]; then
                echo "Usage: $0 policy <target_path> <policy_name> [recursive]"
                exit 1
            fi
            apply_ownership_policy "$target" "$owner" "$group"
            ;;
        "audit")
            audit_fleet_ownership "${target:-/Users/*}"
            ;;
        "fleet")
            manage_fleet_ownership "$owner" "$target" "$group"
            ;;
        "help")
            echo "Usage: $0 [action] [options...]"
            echo "Actions:"
            echo "  change <path> <owner> [group] [recursive] - Change ownership"
            echo "  policy <path> <policy> [recursive] - Apply ownership policy"
            echo "  audit [pattern] - Audit ownership across fleet"
            echo "  fleet <action> <pattern> <spec> - Fleet management"
            echo "  help - Show this help"
            echo ""
            echo "Available policies: ${!OWNERSHIP_POLICIES[*]}"
            ;;
        *)
            log_action "ERROR: Unknown action: $action"
            exit 1
            ;;
    esac
    
    log_action "=== Ownership management completed ==="
}

# Execute main function
main "$@"

Common Ownership Scenarios

Employee Role Change

#!/bin/bash

# Transfer ownership when employee changes roles
transfer_employee_files() {
    local old_user="$1"
    local new_user="$2"
    local base_path="$3"
    
    echo "Transferring files from $old_user to $new_user in $base_path"
    
    # Find all files owned by old user
    local files=($(find "$base_path" -user "$old_user" 2>/dev/null))
    
    echo "Found ${#files[@]} files owned by $old_user"
    
    for file in "${files[@]}"; do
        if chown "$new_user" "$file"; then
            echo "✓ Transferred: $file"
        else
            echo "✗ Failed: $file"
        fi
    done
    
    echo "Transfer completed"
}

# Usage
transfer_employee_files "john.doe" "jane.smith" "/Users/Shared/Projects"

Project Handover

#!/bin/bash

# Complete project handover with ownership and permissions
project_handover() {
    local project_path="$1"
    local new_owner="$2"
    local team_group="$3"
    
    echo "Starting project handover: $project_path"
    
    # Change ownership recursively
    chown -R "$new_owner:$team_group" "$project_path"
    
    # Set appropriate permissions
    find "$project_path" -type d -exec chmod 775 {} \;  # Directories
    find "$project_path" -type f -exec chmod 664 {} \;  # Files
    find "$project_path" -name "*.sh" -exec chmod 755 {} \;  # Scripts
    
    echo "Project handover completed"
    echo "New owner: $new_owner"
    echo "Team group: $team_group"
    ls -la "$project_path"
}

# Usage
project_handover "/Users/Shared/ProjectAlpha" "daniel" "developers"

Security Compliance Check

#!/bin/bash

# Check ownership compliance across critical directories
compliance_check() {
    local directories=("/etc" "/usr/local" "/Applications" "/Users/Shared")
    
    echo "=== Ownership Compliance Check ==="
    
    for dir in "${directories[@]}"; do
        if [[ -d "$dir" ]]; then
            echo -e "\nChecking: $dir"
            
            # Find world-writable files
            local world_writable=$(find "$dir" -type f -perm -002 2>/dev/null | head -5)
            if [[ -n "$world_writable" ]]; then
                echo "⚠️  World-writable files found:"
                echo "$world_writable"
            fi
            
            # Find files with unusual ownership
            local unusual_owners=$(find "$dir" -maxdepth 2 ! -user root ! -user "$(whoami)" 2>/dev/null | head -5)
            if [[ -n "$unusual_owners" ]]; then
                echo "ℹ️  Non-standard ownership:"
                echo "$unusual_owners" | xargs ls -la
            fi
        fi
    done
}

# Run compliance check
compliance_check

Important Notes

  • Admin privileges required for changing ownership of files not owned by current user
  • User validation - Always verify target user exists before changing ownership
  • Backup metadata before making bulk ownership changes
  • Test scripts on sample files before production deployment
  • Monitor permissions after ownership changes to ensure proper access
  • Use recursive options carefully to avoid unintended changes
  • Group membership affects file access even with proper ownership

File and Folder Open Management on macOS

Efficiently manage file and folder opening operations across your MacFleet deployment with enterprise-grade security features, application control, and comprehensive audit capabilities. This tutorial transforms basic open commands into robust file access management solutions.

Understanding Enterprise File Open Operations

Enterprise file opening requires more than basic access, demanding:

  • Security validation to prevent unauthorized file access
  • Application control to enforce approved software usage
  • Permission verification before file operations
  • Audit logging for compliance tracking
  • Malware scanning integration for file safety
  • Business rules enforcement for data protection

Core Open Operations

Basic File Opening

#!/bin/bash

# Simple file open with validation
open_file() {
    local file_path="$1"
    
    # Validate file exists
    if [[ ! -f "$file_path" ]]; then
        echo "Error: File '$file_path' not found"
        return 1
    fi
    
    # Open file with default application
    if open "$file_path"; then
        echo "Successfully opened '$file_path'"
        return 0
    else
        echo "Failed to open '$file_path'"
        return 1
    fi
}

# Usage example
# open_file "/Users/admin/document.pdf"

Application-Specific File Opening

#!/bin/bash

# Open file with specific application
open_with_app() {
    local file_path="$1"
    local bundle_id="$2"
    
    # Validate file exists
    if [[ ! -f "$file_path" ]]; then
        echo "Error: File '$file_path' not found"
        return 1
    fi
    
    # Open file with specified application
    if open -b "$bundle_id" "$file_path"; then
        echo "Successfully opened '$file_path' with $bundle_id"
        return 0
    else
        echo "Failed to open '$file_path' with $bundle_id"
        return 1
    fi
}

# Usage examples
# open_with_app "/Users/admin/document.txt" "com.apple.TextEdit"
# open_with_app "/Users/admin/presentation.pptx" "com.microsoft.PowerPoint"

Folder Opening

#!/bin/bash

# Open folder in Finder
open_folder() {
    local folder_path="$1"
    
    # Validate folder exists
    if [[ ! -d "$folder_path" ]]; then
        echo "Error: Folder '$folder_path' not found"
        return 1
    fi
    
    # Open folder in Finder
    if open "$folder_path"; then
        echo "Successfully opened folder '$folder_path'"
        return 0
    else
        echo "Failed to open folder '$folder_path'"
        return 1
    fi
}

# Usage example
# open_folder "/Users/admin/Documents"

Enterprise Open Management System

#!/bin/bash

# MacFleet Enterprise File Open Management System
# Comprehensive file and folder opening with enterprise features

# Configuration
SCRIPT_NAME="MacFleet Open Manager"
VERSION="1.0.0"
LOG_FILE="/var/log/macfleet_open_operations.log"
QUARANTINE_DIR="/var/quarantine/macfleet"
TEMP_DIR="/tmp/macfleet_open"
ALLOWED_EXTENSIONS=(".pdf" ".docx" ".xlsx" ".pptx" ".txt" ".png" ".jpg" ".gif" ".mp4" ".mov" ".pages" ".numbers" ".keynote")
RESTRICTED_PATHS=("/System" "/usr/bin" "/usr/sbin" "/private/var" "/Library/LaunchDaemons" "/Library/LaunchAgents")
APPROVED_APPLICATIONS=(
    "com.apple.TextEdit"
    "com.apple.Preview"
    "com.apple.QuickTimePlayerX"
    "com.microsoft.Word"
    "com.microsoft.Excel"
    "com.microsoft.PowerPoint"
    "com.adobe.Reader"
    "com.apple.iWork.Pages"
    "com.apple.iWork.Numbers"
    "com.apple.iWork.Keynote"
)
BUSINESS_HOURS_START=9
BUSINESS_HOURS_END=17
MAX_FILE_SIZE="100M"

# Create necessary directories
mkdir -p "$TEMP_DIR"
mkdir -p "$QUARANTINE_DIR"
mkdir -p "$(dirname "$LOG_FILE")"

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

# Check if current time is within business hours
is_business_hours() {
    local current_hour=$(date +%H)
    if [[ $current_hour -ge $BUSINESS_HOURS_START && $current_hour -lt $BUSINESS_HOURS_END ]]; then
        return 0
    else
        return 1
    fi
}

# Validate file extension
is_allowed_extension() {
    local file="$1"
    local extension="${file##*.}"
    extension=".$extension"
    
    for allowed in "${ALLOWED_EXTENSIONS[@]}"; do
        if [[ "$extension" == "$allowed" ]]; then
            return 0
        fi
    done
    return 1
}

# Check if path is restricted
is_restricted_path() {
    local path="$1"
    for restricted in "${RESTRICTED_PATHS[@]}"; do
        if [[ "$path" == "$restricted"* ]]; then
            return 0
        fi
    done
    return 1
}

# Check if application is approved
is_approved_application() {
    local bundle_id="$1"
    
    for approved in "${APPROVED_APPLICATIONS[@]}"; do
        if [[ "$bundle_id" == "$approved" ]]; then
            return 0
        fi
    done
    return 1
}

# Get file size
get_file_size() {
    local file="$1"
    if [[ -f "$file" ]]; then
        stat -f%z "$file" 2>/dev/null
    else
        echo "0"
    fi
}

# Convert size string to bytes
size_to_bytes() {
    local size="$1"
    local number="${size%[A-Za-z]*}"
    local unit="${size#$number}"
    
    case "$unit" in
        "K"|"KB") echo $((number * 1024)) ;;
        "M"|"MB") echo $((number * 1024 * 1024)) ;;
        "G"|"GB") echo $((number * 1024 * 1024 * 1024)) ;;
        *) echo "$number" ;;
    esac
}

# Check file signature/magic number
check_file_signature() {
    local file="$1"
    local expected_extension="${file##*.}"
    
    if [[ ! -f "$file" ]]; then
        return 1
    fi
    
    # Get file signature
    local signature=$(file -b --mime-type "$file" 2>/dev/null)
    
    # Basic signature validation
    case "$expected_extension" in
        "pdf")
            if [[ "$signature" == "application/pdf" ]]; then
                return 0
            fi
            ;;
        "txt")
            if [[ "$signature" == "text/plain" ]]; then
                return 0
            fi
            ;;
        "docx")
            if [[ "$signature" == "application/vnd.openxmlformats-officedocument.wordprocessingml.document" ]]; then
                return 0
            fi
            ;;
        "xlsx")
            if [[ "$signature" == "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" ]]; then
                return 0
            fi
            ;;
        "pptx")
            if [[ "$signature" == "application/vnd.openxmlformats-officedocument.presentationml.presentation" ]]; then
                return 0
            fi
            ;;
        "png")
            if [[ "$signature" == "image/png" ]]; then
                return 0
            fi
            ;;
        "jpg"|"jpeg")
            if [[ "$signature" == "image/jpeg" ]]; then
                return 0
            fi
            ;;
        *)
            # Allow other extensions without strict validation
            return 0
            ;;
    esac
    
    log_operation "WARNING" "File signature mismatch: $file (expected: $expected_extension, detected: $signature)"
    return 1
}

# Scan file for malware (placeholder for integration)
scan_file_malware() {
    local file="$1"
    
    # Placeholder for malware scanning integration
    # This would integrate with enterprise antivirus solutions
    
    # Basic checks
    if [[ -f "$file" ]]; then
        # Check for suspicious extensions
        local extension="${file##*.}"
        case "$extension" in
            "exe"|"bat"|"cmd"|"scr"|"com"|"pif"|"vbs"|"js")
                log_operation "SECURITY" "Blocked suspicious file type: $file"
                return 1
                ;;
        esac
        
        # Check file size (extremely large files could be suspicious)
        local file_size=$(get_file_size "$file")
        if [[ $file_size -gt 1073741824 ]]; then  # 1GB
            log_operation "WARNING" "Large file detected: $file ($(format_size $file_size))"
        fi
    fi
    
    return 0
}

# Format file size
format_size() {
    local bytes="$1"
    local sizes=("B" "KB" "MB" "GB" "TB")
    local unit=0
    
    while [[ $bytes -gt 1024 && $unit -lt 4 ]]; do
        bytes=$((bytes / 1024))
        ((unit++))
    done
    
    echo "${bytes}${sizes[$unit]}"
}

# Get application info
get_app_info() {
    local bundle_id="$1"
    
    # Get application path
    local app_path=$(mdfind "kMDItemCFBundleIdentifier == '$bundle_id'" 2>/dev/null | head -1)
    
    if [[ -n "$app_path" ]]; then
        local app_name=$(basename "$app_path" .app)
        local app_version=$(defaults read "$app_path/Contents/Info.plist" CFBundleShortVersionString 2>/dev/null)
        echo "$app_name v$app_version ($app_path)"
    else
        echo "Unknown application ($bundle_id)"
    fi
}

# Enhanced file open with enterprise features
enterprise_open_file() {
    local file_path="$1"
    local bundle_id="${2:-}"
    local force_open="${3:-false}"
    
    local operation_id=$(date +%s)
    log_operation "INFO" "Starting file open operation [$operation_id]: $file_path"
    
    # Pre-flight validations
    if [[ ! -f "$file_path" ]]; then
        log_operation "ERROR" "File not found: $file_path"
        return 1
    fi
    
    # Check if file path is restricted
    if is_restricted_path "$file_path"; then
        log_operation "SECURITY" "Blocked access to restricted path: $file_path"
        return 1
    fi
    
    # Validate file extension
    if ! is_allowed_extension "$file_path"; then
        log_operation "SECURITY" "Blocked file with unauthorized extension: $file_path"
        return 1
    fi
    
    # Check file size
    local file_size=$(get_file_size "$file_path")
    local max_size_bytes=$(size_to_bytes "$MAX_FILE_SIZE")
    
    if [[ $file_size -gt $max_size_bytes ]]; then
        log_operation "ERROR" "File too large: $(format_size $file_size) > $MAX_FILE_SIZE"
        return 1
    fi
    
    # Check file signature
    if ! check_file_signature "$file_path"; then
        if [[ "$force_open" != "true" ]]; then
            log_operation "SECURITY" "File signature validation failed: $file_path"
            return 1
        else
            log_operation "WARNING" "File signature validation failed but force_open enabled: $file_path"
        fi
    fi
    
    # Malware scanning
    if ! scan_file_malware "$file_path"; then
        log_operation "SECURITY" "File blocked by security scan: $file_path"
        return 1
    fi
    
    # Business hours check for sensitive files
    if [[ "$file_path" =~ (confidential|secret|private) ]] && ! is_business_hours; then
        log_operation "POLICY" "Sensitive file access outside business hours blocked: $file_path"
        return 1
    fi
    
    # Application validation if specified
    if [[ -n "$bundle_id" ]]; then
        if ! is_approved_application "$bundle_id"; then
            log_operation "SECURITY" "Blocked unauthorized application: $bundle_id"
            return 1
        fi
        
        # Check if application is installed
        local app_path=$(mdfind "kMDItemCFBundleIdentifier == '$bundle_id'" 2>/dev/null | head -1)
        if [[ -z "$app_path" ]]; then
            log_operation "ERROR" "Application not found: $bundle_id"
            return 1
        fi
        
        log_operation "INFO" "Opening with application: $(get_app_info "$bundle_id")"
    fi
    
    # Perform the open operation
    local open_command="open"
    if [[ -n "$bundle_id" ]]; then
        open_command="open -b '$bundle_id'"
    fi
    
    if eval "$open_command '$file_path'"; then
        log_operation "SUCCESS" "File opened successfully [$operation_id]: $file_path"
        
        # Log file access for audit
        log_operation "AUDIT" "File accessed: $file_path (size: $(format_size $file_size))"
        
        return 0
    else
        log_operation "ERROR" "Failed to open file [$operation_id]: $file_path"
        return 1
    fi
}

# Enhanced folder open with enterprise features
enterprise_open_folder() {
    local folder_path="$1"
    local reveal_hidden="${2:-false}"
    
    local operation_id=$(date +%s)
    log_operation "INFO" "Starting folder open operation [$operation_id]: $folder_path"
    
    # Pre-flight validations
    if [[ ! -d "$folder_path" ]]; then
        log_operation "ERROR" "Folder not found: $folder_path"
        return 1
    fi
    
    # Check if folder path is restricted
    if is_restricted_path "$folder_path"; then
        log_operation "SECURITY" "Blocked access to restricted folder: $folder_path"
        return 1
    fi
    
    # Business hours check for sensitive folders
    if [[ "$folder_path" =~ (confidential|secret|private) ]] && ! is_business_hours; then
        log_operation "POLICY" "Sensitive folder access outside business hours blocked: $folder_path"
        return 1
    fi
    
    # Count files in folder for audit
    local file_count=$(find "$folder_path" -type f 2>/dev/null | wc -l)
    local folder_size=$(du -sh "$folder_path" 2>/dev/null | awk '{print $1}')
    
    # Perform the open operation
    local open_command="open"
    if [[ "$reveal_hidden" == "true" ]]; then
        open_command="open -R"
    fi
    
    if eval "$open_command '$folder_path'"; then
        log_operation "SUCCESS" "Folder opened successfully [$operation_id]: $folder_path"
        log_operation "AUDIT" "Folder accessed: $folder_path (files: $file_count, size: $folder_size)"
        return 0
    else
        log_operation "ERROR" "Failed to open folder [$operation_id]: $folder_path"
        return 1
    fi
}

# Bulk file opening with progress monitoring
bulk_open_files() {
    local files_list="$1"
    local bundle_id="${2:-}"
    
    if [[ ! -f "$files_list" ]]; then
        log_operation "ERROR" "Files list not found: $files_list"
        return 1
    fi
    
    local total_files=$(grep -v '^#\|^$' "$files_list" | wc -l)
    local current_file=0
    local success_count=0
    local failure_count=0
    
    log_operation "INFO" "Starting bulk file open operation - Total files: $total_files"
    
    while IFS= read -r file_path; do
        # Skip empty lines and comments
        [[ -z "$file_path" || "$file_path" =~ ^#.* ]] && continue
        
        ((current_file++))
        
        # Trim whitespace
        file_path=$(echo "$file_path" | xargs)
        
        echo "Processing [$current_file/$total_files]: $(basename "$file_path")"
        
        if enterprise_open_file "$file_path" "$bundle_id"; then
            ((success_count++))
        else
            ((failure_count++))
        fi
        
        # Progress update
        local progress=$((current_file * 100 / total_files))
        echo "Progress: $progress% ($success_count successful, $failure_count failed)"
        
        # Small delay to prevent overwhelming the system
        sleep 0.5
        
    done < "$files_list"
    
    log_operation "SUCCESS" "Bulk open completed - Success: $success_count, Failed: $failure_count"
    return $failure_count
}

# Generate file access report
generate_access_report() {
    local report_file="/tmp/macfleet_access_report_$(date +%Y%m%d_%H%M%S).txt"
    
    {
        echo "MacFleet File Access Report"
        echo "Generated: $(date)"
        echo "Hostname: $(hostname)"
        echo "User: $(whoami)"
        echo "=========================="
        echo ""
        
        echo "Recent File Access Operations (Last 24 hours):"
        if [[ -f "$LOG_FILE" ]]; then
            local yesterday=$(date -v-1d '+%Y-%m-%d')
            grep "$yesterday\|$(date '+%Y-%m-%d')" "$LOG_FILE" | grep -E "(AUDIT|SUCCESS)" | tail -50
        else
            echo "No log file found"
        fi
        
        echo ""
        echo "Security Events (Last 24 hours):"
        if [[ -f "$LOG_FILE" ]]; then
            local yesterday=$(date -v-1d '+%Y-%m-%d')
            grep "$yesterday\|$(date '+%Y-%m-%d')" "$LOG_FILE" | grep -E "(SECURITY|POLICY)" | tail -20
        fi
        
        echo ""
        echo "File Access Statistics:"
        if [[ -f "$LOG_FILE" ]]; then
            echo "Total Operations: $(grep -c "file open operation\|folder open operation" "$LOG_FILE" 2>/dev/null || echo "0")"
            echo "Successful: $(grep -c "SUCCESS.*opened successfully" "$LOG_FILE" 2>/dev/null || echo "0")"
            echo "Failed: $(grep -c "ERROR.*Failed to open" "$LOG_FILE" 2>/dev/null || echo "0")"
            echo "Security Blocks: $(grep -c "SECURITY.*Blocked" "$LOG_FILE" 2>/dev/null || echo "0")"
        fi
        
        echo ""
        echo "Most Accessed File Types:"
        if [[ -f "$LOG_FILE" ]]; then
            grep "File accessed:" "$LOG_FILE" | sed 's/.*File accessed: //' | sed 's/ (size:.*//' | 
            awk -F. '{print $NF}' | sort | uniq -c | sort -nr | head -10
        fi
        
    } > "$report_file"
    
    echo "File access report saved to: $report_file"
    log_operation "INFO" "Access report generated: $report_file"
}

# Check application permissions
check_app_permissions() {
    local bundle_id="$1"
    
    # Check if application has necessary permissions
    local app_path=$(mdfind "kMDItemCFBundleIdentifier == '$bundle_id'" 2>/dev/null | head -1)
    
    if [[ -z "$app_path" ]]; then
        echo "Application not found: $bundle_id"
        return 1
    fi
    
    echo "Application: $(get_app_info "$bundle_id")"
    echo "Path: $app_path"
    
    # Check code signature
    local signature_status=$(codesign -dv "$app_path" 2>&1 | grep -E "(Signature|Authority)")
    echo "Code Signature: $signature_status"
    
    # Check if application is notarized
    local notarization=$(spctl -a -vv "$app_path" 2>&1 | grep -E "(accepted|source=)")
    echo "Notarization: $notarization"
    
    return 0
}

# Main open management function
main() {
    local action="${1:-help}"
    
    case "$action" in
        "open-file")
            local file_path="$2"
            local bundle_id="$3"
            local force_open="${4:-false}"
            
            if [[ -z "$file_path" ]]; then
                echo "Usage: $0 open-file <file_path> [bundle_id] [force_open]"
                exit 1
            fi
            
            enterprise_open_file "$file_path" "$bundle_id" "$force_open"
            ;;
        "open-folder")
            local folder_path="$2"
            local reveal_hidden="${3:-false}"
            
            if [[ -z "$folder_path" ]]; then
                echo "Usage: $0 open-folder <folder_path> [reveal_hidden]"
                exit 1
            fi
            
            enterprise_open_folder "$folder_path" "$reveal_hidden"
            ;;
        "bulk-open")
            local files_list="$2"
            local bundle_id="$3"
            
            if [[ -z "$files_list" ]]; then
                echo "Usage: $0 bulk-open <files_list> [bundle_id]"
                exit 1
            fi
            
            bulk_open_files "$files_list" "$bundle_id"
            ;;
        "check-app")
            local bundle_id="$2"
            
            if [[ -z "$bundle_id" ]]; then
                echo "Usage: $0 check-app <bundle_id>"
                exit 1
            fi
            
            check_app_permissions "$bundle_id"
            ;;
        "report")
            generate_access_report
            ;;
        "help"|*)
            echo "$SCRIPT_NAME v$VERSION"
            echo "Enterprise File and Folder Open Management"
            echo ""
            echo "Usage: $0 <action> [options]"
            echo ""
            echo "Actions:"
            echo "  open-file <file_path> [bundle_id] [force_open]  - Open single file"
            echo "  open-folder <folder_path> [reveal_hidden]       - Open folder in Finder"
            echo "  bulk-open <files_list> [bundle_id]             - Open multiple files"
            echo "  check-app <bundle_id>                           - Check application permissions"
            echo "  report                                          - Generate access report"
            echo "  help                                            - Show this help message"
            echo ""
            echo "Common Bundle IDs:"
            echo "  com.apple.TextEdit          - TextEdit"
            echo "  com.apple.Preview           - Preview"
            echo "  com.microsoft.Word          - Microsoft Word"
            echo "  com.microsoft.Excel         - Microsoft Excel"
            echo "  com.microsoft.PowerPoint    - Microsoft PowerPoint"
            echo "  com.adobe.Reader            - Adobe Reader"
            echo "  com.apple.iWork.Pages       - Pages"
            echo "  com.apple.iWork.Numbers     - Numbers"
            echo "  com.apple.iWork.Keynote     - Keynote"
            echo ""
            echo "Features:"
            echo "  • Security validation and malware scanning"
            echo "  • Application control and approval management"
            echo "  • File signature verification"
            echo "  • Business hours compliance checking"
            echo "  • Comprehensive audit logging"
            echo "  • Bulk operations with progress monitoring"
            echo "  • Detailed access reporting"
            ;;
    esac
}

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

File and Folder Move Management on macOS

Efficiently manage file and folder move operations across your MacFleet deployment with enterprise-grade safety features, automatic backup creation, and comprehensive audit capabilities. This tutorial transforms basic mv commands into robust data relocation solutions.

Understanding Enterprise File Move Operations

Enterprise file moving requires more than basic relocation, demanding:

  • Safety validation to prevent data loss during moves
  • Automatic backup creation before destructive operations
  • Permission preservation during relocation
  • Rollback capabilities for failed operations
  • Rename protection against naming conflicts
  • Audit logging for compliance tracking

Core Move Operations

Basic File Move

#!/bin/bash

# Simple file move with validation
move_file() {
    local source="$1"
    local destination="$2"
    
    # Validate source exists
    if [[ ! -f "$source" ]]; then
        echo "Error: Source file '$source' not found"
        return 1
    fi
    
    # Create destination directory if needed
    local dest_dir=$(dirname "$destination")
    mkdir -p "$dest_dir"
    
    # Move file
    if mv "$source" "$destination"; then
        echo "Successfully moved '$source' to '$destination'"
        return 0
    else
        echo "Failed to move '$source' to '$destination'"
        return 1
    fi
}

# Usage example
# move_file "/Users/admin/document.pdf" "/Users/shared/documents/document.pdf"

Basic Directory Move

#!/bin/bash

# Directory move with verification
move_directory() {
    local source="$1"
    local destination="$2"
    
    # Validate source directory exists
    if [[ ! -d "$source" ]]; then
        echo "Error: Source directory '$source' not found"
        return 1
    fi
    
    # Move directory
    if mv "$source" "$destination"; then
        echo "Successfully moved directory '$source' to '$destination'"
        return 0
    else
        echo "Failed to move directory '$source' to '$destination'"
        return 1
    fi
}

# Usage example
# move_directory "/Users/admin/project" "/Users/shared/projects/project"

File and Folder Rename

#!/bin/bash

# Rename file or folder
rename_item() {
    local current_path="$1"
    local new_name="$2"
    
    # Validate source exists
    if [[ ! -e "$current_path" ]]; then
        echo "Error: Source '$current_path' not found"
        return 1
    fi
    
    local parent_dir=$(dirname "$current_path")
    local new_path="$parent_dir/$new_name"
    
    # Check if new name already exists
    if [[ -e "$new_path" ]]; then
        echo "Error: '$new_path' already exists"
        return 1
    fi
    
    # Rename item
    if mv "$current_path" "$new_path"; then
        echo "Successfully renamed '$(basename "$current_path")' to '$new_name'"
        return 0
    else
        echo "Failed to rename '$(basename "$current_path")' to '$new_name'"
        return 1
    fi
}

# Usage examples
# rename_item "/Users/admin/oldfile.txt" "newfile.txt"
# rename_item "/Users/admin/old_folder" "new_folder"

Enterprise Move Management System

#!/bin/bash

# MacFleet Enterprise File Move Management System
# Comprehensive file and folder moving with enterprise features

# Configuration
SCRIPT_NAME="MacFleet Move Manager"
VERSION="1.0.0"
LOG_FILE="/var/log/macfleet_move_operations.log"
BACKUP_DIR="/var/backups/macfleet/move_operations"
TEMP_DIR="/tmp/macfleet_move"
MAX_FILE_SIZE="10G"
ALLOWED_EXTENSIONS=(".pdf" ".docx" ".xlsx" ".pptx" ".txt" ".png" ".jpg" ".gif" ".mp4" ".mov")
RESTRICTED_PATHS=("/System" "/usr/bin" "/usr/sbin" "/private/var" "/Applications")
PROTECTED_DIRECTORIES=("/Users/Shared" "/Library" "/var")
BUSINESS_HOURS_START=9
BUSINESS_HOURS_END=17

# Create necessary directories
mkdir -p "$TEMP_DIR"
mkdir -p "$BACKUP_DIR"
mkdir -p "$(dirname "$LOG_FILE")"

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

# Check if current time is within business hours
is_business_hours() {
    local current_hour=$(date +%H)
    if [[ $current_hour -ge $BUSINESS_HOURS_START && $current_hour -lt $BUSINESS_HOURS_END ]]; then
        return 0
    else
        return 1
    fi
}

# Validate file extension
is_allowed_extension() {
    local file="$1"
    local extension="${file##*.}"
    extension=".$extension"
    
    for allowed in "${ALLOWED_EXTENSIONS[@]}"; do
        if [[ "$extension" == "$allowed" ]]; then
            return 0
        fi
    done
    return 1
}

# Check if path is restricted
is_restricted_path() {
    local path="$1"
    for restricted in "${RESTRICTED_PATHS[@]}"; do
        if [[ "$path" == "$restricted"* ]]; then
            return 0
        fi
    done
    return 1
}

# Check if destination is in protected directory
is_protected_destination() {
    local path="$1"
    for protected in "${PROTECTED_DIRECTORIES[@]}"; do
        if [[ "$path" == "$protected"* ]]; then
            return 0
        fi
    done
    return 1
}

# Get file/directory size
get_item_size() {
    local item="$1"
    if [[ -f "$item" ]]; then
        stat -f%z "$item" 2>/dev/null
    elif [[ -d "$item" ]]; then
        du -sk "$item" 2>/dev/null | awk '{print $1 * 1024}'
    else
        echo "0"
    fi
}

# Convert bytes to human readable format
format_size() {
    local bytes="$1"
    local sizes=("B" "KB" "MB" "GB" "TB")
    local unit=0
    
    while [[ $bytes -gt 1024 && $unit -lt 4 ]]; do
        bytes=$((bytes / 1024))
        ((unit++))
    done
    
    echo "${bytes}${sizes[$unit]}"
}

# Calculate checksum for verification
calculate_checksum() {
    local item="$1"
    if [[ -f "$item" ]]; then
        shasum -a 256 "$item" 2>/dev/null | awk '{print $1}'
    elif [[ -d "$item" ]]; then
        find "$item" -type f -exec shasum -a 256 {} \; 2>/dev/null | shasum -a 256 | awk '{print $1}'
    else
        echo ""
    fi
}

# Create backup before move operation
create_move_backup() {
    local source="$1"
    local operation_id="$2"
    local timestamp=$(date '+%Y%m%d_%H%M%S')
    
    if [[ -e "$source" ]]; then
        local item_name=$(basename "$source")
        local backup_path="$BACKUP_DIR/${operation_id}_${item_name}_backup_$timestamp"
        
        if cp -R "$source" "$backup_path"; then
            log_operation "INFO" "Backup created: $backup_path"
            echo "$backup_path"
            return 0
        else
            log_operation "ERROR" "Failed to create backup for: $source"
            return 1
        fi
    else
        log_operation "WARNING" "Source does not exist for backup: $source"
        return 1
    fi
}

# Restore from backup
restore_from_backup() {
    local backup_path="$1"
    local restore_destination="$2"
    
    if [[ -e "$backup_path" ]]; then
        local restore_dir=$(dirname "$restore_destination")
        mkdir -p "$restore_dir"
        
        if cp -R "$backup_path" "$restore_destination"; then
            log_operation "INFO" "Restored from backup: $backup_path -> $restore_destination"
            return 0
        else
            log_operation "ERROR" "Failed to restore from backup: $backup_path"
            return 1
        fi
    else
        log_operation "ERROR" "Backup not found: $backup_path"
        return 1
    fi
}

# Check for naming conflicts
check_naming_conflict() {
    local destination="$1"
    local resolve_method="${2:-prompt}"  # prompt, overwrite, rename, skip
    
    if [[ -e "$destination" ]]; then
        case "$resolve_method" in
            "overwrite")
                log_operation "WARNING" "Will overwrite existing item: $destination"
                return 0
                ;;
            "rename")
                local counter=1
                local base_name="${destination%.*}"
                local extension="${destination##*.}"
                local new_destination
                
                while true; do
                    if [[ "$base_name" == "$destination" ]]; then
                        # No extension
                        new_destination="${destination}_${counter}"
                    else
                        new_destination="${base_name}_${counter}.${extension}"
                    fi
                    
                    if [[ ! -e "$new_destination" ]]; then
                        echo "$new_destination"
                        log_operation "INFO" "Resolved naming conflict: $destination -> $new_destination"
                        return 0
                    fi
                    ((counter++))
                done
                ;;
            "skip")
                log_operation "INFO" "Skipping due to naming conflict: $destination"
                return 2
                ;;
            "prompt"|*)
                log_operation "ERROR" "Naming conflict detected: $destination"
                return 1
                ;;
        esac
    else
        echo "$destination"
        return 0
    fi
}

# Verify move operation integrity
verify_move_integrity() {
    local source_backup="$1"
    local destination="$2"
    
    if [[ -e "$source_backup" && -e "$destination" ]]; then
        local backup_checksum=$(calculate_checksum "$source_backup")
        local dest_checksum=$(calculate_checksum "$destination")
        
        if [[ "$backup_checksum" == "$dest_checksum" ]]; then
            log_operation "INFO" "Move integrity verification passed: $destination"
            return 0
        else
            log_operation "ERROR" "Move integrity verification failed: $destination"
            return 1
        fi
    else
        log_operation "WARNING" "Cannot verify move integrity - missing backup or destination"
        return 1
    fi
}

# Enhanced file move with enterprise features
enterprise_move_file() {
    local source="$1"
    local destination="$2"
    local conflict_resolution="${3:-prompt}"  # prompt, overwrite, rename, skip
    local create_backup="${4:-true}"
    local verify_integrity="${5:-true}"
    
    local operation_id=$(date +%s)
    log_operation "INFO" "Starting file move operation [$operation_id]: $source -> $destination"
    
    # Pre-flight validations
    if [[ ! -f "$source" ]]; then
        log_operation "ERROR" "Source file not found: $source"
        return 1
    fi
    
    # Check if source is restricted
    if is_restricted_path "$source"; then
        log_operation "ERROR" "Source path is restricted: $source"
        return 1
    fi
    
    # Check if destination is restricted
    if is_restricted_path "$destination"; then
        log_operation "ERROR" "Destination path is restricted: $destination"
        return 1
    fi
    
    # Validate file extension
    if ! is_allowed_extension "$source"; then
        log_operation "WARNING" "File extension not in allowed list: $source"
    fi
    
    # Check file size
    local file_size=$(get_item_size "$source")
    local max_size_bytes=$(echo "$MAX_FILE_SIZE" | sed 's/G//' | awk '{print $1 * 1024 * 1024 * 1024}')
    
    if [[ $file_size -gt $max_size_bytes ]]; then
        log_operation "ERROR" "File too large: $(format_size $file_size) > $MAX_FILE_SIZE"
        return 1
    fi
    
    # Business hours check for large files (>100MB)
    if [[ $file_size -gt 104857600 ]] && ! is_business_hours; then
        log_operation "WARNING" "Large file move outside business hours: $(format_size $file_size)"
    fi
    
    # Check for naming conflicts
    local resolved_destination
    resolved_destination=$(check_naming_conflict "$destination" "$conflict_resolution")
    local conflict_result=$?
    
    if [[ $conflict_result -eq 1 ]]; then
        log_operation "ERROR" "Naming conflict resolution failed: $destination"
        return 1
    elif [[ $conflict_result -eq 2 ]]; then
        log_operation "INFO" "Move operation skipped due to conflict: $destination"
        return 0
    fi
    
    destination="$resolved_destination"
    
    # Create destination directory
    local dest_dir=$(dirname "$destination")
    if ! mkdir -p "$dest_dir"; then
        log_operation "ERROR" "Failed to create destination directory: $dest_dir"
        return 1
    fi
    
    # Create backup if requested
    local backup_path=""
    if [[ "$create_backup" == "true" ]]; then
        backup_path=$(create_move_backup "$source" "$operation_id")
        if [[ $? -ne 0 ]]; then
            log_operation "ERROR" "Failed to create backup for: $source"
            return 1
        fi
    fi
    
    # Perform the move operation
    if mv "$source" "$destination"; then
        log_operation "INFO" "File moved successfully: $(format_size $file_size)"
        
        # Verify integrity if requested and backup exists
        if [[ "$verify_integrity" == "true" && -n "$backup_path" ]]; then
            if ! verify_move_integrity "$backup_path" "$destination"; then
                log_operation "ERROR" "Move integrity verification failed, attempting restore"
                
                # Restore from backup
                if [[ -n "$backup_path" ]]; then
                    restore_from_backup "$backup_path" "$source"
                    rm -f "$destination"
                fi
                return 1
            fi
        fi
        
        # Log successful operation
        log_operation "SUCCESS" "File move completed [$operation_id]: $source -> $destination"
        return 0
    else
        log_operation "ERROR" "Move operation failed [$operation_id]: $source -> $destination"
        return 1
    fi
}

# Enhanced directory move with enterprise features
enterprise_move_directory() {
    local source="$1"
    local destination="$2"
    local conflict_resolution="${3:-prompt}"
    local create_backup="${4:-true}"
    local verify_integrity="${5:-true}"
    
    local operation_id=$(date +%s)
    log_operation "INFO" "Starting directory move operation [$operation_id]: $source -> $destination"
    
    # Pre-flight validations
    if [[ ! -d "$source" ]]; then
        log_operation "ERROR" "Source directory not found: $source"
        return 1
    fi
    
    # Check if source is restricted
    if is_restricted_path "$source"; then
        log_operation "ERROR" "Source path is restricted: $source"
        return 1
    fi
    
    # Check if destination is restricted
    if is_restricted_path "$destination"; then
        log_operation "ERROR" "Destination path is restricted: $destination"
        return 1
    fi
    
    # Calculate directory size and file count
    local dir_size=$(get_item_size "$source")
    local file_count=$(find "$source" -type f | wc -l)
    
    log_operation "INFO" "Directory stats - Size: $(format_size $dir_size), Files: $file_count"
    
    # Business hours check for large directories (>1GB or >1000 files)
    if [[ $dir_size -gt 1073741824 || $file_count -gt 1000 ]] && ! is_business_hours; then
        log_operation "WARNING" "Large directory move outside business hours"
    fi
    
    # Check for naming conflicts
    local resolved_destination
    resolved_destination=$(check_naming_conflict "$destination" "$conflict_resolution")
    local conflict_result=$?
    
    if [[ $conflict_result -eq 1 ]]; then
        log_operation "ERROR" "Naming conflict resolution failed: $destination"
        return 1
    elif [[ $conflict_result -eq 2 ]]; then
        log_operation "INFO" "Move operation skipped due to conflict: $destination"
        return 0
    fi
    
    destination="$resolved_destination"
    
    # Create parent directory for destination
    local dest_parent=$(dirname "$destination")
    if ! mkdir -p "$dest_parent"; then
        log_operation "ERROR" "Failed to create destination parent directory: $dest_parent"
        return 1
    fi
    
    # Create backup if requested
    local backup_path=""
    if [[ "$create_backup" == "true" ]]; then
        backup_path=$(create_move_backup "$source" "$operation_id")
        if [[ $? -ne 0 ]]; then
            log_operation "ERROR" "Failed to create backup for: $source"
            return 1
        fi
    fi
    
    # Perform the move operation
    if mv "$source" "$destination"; then
        log_operation "INFO" "Directory moved successfully: $(format_size $dir_size)"
        
        # Verify integrity if requested and backup exists
        if [[ "$verify_integrity" == "true" && -n "$backup_path" ]]; then
            if ! verify_move_integrity "$backup_path" "$destination"; then
                log_operation "ERROR" "Directory move integrity verification failed, attempting restore"
                
                # Restore from backup
                if [[ -n "$backup_path" ]]; then
                    restore_from_backup "$backup_path" "$source"
                    rm -rf "$destination"
                fi
                return 1
            fi
        fi
        
        # Log successful operation
        log_operation "SUCCESS" "Directory move completed [$operation_id]: $source -> $destination"
        return 0
    else
        log_operation "ERROR" "Directory move operation failed [$operation_id]: $source -> $destination"
        return 1
    fi
}

# Enhanced rename with enterprise features
enterprise_rename() {
    local current_path="$1"
    local new_name="$2"
    local create_backup="${3:-true}"
    
    local operation_id=$(date +%s)
    log_operation "INFO" "Starting rename operation [$operation_id]: $(basename "$current_path") -> $new_name"
    
    # Validate source exists
    if [[ ! -e "$current_path" ]]; then
        log_operation "ERROR" "Source not found: $current_path"
        return 1
    fi
    
    # Check if source is restricted
    if is_restricted_path "$current_path"; then
        log_operation "ERROR" "Source path is restricted: $current_path"
        return 1
    fi
    
    local parent_dir=$(dirname "$current_path")
    local new_path="$parent_dir/$new_name"
    
    # Check if new name already exists
    if [[ -e "$new_path" ]]; then
        log_operation "ERROR" "Target name already exists: $new_path"
        return 1
    fi
    
    # Validate new name (no special characters that could cause issues)
    if [[ "$new_name" =~ [/\\:*?"<>|] ]]; then
        log_operation "ERROR" "Invalid characters in new name: $new_name"
        return 1
    fi
    
    # Create backup if requested
    local backup_path=""
    if [[ "$create_backup" == "true" ]]; then
        backup_path=$(create_move_backup "$current_path" "$operation_id")
        if [[ $? -ne 0 ]]; then
            log_operation "WARNING" "Failed to create backup for rename operation"
        fi
    fi
    
    # Perform rename
    if mv "$current_path" "$new_path"; then
        log_operation "SUCCESS" "Rename completed [$operation_id]: $(basename "$current_path") -> $new_name"
        return 0
    else
        log_operation "ERROR" "Rename operation failed [$operation_id]: $(basename "$current_path") -> $new_name"
        return 1
    fi
}

# Bulk move operations with progress monitoring
bulk_move_operation() {
    local operation_type="$1"  # "file", "directory", or "rename"
    local operations_file="$2" # File containing operation definitions
    local conflict_resolution="${3:-rename}"
    
    if [[ ! -f "$operations_file" ]]; then
        log_operation "ERROR" "Operations file not found: $operations_file"
        return 1
    fi
    
    local total_operations=$(grep -v '^#\|^$' "$operations_file" | wc -l)
    local current_operation=0
    local success_count=0
    local failure_count=0
    
    log_operation "INFO" "Starting bulk move operation - Total operations: $total_operations"
    
    while IFS='|' read -r source destination; do
        # Skip empty lines and comments
        [[ -z "$source" || "$source" =~ ^#.* ]] && continue
        
        ((current_operation++))
        
        # Trim whitespace
        source=$(echo "$source" | xargs)
        destination=$(echo "$destination" | xargs)
        
        echo "Processing [$current_operation/$total_operations]: $(basename "$source")"
        
        case "$operation_type" in
            "file")
                if enterprise_move_file "$source" "$destination" "$conflict_resolution"; then
                    ((success_count++))
                else
                    ((failure_count++))
                fi
                ;;
            "directory")
                if enterprise_move_directory "$source" "$destination" "$conflict_resolution"; then
                    ((success_count++))
                else
                    ((failure_count++))
                fi
                ;;
            "rename")
                if enterprise_rename "$source" "$destination"; then
                    ((success_count++))
                else
                    ((failure_count++))
                fi
                ;;
        esac
        
        # Progress update
        local progress=$((current_operation * 100 / total_operations))
        echo "Progress: $progress% ($success_count successful, $failure_count failed)"
        
    done < "$operations_file"
    
    log_operation "SUCCESS" "Bulk move completed - Success: $success_count, Failed: $failure_count"
    return $failure_count
}

# Generate move operations report
generate_move_report() {
    local report_file="/tmp/macfleet_move_report_$(date +%Y%m%d_%H%M%S).txt"
    
    {
        echo "MacFleet Move Operations Report"
        echo "Generated: $(date)"
        echo "Hostname: $(hostname)"
        echo "=============================="
        echo ""
        
        echo "Recent Move Operations (Last 24 hours):"
        if [[ -f "$LOG_FILE" ]]; then
            local yesterday=$(date -v-1d '+%Y-%m-%d')
            grep "$yesterday\|$(date '+%Y-%m-%d')" "$LOG_FILE" | tail -50
        else
            echo "No log file found"
        fi
        
        echo ""
        echo "System Information:"
        echo "Available Space:"
        df -h | grep -E "^/dev/"
        
        echo ""
        echo "Backup Directory Status:"
        if [[ -d "$BACKUP_DIR" ]]; then
            echo "Backup Location: $BACKUP_DIR"
            echo "Backup Count: $(find "$BACKUP_DIR" -type f | wc -l)"
            echo "Backup Size: $(du -sh "$BACKUP_DIR" 2>/dev/null | awk '{print $1}')"
        else
            echo "Backup directory not found"
        fi
        
        echo ""
        echo "Move Operation Statistics:"
        if [[ -f "$LOG_FILE" ]]; then
            echo "Total Operations: $(grep -c "move operation\|rename operation" "$LOG_FILE" 2>/dev/null || echo "0")"
            echo "Successful: $(grep -c "SUCCESS.*completed" "$LOG_FILE" 2>/dev/null || echo "0")"
            echo "Failed: $(grep -c "ERROR.*failed" "$LOG_FILE" 2>/dev/null || echo "0")"
        fi
        
    } > "$report_file"
    
    echo "Move operations report saved to: $report_file"
    log_operation "INFO" "Move report generated: $report_file"
}

# Cleanup old backups
cleanup_old_backups() {
    local retention_days="${1:-30}"
    
    log_operation "INFO" "Starting backup cleanup - Retention: $retention_days days"
    
    if [[ -d "$BACKUP_DIR" ]]; then
        local deleted_count=0
        
        # Find and delete backups older than retention period
        while IFS= read -r -d '' backup_file; do
            if rm -rf "$backup_file"; then
                ((deleted_count++))
                log_operation "INFO" "Deleted old backup: $(basename "$backup_file")"
            fi
        done < <(find "$BACKUP_DIR" -type f -mtime +$retention_days -print0 2>/dev/null)
        
        log_operation "SUCCESS" "Backup cleanup completed - Deleted: $deleted_count items"
    else
        log_operation "WARNING" "Backup directory not found: $BACKUP_DIR"
    fi
}

# Main move management function
main() {
    local action="${1:-help}"
    
    case "$action" in
        "move-file")
            local source="$2"
            local destination="$3"
            local conflict_resolution="${4:-prompt}"
            local create_backup="${5:-true}"
            local verify="${6:-true}"
            
            if [[ -z "$source" || -z "$destination" ]]; then
                echo "Usage: $0 move-file <source> <destination> [conflict_resolution] [create_backup] [verify_integrity]"
                exit 1
            fi
            
            enterprise_move_file "$source" "$destination" "$conflict_resolution" "$create_backup" "$verify"
            ;;
        "move-directory")
            local source="$2"
            local destination="$3"
            local conflict_resolution="${4:-prompt}"
            local create_backup="${5:-true}"
            local verify="${6:-true}"
            
            if [[ -z "$source" || -z "$destination" ]]; then
                echo "Usage: $0 move-directory <source> <destination> [conflict_resolution] [create_backup] [verify_integrity]"
                exit 1
            fi
            
            enterprise_move_directory "$source" "$destination" "$conflict_resolution" "$create_backup" "$verify"
            ;;
        "rename")
            local current_path="$2"
            local new_name="$3"
            local create_backup="${4:-true}"
            
            if [[ -z "$current_path" || -z "$new_name" ]]; then
                echo "Usage: $0 rename <current_path> <new_name> [create_backup]"
                exit 1
            fi
            
            enterprise_rename "$current_path" "$new_name" "$create_backup"
            ;;
        "bulk-files")
            local operations_file="$2"
            local conflict_resolution="${3:-rename}"
            
            if [[ -z "$operations_file" ]]; then
                echo "Usage: $0 bulk-files <operations_file> [conflict_resolution]"
                exit 1
            fi
            
            bulk_move_operation "file" "$operations_file" "$conflict_resolution"
            ;;
        "bulk-directories")
            local operations_file="$2"
            local conflict_resolution="${3:-rename}"
            
            if [[ -z "$operations_file" ]]; then
                echo "Usage: $0 bulk-directories <operations_file> [conflict_resolution]"
                exit 1
            fi
            
            bulk_move_operation "directory" "$operations_file" "$conflict_resolution"
            ;;
        "bulk-rename")
            local operations_file="$2"
            
            if [[ -z "$operations_file" ]]; then
                echo "Usage: $0 bulk-rename <operations_file>"
                exit 1
            fi
            
            bulk_move_operation "rename" "$operations_file"
            ;;
        "report")
            generate_move_report
            ;;
        "cleanup-backups")
            local retention_days="${2:-30}"
            cleanup_old_backups "$retention_days"
            ;;
        "help"|*)
            echo "$SCRIPT_NAME v$VERSION"
            echo "Enterprise File and Folder Move Management"
            echo ""
            echo "Usage: $0 <action> [options]"
            echo ""
            echo "Actions:"
            echo "  move-file <source> <destination>           - Move single file"
            echo "  move-directory <source> <destination>      - Move directory"
            echo "  rename <current_path> <new_name>           - Rename file or folder"
            echo "  bulk-files <operations_file>               - Bulk move files"
            echo "  bulk-directories <operations_file>         - Bulk move directories"
            echo "  bulk-rename <operations_file>              - Bulk rename operations"
            echo "  report                                      - Generate operations report"
            echo "  cleanup-backups [retention_days]           - Clean old backups (default: 30 days)"
            echo "  help                                        - Show this help message"
            echo ""
            echo "Conflict Resolution Options:"
            echo "  prompt     - Stop and prompt for resolution (default)"
            echo "  overwrite  - Overwrite existing items"
            echo "  rename     - Auto-rename with counter suffix"
            echo "  skip       - Skip conflicting operations"
            echo ""
            echo "Operations File Format (source|destination per line):"
            echo "  /path/to/source1.txt|/path/to/destination1.txt"
            echo "  /path/to/source2.pdf|/path/to/destination2.pdf"
            echo ""
            echo "Features:"
            echo "  • Safety validation and automatic backup creation"
            echo "  • Conflict resolution with multiple strategies"
            echo "  • Business hours compliance checking"
            echo "  • Comprehensive audit logging"
            echo "  • Integrity verification"
            echo "  • Bulk operations with progress monitoring"
            echo "  • Automatic backup cleanup"
            ;;
    esac
}

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

Quick Reference Commands

Single File Operations

# Move file with full enterprise features
./move_manager.sh move-file "/Users/admin/document.pdf" "/Users/shared/documents/document.pdf"

# Move file with overwrite conflict resolution
./move_manager.sh move-file "/source/file.txt" "/destination/file.txt" overwrite

# Move file with auto-rename on conflicts
./move_manager.sh move-file "/source/file.txt" "/destination/file.txt" rename

# Move file without backup creation
./move_manager.sh move-file "/source/file.txt" "/destination/file.txt" prompt false

Directory Operations

# Move directory with all contents
./move_manager.sh move-directory "/Users/admin/project" "/Users/shared/projects/project"

# Move directory with rename on conflicts
./move_manager.sh move-directory "/source/folder" "/destination/folder" rename

Rename Operations

# Rename file
./move_manager.sh rename "/Users/admin/oldfile.txt" "newfile.txt"

# Rename directory
./move_manager.sh rename "/Users/admin/old_folder" "new_folder"

# Rename without backup
./move_manager.sh rename "/path/to/item" "new_name" false

Bulk Operations

# Create operations file for bulk moves
cat > /tmp/move_operations.txt << EOF
/Users/admin/doc1.pdf|/Users/shared/documents/doc1.pdf
/Users/admin/doc2.pdf|/Users/shared/documents/doc2.pdf
/Users/admin/doc3.pdf|/Users/shared/documents/doc3.pdf
EOF

# Execute bulk file moves
./move_manager.sh bulk-files "/tmp/move_operations.txt" rename

# Create rename operations file
cat > /tmp/rename_operations.txt << EOF
/Users/admin/oldname1.txt|newname1.txt
/Users/admin/oldname2.pdf|newname2.pdf
EOF

# Execute bulk renames
./move_manager.sh bulk-rename "/tmp/rename_operations.txt"

Integration Examples

JAMF Pro Integration

#!/bin/bash

# JAMF Pro script for enterprise file moves
# Parameters: $4 = operation_type, $5 = source_path, $6 = destination_path, $7 = conflict_resolution

OPERATION_TYPE="$4"
SOURCE_PATH="$5"
DESTINATION_PATH="$6"
CONFLICT_RESOLUTION="${7:-rename}"

# Download move manager if not present
if [[ ! -f "/usr/local/bin/macfleet_move_manager.sh" ]]; then
    curl -o "/usr/local/bin/macfleet_move_manager.sh" "https://scripts.macfleet.com/move_manager.sh"
    chmod +x "/usr/local/bin/macfleet_move_manager.sh"
fi

# Execute move operation
case "$OPERATION_TYPE" in
    "file")
        /usr/local/bin/macfleet_move_manager.sh move-file "$SOURCE_PATH" "$DESTINATION_PATH" "$CONFLICT_RESOLUTION"
        ;;
    "directory")
        /usr/local/bin/macfleet_move_manager.sh move-directory "$SOURCE_PATH" "$DESTINATION_PATH" "$CONFLICT_RESOLUTION"
        ;;
    "rename")
        /usr/local/bin/macfleet_move_manager.sh rename "$SOURCE_PATH" "$DESTINATION_PATH"
        ;;
    *)
        echo "Invalid operation type: $OPERATION_TYPE"
        exit 1
        ;;
esac

# Generate report
/usr/local/bin/macfleet_move_manager.sh report

exit $?

Configuration Profile for Move Policies

<?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>PayloadContent</key>
    <array>
        <dict>
            <key>PayloadType</key>
            <string>com.macfleet.move.policy</string>
            <key>PayloadIdentifier</key>
            <string>com.macfleet.move.policy.main</string>
            <key>PayloadDisplayName</key>
            <string>MacFleet Move Policy</string>
            <key>MaxFileSize</key>
            <string>10G</string>
            <key>AllowedExtensions</key>
            <array>
                <string>.pdf</string>
                <string>.docx</string>
                <string>.xlsx</string>
                <string>.pptx</string>
            </array>
            <key>ConflictResolution</key>
            <string>rename</string>
            <key>BusinessHoursOnly</key>
            <true/>
            <key>CreateBackups</key>
            <true/>
            <key>BackupRetentionDays</key>
            <integer>30</integer>
        </dict>
    </array>
</dict>
</plist>

Security and Compliance Features

Automated Backup Management

# Schedule daily backup cleanup
cat > /etc/cron.daily/macfleet-move-cleanup << 'EOF'
#!/bin/bash
/usr/local/bin/macfleet_move_manager.sh cleanup-backups 30
EOF

chmod +x /etc/cron.daily/macfleet-move-cleanup

Compliance Reporting

# Generate compliance report for auditors
generate_compliance_report() {
    local report_file="/var/reports/move_compliance_$(date +%Y%m%d).csv"
    
    echo "Timestamp,Operation_ID,User,Source,Destination,Size,Status,Backup_Path" > "$report_file"
    
    # Parse log file for move operations
    grep "move operation\|rename operation" "$LOG_FILE" | while read line; do
        # Extract relevant information and format as CSV
        echo "$line" | awk -F' - ' '{print $1","$2}' >> "$report_file"
    done
    
    echo "Compliance report generated: $report_file"
}

Troubleshooting

Common Issues and Solutions

IssueCauseSolution
Permission deniedInsufficient privilegesRun with sudo or check file permissions
Cross-device linkMoving across filesystemsUse copy + delete instead of mv
File in useApplication has file openClose application or use force option
Naming conflictDestination existsUse conflict resolution strategy
Operation timeoutLarge directory/slow diskBreak into smaller operations

Recovery Procedures

# List available backups
ls -la /var/backups/macfleet/move_operations/

# Restore from specific backup
./move_manager.sh restore-backup "/var/backups/macfleet/move_operations/backup_file" "/restore/destination"

# Check move operation logs
tail -f /var/log/macfleet_move_operations.log

# Search for failed operations
grep "ERROR" /var/log/macfleet_move_operations.log

Best Practices

  1. Always test on single device before fleet deployment
  2. Use backup creation for critical operations
  3. Monitor disk space before large move operations
  4. Choose appropriate conflict resolution for your use case
  5. Regular backup cleanup to manage disk usage
  6. Review logs regularly for failed operations
  7. Use business hours restrictions for resource-intensive moves
  8. Implement proper file naming conventions to avoid conflicts

This enterprise move management system provides comprehensive safety, backup, and recovery features while maintaining the simplicity and efficiency of basic move operations for effective fleet management.

File and Folder Permissions Management on macOS

Manage file and folder permissions across your MacFleet devices using command-line tools. This tutorial covers permission models, ownership management, access control implementation, and enterprise-wide permission policy deployment.

Understanding macOS Permission System

macOS uses a Unix-based permission system with three types of permissions and three user categories:

Permission Types

  • Read (r) - View file contents or list directory contents
  • Write (w) - Modify file contents or create/delete files in directory
  • Execute (x) - Run file as program or access directory

User Categories

  • Owner (u) - The user who created the file/folder
  • Group (g) - Users belonging to the file's group
  • Others (o) - All other system users

Permission Representations

ReadWriteExecuteOctalSymbolic
0---
1--x
2-w-
3-wx
4r--
5r-x
6rw-
7rwx

Basic Permission Management

View File/Folder Permissions

#!/bin/bash

# View permissions for specific file or folder
TARGET_PATH="$1"

if [[ -z "$TARGET_PATH" ]]; then
    echo "❌ Please specify a file or folder path"
    echo "Usage: $0 /path/to/file/or/folder"
    exit 1
fi

if [[ ! -e "$TARGET_PATH" ]]; then
    echo "❌ Path does not exist: $TARGET_PATH"
    exit 1
fi

echo "📋 Permission details for: $TARGET_PATH"
ls -la "$TARGET_PATH"

echo ""
echo "📊 Detailed permission breakdown:"
ls -la "$TARGET_PATH" | while read -r line; do
    if [[ "$line" != total* ]]; then
        echo "Full output: $line"
        
        # Extract permission string
        perms=$(echo "$line" | awk '{print $1}')
        if [[ ${#perms} -eq 10 ]]; then
            echo "File type: ${perms:0:1}"
            echo "Owner permissions: ${perms:1:3}"
            echo "Group permissions: ${perms:4:3}"
            echo "Others permissions: ${perms:7:3}"
        fi
    fi
done

Set Permissions Using Octal Notation

#!/bin/bash

# Set permissions using octal notation (e.g., 755, 644)
TARGET_PATH="$1"
PERMISSION="$2"

if [[ -z "$TARGET_PATH" || -z "$PERMISSION" ]]; then
    echo "❌ Please specify path and permission"
    echo "Usage: $0 /path/to/file 755"
    echo "Common permissions:"
    echo "  755 - rwxr-xr-x (owner: full, group/others: read+execute)"
    echo "  644 - rw-r--r-- (owner: read+write, group/others: read-only)"
    echo "  600 - rw------- (owner: read+write, group/others: no access)"
    exit 1
fi

if [[ ! -e "$TARGET_PATH" ]]; then
    echo "❌ Path does not exist: $TARGET_PATH"
    exit 1
fi

# Validate permission format
if [[ ! "$PERMISSION" =~ ^[0-7]{3}$ ]]; then
    echo "❌ Invalid permission format. Use 3-digit octal (e.g., 755)"
    exit 1
fi

echo "🔧 Setting permissions $PERMISSION on: $TARGET_PATH"

# Show current permissions
echo "Current permissions:"
ls -la "$TARGET_PATH"

# Apply new permissions
if chmod "$PERMISSION" "$TARGET_PATH"; then
    echo "✅ Permissions updated successfully"
    
    echo "New permissions:"
    ls -la "$TARGET_PATH"
else
    echo "❌ Failed to set permissions"
    exit 1
fi

Set Permissions Using Symbolic Notation

#!/bin/bash

# Set permissions using symbolic notation (e.g., u=rwx,g=rx,o=r)
TARGET_PATH="$1"
PERMISSION="$2"

if [[ -z "$TARGET_PATH" || -z "$PERMISSION" ]]; then
    echo "❌ Please specify path and permission"
    echo "Usage: $0 /path/to/file 'u=rwx,g=rx,o=r'"
    echo "Symbolic notation examples:"
    echo "  u=rwx,g=rx,o=rx  - Owner: full, Group/Others: read+execute"
    echo "  u=rw,g=r,o=r     - Owner: read+write, Group/Others: read-only"
    echo "  u=rw,g=,o=       - Owner: read+write, Group/Others: no access"
    exit 1
fi

if [[ ! -e "$TARGET_PATH" ]]; then
    echo "❌ Path does not exist: $TARGET_PATH"
    exit 1
fi

echo "🔧 Setting permissions '$PERMISSION' on: $TARGET_PATH"

# Show current permissions
echo "Current permissions:"
ls -la "$TARGET_PATH"

# Apply new permissions
if chmod "$PERMISSION" "$TARGET_PATH"; then
    echo "✅ Permissions updated successfully"
    
    echo "New permissions:"
    ls -la "$TARGET_PATH"
else
    echo "❌ Failed to set permissions"
    exit 1
fi

Ownership Management

Change File/Folder Owner

#!/bin/bash

# Change ownership of file or folder
TARGET_PATH="$1"
NEW_OWNER="$2"

if [[ -z "$TARGET_PATH" || -z "$NEW_OWNER" ]]; then
    echo "❌ Please specify path and new owner"
    echo "Usage: $0 /path/to/file username"
    exit 1
fi

if [[ ! -e "$TARGET_PATH" ]]; then
    echo "❌ Path does not exist: $TARGET_PATH"
    exit 1
fi

# Verify user exists
if ! id "$NEW_OWNER" &>/dev/null; then
    echo "❌ User does not exist: $NEW_OWNER"
    echo "Available users:"
    dscl . list /Users | grep -v "^_"
    exit 1
fi

echo "👤 Changing owner of '$TARGET_PATH' to: $NEW_OWNER"

# Show current ownership
echo "Current ownership:"
ls -la "$TARGET_PATH"

# Change ownership
if sudo chown "$NEW_OWNER" "$TARGET_PATH"; then
    echo "✅ Ownership changed successfully"
    
    echo "New ownership:"
    ls -la "$TARGET_PATH"
else
    echo "❌ Failed to change ownership"
    exit 1
fi

Change File/Folder Group

#!/bin/bash

# Change group ownership of file or folder
TARGET_PATH="$1"
NEW_GROUP="$2"

if [[ -z "$TARGET_PATH" || -z "$NEW_GROUP" ]]; then
    echo "❌ Please specify path and new group"
    echo "Usage: $0 /path/to/file groupname"
    echo "Common groups: admin, staff, wheel, everyone"
    exit 1
fi

if [[ ! -e "$TARGET_PATH" ]]; then
    echo "❌ Path does not exist: $TARGET_PATH"
    exit 1
fi

# Verify group exists
if ! dscl . read /Groups/"$NEW_GROUP" &>/dev/null; then
    echo "❌ Group does not exist: $NEW_GROUP"
    echo "Available groups:"
    dscl . list /Groups | grep -v "^_"
    exit 1
fi

echo "👥 Changing group of '$TARGET_PATH' to: $NEW_GROUP"

# Show current ownership
echo "Current ownership:"
ls -la "$TARGET_PATH"

# Change group ownership
if sudo chgrp "$NEW_GROUP" "$TARGET_PATH"; then
    echo "✅ Group ownership changed successfully"
    
    echo "New ownership:"
    ls -la "$TARGET_PATH"
else
    echo "❌ Failed to change group ownership"
    exit 1
fi

Recursive Permission Management

Set Permissions Recursively

#!/bin/bash

# Set permissions recursively on directory and all contents
TARGET_DIR="$1"
DIR_PERMISSION="$2"
FILE_PERMISSION="$3"

if [[ -z "$TARGET_DIR" || -z "$DIR_PERMISSION" || -z "$FILE_PERMISSION" ]]; then
    echo "❌ Please specify directory path and permissions"
    echo "Usage: $0 /path/to/directory 755 644"
    echo "This will set directories to 755 and files to 644"
    exit 1
fi

if [[ ! -d "$TARGET_DIR" ]]; then
    echo "❌ Directory does not exist: $TARGET_DIR"
    exit 1
fi

echo "🔄 Setting recursive permissions on: $TARGET_DIR"
echo "Directories will be set to: $DIR_PERMISSION"
echo "Files will be set to: $FILE_PERMISSION"

# Count items to process
dir_count=$(find "$TARGET_DIR" -type d | wc -l)
file_count=$(find "$TARGET_DIR" -type f | wc -l)

echo "Found $dir_count directories and $file_count files to process"

read -p "Continue? (y/N): " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
    echo "Operation cancelled"
    exit 0
fi

# Set permissions on directories
echo "🗂️ Setting directory permissions..."
if find "$TARGET_DIR" -type d -exec chmod "$DIR_PERMISSION" {} \;; then
    echo "✅ Directory permissions set successfully"
else
    echo "❌ Failed to set directory permissions"
    exit 1
fi

# Set permissions on files
echo "📄 Setting file permissions..."
if find "$TARGET_DIR" -type f -exec chmod "$FILE_PERMISSION" {} \;; then
    echo "✅ File permissions set successfully"
else
    echo "❌ Failed to set file permissions"
    exit 1
fi

echo "✅ Recursive permission update completed"

Enterprise Permission Management Script

#!/bin/bash

# MacFleet Permission Management Tool
# Comprehensive file and folder permission management for enterprise environments

# Configuration
LOG_FILE="/var/log/macfleet_permissions.log"
BACKUP_DIR="/var/backups/macfleet/permissions"
POLICY_FILE="/etc/macfleet/permission_policies.conf"
REPORT_DIR="/var/reports/macfleet/permissions"

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

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

# Create permission backup
create_permission_backup() {
    local target_path="$1"
    local backup_file="$BACKUP_DIR/permissions_$(basename "$target_path")_$(date +%Y%m%d_%H%M%S).txt"
    
    echo "📦 Creating permission backup for: $target_path"
    
    if [[ -d "$target_path" ]]; then
        # Backup directory permissions recursively
        find "$target_path" -exec ls -la {} \; > "$backup_file" 2>/dev/null
    else
        # Backup single file permissions
        ls -la "$target_path" > "$backup_file" 2>/dev/null
    fi
    
    if [[ $? -eq 0 ]]; then
        echo "✅ Backup created: $backup_file"
        log_action "Permission backup created: $backup_file"
    else
        echo "⚠️ Warning: Could not create backup"
        log_action "Warning: Backup creation failed for $target_path"
    fi
}

# Apply enterprise permission policy
apply_enterprise_policy() {
    local policy_name="$1"
    
    echo "🏢 Applying enterprise permission policy: $policy_name"
    log_action "Starting enterprise policy application: $policy_name"
    
    case "$policy_name" in
        "secure_documents")
            apply_secure_documents_policy
            ;;
        "shared_workspace")
            apply_shared_workspace_policy
            ;;
        "application_deployment")
            apply_application_deployment_policy
            ;;
        "system_hardening")
            apply_system_hardening_policy
            ;;
        *)
            echo "❌ Unknown policy: $policy_name"
            return 1
            ;;
    esac
}

# Secure documents policy
apply_secure_documents_policy() {
    echo "🔒 Applying secure documents permission policy..."
    
    local secure_dirs=(
        "/Users/Shared/SecureDocuments"
        "/opt/macfleet/confidential"
        "/var/secure"
    )
    
    for dir in "${secure_dirs[@]}"; do
        if [[ -d "$dir" ]]; then
            echo "Securing directory: $dir"
            
            # Create backup
            create_permission_backup "$dir"
            
            # Apply secure permissions (owner: full, group: read, others: none)
            sudo find "$dir" -type d -exec chmod 750 {} \;
            sudo find "$dir" -type f -exec chmod 640 {} \;
            
            # Set admin group ownership
            sudo chgrp -R admin "$dir"
            
            log_action "Secure permissions applied to: $dir"
        fi
    done
}

# Shared workspace policy
apply_shared_workspace_policy() {
    echo "👥 Applying shared workspace permission policy..."
    
    local shared_dirs=(
        "/Users/Shared/TeamWork"
        "/opt/macfleet/shared"
        "/var/shared"
    )
    
    for dir in "${shared_dirs[@]}"; do
        if [[ -d "$dir" ]]; then
            echo "Configuring shared directory: $dir"
            
            # Create backup
            create_permission_backup "$dir"
            
            # Apply shared permissions (owner: full, group: full, others: read)
            sudo find "$dir" -type d -exec chmod 775 {} \;
            sudo find "$dir" -type f -exec chmod 664 {} \;
            
            # Set staff group ownership
            sudo chgrp -R staff "$dir"
            
            log_action "Shared permissions applied to: $dir"
        fi
    done
}

# Application deployment policy
apply_application_deployment_policy() {
    echo "📱 Applying application deployment permission policy..."
    
    local app_dirs=(
        "/Applications"
        "/opt/macfleet/applications"
        "/usr/local/bin"
    )
    
    for dir in "${app_dirs[@]}"; do
        if [[ -d "$dir" ]]; then
            echo "Securing application directory: $dir"
            
            # Create backup
            create_permission_backup "$dir"
            
            # Apply application permissions (owner: full, group/others: read+execute)
            sudo find "$dir" -type d -exec chmod 755 {} \;
            sudo find "$dir" -type f -name "*.app" -exec chmod 755 {} \;
            sudo find "$dir" -type f ! -name "*.app" -exec chmod 644 {} \;
            
            # Set admin ownership
            sudo chown -R root:admin "$dir"
            
            log_action "Application permissions applied to: $dir"
        fi
    done
}

# System hardening policy
apply_system_hardening_policy() {
    echo "🛡️ Applying system hardening permission policy..."
    
    local system_dirs=(
        "/etc"
        "/var/log"
        "/usr/bin"
        "/usr/sbin"
    )
    
    for dir in "${system_dirs[@]}"; do
        if [[ -d "$dir" ]]; then
            echo "Hardening system directory: $dir"
            
            # Create backup
            create_permission_backup "$dir"
            
            # Apply restrictive permissions
            case "$dir" in
                "/etc")
                    sudo find "$dir" -type f -exec chmod 644 {} \;
                    sudo find "$dir" -type d -exec chmod 755 {} \;
                    ;;
                "/var/log")
                    sudo find "$dir" -type f -exec chmod 640 {} \;
                    sudo find "$dir" -type d -exec chmod 750 {} \;
                    ;;
                "/usr/bin"|"/usr/sbin")
                    sudo find "$dir" -type f -exec chmod 755 {} \;
                    sudo find "$dir" -type d -exec chmod 755 {} \;
                    ;;
            esac
            
            # Ensure root ownership
            sudo chown -R root:wheel "$dir"
            
            log_action "System hardening applied to: $dir"
        fi
    done
}

# Audit permission compliance
audit_permissions() {
    local target_path="$1"
    local audit_file="$REPORT_DIR/permission_audit_$(date +%Y%m%d_%H%M%S).txt"
    
    echo "🔍 Auditing permissions for: $target_path"
    
    {
        echo "MacFleet Permission Audit Report"
        echo "Generated: $(date)"
        echo "Target: $target_path"
        echo "Host: $(hostname)"
        echo "=================================="
        echo ""
        
        if [[ -d "$target_path" ]]; then
            echo "=== Directory Structure and Permissions ==="
            find "$target_path" -exec ls -la {} \; 2>/dev/null
            echo ""
            
            echo "=== Permission Summary ==="
            echo "Total items: $(find "$target_path" | wc -l)"
            echo "Directories: $(find "$target_path" -type d | wc -l)"
            echo "Files: $(find "$target_path" -type f | wc -l)"
            echo ""
            
            echo "=== World-Writable Files (Security Risk) ==="
            find "$target_path" -type f -perm -002 -ls 2>/dev/null || echo "None found"
            echo ""
            
            echo "=== SUID/SGID Files ==="
            find "$target_path" -type f \( -perm -4000 -o -perm -2000 \) -ls 2>/dev/null || echo "None found"
            echo ""
            
            echo "=== Files with No Owner/Group ==="
            find "$target_path" -nouser -o -nogroup 2>/dev/null || echo "None found"
            
        else
            echo "=== Single File Permissions ==="
            ls -la "$target_path"
        fi
        
    } > "$audit_file"
    
    echo "📊 Audit report saved to: $audit_file"
    log_action "Permission audit completed: $audit_file"
}

# Fix common permission issues
fix_common_issues() {
    echo "🔧 Fixing common permission issues..."
    
    # Fix world-writable files
    echo "Fixing world-writable files..."
    local world_writable
    world_writable=$(find /Users -type f -perm -002 2>/dev/null | head -10)
    
    if [[ -n "$world_writable" ]]; then
        echo "Found world-writable files:"
        echo "$world_writable"
        
        echo "$world_writable" | while read -r file; do
            if [[ -f "$file" ]]; then
                echo "Fixing: $file"
                sudo chmod o-w "$file"
                log_action "Removed world-write permission from: $file"
            fi
        done
    else
        echo "✅ No world-writable files found"
    fi
    
    # Fix common application permission issues
    echo "Fixing application permissions..."
    if [[ -d "/Applications" ]]; then
        sudo find /Applications -name "*.app" -type d -exec chmod 755 {} \; 2>/dev/null
        log_action "Fixed application permissions in /Applications"
    fi
    
    # Fix user home directory permissions
    echo "Fixing user home directory permissions..."
    for user_home in /Users/*; do
        if [[ -d "$user_home" && "$(basename "$user_home")" != "Shared" ]]; then
            username=$(basename "$user_home")
            if id "$username" &>/dev/null; then
                sudo chmod 755 "$user_home"
                sudo chown "$username:staff" "$user_home"
                log_action "Fixed home directory permissions for: $username"
            fi
        fi
    done
    
    echo "✅ Common permission issues fixed"
}

# Generate permission report
generate_permission_report() {
    local report_file="$REPORT_DIR/permission_report_$(date +%Y%m%d_%H%M%S).txt"
    
    echo "📊 Generating comprehensive permission report..."
    
    {
        echo "MacFleet Permission Management Report"
        echo "Generated: $(date)"
        echo "Hostname: $(hostname)"
        echo "User: $(whoami)"
        echo "======================================="
        echo ""
        
        echo "=== System Information ==="
        echo "macOS Version: $(sw_vers -productVersion)"
        echo "Build: $(sw_vers -buildVersion)"
        echo "Kernel: $(uname -r)"
        echo ""
        
        echo "=== Critical Directory Permissions ==="
        for dir in "/Applications" "/System" "/usr" "/etc" "/var"; do
            if [[ -d "$dir" ]]; then
                echo "$dir: $(ls -ld "$dir" | awk '{print $1, $3, $4}')"
            fi
        done
        echo ""
        
        echo "=== User Home Directory Permissions ==="
        for user_home in /Users/*; do
            if [[ -d "$user_home" ]]; then
                echo "$(basename "$user_home"): $(ls -ld "$user_home" | awk '{print $1, $3, $4}')"
            fi
        done
        echo ""
        
        echo "=== Security Concerns ==="
        echo "World-writable files: $(find /Users -type f -perm -002 2>/dev/null | wc -l)"
        echo "SUID files: $(find /usr -type f -perm -4000 2>/dev/null | wc -l)"
        echo "SGID files: $(find /usr -type f -perm -2000 2>/dev/null | wc -l)"
        echo ""
        
        echo "=== Recent Permission Changes ==="
        tail -20 "$LOG_FILE" 2>/dev/null || echo "No recent changes logged"
        
    } > "$report_file"
    
    echo "📊 Report saved to: $report_file"
    log_action "Permission report generated: $report_file"
}

# Main execution function
main() {
    local action="${1:-help}"
    local target="${2:-}"
    local permission="${3:-}"
    
    log_action "=== MacFleet Permission Management Started ==="
    
    setup_directories
    
    case "$action" in
        "view")
            if [[ -n "$target" ]]; then
                audit_permissions "$target"
            else
                echo "❌ Please specify target path"
                echo "Usage: $0 view /path/to/target"
            fi
            ;;
        "set")
            if [[ -n "$target" && -n "$permission" ]]; then
                create_permission_backup "$target"
                chmod "$permission" "$target"
                log_action "Set permissions $permission on $target"
            else
                echo "❌ Please specify target and permission"
                echo "Usage: $0 set /path/to/target 755"
            fi
            ;;
        "policy")
            if [[ -n "$target" ]]; then
                apply_enterprise_policy "$target"
            else
                echo "❌ Please specify policy name"
                echo "Available policies: secure_documents, shared_workspace, application_deployment, system_hardening"
            fi
            ;;
        "audit")
            if [[ -n "$target" ]]; then
                audit_permissions "$target"
            else
                audit_permissions "/Users"
            fi
            ;;
        "fix")
            fix_common_issues
            ;;
        "report")
            generate_permission_report
            ;;
        "help"|*)
            echo "MacFleet Permission Management Tool"
            echo "Usage: $0 [action] [target] [permission]"
            echo ""
            echo "Actions:"
            echo "  view [path]       - View permissions for path"
            echo "  set [path] [perm] - Set permissions (e.g., 755)"
            echo "  policy [name]     - Apply enterprise permission policy"
            echo "  audit [path]      - Audit permissions and security"
            echo "  fix               - Fix common permission issues"
            echo "  report            - Generate comprehensive report"
            echo "  help              - Show this help message"
            echo ""
            echo "Policies:"
            echo "  secure_documents     - Apply secure document permissions"
            echo "  shared_workspace     - Configure shared workspace permissions"
            echo "  application_deployment - Set application directory permissions"
            echo "  system_hardening     - Apply system security hardening"
            ;;
    esac
    
    log_action "=== MacFleet Permission Management Completed ==="
}

# Execute main function
main "$@"

Common Permission Scenarios

Secure File Storage

# Create secure directory with restricted access
sudo mkdir -p /opt/macfleet/secure
sudo chmod 700 /opt/macfleet/secure
sudo chown root:admin /opt/macfleet/secure

Shared Team Directory

# Create shared directory for team collaboration
sudo mkdir -p /Users/Shared/TeamProject
sudo chmod 775 /Users/Shared/TeamProject
sudo chgrp staff /Users/Shared/TeamProject

Application Deployment

# Set standard application permissions
sudo chmod 755 /Applications/MyApp.app
sudo chown root:admin /Applications/MyApp.app

Permission Reference Guide

Common Permission Patterns

Use CaseOctalSymbolicDescription
Private file600rw-------Owner read/write only
Shared file644rw-r--r--Owner write, others read
Executable755rwxr-xr-xOwner full, others read/execute
Secure directory700rwx------Owner access only
Shared directory755rwxr-xr-xOwner full, others read/list
Team directory775rwxrwxr-xOwner/group full, others read

Quick Commands Reference

# View permissions
ls -la filename
stat -f "%A %N" filename

# Set permissions
chmod 755 filename              # Octal notation
chmod u=rwx,g=rx,o=rx filename  # Symbolic notation

# Change ownership
chown user:group filename       # Change both user and group
chown user filename            # Change user only
chgrp group filename           # Change group only

# Recursive operations
chmod -R 755 directory/        # Apply to all contents
chown -R user:group directory/ # Change ownership recursively

Security Considerations

  • Principle of Least Privilege - Grant minimum necessary permissions
  • Regular Audits - Monitor permission changes and compliance
  • Backup Before Changes - Always create backups before modifications
  • World-Writable Files - Avoid or carefully control world-writable permissions
  • SUID/SGID Files - Monitor and limit special permission files
  • System Directory Protection - Maintain strict permissions on system directories

Troubleshooting

Permission Denied Errors

# Check current permissions
ls -la /path/to/file

# Check if you have sudo access
sudo -l

# Fix common permission issues
sudo chmod +r /path/to/file    # Add read permission
sudo chmod +x /path/to/file    # Add execute permission

Ownership Issues

# Check current ownership
ls -la /path/to/file

# Fix ownership
sudo chown $(whoami) /path/to/file    # Make current user owner
sudo chgrp staff /path/to/file        # Set to staff group

Important Notes

  • Administrative privileges may be required for system files
  • Backup permissions before making changes for easy restoration
  • Test changes on individual devices before fleet deployment
  • Document permission policies for compliance and auditing
  • Monitor security with regular permission audits

File Encryption Management on macOS

Secure sensitive data across your MacFleet devices using advanced file encryption and decryption techniques. This tutorial covers OpenSSL encryption methods, enterprise key management, security policies, and compliance monitoring for comprehensive data protection.

Understanding File Encryption on macOS

File encryption protects sensitive data by converting it into an unreadable format that can only be accessed with the correct decryption key. While macOS offers FileVault for full-disk encryption, selective file encryption provides granular control over specific documents and data files.

Key Encryption Methods

  • DES (Data Encryption Standard) - Legacy encryption for basic protection
  • AES-256-CBC - Advanced Encryption Standard with 256-bit keys
  • AES-256-GCM - AES with Galois/Counter Mode for authenticated encryption
  • ChaCha20-Poly1305 - Modern stream cipher with authentication
  • RSA - Public-key encryption for key exchange and digital signatures

Basic File Encryption

Simple File Encryption

#!/bin/bash

# Basic file encryption using OpenSSL
INPUT_FILE="/path/to/original.txt"
OUTPUT_FILE="/path/to/encrypted.txt"
PASSWORD="your_secure_password"

openssl des -in "$INPUT_FILE" -out "$OUTPUT_FILE" -k "$PASSWORD"

echo "File encrypted successfully: $OUTPUT_FILE"

Enhanced File Encryption

#!/bin/bash

# Enhanced file encryption with validation
encrypt_file() {
    local input_file="$1"
    local output_file="$2"
    local password="$3"
    local algorithm="${4:-aes-256-cbc}"
    
    # Validate input parameters
    if [[ -z "$input_file" ]] || [[ -z "$output_file" ]] || [[ -z "$password" ]]; then
        echo "❌ Error: Missing required parameters"
        echo "Usage: encrypt_file <input_file> <output_file> <password> [algorithm]"
        return 1
    fi
    
    # Check if input file exists
    if [[ ! -f "$input_file" ]]; then
        echo "❌ Error: Input file does not exist: $input_file"
        return 1
    fi
    
    # Create output directory if it doesn't exist
    local output_dir
    output_dir=$(dirname "$output_file")
    mkdir -p "$output_dir"
    
    echo "🔒 Encrypting file with $algorithm..."
    echo "  Input: $input_file"
    echo "  Output: $output_file"
    
    # Perform encryption
    if openssl "$algorithm" -in "$input_file" -out "$output_file" -k "$password" 2>/dev/null; then
        echo "✅ File encrypted successfully"
        
        # Verify encrypted file was created
        if [[ -f "$output_file" ]]; then
            local file_size
            file_size=$(stat -f%z "$output_file" 2>/dev/null || echo "0")
            echo "  Encrypted file size: ${file_size} bytes"
        fi
        
        return 0
    else
        echo "❌ Encryption failed"
        return 1
    fi
}

# Usage examples
encrypt_file "/Users/john/Documents/sensitive.txt" "/Users/john/Encrypted/sensitive.enc" "mypassword123" "aes-256-cbc"

AES-256 Strong Encryption

#!/bin/bash

# Advanced AES-256-CBC encryption with salt
encrypt_file_aes256() {
    local input_file="$1"
    local output_file="$2"
    local password="$3"
    
    echo "🔐 Performing AES-256-CBC encryption..."
    
    # Use AES-256-CBC with salt for enhanced security
    if openssl aes-256-cbc -salt -in "$input_file" -out "$output_file" -k "$password"; then
        echo "✅ AES-256 encryption completed"
        
        # Generate file hash for integrity verification
        local hash
        hash=$(shasum -a 256 "$output_file" | cut -d' ' -f1)
        echo "  File hash (SHA-256): $hash"
        
        # Save hash for verification
        echo "$hash" > "${output_file}.sha256"
        echo "  Hash saved to: ${output_file}.sha256"
        
        return 0
    else
        echo "❌ AES-256 encryption failed"
        return 1
    fi
}

# Example usage
encrypt_file_aes256 "/path/to/document.pdf" "/path/to/document.pdf.enc" "strong_password_123!"

File Decryption

Basic File Decryption

#!/bin/bash

# Basic file decryption using OpenSSL
INPUT_FILE="/path/to/encrypted.txt"
OUTPUT_FILE="/path/to/decrypted.txt"
PASSWORD="your_secure_password"

openssl des -d -in "$INPUT_FILE" -out "$OUTPUT_FILE" -k "$PASSWORD"

echo "File decrypted successfully: $OUTPUT_FILE"

Advanced File Decryption

#!/bin/bash

# Advanced file decryption with verification
decrypt_file() {
    local input_file="$1"
    local output_file="$2"
    local password="$3"
    local algorithm="${4:-aes-256-cbc}"
    
    # Validate parameters
    if [[ -z "$input_file" ]] || [[ -z "$output_file" ]] || [[ -z "$password" ]]; then
        echo "❌ Error: Missing required parameters"
        echo "Usage: decrypt_file <input_file> <output_file> <password> [algorithm]"
        return 1
    fi
    
    # Check if encrypted file exists
    if [[ ! -f "$input_file" ]]; then
        echo "❌ Error: Encrypted file does not exist: $input_file"
        return 1
    fi
    
    echo "🔓 Decrypting file with $algorithm..."
    echo "  Input: $input_file"
    echo "  Output: $output_file"
    
    # Create output directory
    local output_dir
    output_dir=$(dirname "$output_file")
    mkdir -p "$output_dir"
    
    # Perform decryption
    if openssl "$algorithm" -d -in "$input_file" -out "$output_file" -k "$password" 2>/dev/null; then
        echo "✅ File decrypted successfully"
        
        # Verify hash if available
        verify_file_integrity "$input_file" "$output_file"
        
        return 0
    else
        echo "❌ Decryption failed - incorrect password or corrupted file"
        return 1
    fi
}

# Verify file integrity
verify_file_integrity() {
    local encrypted_file="$1"
    local decrypted_file="$2"
    local hash_file="${encrypted_file}.sha256"
    
    if [[ -f "$hash_file" ]]; then
        echo "🔍 Verifying file integrity..."
        local stored_hash expected_hash
        stored_hash=$(cat "$hash_file")
        
        # For verification, we need the original file hash (this is a simplified example)
        if [[ -f "$decrypted_file" ]]; then
            echo "  File integrity check completed"
        fi
    fi
}

# Usage example
decrypt_file "/path/to/document.pdf.enc" "/path/to/document_recovered.pdf" "strong_password_123!" "aes-256-cbc"

Batch File Operations

Encrypt Multiple Files

#!/bin/bash

# Batch encrypt multiple files
batch_encrypt() {
    local source_dir="$1"
    local encrypted_dir="$2"
    local password="$3"
    local file_pattern="${4:-*}"
    
    echo "📁 Batch encryption starting..."
    echo "  Source: $source_dir"
    echo "  Target: $encrypted_dir"
    echo "  Pattern: $file_pattern"
    
    # Create encrypted directory
    mkdir -p "$encrypted_dir"
    
    local count=0
    local success=0
    
    # Process files matching pattern
    while IFS= read -r -d '' file; do
        if [[ -f "$file" ]]; then
            local relative_path
            relative_path=$(realpath --relative-to="$source_dir" "$file")
            local encrypted_file="$encrypted_dir/${relative_path}.enc"
            
            # Create subdirectories if needed
            mkdir -p "$(dirname "$encrypted_file")"
            
            echo "  Processing: $relative_path"
            
            if openssl aes-256-cbc -salt -in "$file" -out "$encrypted_file" -k "$password" 2>/dev/null; then
                ((success++))
                echo "    ✅ Encrypted"
            else
                echo "    ❌ Failed"
            fi
            
            ((count++))
        fi
    done < <(find "$source_dir" -name "$file_pattern" -type f -print0)
    
    echo "🎉 Batch encryption completed: $success/$count files encrypted"
}

# Usage example
batch_encrypt "/Users/john/Documents" "/Users/john/Encrypted" "batch_password123" "*.txt"

Decrypt Multiple Files

#!/bin/bash

# Batch decrypt multiple files
batch_decrypt() {
    local encrypted_dir="$1"
    local output_dir="$2"
    local password="$3"
    
    echo "📂 Batch decryption starting..."
    echo "  Source: $encrypted_dir"
    echo "  Target: $output_dir"
    
    # Create output directory
    mkdir -p "$output_dir"
    
    local count=0
    local success=0
    
    # Process .enc files
    while IFS= read -r -d '' file; do
        if [[ -f "$file" && "$file" == *.enc ]]; then
            local relative_path
            relative_path=$(realpath --relative-to="$encrypted_dir" "$file")
            # Remove .enc extension
            local decrypted_file="$output_dir/${relative_path%.enc}"
            
            # Create subdirectories if needed
            mkdir -p "$(dirname "$decrypted_file")"
            
            echo "  Processing: $relative_path"
            
            if openssl aes-256-cbc -d -in "$file" -out "$decrypted_file" -k "$password" 2>/dev/null; then
                ((success++))
                echo "    ✅ Decrypted"
            else
                echo "    ❌ Failed"
            fi
            
            ((count++))
        fi
    done < <(find "$encrypted_dir" -name "*.enc" -type f -print0)
    
    echo "🎉 Batch decryption completed: $success/$count files decrypted"
}

# Usage example
batch_decrypt "/Users/john/Encrypted" "/Users/john/Decrypted" "batch_password123"

Enterprise Encryption Management Script

#!/bin/bash

# MacFleet File Encryption Management System
# Comprehensive encryption/decryption management for enterprise environments

# Configuration
LOG_FILE="/var/log/macfleet_encryption.log"
CONFIG_FILE="/etc/macfleet/encryption_policy.conf"
KEY_STORE="/var/lib/macfleet/keys"
AUDIT_LOG="/var/log/macfleet_encryption_audit.log"

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

# Audit logging
audit_log() {
    echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" >> "$AUDIT_LOG"
}

# Setup environment
setup_environment() {
    sudo mkdir -p "$(dirname "$LOG_FILE")" 2>/dev/null
    sudo mkdir -p "$(dirname "$CONFIG_FILE")" 2>/dev/null
    sudo mkdir -p "$KEY_STORE" 2>/dev/null
    sudo chmod 700 "$KEY_STORE" 2>/dev/null
}

# Load configuration
load_config() {
    if [[ -f "$CONFIG_FILE" ]]; then
        source "$CONFIG_FILE"
        log_action "Configuration loaded from $CONFIG_FILE"
    else
        # Default configuration
        DEFAULT_ALGORITHM="aes-256-cbc"
        REQUIRE_STRONG_PASSWORDS=true
        MIN_PASSWORD_LENGTH=12
        ENCRYPTION_ENABLED=true
        AUTO_BACKUP_KEYS=true
        COMPLIANCE_MODE="HIPAA"  # HIPAA, PCI-DSS, GDPR
        
        log_action "Using default encryption configuration"
    fi
}

# Validate password strength
validate_password() {
    local password="$1"
    
    if [[ "$REQUIRE_STRONG_PASSWORDS" != "true" ]]; then
        return 0
    fi
    
    # Check minimum length
    if [[ ${#password} -lt $MIN_PASSWORD_LENGTH ]]; then
        echo "❌ Password too short (minimum $MIN_PASSWORD_LENGTH characters)"
        return 1
    fi
    
    # Check complexity
    local has_upper has_lower has_digit has_special
    has_upper=$(echo "$password" | grep -c '[A-Z]')
    has_lower=$(echo "$password" | grep -c '[a-z]')
    has_digit=$(echo "$password" | grep -c '[0-9]')
    has_special=$(echo "$password" | grep -c '[^A-Za-z0-9]')
    
    if [[ $has_upper -eq 0 ]] || [[ $has_lower -eq 0 ]] || [[ $has_digit -eq 0 ]] || [[ $has_special -eq 0 ]]; then
        echo "❌ Password must contain uppercase, lowercase, digit, and special character"
        return 1
    fi
    
    return 0
}

# Generate secure key
generate_secure_key() {
    local key_name="$1"
    local key_file="$KEY_STORE/${key_name}.key"
    
    # Generate random 256-bit key
    openssl rand -base64 32 > "$key_file"
    chmod 600 "$key_file"
    
    log_action "Generated secure key: $key_name"
    audit_log "KEY_GENERATED: $key_name by $(whoami)"
    
    echo "$key_file"
}

# Encrypt file with enterprise features
enterprise_encrypt() {
    local input_file="$1"
    local output_file="$2"
    local key_name="$3"
    local algorithm="${4:-$DEFAULT_ALGORITHM}"
    
    if [[ "$ENCRYPTION_ENABLED" != "true" ]]; then
        echo "❌ Encryption is disabled by policy"
        return 1
    fi
    
    # Validate input file
    if [[ ! -f "$input_file" ]]; then
        echo "❌ Input file not found: $input_file"
        return 1
    fi
    
    # Get or generate key
    local key_file="$KEY_STORE/${key_name}.key"
    if [[ ! -f "$key_file" ]]; then
        echo "🔑 Generating new encryption key: $key_name"
        generate_secure_key "$key_name"
    fi
    
    local password
    password=$(cat "$key_file")
    
    echo "🔒 Enterprise encryption starting..."
    echo "  Algorithm: $algorithm"
    echo "  Input: $input_file"
    echo "  Output: $output_file"
    echo "  Key: $key_name"
    
    # Create metadata file
    local metadata_file="${output_file}.meta"
    cat > "$metadata_file" << EOF
{
    "algorithm": "$algorithm",
    "key_name": "$key_name",
    "encrypted_by": "$(whoami)",
    "timestamp": "$(date -u +%Y-%m-%dT%H:%M:%SZ)",
    "hostname": "$(hostname)",
    "compliance_mode": "$COMPLIANCE_MODE",
    "file_size": $(stat -f%z "$input_file"),
    "original_name": "$(basename "$input_file")"
}
EOF
    
    # Perform encryption
    if openssl "$algorithm" -salt -in "$input_file" -out "$output_file" -pass file:"$key_file"; then
        # Generate integrity hash
        local hash
        hash=$(shasum -a 256 "$output_file" | cut -d' ' -f1)
        echo "  \"integrity_hash\": \"$hash\"" >> "$metadata_file"
        
        log_action "File encrypted: $input_file -> $output_file (key: $key_name)"
        audit_log "ENCRYPT: $input_file -> $output_file by $(whoami) using $key_name"
        
        echo "✅ Enterprise encryption completed"
        echo "  Metadata: $metadata_file"
        
        # Backup key if enabled
        if [[ "$AUTO_BACKUP_KEYS" == "true" ]]; then
            backup_key "$key_name"
        fi
        
        return 0
    else
        echo "❌ Encryption failed"
        log_action "Encryption failed: $input_file"
        return 1
    fi
}

# Decrypt file with enterprise features
enterprise_decrypt() {
    local input_file="$1"
    local output_file="$2"
    local key_name="$3"
    
    # Check if encrypted file exists
    if [[ ! -f "$input_file" ]]; then
        echo "❌ Encrypted file not found: $input_file"
        return 1
    fi
    
    # Load metadata
    local metadata_file="${input_file}.meta"
    if [[ ! -f "$metadata_file" ]]; then
        echo "⚠️  Metadata file not found, using default algorithm"
        local algorithm="$DEFAULT_ALGORITHM"
    else
        local algorithm
        algorithm=$(grep '"algorithm"' "$metadata_file" | cut -d'"' -f4)
        echo "📋 Loaded metadata: algorithm=$algorithm"
    fi
    
    # Get key
    local key_file="$KEY_STORE/${key_name}.key"
    if [[ ! -f "$key_file" ]]; then
        echo "❌ Decryption key not found: $key_name"
        return 1
    fi
    
    echo "🔓 Enterprise decryption starting..."
    echo "  Algorithm: $algorithm"
    echo "  Input: $input_file"
    echo "  Output: $output_file"
    echo "  Key: $key_name"
    
    # Perform decryption
    if openssl "$algorithm" -d -in "$input_file" -out "$output_file" -pass file:"$key_file"; then
        # Verify integrity if hash available
        if [[ -f "$metadata_file" ]]; then
            verify_integrity "$input_file" "$metadata_file"
        fi
        
        log_action "File decrypted: $input_file -> $output_file (key: $key_name)"
        audit_log "DECRYPT: $input_file -> $output_file by $(whoami) using $key_name"
        
        echo "✅ Enterprise decryption completed"
        return 0
    else
        echo "❌ Decryption failed"
        log_action "Decryption failed: $input_file"
        audit_log "DECRYPT_FAILED: $input_file by $(whoami)"
        return 1
    fi
}

# Verify file integrity
verify_integrity() {
    local encrypted_file="$1"
    local metadata_file="$2"
    
    if [[ -f "$metadata_file" ]]; then
        local stored_hash current_hash
        stored_hash=$(grep '"integrity_hash"' "$metadata_file" | cut -d'"' -f4)
        current_hash=$(shasum -a 256 "$encrypted_file" | cut -d' ' -f1)
        
        if [[ "$stored_hash" == "$current_hash" ]]; then
            echo "✅ File integrity verified"
        else
            echo "⚠️  File integrity check failed - file may be corrupted"
            log_action "Integrity check failed: $encrypted_file"
        fi
    fi
}

# Backup encryption key
backup_key() {
    local key_name="$1"
    local key_file="$KEY_STORE/${key_name}.key"
    local backup_dir="$KEY_STORE/backups"
    
    mkdir -p "$backup_dir"
    
    local backup_file="$backup_dir/${key_name}_$(date +%Y%m%d_%H%M%S).key"
    cp "$key_file" "$backup_file"
    
    log_action "Key backed up: $key_name -> $backup_file"
}

# Generate encryption report
generate_encryption_report() {
    local report_file="/tmp/macfleet_encryption_report_$(date +%Y%m%d_%H%M%S).txt"
    
    {
        echo "MacFleet Encryption Management Report"
        echo "===================================="
        echo "Generated: $(date)"
        echo "Hostname: $(hostname)"
        echo "Compliance Mode: $COMPLIANCE_MODE"
        echo ""
        
        echo "Configuration:"
        echo "  Default Algorithm: $DEFAULT_ALGORITHM"
        echo "  Strong Passwords: $REQUIRE_STRONG_PASSWORDS"
        echo "  Min Password Length: $MIN_PASSWORD_LENGTH"
        echo "  Encryption Enabled: $ENCRYPTION_ENABLED"
        echo ""
        
        echo "Available Keys:"
        if ls "$KEY_STORE"/*.key >/dev/null 2>&1; then
            for key_file in "$KEY_STORE"/*.key; do
                local key_name
                key_name=$(basename "$key_file" .key)
                echo "  $key_name ($(stat -f%Sm "$key_file"))"
            done
        else
            echo "  No keys found"
        fi
        echo ""
        
        echo "Recent Encryption Activity:"
        if [[ -f "$AUDIT_LOG" ]]; then
            tail -10 "$AUDIT_LOG"
        else
            echo "  No activity logged"
        fi
        
    } > "$report_file"
    
    echo "📄 Encryption report generated: $report_file"
    log_action "Report generated: $report_file"
}

# Main function
main() {
    case "${1:-status}" in
        "encrypt")
            setup_environment
            load_config
            log_action "=== File Encryption Request ==="
            enterprise_encrypt "$2" "$3" "$4" "$5"
            ;;
        "decrypt")
            setup_environment
            load_config
            log_action "=== File Decryption Request ==="
            enterprise_decrypt "$2" "$3" "$4"
            ;;
        "generate-key")
            setup_environment
            load_config
            log_action "=== Key Generation Request ==="
            generate_secure_key "$2"
            ;;
        "report")
            setup_environment
            load_config
            generate_encryption_report
            ;;
        "list-algorithms")
            echo "📋 Available encryption algorithms:"
            openssl list-cipher-commands | tr ' ' '\n' | sort
            ;;
        "status"|*)
            setup_environment
            load_config
            echo "📊 MacFleet Encryption Status:"
            echo "=============================="
            echo "Encryption Enabled: $ENCRYPTION_ENABLED"
            echo "Default Algorithm: $DEFAULT_ALGORITHM"
            echo "Compliance Mode: $COMPLIANCE_MODE"
            echo "Key Store: $KEY_STORE"
            
            if ls "$KEY_STORE"/*.key >/dev/null 2>&1; then
                echo "Available Keys: $(ls "$KEY_STORE"/*.key | wc -l)"
            else
                echo "Available Keys: 0"
            fi
            ;;
    esac
}

# Execute main function with parameters
main "$@"

Encryption Algorithms Reference

Quick Comparison

AlgorithmKey SizeSecurityPerformanceUse Case
DES56-bitLowFastLegacy systems only
AES-128-CBC128-bitGoodFastGeneral purpose
AES-256-CBC256-bitExcellentMediumHigh security
AES-256-GCM256-bitExcellentMediumAuthenticated encryption
ChaCha20256-bitExcellentFastModern alternative

List Available Algorithms

# Display all available encryption algorithms
openssl list-cipher-commands

# Common secure algorithms
openssl enc -ciphers | grep -E "(aes|chacha)"

Security Best Practices

Password Management

#!/bin/bash

# Generate secure password
generate_secure_password() {
    local length="${1:-16}"
    
    # Generate password with mixed characters
    openssl rand -base64 "$length" | tr -d "=+/" | cut -c1-"$length"
}

# Example: Generate 20-character password
secure_password=$(generate_secure_password 20)
echo "Generated password: $secure_password"

Key Rotation

#!/bin/bash

# Rotate encryption keys
rotate_encryption_key() {
    local old_key="$1"
    local new_key="$2"
    local files_dir="$3"
    
    echo "🔄 Rotating encryption key: $old_key -> $new_key"
    
    # Generate new key
    generate_secure_key "$new_key"
    
    # Re-encrypt files with new key
    while IFS= read -r -d '' file; do
        if [[ "$file" == *.enc ]]; then
            local temp_file="/tmp/temp_decrypt_$$"
            
            # Decrypt with old key
            if enterprise_decrypt "$file" "$temp_file" "$old_key"; then
                # Re-encrypt with new key
                if enterprise_encrypt "$temp_file" "$file" "$new_key"; then
                    echo "  ✅ Rotated: $(basename "$file")"
                fi
            fi
            
            # Clean up
            rm -f "$temp_file"
        fi
    done < <(find "$files_dir" -name "*.enc" -type f -print0)
    
    echo "🎉 Key rotation completed"
}

Troubleshooting

Common Issues

  1. Encryption fails with "bad decrypt"

    • Verify correct algorithm is used
    • Check password/key file integrity
    • Ensure sufficient disk space
  2. Permission denied errors

    • Check file permissions
    • Verify key store access rights
    • Run with appropriate user privileges
  3. Corrupted encrypted files

    • Verify file integrity hashes
    • Check for disk errors
    • Restore from backups if available

Verification Commands

# Test encryption/decryption cycle
test_encryption() {
    local test_file="/tmp/test_encrypt.txt"
    local encrypted_file="/tmp/test_encrypt.enc"
    local decrypted_file="/tmp/test_decrypt.txt"
    
    # Create test file
    echo "This is a test file for encryption" > "$test_file"
    
    # Encrypt
    openssl aes-256-cbc -in "$test_file" -out "$encrypted_file" -k "testpassword"
    
    # Decrypt
    openssl aes-256-cbc -d -in "$encrypted_file" -out "$decrypted_file" -k "testpassword"
    
    # Compare
    if diff "$test_file" "$decrypted_file" >/dev/null; then
        echo "✅ Encryption/decryption test passed"
    else
        echo "❌ Encryption/decryption test failed"
    fi
    
    # Cleanup
    rm -f "$test_file" "$encrypted_file" "$decrypted_file"
}

Important Notes

  • Algorithm selection: Use AES-256-CBC or stronger for sensitive data
  • Password security: Implement strong password policies for enterprise use
  • Key management: Securely store and backup encryption keys
  • Compliance: Ensure encryption methods meet regulatory requirements
  • Performance: Consider file size and system resources when choosing algorithms
  • Backup strategy: Always maintain secure backups of encryption keys

Enterprise Deployment

For enterprise deployment, consider:

  1. Policy definition - Establish encryption standards and procedures
  2. Key management - Implement secure key storage and rotation
  3. Compliance monitoring - Ensure adherence to regulatory requirements
  4. User training - Educate users on proper encryption practices
  5. Audit trails - Maintain comprehensive logs of encryption activities