Tutorial

Neue Updates und Verbesserungen zu Macfleet.

Wichtiger Hinweis

Die in diesen Tutorials bereitgestellten Codebeispiele und Skripte dienen nur zu Bildungszwecken. Macfleet ist nicht verantwortlich für Probleme, Schäden oder Sicherheitslücken, die durch die Verwendung, Änderung oder Implementierung dieser Beispiele entstehen können. Überprüfen und testen Sie Code immer in einer sicheren Umgebung, bevor Sie ihn in Produktionssystemen verwenden.

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

Neue Updates und Verbesserungen zu Macfleet.

Konfiguration eines GitHub Actions Runners auf einem Mac Mini (Apple Silicon)

GitHub Actions Runner

GitHub Actions ist eine leistungsstarke CI/CD-Plattform, die es Ihnen ermöglicht, Ihre Software-Entwicklungsworkflows zu automatisieren. Während GitHub gehostete Runner anbietet, bieten selbst-gehostete Runner erhöhte Kontrolle und Anpassung für Ihr CI/CD-Setup. Dieses Tutorial führt Sie durch die Einrichtung, Konfiguration und Verbindung eines selbst-gehosteten Runners auf einem Mac mini zur Ausführung von macOS-Pipelines.

Voraussetzungen

Bevor Sie beginnen, stellen Sie sicher, dass Sie haben:

  • Einen Mac mini (registrieren Sie sich bei Macfleet)
  • Ein GitHub-Repository mit Administratorrechten
  • Einen installierten Paketmanager (vorzugsweise Homebrew)
  • Git auf Ihrem System installiert

Schritt 1: Ein dediziertes Benutzerkonto erstellen

Erstellen Sie zunächst ein dediziertes Benutzerkonto für den GitHub Actions Runner:

# Das 'gh-runner' Benutzerkonto erstellen
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

# Das Passwort für den Benutzer setzen
sudo dscl . -passwd /Users/gh-runner ihr_passwort

# 'gh-runner' zur 'admin'-Gruppe hinzufügen
sudo dscl . -append /Groups/admin GroupMembership gh-runner

Wechseln Sie zum neuen Benutzerkonto:

su gh-runner

Schritt 2: Erforderliche Software installieren

Installieren Sie Git und Rosetta 2 (wenn Sie Apple Silicon verwenden):

# Git installieren, falls noch nicht installiert
brew install git

# Rosetta 2 für Apple Silicon Macs installieren
softwareupdate --install-rosetta

Schritt 3: Den GitHub Actions Runner konfigurieren

  1. Gehen Sie zu Ihrem GitHub-Repository
  2. Navigieren Sie zu Einstellungen > Actions > Runners

GitHub Actions Runner

  1. Klicken Sie auf "New self-hosted runner" (https://github.com/<username>/<repository>/settings/actions/runners/new)
  2. Wählen Sie macOS als Runner-Image und ARM64 als Architektur
  3. Folgen Sie den bereitgestellten Befehlen, um den Runner herunterzuladen und zu konfigurieren

GitHub Actions Runner

Erstellen Sie eine .env-Datei im _work-Verzeichnis des Runners:

# _work/.env Datei
ImageOS=macos15
XCODE_15_DEVELOPER_DIR=/Applications/Xcode.app/Contents/Developer
  1. Führen Sie das run.sh-Skript in Ihrem Runner-Verzeichnis aus, um die Einrichtung abzuschließen.
  2. Überprüfen Sie, dass der Runner aktiv ist und auf Jobs im Terminal wartet, und überprüfen Sie die GitHub-Repository-Einstellungen für die Runner-Zuordnung und den Idle-Status.

GitHub Actions Runner

Schritt 4: Sudoers konfigurieren (Optional)

Wenn Ihre Actions Root-Privilegien benötigen, konfigurieren Sie die sudoers-Datei:

sudo visudo

Fügen Sie die folgende Zeile hinzu:

gh-runner ALL=(ALL) NOPASSWD: ALL

Schritt 5: Den Runner in Workflows verwenden

Konfigurieren Sie Ihren GitHub Actions Workflow, um den selbst-gehosteten Runner zu verwenden:

name: Beispiel-Workflow

on:
  workflow_dispatch:

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

Der Runner ist bei Ihrem Repository authentifiziert und mit self-hosted, macOS und ARM64 markiert. Verwenden Sie ihn in Ihren Workflows, indem Sie diese Labels im runs-on-Feld angeben:

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

Best Practices

  • Halten Sie Ihre Runner-Software auf dem neuesten Stand
  • Überwachen Sie regelmäßig Runner-Logs auf Probleme
  • Verwenden Sie spezifische Labels für verschiedene Runner-Typen
  • Implementieren Sie angemessene Sicherheitsmaßnahmen
  • Erwägen Sie die Verwendung mehrerer Runner für Lastverteilung

Fehlerbehebung

Häufige Probleme und Lösungen:

  1. Runner verbindet sich nicht:

    • Überprüfen Sie die Netzwerkverbindung
    • Überprüfen Sie die Gültigkeit des GitHub-Tokens
    • Stellen Sie angemessene Berechtigungen sicher
  2. Build-Fehler:

    • Überprüfen Sie die Xcode-Installation
    • Überprüfen Sie erforderliche Abhängigkeiten
    • Überprüfen Sie Workflow-Logs
  3. Berechtigungsprobleme:

    • Überprüfen Sie Benutzerberechtigungen
    • Überprüfen Sie sudoers-Konfiguration
    • Überprüfen Sie Dateisystem-Berechtigungen

Fazit

Sie haben jetzt einen selbst-gehosteten GitHub Actions Runner auf Ihrem Mac mini konfiguriert. Diese Einrichtung bietet Ihnen mehr Kontrolle über Ihre CI/CD-Umgebung und ermöglicht es Ihnen, macOS-spezifische Workflows effizient auszuführen.

Denken Sie daran, Ihren Runner regelmäßig zu warten und ihn mit den neuesten Sicherheitspatches und Software-Versionen auf dem neuesten Stand zu halten.

Native App

Macfleet native App

Macfleet Installationsanleitung

Macfleet ist eine leistungsstarke Flottenmanagement-Lösung, die speziell für Cloud-gehostete Mac Mini-Umgebungen entwickelt wurde. Als Mac Mini Cloud-Hosting-Anbieter können Sie Macfleet verwenden, um Ihre gesamte Flotte virtualisierter Mac-Instanzen zu überwachen, zu verwalten und zu optimieren.

Diese Installationsanleitung führt Sie durch die Einrichtung der Macfleet-Überwachung auf macOS-, Windows- und Linux-Systemen, um eine umfassende Übersicht über Ihre Cloud-Infrastruktur zu gewährleisten.

🍎 macOS

  • Laden Sie die .dmg-Datei für Mac hier herunter
  • Doppelklicken Sie auf die heruntergeladene .dmg-Datei
  • Ziehen Sie die Macfleet-App in den Anwendungsordner
  • Werfen Sie die .dmg-Datei aus
  • Öffnen Sie Systemeinstellungen > Sicherheit & Datenschutz
    • Datenschutz-Tab > Bedienungshilfen
    • Aktivieren Sie Macfleet, um Überwachung zu erlauben
  • Starten Sie Macfleet aus den Anwendungen
  • Die Verfolgung startet automatisch

🪟 Windows

  • Laden Sie die .exe-Datei für Windows hier herunter
  • Rechtsklick auf die .exe-Datei > "Als Administrator ausführen"
  • Folgen Sie dem Installationsassistenten
  • Akzeptieren Sie die Allgemeinen Geschäftsbedingungen
  • Erlauben Sie in Windows Defender, wenn aufgefordert
  • Gewähren Sie Anwendungsüberwachungsberechtigungen
  • Starten Sie Macfleet aus dem Startmenü
  • Die Anwendung beginnt automatisch mit der Verfolgung

🐧 Linux

  • Laden Sie das .deb-Paket (Ubuntu/Debian) oder .rpm (CentOS/RHEL) hier herunter
  • Installieren Sie mit Ihrem Paketmanager
    • Ubuntu/Debian: sudo dpkg -i Macfleet-linux.deb
    • CentOS/RHEL: sudo rpm -ivh Macfleet-linux.rpm
  • Erlauben Sie X11-Zugriffsberechtigungen, wenn aufgefordert
  • Fügen Sie den Benutzer zu entsprechenden Gruppen hinzu, falls erforderlich
  • Starten Sie Macfleet aus dem Anwendungsmenü
  • Die Anwendung beginnt automatisch mit der Verfolgung

Hinweis: Nach der Installation auf allen Systemen melden Sie sich mit Ihren Macfleet-Anmeldedaten an, um Daten mit Ihrem Dashboard zu synchronisieren.