Tutorial

Novas atualizações e melhorias para a Macfleet.

Aviso importante

Os exemplos de código e scripts fornecidos nestes tutoriais são apenas para fins educacionais. A Macfleet não é responsável por quaisquer problemas, danos ou vulnerabilidades de segurança que possam surgir do uso, modificação ou implementação destes exemplos. Sempre revise e teste o código em um ambiente seguro antes de usá-lo em sistemas de produção.

Delete Mobile Accounts on macOS Devices

This comprehensive guide demonstrates how to delete mobile accounts on macOS devices for effective user management, device reassignment, and organizational cleanup scenarios.

Overview

Mobile accounts on macOS are user profiles designed for seamless access to resources across different devices within organizations. Unlike local accounts, mobile accounts are centrally managed by directory services like Open Directory or Active Directory, enabling administrators to control access, enforce policies, and manage user data centrally.

Common Scenarios for Mobile Account Deletion

  • Employee departures: Clean up accounts when employees leave the organization
  • Role changes: Remove old mobile accounts when users change positions
  • Device reassignment: Prepare devices for new users
  • Security compliance: Remove inactive or compromised accounts
  • Storage optimization: Free up disk space by removing unused accounts
  • Organizational restructuring: Clean up accounts during company changes

Basic Mobile Account Deletion

Simple Mobile Account Removal Script

Create a basic script to remove all mobile accounts from a macOS device:

#!/bin/bash

# Basic mobile account deletion script
# Usage: ./delete_mobile_accounts.sh

delete_mobile_accounts() {
    echo "Starting mobile account deletion process..."
    
    # Check if running as root
    if [ "$EUID" -ne 0 ]; then
        echo "Error: This script must be run as root"
        exit 1
    fi
    
    # Counter for deleted accounts
    local deleted_count=0
    
    # Loop through all users
    for username in $(dscl . -list /Users | grep -v '^_'); do
        # Check if user has mobile account authentication
        auth_authority=$(dscl . -read "/Users/$username" AuthenticationAuthority 2>/dev/null | grep "LocalCachedUser")
        
        if [ -n "$auth_authority" ]; then
            echo "Removing mobile account: $username"
            
            # Delete user from directory services
            dscl . -delete "/Users/$username"
            
            # Remove user's home directory
            rm -rf "/Users/$username"
            
            ((deleted_count++))
        fi
    done
    
    echo "Mobile accounts removal complete. Deleted $deleted_count accounts."
    echo "Note: Please restart the device for changes to take full effect."
}

# Execute deletion
delete_mobile_accounts

Enhanced Mobile Account Management Script

#!/bin/bash

# Enhanced mobile account management with safety checks and logging
# Usage: ./enhanced_mobile_account_manager.sh

enhanced_mobile_account_manager() {
    local log_file="/var/log/macfleet_mobile_accounts.log"
    local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
    local backup_dir="/var/backups/macfleet/mobile_accounts"
    
    # Check if running as root
    if [ "$EUID" -ne 0 ]; then
        echo "Error: This script must be run as root"
        exit 1
    fi
    
    # Create log directory
    mkdir -p /var/log
    mkdir -p "$backup_dir"
    
    echo "[$timestamp] Enhanced mobile account manager started" >> "$log_file"
    
    # Display current mobile accounts
    display_mobile_accounts
    
    # Confirm deletion
    echo ""
    read -p "Do you want to proceed with mobile account deletion? (y/N): " confirm
    
    if [ "$confirm" = "y" ] || [ "$confirm" = "Y" ]; then
        create_account_backup
        delete_mobile_accounts_enhanced
    else
        echo "Operation cancelled."
        echo "[$timestamp] Mobile account deletion cancelled by user" >> "$log_file"
    fi
}

display_mobile_accounts() {
    echo "======================================="
    echo "Current Mobile Accounts on Device"
    echo "======================================="
    
    local mobile_accounts_found=false
    
    for username in $(dscl . -list /Users | grep -v '^_'); do
        auth_authority=$(dscl . -read "/Users/$username" AuthenticationAuthority 2>/dev/null | grep "LocalCachedUser")
        
        if [ -n "$auth_authority" ]; then
            mobile_accounts_found=true
            
            # Get additional user information
            local real_name=$(dscl . -read "/Users/$username" RealName 2>/dev/null | cut -d: -f2 | xargs)
            local uid=$(dscl . -read "/Users/$username" UniqueID 2>/dev/null | cut -d: -f2 | xargs)
            local home_dir=$(dscl . -read "/Users/$username" NFSHomeDirectory 2>/dev/null | cut -d: -f2 | xargs)
            local last_login=$(last -1 "$username" 2>/dev/null | head -1 | awk '{print $3, $4, $5, $6}')
            
            echo "Username: $username"
            echo "  Real Name: $real_name"
            echo "  UID: $uid"
            echo "  Home Directory: $home_dir"
            echo "  Last Login: $last_login"
            
            # Check home directory size
            if [ -d "$home_dir" ]; then
                local dir_size=$(du -sh "$home_dir" 2>/dev/null | cut -f1)
                echo "  Home Directory Size: $dir_size"
            fi
            
            echo ""
        fi
    done
    
    if [ "$mobile_accounts_found" = false ]; then
        echo "No mobile accounts found on this device."
        echo "[$timestamp] No mobile accounts found on device" >> "$log_file"
        exit 0
    fi
}

create_account_backup() {
    echo "Creating backup of mobile account information..."
    
    local backup_file="$backup_dir/mobile_accounts_backup_$(date +%Y%m%d_%H%M%S).txt"
    
    cat > "$backup_file" << EOF
MacFleet Mobile Account Backup
Generated: $(date)
Device: $(scutil --get ComputerName)
macOS Version: $(sw_vers -productVersion)

Mobile Accounts Found:
EOF
    
    for username in $(dscl . -list /Users | grep -v '^_'); do
        auth_authority=$(dscl . -read "/Users/$username" AuthenticationAuthority 2>/dev/null | grep "LocalCachedUser")
        
        if [ -n "$auth_authority" ]; then
            echo "Username: $username" >> "$backup_file"
            dscl . -read "/Users/$username" >> "$backup_file"
            echo "---" >> "$backup_file"
        fi
    done
    
    echo "Backup created: $backup_file"
    echo "[$timestamp] Mobile account backup created: $backup_file" >> "$log_file"
}

delete_mobile_accounts_enhanced() {
    echo "======================================="
    echo "Deleting Mobile Accounts"
    echo "======================================="
    
    local deleted_count=0
    local failed_count=0
    
    for username in $(dscl . -list /Users | grep -v '^_'); do
        auth_authority=$(dscl . -read "/Users/$username" AuthenticationAuthority 2>/dev/null | grep "LocalCachedUser")
        
        if [ -n "$auth_authority" ]; then
            echo "Processing mobile account: $username"
            
            # Check if user is currently logged in
            if who | grep -q "^$username "; then
                echo "  Warning: User $username is currently logged in. Skipping..."
                echo "[$timestamp] Skipped deletion of $username - user currently logged in" >> "$log_file"
                ((failed_count++))
                continue
            fi
            
            # Delete user from directory services
            if dscl . -delete "/Users/$username" 2>/dev/null; then
                echo "  Deleted user record from directory services"
            else
                echo "  Warning: Failed to delete user record from directory services"
                echo "[$timestamp] Failed to delete user record for $username" >> "$log_file"
                ((failed_count++))
                continue
            fi
            
            # Remove user's home directory
            local home_dir=$(dscl . -read "/Users/$username" NFSHomeDirectory 2>/dev/null | cut -d: -f2 | xargs)
            if [ -d "$home_dir" ]; then
                if rm -rf "$home_dir" 2>/dev/null; then
                    echo "  Removed home directory: $home_dir"
                else
                    echo "  Warning: Failed to remove home directory: $home_dir"
                    echo "[$timestamp] Failed to remove home directory for $username: $home_dir" >> "$log_file"
                fi
            fi
            
            echo "  Successfully deleted mobile account: $username"
            echo "[$timestamp] Successfully deleted mobile account: $username" >> "$log_file"
            ((deleted_count++))
        fi
    done
    
    echo ""
    echo "======================================="
    echo "Mobile Account Deletion Summary"
    echo "======================================="
    echo "Successfully deleted: $deleted_count accounts"
    echo "Failed to delete: $failed_count accounts"
    echo "Total processed: $((deleted_count + failed_count)) accounts"
    echo ""
    echo "Note: Please restart the device for changes to take full effect."
    
    echo "[$timestamp] Mobile account deletion completed - Success: $deleted_count, Failed: $failed_count" >> "$log_file"
}

# Execute enhanced management
enhanced_mobile_account_manager

Advanced Mobile Account Management

Selective Mobile Account Management

#!/bin/bash

# Selective mobile account management system
# Usage: ./selective_mobile_account_manager.sh

selective_mobile_account_manager() {
    local log_file="/var/log/macfleet_selective_mobile_accounts.log"
    local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
    
    # Check if running as root
    if [ "$EUID" -ne 0 ]; then
        echo "Error: This script must be run as root"
        exit 1
    fi
    
    echo "[$timestamp] Selective mobile account manager started" >> "$log_file"
    
    while true; do
        display_selective_menu
        read -p "Select an option (1-7): " choice
        
        case $choice in
            1)
                list_mobile_accounts_detailed
                ;;
            2)
                delete_specific_mobile_account
                ;;
            3)
                delete_inactive_mobile_accounts
                ;;
            4)
                delete_mobile_accounts_by_criteria
                ;;
            5)
                export_mobile_account_report
                ;;
            6)
                restore_mobile_account_backup
                ;;
            7)
                echo "Exiting selective mobile account manager."
                exit 0
                ;;
            *)
                echo "Invalid option. Please try again."
                ;;
        esac
        
        echo ""
        read -p "Press Enter to continue..."
    done
}

display_selective_menu() {
    clear
    echo "======================================="
    echo "MacFleet Selective Mobile Account Manager"
    echo "======================================="
    echo ""
    echo "1. List all mobile accounts with details"
    echo "2. Delete specific mobile account"
    echo "3. Delete inactive mobile accounts"
    echo "4. Delete mobile accounts by criteria"
    echo "5. Export mobile account report"
    echo "6. Restore from backup"
    echo "7. Exit"
    echo ""
}

list_mobile_accounts_detailed() {
    echo "======================================="
    echo "Detailed Mobile Account Information"
    echo "======================================="
    
    local mobile_accounts=()
    local count=0
    
    for username in $(dscl . -list /Users | grep -v '^_'); do
        auth_authority=$(dscl . -read "/Users/$username" AuthenticationAuthority 2>/dev/null | grep "LocalCachedUser")
        
        if [ -n "$auth_authority" ]; then
            mobile_accounts+=("$username")
            ((count++))
            
            echo "[$count] Mobile Account: $username"
            
            # Get detailed information
            local real_name=$(dscl . -read "/Users/$username" RealName 2>/dev/null | cut -d: -f2 | xargs)
            local uid=$(dscl . -read "/Users/$username" UniqueID 2>/dev/null | cut -d: -f2 | xargs)
            local gid=$(dscl . -read "/Users/$username" PrimaryGroupID 2>/dev/null | cut -d: -f2 | xargs)
            local home_dir=$(dscl . -read "/Users/$username" NFSHomeDirectory 2>/dev/null | cut -d: -f2 | xargs)
            local shell=$(dscl . -read "/Users/$username" UserShell 2>/dev/null | cut -d: -f2 | xargs)
            
            echo "    Real Name: $real_name"
            echo "    UID: $uid"
            echo "    GID: $gid"
            echo "    Home Directory: $home_dir"
            echo "    Shell: $shell"
            
            # Check if user is currently logged in
            if who | grep -q "^$username "; then
                echo "    Status: Currently logged in"
            else
                echo "    Status: Not logged in"
            fi
            
            # Get last login information
            local last_login=$(last -1 "$username" 2>/dev/null | head -1)
            if [ -n "$last_login" ]; then
                echo "    Last Login: $last_login"
            else
                echo "    Last Login: Never"
            fi
            
            # Check home directory size
            if [ -d "$home_dir" ]; then
                local dir_size=$(du -sh "$home_dir" 2>/dev/null | cut -f1)
                echo "    Home Directory Size: $dir_size"
                
                # Check last modification time
                local last_modified=$(stat -f "%Sm" "$home_dir" 2>/dev/null)
                echo "    Last Modified: $last_modified"
            else
                echo "    Home Directory: Not found"
            fi
            
            echo ""
        fi
    done
    
    if [ $count -eq 0 ]; then
        echo "No mobile accounts found on this device."
    else
        echo "Total mobile accounts found: $count"
    fi
}

delete_specific_mobile_account() {
    echo "======================================="
    echo "Delete Specific Mobile Account"
    echo "======================================="
    
    # List mobile accounts with numbers
    local mobile_accounts=()
    local count=0
    
    for username in $(dscl . -list /Users | grep -v '^_'); do
        auth_authority=$(dscl . -read "/Users/$username" AuthenticationAuthority 2>/dev/null | grep "LocalCachedUser")
        
        if [ -n "$auth_authority" ]; then
            mobile_accounts+=("$username")
            ((count++))
            echo "[$count] $username"
        fi
    done
    
    if [ $count -eq 0 ]; then
        echo "No mobile accounts found on this device."
        return
    fi
    
    echo ""
    read -p "Enter the number of the account to delete (1-$count): " selection
    
    if [[ "$selection" =~ ^[0-9]+$ ]] && [ "$selection" -ge 1 ] && [ "$selection" -le $count ]; then
        local selected_user="${mobile_accounts[$((selection-1))]}"
        
        echo ""
        echo "Selected account: $selected_user"
        
        # Show account details
        local real_name=$(dscl . -read "/Users/$selected_user" RealName 2>/dev/null | cut -d: -f2 | xargs)
        local home_dir=$(dscl . -read "/Users/$selected_user" NFSHomeDirectory 2>/dev/null | cut -d: -f2 | xargs)
        
        echo "Real Name: $real_name"
        echo "Home Directory: $home_dir"
        
        # Check if user is logged in
        if who | grep -q "^$selected_user "; then
            echo "Warning: User is currently logged in!"
            read -p "Do you want to continue anyway? (y/N): " force_delete
            if [ "$force_delete" != "y" ] && [ "$force_delete" != "Y" ]; then
                echo "Deletion cancelled."
                return
            fi
        fi
        
        echo ""
        read -p "Are you sure you want to delete this account? (y/N): " confirm
        
        if [ "$confirm" = "y" ] || [ "$confirm" = "Y" ]; then
            delete_single_mobile_account "$selected_user"
        else
            echo "Deletion cancelled."
        fi
    else
        echo "Invalid selection."
    fi
}

delete_single_mobile_account() {
    local username="$1"
    
    echo "Deleting mobile account: $username"
    
    # Create backup of user data
    local backup_dir="/var/backups/macfleet/mobile_accounts"
    mkdir -p "$backup_dir"
    
    local backup_file="$backup_dir/${username}_backup_$(date +%Y%m%d_%H%M%S).txt"
    
    echo "Creating backup of user data..."
    dscl . -read "/Users/$username" > "$backup_file"
    
    # Delete user from directory services
    if dscl . -delete "/Users/$username" 2>/dev/null; then
        echo "User record deleted from directory services"
    else
        echo "Failed to delete user record from directory services"
        return 1
    fi
    
    # Remove user's home directory
    local home_dir=$(dscl . -read "/Users/$username" NFSHomeDirectory 2>/dev/null | cut -d: -f2 | xargs)
    if [ -d "$home_dir" ]; then
        read -p "Do you want to remove the home directory? (y/N): " remove_home
        if [ "$remove_home" = "y" ] || [ "$remove_home" = "Y" ]; then
            if rm -rf "$home_dir"; then
                echo "Home directory removed: $home_dir"
            else
                echo "Failed to remove home directory: $home_dir"
            fi
        else
            echo "Home directory preserved: $home_dir"
        fi
    fi
    
    echo "Successfully deleted mobile account: $username"
    echo "Backup created: $backup_file"
    echo "[$timestamp] Successfully deleted mobile account: $username" >> "$log_file"
}

delete_inactive_mobile_accounts() {
    echo "======================================="
    echo "Delete Inactive Mobile Accounts"
    echo "======================================="
    
    read -p "Enter number of days since last login to consider inactive (default: 30): " days_inactive
    days_inactive=${days_inactive:-30}
    
    echo "Searching for mobile accounts inactive for more than $days_inactive days..."
    
    local inactive_accounts=()
    local current_timestamp=$(date +%s)
    local cutoff_timestamp=$((current_timestamp - (days_inactive * 24 * 60 * 60)))
    
    for username in $(dscl . -list /Users | grep -v '^_'); do
        auth_authority=$(dscl . -read "/Users/$username" AuthenticationAuthority 2>/dev/null | grep "LocalCachedUser")
        
        if [ -n "$auth_authority" ]; then
            # Check last login
            local last_login=$(last -1 "$username" 2>/dev/null | head -1 | awk '{print $3, $4, $5, $6}')
            
            if [ -n "$last_login" ]; then
                local last_login_timestamp=$(date -j -f "%a %b %d %H:%M:%S %Y" "$last_login" +%s 2>/dev/null)
                
                if [ -n "$last_login_timestamp" ] && [ "$last_login_timestamp" -lt "$cutoff_timestamp" ]; then
                    inactive_accounts+=("$username")
                    echo "Inactive account found: $username (last login: $last_login)"
                fi
            else
                # No login record found - consider as inactive
                inactive_accounts+=("$username")
                echo "Inactive account found: $username (no login record)"
            fi
        fi
    done
    
    if [ ${#inactive_accounts[@]} -eq 0 ]; then
        echo "No inactive mobile accounts found."
        return
    fi
    
    echo ""
    echo "Found ${#inactive_accounts[@]} inactive mobile accounts."
    read -p "Do you want to delete all inactive accounts? (y/N): " confirm
    
    if [ "$confirm" = "y" ] || [ "$confirm" = "Y" ]; then
        for username in "${inactive_accounts[@]}"; do
            echo "Deleting inactive account: $username"
            delete_single_mobile_account "$username"
        done
        echo "Inactive mobile accounts deletion completed."
    else
        echo "Deletion cancelled."
    fi
}

delete_mobile_accounts_by_criteria() {
    echo "======================================="
    echo "Delete Mobile Accounts by Criteria"
    echo "======================================="
    
    echo "Available criteria:"
    echo "1. By UID range"
    echo "2. By home directory pattern"
    echo "3. By real name pattern"
    echo "4. By last login date"
    echo ""
    read -p "Select criteria (1-4): " criteria
    
    case $criteria in
        1)
            delete_by_uid_range
            ;;
        2)
            delete_by_home_pattern
            ;;
        3)
            delete_by_name_pattern
            ;;
        4)
            delete_by_login_date
            ;;
        *)
            echo "Invalid criteria selected."
            ;;
    esac
}

delete_by_uid_range() {
    read -p "Enter minimum UID: " min_uid
    read -p "Enter maximum UID: " max_uid
    
    echo "Searching for mobile accounts with UID between $min_uid and $max_uid..."
    
    local matching_accounts=()
    
    for username in $(dscl . -list /Users | grep -v '^_'); do
        auth_authority=$(dscl . -read "/Users/$username" AuthenticationAuthority 2>/dev/null | grep "LocalCachedUser")
        
        if [ -n "$auth_authority" ]; then
            local uid=$(dscl . -read "/Users/$username" UniqueID 2>/dev/null | cut -d: -f2 | xargs)
            
            if [ "$uid" -ge "$min_uid" ] && [ "$uid" -le "$max_uid" ]; then
                matching_accounts+=("$username")
                echo "Found matching account: $username (UID: $uid)"
            fi
        fi
    done
    
    if [ ${#matching_accounts[@]} -eq 0 ]; then
        echo "No mobile accounts found matching the UID criteria."
        return
    fi
    
    echo ""
    echo "Found ${#matching_accounts[@]} matching mobile accounts."
    read -p "Do you want to delete all matching accounts? (y/N): " confirm
    
    if [ "$confirm" = "y" ] || [ "$confirm" = "Y" ]; then
        for username in "${matching_accounts[@]}"; do
            delete_single_mobile_account "$username"
        done
        echo "Mobile accounts deletion by UID range completed."
    else
        echo "Deletion cancelled."
    fi
}

delete_by_home_pattern() {
    read -p "Enter home directory pattern (e.g., /Users/temp*): " pattern
    
    echo "Searching for mobile accounts with home directory matching pattern: $pattern"
    
    local matching_accounts=()
    
    for username in $(dscl . -list /Users | grep -v '^_'); do
        auth_authority=$(dscl . -read "/Users/$username" AuthenticationAuthority 2>/dev/null | grep "LocalCachedUser")
        
        if [ -n "$auth_authority" ]; then
            local home_dir=$(dscl . -read "/Users/$username" NFSHomeDirectory 2>/dev/null | cut -d: -f2 | xargs)
            
            if [[ "$home_dir" == $pattern ]]; then
                matching_accounts+=("$username")
                echo "Found matching account: $username (Home: $home_dir)"
            fi
        fi
    done
    
    if [ ${#matching_accounts[@]} -eq 0 ]; then
        echo "No mobile accounts found matching the home directory pattern."
        return
    fi
    
    echo ""
    echo "Found ${#matching_accounts[@]} matching mobile accounts."
    read -p "Do you want to delete all matching accounts? (y/N): " confirm
    
    if [ "$confirm" = "y" ] || [ "$confirm" = "Y" ]; then
        for username in "${matching_accounts[@]}"; do
            delete_single_mobile_account "$username"
        done
        echo "Mobile accounts deletion by home directory pattern completed."
    else
        echo "Deletion cancelled."
    fi
}

delete_by_name_pattern() {
    read -p "Enter real name pattern (e.g., *Test*): " pattern
    
    echo "Searching for mobile accounts with real name matching pattern: $pattern"
    
    local matching_accounts=()
    
    for username in $(dscl . -list /Users | grep -v '^_'); do
        auth_authority=$(dscl . -read "/Users/$username" AuthenticationAuthority 2>/dev/null | grep "LocalCachedUser")
        
        if [ -n "$auth_authority" ]; then
            local real_name=$(dscl . -read "/Users/$username" RealName 2>/dev/null | cut -d: -f2 | xargs)
            
            if [[ "$real_name" == $pattern ]]; then
                matching_accounts+=("$username")
                echo "Found matching account: $username (Real Name: $real_name)"
            fi
        fi
    done
    
    if [ ${#matching_accounts[@]} -eq 0 ]; then
        echo "No mobile accounts found matching the real name pattern."
        return
    fi
    
    echo ""
    echo "Found ${#matching_accounts[@]} matching mobile accounts."
    read -p "Do you want to delete all matching accounts? (y/N): " confirm
    
    if [ "$confirm" = "y" ] || [ "$confirm" = "Y" ]; then
        for username in "${matching_accounts[@]}"; do
            delete_single_mobile_account "$username"
        done
        echo "Mobile accounts deletion by real name pattern completed."
    else
        echo "Deletion cancelled."
    fi
}

delete_by_login_date() {
    read -p "Enter cutoff date (YYYY-MM-DD): " cutoff_date
    
    local cutoff_timestamp=$(date -j -f "%Y-%m-%d" "$cutoff_date" +%s 2>/dev/null)
    
    if [ -z "$cutoff_timestamp" ]; then
        echo "Invalid date format. Please use YYYY-MM-DD format."
        return
    fi
    
    echo "Searching for mobile accounts with last login before $cutoff_date..."
    
    local matching_accounts=()
    
    for username in $(dscl . -list /Users | grep -v '^_'); do
        auth_authority=$(dscl . -read "/Users/$username" AuthenticationAuthority 2>/dev/null | grep "LocalCachedUser")
        
        if [ -n "$auth_authority" ]; then
            local last_login=$(last -1 "$username" 2>/dev/null | head -1 | awk '{print $3, $4, $5, $6}')
            
            if [ -n "$last_login" ]; then
                local last_login_timestamp=$(date -j -f "%a %b %d %H:%M:%S %Y" "$last_login" +%s 2>/dev/null)
                
                if [ -n "$last_login_timestamp" ] && [ "$last_login_timestamp" -lt "$cutoff_timestamp" ]; then
                    matching_accounts+=("$username")
                    echo "Found matching account: $username (last login: $last_login)"
                fi
            else
                # No login record - consider as before cutoff
                matching_accounts+=("$username")
                echo "Found matching account: $username (no login record)"
            fi
        fi
    done
    
    if [ ${#matching_accounts[@]} -eq 0 ]; then
        echo "No mobile accounts found with last login before $cutoff_date."
        return
    fi
    
    echo ""
    echo "Found ${#matching_accounts[@]} matching mobile accounts."
    read -p "Do you want to delete all matching accounts? (y/N): " confirm
    
    if [ "$confirm" = "y" ] || [ "$confirm" = "Y" ]; then
        for username in "${matching_accounts[@]}"; do
            delete_single_mobile_account "$username"
        done
        echo "Mobile accounts deletion by login date completed."
    else
        echo "Deletion cancelled."
    fi
}

export_mobile_account_report() {
    echo "======================================="
    echo "Export Mobile Account Report"
    echo "======================================="
    
    local report_file="/tmp/mobile_accounts_report_$(date +%Y%m%d_%H%M%S).txt"
    
    cat > "$report_file" << EOF
MacFleet Mobile Account Report
Generated: $(date)
Device: $(scutil --get ComputerName)
macOS Version: $(sw_vers -productVersion)

Mobile Accounts Summary:
EOF
    
    local count=0
    for username in $(dscl . -list /Users | grep -v '^_'); do
        auth_authority=$(dscl . -read "/Users/$username" AuthenticationAuthority 2>/dev/null | grep "LocalCachedUser")
        
        if [ -n "$auth_authority" ]; then
            ((count++))
            
            echo "" >> "$report_file"
            echo "[$count] Username: $username" >> "$report_file"
            
            # Get detailed information
            local real_name=$(dscl . -read "/Users/$username" RealName 2>/dev/null | cut -d: -f2 | xargs)
            local uid=$(dscl . -read "/Users/$username" UniqueID 2>/dev/null | cut -d: -f2 | xargs)
            local home_dir=$(dscl . -read "/Users/$username" NFSHomeDirectory 2>/dev/null | cut -d: -f2 | xargs)
            local last_login=$(last -1 "$username" 2>/dev/null | head -1)
            
            echo "    Real Name: $real_name" >> "$report_file"
            echo "    UID: $uid" >> "$report_file"
            echo "    Home Directory: $home_dir" >> "$report_file"
            echo "    Last Login: $last_login" >> "$report_file"
            
            # Check if user is logged in
            if who | grep -q "^$username "; then
                echo "    Status: Currently logged in" >> "$report_file"
            else
                echo "    Status: Not logged in" >> "$report_file"
            fi
            
            # Check home directory size
            if [ -d "$home_dir" ]; then
                local dir_size=$(du -sh "$home_dir" 2>/dev/null | cut -f1)
                echo "    Home Directory Size: $dir_size" >> "$report_file"
            fi
        fi
    done
    
    echo "" >> "$report_file"
    echo "Total Mobile Accounts: $count" >> "$report_file"
    
    echo "Mobile account report exported to: $report_file"
}

restore_mobile_account_backup() {
    echo "======================================="
    echo "Restore Mobile Account Backup"
    echo "======================================="
    
    local backup_dir="/var/backups/macfleet/mobile_accounts"
    
    if [ ! -d "$backup_dir" ]; then
        echo "No backup directory found: $backup_dir"
        return
    fi
    
    echo "Available backups:"
    ls -la "$backup_dir"/*.txt 2>/dev/null || echo "No backup files found."
    
    echo ""
    read -p "Enter the backup filename to restore: " backup_file
    
    if [ -f "$backup_dir/$backup_file" ]; then
        echo "Backup file found: $backup_dir/$backup_file"
        echo "Note: This feature shows backup content for reference."
        echo "Manual restoration may be required for complex scenarios."
        echo ""
        cat "$backup_dir/$backup_file"
    else
        echo "Backup file not found: $backup_dir/$backup_file"
    fi
}

# Execute selective management
selective_mobile_account_manager

Enterprise Mobile Account Management

Automated Mobile Account Cleanup

#!/bin/bash

# Automated mobile account cleanup for enterprise environments
# Usage: ./automated_mobile_cleanup.sh

automated_mobile_cleanup() {
    local config_file="/etc/macfleet/mobile_cleanup_config.conf"
    local log_file="/var/log/macfleet_automated_cleanup.log"
    local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
    
    # Check if running as root
    if [ "$EUID" -ne 0 ]; then
        echo "Error: This script must be run as root"
        exit 1
    fi
    
    # Create configuration if it doesn't exist
    if [ ! -f "$config_file" ]; then
        create_cleanup_config
    fi
    
    source "$config_file"
    
    echo "[$timestamp] Automated mobile account cleanup started" >> "$log_file"
    
    # Execute cleanup based on configuration
    execute_automated_cleanup
}

create_cleanup_config() {
    mkdir -p /etc/macfleet
    
    cat > "/etc/macfleet/mobile_cleanup_config.conf" << 'EOF'
# MacFleet Automated Mobile Account Cleanup Configuration

# Organization settings
ORGANIZATION_NAME="MacFleet Organization"
IT_CONTACT="support@macfleet.com"

# Cleanup criteria
CLEANUP_INACTIVE_DAYS="30"
CLEANUP_ENABLED="true"
PRESERVE_ADMIN_ACCOUNTS="true"

# Safety settings
REQUIRE_CONFIRMATION="true"
CREATE_BACKUP="true"
PRESERVE_HOME_DATA="false"
SKIP_LOGGED_IN_USERS="true"

# Notification settings
SEND_NOTIFICATIONS="true"
NOTIFICATION_EMAIL="admin@macfleet.com"

# Scheduling
ENABLE_SCHEDULED_CLEANUP="false"
CLEANUP_SCHEDULE="weekly"
CLEANUP_TIME="02:00"

# Logging
ENABLE_DETAILED_LOGGING="true"
LOG_RETENTION_DAYS="90"
EOF
    
    echo "Cleanup configuration created at /etc/macfleet/mobile_cleanup_config.conf"
}

execute_automated_cleanup() {
    echo "[$timestamp] Executing automated mobile account cleanup" >> "$log_file"
    
    # Check if cleanup is enabled
    if [ "$CLEANUP_ENABLED" != "true" ]; then
        echo "[$timestamp] Automated cleanup is disabled" >> "$log_file"
        echo "Automated cleanup is disabled in configuration."
        return
    fi
    
    # Display cleanup configuration
    echo "======================================="
    echo "MacFleet Automated Mobile Account Cleanup"
    echo "======================================="
    echo "Organization: $ORGANIZATION_NAME"
    echo "Cleanup inactive accounts older than: $CLEANUP_INACTIVE_DAYS days"
    echo "Preserve admin accounts: $PRESERVE_ADMIN_ACCOUNTS"
    echo "Create backup: $CREATE_BACKUP"
    echo "Skip logged in users: $SKIP_LOGGED_IN_USERS"
    echo ""
    
    # Require confirmation if enabled
    if [ "$REQUIRE_CONFIRMATION" = "true" ]; then
        read -p "Do you want to proceed with automated cleanup? (y/N): " confirm
        if [ "$confirm" != "y" ] && [ "$confirm" != "Y" ]; then
            echo "[$timestamp] Automated cleanup cancelled by user" >> "$log_file"
            echo "Automated cleanup cancelled."
            return
        fi
    fi
    
    # Find accounts to cleanup
    local accounts_to_cleanup=()
    local current_timestamp=$(date +%s)
    local cutoff_timestamp=$((current_timestamp - (CLEANUP_INACTIVE_DAYS * 24 * 60 * 60)))
    
    echo "Scanning for mobile accounts to cleanup..."
    
    for username in $(dscl . -list /Users | grep -v '^_'); do
        auth_authority=$(dscl . -read "/Users/$username" AuthenticationAuthority 2>/dev/null | grep "LocalCachedUser")
        
        if [ -n "$auth_authority" ]; then
            local should_cleanup=true
            
            # Check if user is admin (if preservation is enabled)
            if [ "$PRESERVE_ADMIN_ACCOUNTS" = "true" ]; then
                if dscl . -read "/Groups/admin" GroupMembership 2>/dev/null | grep -q "$username"; then
                    echo "Skipping admin account: $username"
                    echo "[$timestamp] Skipped admin account: $username" >> "$log_file"
                    should_cleanup=false
                fi
            fi
            
            # Check if user is logged in (if skip is enabled)
            if [ "$SKIP_LOGGED_IN_USERS" = "true" ] && who | grep -q "^$username "; then
                echo "Skipping logged in user: $username"
                echo "[$timestamp] Skipped logged in user: $username" >> "$log_file"
                should_cleanup=false
            fi
            
            # Check last login date
            if [ "$should_cleanup" = true ]; then
                local last_login=$(last -1 "$username" 2>/dev/null | head -1 | awk '{print $3, $4, $5, $6}')
                
                if [ -n "$last_login" ]; then
                    local last_login_timestamp=$(date -j -f "%a %b %d %H:%M:%S %Y" "$last_login" +%s 2>/dev/null)
                    
                    if [ -n "$last_login_timestamp" ] && [ "$last_login_timestamp" -lt "$cutoff_timestamp" ]; then
                        accounts_to_cleanup+=("$username")
                        echo "Account marked for cleanup: $username (last login: $last_login)"
                    fi
                else
                    # No login record - consider for cleanup
                    accounts_to_cleanup+=("$username")
                    echo "Account marked for cleanup: $username (no login record)"
                fi
            fi
        fi
    done
    
    if [ ${#accounts_to_cleanup[@]} -eq 0 ]; then
        echo "No mobile accounts found that meet cleanup criteria."
        echo "[$timestamp] No mobile accounts found for cleanup" >> "$log_file"
        return
    fi
    
    echo ""
    echo "Found ${#accounts_to_cleanup[@]} mobile accounts for cleanup:"
    for account in "${accounts_to_cleanup[@]}"; do
        echo "  - $account"
    done
    
    # Create backup if enabled
    if [ "$CREATE_BACKUP" = "true" ]; then
        create_automated_backup "${accounts_to_cleanup[@]}"
    fi
    
    # Cleanup accounts
    local success_count=0
    local failure_count=0
    
    echo ""
    echo "Starting automated cleanup..."
    
    for username in "${accounts_to_cleanup[@]}"; do
        echo "Processing: $username"
        
        # Delete user from directory services
        if dscl . -delete "/Users/$username" 2>/dev/null; then
            echo "  Deleted user record from directory services"
            
            # Handle home directory based on configuration
            local home_dir=$(dscl . -read "/Users/$username" NFSHomeDirectory 2>/dev/null | cut -d: -f2 | xargs)
            
            if [ -d "$home_dir" ]; then
                if [ "$PRESERVE_HOME_DATA" = "true" ]; then
                    echo "  Preserved home directory: $home_dir"
                else
                    if rm -rf "$home_dir" 2>/dev/null; then
                        echo "  Removed home directory: $home_dir"
                    else
                        echo "  Warning: Failed to remove home directory: $home_dir"
                    fi
                fi
            fi
            
            echo "  Successfully cleaned up account: $username"
            echo "[$timestamp] Successfully cleaned up account: $username" >> "$log_file"
            ((success_count++))
        else
            echo "  Failed to cleanup account: $username"
            echo "[$timestamp] Failed to cleanup account: $username" >> "$log_file"
            ((failure_count++))
        fi
    done
    
    # Generate cleanup summary
    echo ""
    echo "======================================="
    echo "Automated Cleanup Summary"
    echo "======================================="
    echo "Total accounts processed: ${#accounts_to_cleanup[@]}"
    echo "Successfully cleaned up: $success_count"
    echo "Failed to cleanup: $failure_count"
    echo "Cleanup completed at: $(date)"
    
    echo "[$timestamp] Automated cleanup completed - Success: $success_count, Failed: $failure_count" >> "$log_file"
    
    # Send notification if enabled
    if [ "$SEND_NOTIFICATIONS" = "true" ]; then
        send_cleanup_notification "$success_count" "$failure_count"
    fi
    
    echo ""
    echo "Note: Please restart the device for changes to take full effect."
}

create_automated_backup() {
    local accounts=("$@")
    local backup_dir="/var/backups/macfleet/automated_cleanup"
    local backup_file="$backup_dir/cleanup_backup_$(date +%Y%m%d_%H%M%S).txt"
    
    mkdir -p "$backup_dir"
    
    echo "Creating backup of accounts to be cleaned up..."
    
    cat > "$backup_file" << EOF
MacFleet Automated Cleanup Backup
Generated: $(date)
Device: $(scutil --get ComputerName)
Organization: $ORGANIZATION_NAME
Cleanup Criteria: Inactive for $CLEANUP_INACTIVE_DAYS days

Accounts to be cleaned up:
EOF
    
    for username in "${accounts[@]}"; do
        echo "" >> "$backup_file"
        echo "Username: $username" >> "$backup_file"
        dscl . -read "/Users/$username" >> "$backup_file" 2>/dev/null
        echo "---" >> "$backup_file"
    done
    
    echo "Backup created: $backup_file"
    echo "[$timestamp] Automated cleanup backup created: $backup_file" >> "$log_file"
}

send_cleanup_notification() {
    local success_count=$1
    local failure_count=$2
    
    local notification_subject="MacFleet Mobile Account Cleanup Report"
    local notification_body="Automated mobile account cleanup completed.

Device: $(scutil --get ComputerName)
Organization: $ORGANIZATION_NAME
Cleanup Date: $(date)

Results:
- Successfully cleaned up: $success_count accounts
- Failed to cleanup: $failure_count accounts
- Total processed: $((success_count + failure_count)) accounts

For detailed logs, check: /var/log/macfleet_automated_cleanup.log

Contact: $IT_CONTACT"
    
    # Use osascript to display notification (for local notifications)
    osascript -e "display notification \"Cleanup completed: $success_count success, $failure_count failed\" with title \"MacFleet Mobile Account Cleanup\""
    
    echo "[$timestamp] Cleanup notification sent" >> "$log_file"
}

# Execute automated cleanup
automated_mobile_cleanup

Troubleshooting and Best Practices

Common Issues and Solutions

  1. Permission Errors: Always run scripts as root using sudo
  2. Logged-in Users: Check for active sessions before deletion
  3. Directory Services: Verify mobile account identification using LocalCachedUser attribute
  4. Home Directory Protection: Create backups before removing home directories
  5. Network Accounts: Ensure network connectivity for directory service operations

Best Practices

  • Test First: Always test scripts in controlled environments
  • Create Backups: Maintain backups of user data before deletion
  • Log Operations: Keep detailed logs of all account operations
  • User Communication: Notify users before account cleanup
  • Schedule Maintenance: Perform cleanup during maintenance windows

Conclusion

Mobile account management is crucial for maintaining clean and secure macOS environments. These scripts provide comprehensive solutions for deleting mobile accounts, from simple cleanup to enterprise-grade automation. Always ensure proper testing and backup procedures before implementing in production environments.

Tutorial

Novas atualizações e melhorias para a Macfleet.

Configurando um Runner do GitHub Actions em um Mac Mini (Apple Silicon)

Runner do GitHub Actions

GitHub Actions é uma plataforma poderosa de CI/CD que permite automatizar seus fluxos de trabalho de desenvolvimento de software. Embora o GitHub ofereça runners hospedados, runners auto-hospedados fornecem maior controle e personalização para sua configuração de CI/CD. Este tutorial o guia através da configuração e conexão de um runner auto-hospedado em um Mac mini para executar pipelines do macOS.

Pré-requisitos

Antes de começar, certifique-se de ter:

  • Um Mac mini (registre-se no Macfleet)
  • Um repositório GitHub com direitos de administrador
  • Um gerenciador de pacotes instalado (preferencialmente Homebrew)
  • Git instalado em seu sistema

Passo 1: Criar uma Conta de Usuário Dedicada

Primeiro, crie uma conta de usuário dedicada para o runner do GitHub Actions:

# Criar a conta de usuário 'gh-runner'
sudo dscl . -create /Users/gh-runner
sudo dscl . -create /Users/gh-runner UserShell /bin/bash
sudo dscl . -create /Users/gh-runner RealName "GitHub runner"
sudo dscl . -create /Users/gh-runner UniqueID "1001"
sudo dscl . -create /Users/gh-runner PrimaryGroupID 20
sudo dscl . -create /Users/gh-runner NFSHomeDirectory /Users/gh-runner

# Definir a senha para o usuário
sudo dscl . -passwd /Users/gh-runner sua_senha

# Adicionar 'gh-runner' ao grupo 'admin'
sudo dscl . -append /Groups/admin GroupMembership gh-runner

Mude para a nova conta de usuário:

su gh-runner

Passo 2: Instalar Software Necessário

Instale Git e Rosetta 2 (se estiver usando Apple Silicon):

# Instalar Git se ainda não estiver instalado
brew install git

# Instalar Rosetta 2 para Macs Apple Silicon
softwareupdate --install-rosetta

Passo 3: Configurar o Runner do GitHub Actions

  1. Vá para seu repositório GitHub
  2. Navegue para Configurações > Actions > Runners

Runner do GitHub Actions

  1. Clique em "New self-hosted runner" (https://github.com/<username>/<repository>/settings/actions/runners/new)
  2. Selecione macOS como imagem do runner e ARM64 como arquitetura
  3. Siga os comandos fornecidos para baixar e configurar o runner

Runner do GitHub Actions

Crie um arquivo .env no diretório _work do runner:

# arquivo _work/.env
ImageOS=macos15
XCODE_15_DEVELOPER_DIR=/Applications/Xcode.app/Contents/Developer
  1. Execute o script run.sh em seu diretório do runner para completar a configuração.
  2. Verifique se o runner está ativo e ouvindo por trabalhos no terminal e verifique as configurações do repositório GitHub para a associação do runner e status Idle.

Runner do GitHub Actions

Passo 4: Configurar Sudoers (Opcional)

Se suas ações requerem privilégios de root, configure o arquivo sudoers:

sudo visudo

Adicione a seguinte linha:

gh-runner ALL=(ALL) NOPASSWD: ALL

Passo 5: Usar o Runner em Fluxos de Trabalho

Configure seu fluxo de trabalho do GitHub Actions para usar o runner auto-hospedado:

name: Fluxo de trabalho de exemplo

on:
  workflow_dispatch:

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

O runner está autenticado em seu repositório e rotulado com self-hosted, macOS, e ARM64. Use-o em seus fluxos de trabalho especificando estes rótulos no campo runs-on:

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

Melhores Práticas

  • Mantenha seu software do runner atualizado
  • Monitore regularmente os logs do runner para problemas
  • Use rótulos específicos para diferentes tipos de runners
  • Implemente medidas de segurança adequadas
  • Considere usar múltiplos runners para balanceamento de carga

Solução de Problemas

Problemas comuns e soluções:

  1. Runner não conectando:

    • Verifique conectividade de rede
    • Verifique validade do token GitHub
    • Certifique-se de permissões adequadas
  2. Falhas de build:

    • Verifique instalação do Xcode
    • Verifique dependências necessárias
    • Revise logs do fluxo de trabalho
  3. Problemas de permissão:

    • Verifique permissões do usuário
    • Verifique configuração sudoers
    • Revise permissões do sistema de arquivos

Conclusão

Agora você tem um runner auto-hospedado do GitHub Actions configurado em seu Mac mini. Esta configuração fornece mais controle sobre seu ambiente CI/CD e permite executar fluxos de trabalho específicos do macOS de forma eficiente.

Lembre-se de manter regularmente seu runner e mantê-lo atualizado com os patches de segurança e versões de software mais recentes.

Aplicativo Nativo

Aplicativo nativo do Macfleet

Guia de Instalação do Macfleet

Macfleet é uma solução poderosa de gerenciamento de frota projetada especificamente para ambientes Mac Mini hospedados na nuvem. Como provedor de hospedagem na nuvem Mac Mini, você pode usar o Macfleet para monitorar, gerenciar e otimizar toda sua frota de instâncias Mac virtualizadas.

Este guia de instalação o conduzirá através da configuração do monitoramento do Macfleet em sistemas macOS, Windows e Linux para garantir supervisão abrangente de sua infraestrutura na nuvem.

🍎 macOS

  • Baixe o arquivo .dmg para Mac aqui
  • Clique duas vezes no arquivo .dmg baixado
  • Arraste o aplicativo Macfleet para a pasta Aplicativos
  • Ejete o arquivo .dmg
  • Abra Preferências do Sistema > Segurança e Privacidade
    • Aba Privacidade > Acessibilidade
    • Marque Macfleet para permitir monitoramento
  • Inicie o Macfleet a partir de Aplicativos
  • O rastreamento inicia automaticamente

🪟 Windows

  • Baixe o arquivo .exe para Windows aqui
  • Clique com o botão direito no arquivo .exe > "Executar como administrador"
  • Siga o assistente de instalação
  • Aceite os termos e condições
  • Permita no Windows Defender se solicitado
  • Conceda permissões de monitoramento de aplicativo
  • Inicie o Macfleet a partir do Menu Iniciar
  • O aplicativo começa o rastreamento automaticamente

🐧 Linux

  • Baixe o pacote .deb (Ubuntu/Debian) ou .rpm (CentOS/RHEL) aqui
  • Instale usando seu gerenciador de pacotes
    • Ubuntu/Debian: sudo dpkg -i Macfleet-linux.deb
    • CentOS/RHEL: sudo rpm -ivh Macfleet-linux.rpm
  • Permita permissões de acesso X11 se solicitado
  • Adicione o usuário aos grupos apropriados se necessário
  • Inicie o Macfleet a partir do menu Aplicativos
  • O aplicativo começa o rastreamento automaticamente

Nota: Após a instalação em todos os sistemas, faça login com suas credenciais do Macfleet para sincronizar dados com seu painel de controle.