Tutorial

Nuevas actualizaciones y mejoras para Macfleet.

Aviso importante

Los ejemplos de código y scripts proporcionados en estos tutoriales son solo para propósitos educativos. Macfleet no es responsable de ningún problema, daño o vulnerabilidad de seguridad que pueda surgir del uso, modificación o implementación de estos ejemplos. Siempre revisa y prueba el código en un entorno seguro antes de usarlo en sistemas de producción.

User Account Management on macOS

Master user account creation and management on your MacFleet devices using powerful command-line tools. This tutorial covers admin and standard user creation, password management, account configuration, and advanced user lifecycle management for enterprise deployments.

Understanding macOS User Management

macOS provides several command-line tools for user account management:

  • sysadminctl - Modern user account management tool (macOS 10.10+)
  • dscl - Directory Services command-line utility for advanced operations
  • passwd - Password management and changes
  • id - User and group information display
  • whoami - Current user identification

Basic User Account Creation

Create Admin User Account

#!/bin/sh

# Set PATH environment variable
export PATH=/usr/bin:/bin:/usr/sbin:/sbin

# Admin user configuration
USERNAME="Daniel"
FULLNAME="Daniel.Hector"
PASSWORD="One@Two#8"
PASSWORDHINT="One to Eight"

# Create admin user account
sysadminctl -addUser "$USERNAME" -fullName "$FULLNAME" -password "$PASSWORD" -hint "$PASSWORDHINT" -admin

echo "Admin user account '$USERNAME' created successfully"

Create Standard User Account

#!/bin/sh

# Set PATH environment variable
export PATH=/usr/bin:/bin:/usr/sbin:/sbin

# Standard user configuration
USERNAME="Daniel"
FULLNAME="Daniel.Hector"
PASSWORD="One@Two#8"
PASSWORDHINT="One to Eight"

# Create standard user account (no -admin flag)
sysadminctl -addUser "$USERNAME" -fullName "$FULLNAME" -password "$PASSWORD" -hint "$PASSWORDHINT"

echo "Standard user account '$USERNAME' created successfully"

Enhanced User Creation with Validation

#!/bin/bash

# Enhanced user creation with validation
create_user_account() {
    local username="$1"
    local fullname="$2"
    local password="$3"
    local hint="$4"
    local is_admin="${5:-false}"
    
    # Validate inputs
    if [[ -z "$username" || -z "$fullname" || -z "$password" ]]; then
        echo "Error: Username, full name, and password are required"
        return 1
    fi
    
    # Check if user already exists
    if id "$username" &>/dev/null; then
        echo "Error: User '$username' already exists"
        return 1
    fi
    
    # Set PATH environment
    export PATH=/usr/bin:/bin:/usr/sbin:/sbin
    
    # Build sysadminctl command
    local cmd="sysadminctl -addUser \"$username\" -fullName \"$fullname\" -password \"$password\""
    
    if [[ -n "$hint" ]]; then
        cmd="$cmd -hint \"$hint\""
    fi
    
    if [[ "$is_admin" == "true" ]]; then
        cmd="$cmd -admin"
        echo "Creating admin user: $username"
    else
        echo "Creating standard user: $username"
    fi
    
    # Execute user creation
    if eval "$cmd"; then
        echo "✓ User '$username' created successfully"
        
        # Display user information
        echo "User details:"
        id "$username"
        return 0
    else
        echo "✗ Failed to create user '$username'"
        return 1
    fi
}

# Usage examples
create_user_account "daniel" "Daniel Hector" "SecurePass123!" "Password hint" "true"
create_user_account "jane" "Jane Smith" "UserPass456!" "Another hint" "false"

Advanced User Management

Batch User Creation

#!/bin/bash

# Batch user creation from configuration
batch_create_users() {
    local config_file="$1"
    
    if [[ ! -f "$config_file" ]]; then
        echo "Error: Configuration file not found: $config_file"
        return 1
    fi
    
    echo "=== Batch User Creation ==="
    
    local success_count=0
    local error_count=0
    
    # Read configuration file (format: username,fullname,password,hint,admin)
    while IFS=',' read -r username fullname password hint is_admin; do
        # Skip empty lines and comments
        [[ -z "$username" || "$username" =~ ^# ]] && continue
        
        echo "Processing user: $username"
        
        if create_user_account "$username" "$fullname" "$password" "$hint" "$is_admin"; then
            ((success_count++))
        else
            ((error_count++))
        fi
        
        echo "---"
    done < "$config_file"
    
    echo "Batch creation completed:"
    echo "✓ Success: $success_count users"
    echo "✗ Errors: $error_count users"
}

# Create sample configuration file
create_user_config() {
    local config_file="/tmp/users_config.csv"
    
    cat > "$config_file" << EOF
# Format: username,fullname,password,hint,admin(true/false)
daniel,Daniel Hector,SecurePass123!,Password hint,true
jane,Jane Smith,UserPass456!,Another hint,false
alex,Alex Johnson,TempPass789!,Temporary password,false
admin,System Administrator,AdminPass000!,Admin access,true
EOF
    
    echo "Sample configuration created: $config_file"
    echo "$config_file"
}

# Usage
config_file=$(create_user_config)
batch_create_users "$config_file"

User Account Modification

#!/bin/bash

# Modify existing user accounts
modify_user_account() {
    local username="$1"
    local action="$2"
    local value="$3"
    
    # Verify user exists
    if ! id "$username" &>/dev/null; then
        echo "Error: User '$username' does not exist"
        return 1
    fi
    
    export PATH=/usr/bin:/bin:/usr/sbin:/sbin
    
    case "$action" in
        "password")
            echo "Changing password for user: $username"
            if sysadminctl -resetPasswordFor "$username" -newPassword "$value"; then
                echo "✓ Password changed successfully"
            else
                echo "✗ Failed to change password"
                return 1
            fi
            ;;
        "fullname")
            echo "Changing full name for user: $username"
            if dscl . -change "/Users/$username" RealName "$(dscl . -read "/Users/$username" RealName | cut -d: -f2 | xargs)" "$value"; then
                echo "✓ Full name changed to: $value"
            else
                echo "✗ Failed to change full name"
                return 1
            fi
            ;;
        "admin")
            if [[ "$value" == "true" ]]; then
                echo "Granting admin privileges to: $username"
                if dseditgroup -o edit -a "$username" -t user admin; then
                    echo "✓ Admin privileges granted"
                else
                    echo "✗ Failed to grant admin privileges"
                    return 1
                fi
            else
                echo "Removing admin privileges from: $username"
                if dseditgroup -o edit -d "$username" -t user admin; then
                    echo "✓ Admin privileges removed"
                else
                    echo "✗ Failed to remove admin privileges"
                    return 1
                fi
            fi
            ;;
        "enable")
            echo "Enabling user account: $username"
            if dscl . -create "/Users/$username" AuthenticationAuthority; then
                echo "✓ User account enabled"
            else
                echo "✗ Failed to enable user account"
                return 1
            fi
            ;;
        "disable")
            echo "Disabling user account: $username"
            if dscl . -delete "/Users/$username" AuthenticationAuthority; then
                echo "✓ User account disabled"
            else
                echo "✗ Failed to disable user account"
                return 1
            fi
            ;;
        *)
            echo "Error: Unknown action '$action'"
            echo "Available actions: password, fullname, admin, enable, disable"
            return 1
            ;;
    esac
}

# Usage examples
modify_user_account "daniel" "password" "NewSecurePass123!"
modify_user_account "jane" "admin" "true"
modify_user_account "alex" "fullname" "Alexander Johnson"

User Account Deletion

#!/bin/bash

# Delete user accounts with options
delete_user_account() {
    local username="$1"
    local delete_home="${2:-true}"
    local backup_home="${3:-false}"
    
    # Verify user exists
    if ! id "$username" &>/dev/null; then
        echo "Error: User '$username' does not exist"
        return 1
    fi
    
    # Prevent deletion of critical system users
    local system_users=("root" "daemon" "nobody" "_www" "_mysql" "_postgresql")
    for sys_user in "${system_users[@]}"; do
        if [[ "$username" == "$sys_user" ]]; then
            echo "Error: Cannot delete system user '$username'"
            return 1
        fi
    done
    
    export PATH=/usr/bin:/bin:/usr/sbin:/sbin
    
    echo "Preparing to delete user: $username"
    
    # Backup home directory if requested
    if [[ "$backup_home" == "true" ]]; then
        local backup_dir="/var/backups/deleted_users"
        local timestamp=$(date +%Y%m%d_%H%M%S)
        local backup_path="$backup_dir/${username}_${timestamp}.tar.gz"
        
        mkdir -p "$backup_dir"
        
        echo "Backing up home directory to: $backup_path"
        if tar -czf "$backup_path" -C "/Users" "$username" 2>/dev/null; then
            echo "✓ Home directory backed up"
        else
            echo "⚠ Warning: Failed to backup home directory"
        fi
    fi
    
    # Delete user account
    local delete_cmd="sysadminctl -deleteUser \"$username\""
    
    if [[ "$delete_home" == "true" ]]; then
        delete_cmd="$delete_cmd -secure"
        echo "Deleting user and home directory..."
    else
        echo "Deleting user account only..."
    fi
    
    if eval "$delete_cmd"; then
        echo "✓ User '$username' deleted successfully"
        return 0
    else
        echo "✗ Failed to delete user '$username'"
        return 1
    fi
}

# Usage examples
delete_user_account "testuser" "true" "true"  # Delete with home, backup first
delete_user_account "tempuser" "false" "false"  # Delete user only, no backup

Enterprise User Management System

#!/bin/bash

# MacFleet User Management Tool
# Comprehensive user account management for fleet devices

# Configuration
SCRIPT_VERSION="1.0.0"
LOG_FILE="/var/log/macfleet_users.log"
REPORT_DIR="/etc/macfleet/reports/users"
CONFIG_DIR="/etc/macfleet/users"
BACKUP_DIR="/var/backups/macfleet_users"

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

# User account categories
declare -A USER_CATEGORIES=(
    ["administrator"]="admin,full_privileges,system_access"
    ["developer"]="standard,sudo_group,development_access"
    ["standard_user"]="standard,basic_privileges,user_access"
    ["service_account"]="standard,no_login,service_access"
    ["temporary_user"]="standard,limited_time,restricted_access"
    ["guest_user"]="standard,guest_privileges,temporary_access"
    ["kiosk_user"]="standard,kiosk_mode,restricted_access"
    ["backup_operator"]="standard,backup_privileges,system_access"
    ["monitoring_user"]="standard,read_only,monitoring_access"
    ["deployment_user"]="admin,deployment_privileges,automated_access"
)

# User management policies
declare -A USER_POLICIES=(
    ["password_strength"]="minimum_8_chars,mixed_case,numbers,special_chars"
    ["password_expiry"]="90_days,180_days,365_days,never"
    ["account_lockout"]="3_attempts,5_attempts,10_attempts,disabled"
    ["session_timeout"]="15_minutes,30_minutes,60_minutes,4_hours"
    ["home_directory"]="local_only,network_shared,encrypted,no_home"
    ["shell_access"]="/bin/bash,/bin/zsh,/usr/bin/false,/sbin/nologin"
)

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

# Enhanced user creation with enterprise features
create_enterprise_user() {
    local username="$1"
    local fullname="$2"
    local password="$3"
    local category="${4:-standard_user}"
    local custom_options="$5"
    
    log_action "Creating enterprise user: $username (Category: $category)"
    
    # Validate inputs
    if [[ -z "$username" || -z "$fullname" || -z "$password" ]]; then
        log_action "ERROR: Username, full name, and password are required"
        return 1
    fi
    
    # Check if user already exists
    if id "$username" &>/dev/null; then
        log_action "ERROR: User '$username' already exists"
        return 1
    fi
    
    # Validate password strength
    if ! validate_password_strength "$password"; then
        log_action "ERROR: Password does not meet strength requirements"
        return 1
    fi
    
    # Generate unique UID
    local new_uid=$(get_next_available_uid)
    
    # Create user account based on category
    export PATH=/usr/bin:/bin:/usr/sbin:/sbin
    
    local is_admin="false"
    local shell="/bin/bash"
    local home_dir="/Users/$username"
    
    # Parse category configuration
    IFS=',' read -ra CATEGORY_PARTS <<< "${USER_CATEGORIES[$category]}"
    local user_type="${CATEGORY_PARTS[0]}"
    local privileges="${CATEGORY_PARTS[1]}"
    local access_level="${CATEGORY_PARTS[2]}"
    
    [[ "$user_type" == "admin" ]] && is_admin="true"
    [[ "$privileges" == "no_login" ]] && shell="/usr/bin/false"
    
    # Create the user account
    local create_cmd="sysadminctl -addUser \"$username\" -fullName \"$fullname\" -password \"$password\" -UID \"$new_uid\""
    
    if [[ "$is_admin" == "true" ]]; then
        create_cmd="$create_cmd -admin"
    fi
    
    if eval "$create_cmd"; then
        log_action "SUCCESS: User '$username' created with UID $new_uid"
        
        # Apply additional configurations
        configure_user_environment "$username" "$category" "$custom_options"
        
        # Generate user report
        local report_file="$REPORT_DIR/user_creation_${username}_$(date +%Y%m%d_%H%M%S).json"
        generate_user_report "$username" "$report_file"
        
        echo "$report_file"
        return 0
    else
        log_action "ERROR: Failed to create user '$username'"
        return 1
    fi
}

# Password strength validation
validate_password_strength() {
    local password="$1"
    local min_length=8
    
    # Check minimum length
    if [[ ${#password} -lt $min_length ]]; then
        echo "Password must be at least $min_length characters long"
        return 1
    fi
    
    # Check for uppercase letter
    if [[ ! "$password" =~ [A-Z] ]]; then
        echo "Password must contain at least one uppercase letter"
        return 1
    fi
    
    # Check for lowercase letter
    if [[ ! "$password" =~ [a-z] ]]; then
        echo "Password must contain at least one lowercase letter"
        return 1
    fi
    
    # Check for digit
    if [[ ! "$password" =~ [0-9] ]]; then
        echo "Password must contain at least one digit"
        return 1
    fi
    
    # Check for special character
    if [[ ! "$password" =~ [^a-zA-Z0-9] ]]; then
        echo "Password must contain at least one special character"
        return 1
    fi
    
    return 0
}

# Get next available UID
get_next_available_uid() {
    local start_uid=1000
    local max_uid=65533
    
    for ((uid=start_uid; uid<=max_uid; uid++)); do
        if ! id -u "$uid" &>/dev/null; then
            echo "$uid"
            return 0
        fi
    done
    
    echo "65534"  # Fallback UID
}

# Configure user environment based on category
configure_user_environment() {
    local username="$1"
    local category="$2"
    local custom_options="$3"
    
    log_action "Configuring environment for user: $username (Category: $category)"
    
    case "$category" in
        "developer")
            # Add to developer group
            dseditgroup -o create -q developer 2>/dev/null
            dseditgroup -o edit -a "$username" -t user developer
            
            # Grant sudo access for development
            echo "$username ALL=(ALL) NOPASSWD: /usr/bin/xcodebuild, /usr/local/bin/brew" > "/etc/sudoers.d/$username"
            ;;
        "service_account")
            # Disable login shell
            dscl . -create "/Users/$username" UserShell /usr/bin/false
            
            # Hide from login window
            dscl . -create "/Users/$username" IsHidden 1
            ;;
        "kiosk_user")
            # Set up kiosk environment
            setup_kiosk_user "$username"
            ;;
        "temporary_user")
            # Set account expiration (30 days)
            local expiry_date=$(date -v +30d +%Y-%m-%d)
            dscl . -create "/Users/$username" AccountExpires "$expiry_date"
            ;;
    esac
    
    # Apply custom options if provided
    if [[ -n "$custom_options" ]]; then
        apply_custom_user_options "$username" "$custom_options"
    fi
}

# Set up kiosk user environment
setup_kiosk_user() {
    local username="$1"
    local kiosk_dir="/Users/$username/Desktop"
    
    # Create kiosk desktop environment
    mkdir -p "$kiosk_dir"
    
    # Create launchd plist for kiosk mode
    cat > "/Library/LaunchAgents/com.macfleet.kiosk.$username.plist" << EOF
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Label</key>
    <string>com.macfleet.kiosk.$username</string>
    <key>ProgramArguments</key>
    <array>
        <string>/System/Applications/Safari.app/Contents/MacOS/Safari</string>
        <string>--kiosk</string>
        <string>https://company-portal.example.com</string>
    </array>
    <key>RunAtLoad</key>
    <true/>
    <key>UserName</key>
    <string>$username</string>
</dict>
</plist>
EOF
    
    chown "$username:staff" "/Library/LaunchAgents/com.macfleet.kiosk.$username.plist"
    chmod 644 "/Library/LaunchAgents/com.macfleet.kiosk.$username.plist"
}

# Generate user report
generate_user_report() {
    local username="$1"
    local report_file="$2"
    
    # Get user information
    local user_info=$(id "$username")
    local user_groups=$(groups "$username")
    local home_dir=$(dscl . -read "/Users/$username" NFSHomeDirectory | cut -d: -f2 | xargs)
    local shell=$(dscl . -read "/Users/$username" UserShell | cut -d: -f2 | xargs)
    local real_name=$(dscl . -read "/Users/$username" RealName | cut -d: -f2 | xargs)
    
    cat > "$report_file" << EOF
{
    "user_report": {
        "username": "$username",
        "timestamp": "$(date -u +%Y-%m-%dT%H:%M:%SZ)",
        "hostname": "$(hostname)",
        "script_version": "$SCRIPT_VERSION",
        "user_details": {
            "real_name": "$real_name",
            "home_directory": "$home_dir",
            "shell": "$shell",
            "user_info": "$user_info",
            "groups": "$user_groups"
        },
        "creation_status": "success",
        "security_settings": {
            "password_policy_applied": true,
            "account_restrictions": [],
            "group_memberships": []
        }
    }
}
EOF
    
    log_action "User report generated: $report_file"
}

# Fleet user management
manage_fleet_users() {
    local action="$1"
    local target_spec="$2"
    local options="$3"
    
    log_action "Fleet user management: $action"
    
    case "$action" in
        "audit")
            audit_fleet_users "$target_spec"
            ;;
        "sync")
            sync_fleet_users "$target_spec" "$options"
            ;;
        "cleanup")
            cleanup_fleet_users "$target_spec" "$options"
            ;;
        "report")
            generate_fleet_user_report
            ;;
    esac
}

# Audit all users on the system
audit_fleet_users() {
    local filter_pattern="$1"
    
    echo "=== Fleet User Audit ==="
    
    local audit_report="$REPORT_DIR/fleet_user_audit_$(date +%Y%m%d_%H%M%S).json"
    
    cat > "$audit_report" << EOF
{
    "audit_info": {
        "timestamp": "$(date -u +%Y-%m-%dT%H:%M:%SZ)",
        "hostname": "$(hostname)",
        "filter_pattern": "$filter_pattern"
    },
    "user_accounts": [],
    "security_summary": {},
    "recommendations": []
}
EOF
    
    # Get all local users
    local users=($(dscl . -list /Users | grep -v "^_" | grep -v "daemon\|nobody\|root"))
    
    for user in "${users[@]}"; do
        if [[ -z "$filter_pattern" || "$user" =~ $filter_pattern ]]; then
            # Get detailed user information
            local uid=$(id -u "$user" 2>/dev/null)
            local gid=$(id -g "$user" 2>/dev/null)
            local groups=$(groups "$user" 2>/dev/null)
            local home=$(dscl . -read "/Users/$user" NFSHomeDirectory 2>/dev/null | cut -d: -f2 | xargs)
            local shell=$(dscl . -read "/Users/$user" UserShell 2>/dev/null | cut -d: -f2 | xargs)
            local last_login=$(last -1 "$user" | head -1 | awk '{print $4, $5, $6, $7}')
            
            # Check if user is admin
            local is_admin="false"
            if dseditgroup -o checkmember -m "$user" admin &>/dev/null; then
                is_admin="true"
            fi
            
            # Add to report
            jq --arg user "$user" \
               --arg uid "$uid" \
               --arg gid "$gid" \
               --arg groups "$groups" \
               --arg home "$home" \
               --arg shell "$shell" \
               --arg last_login "$last_login" \
               --arg is_admin "$is_admin" \
               '.user_accounts += [{
                   "username": $user,
                   "uid": $uid,
                   "gid": $gid,
                   "groups": $groups,
                   "home_directory": $home,
                   "shell": $shell,
                   "last_login": $last_login,
                   "is_admin": ($is_admin == "true")
               }]' "$audit_report" > "${audit_report}.tmp" && mv "${audit_report}.tmp" "$audit_report"
        fi
    done
    
    # Generate security summary
    local total_users=$(echo "${users[@]}" | wc -w)
    local admin_users=$(dseditgroup -o checkmember -m "" admin 2>/dev/null | wc -l)
    local inactive_users=0
    
    # Check for inactive users (no login in 90 days)
    for user in "${users[@]}"; do
        local last_login_timestamp=$(last -1 "$user" | head -1 | awk '{print $4, $5, $6, $7}')
        if [[ -n "$last_login_timestamp" ]]; then
            local days_since_login=$(( ($(date +%s) - $(date -j -f "%b %d %H:%M" "$last_login_timestamp" +%s 2>/dev/null || echo 0)) / 86400 ))
            if [[ $days_since_login -gt 90 ]]; then
                ((inactive_users++))
            fi
        fi
    done
    
    jq --argjson total "$total_users" \
       --argjson admins "$admin_users" \
       --argjson inactive "$inactive_users" \
       '.security_summary = {
           "total_users": $total,
           "admin_users": $admins,
           "inactive_users": $inactive,
           "security_score": (100 - ($admins * 10) - ($inactive * 5))
       }' "$audit_report" > "${audit_report}.tmp" && mv "${audit_report}.tmp" "$audit_report"
    
    log_action "Fleet user audit completed: $audit_report"
    echo "$audit_report"
}

# Main execution function
main() {
    local action="${1:-create}"
    local username="${2:-}"
    local fullname="${3:-}"
    local password="${4:-}"
    local options="${5:-}"
    
    log_action "=== MacFleet User Management Started ==="
    log_action "Action: $action, User: $username"
    
    case "$action" in
        "create")
            if [[ -z "$username" || -z "$fullname" || -z "$password" ]]; then
                echo "Usage: $0 create <username> <fullname> <password> [category]"
                exit 1
            fi
            create_enterprise_user "$username" "$fullname" "$password" "$options"
            ;;
        "modify")
            if [[ -z "$username" || -z "$fullname" ]]; then
                echo "Usage: $0 modify <username> <action> <value>"
                exit 1
            fi
            modify_user_account "$username" "$fullname" "$password"
            ;;
        "delete")
            if [[ -z "$username" ]]; then
                echo "Usage: $0 delete <username> [delete_home] [backup_home]"
                exit 1
            fi
            delete_user_account "$username" "$fullname" "$password"
            ;;
        "audit")
            audit_fleet_users "$username"
            ;;
        "fleet")
            manage_fleet_users "$username" "$fullname" "$password"
            ;;
        "help")
            echo "Usage: $0 [action] [options...]"
            echo "Actions:"
            echo "  create <username> <fullname> <password> [category] - Create user"
            echo "  modify <username> <action> <value> - Modify user"
            echo "  delete <username> [delete_home] [backup_home] - Delete user"
            echo "  audit [pattern] - Audit users"
            echo "  fleet <action> [pattern] [options] - Fleet management"
            echo "  help - Show this help"
            echo ""
            echo "Categories: ${!USER_CATEGORIES[*]}"
            ;;
        *)
            log_action "ERROR: Unknown action: $action"
            exit 1
            ;;
    esac
    
    log_action "=== User management completed ==="
}

# Execute main function
main "$@"

Common User Management Tasks

User Information Display

#!/bin/bash

# Display comprehensive user information
show_user_info() {
    local username="$1"
    
    if ! id "$username" &>/dev/null; then
        echo "User '$username' does not exist"
        return 1
    fi
    
    echo "=== User Information: $username ==="
    
    # Basic user information
    echo "User ID Information:"
    id "$username"
    
    # Group memberships
    echo -e "\nGroup Memberships:"
    groups "$username"
    
    # Home directory information
    local home_dir=$(dscl . -read "/Users/$username" NFSHomeDirectory | cut -d: -f2 | xargs)
    echo -e "\nHome Directory: $home_dir"
    if [[ -d "$home_dir" ]]; then
        echo "Home directory size: $(du -sh "$home_dir" | cut -f1)"
    fi
    
    # Login shell
    local shell=$(dscl . -read "/Users/$username" UserShell | cut -d: -f2 | xargs)
    echo -e "\nLogin Shell: $shell"
    
    # Account status
    echo -e "\nAccount Status:"
    if dscl . -read "/Users/$username" AuthenticationAuthority &>/dev/null; then
        echo "Account: Enabled"
    else
        echo "Account: Disabled"
    fi
    
    # Admin status
    if dseditgroup -o checkmember -m "$username" admin &>/dev/null; then
        echo "Admin Privileges: Yes"
    else
        echo "Admin Privileges: No"
    fi
    
    # Last login
    echo -e "\nLast Login:"
    last -1 "$username" | head -1
}

# Usage
show_user_info "daniel"

Password Management

#!/bin/bash

# Comprehensive password management
manage_user_password() {
    local username="$1"
    local action="$2"
    local new_password="$3"
    
    if ! id "$username" &>/dev/null; then
        echo "User '$username' does not exist"
        return 1
    fi
    
    export PATH=/usr/bin:/bin:/usr/sbin:/sbin
    
    case "$action" in
        "change")
            if [[ -z "$new_password" ]]; then
                echo "New password required"
                return 1
            fi
            
            if ! validate_password_strength "$new_password"; then
                return 1
            fi
            
            if sysadminctl -resetPasswordFor "$username" -newPassword "$new_password"; then
                echo "Password changed successfully for user: $username"
                
                # Force password change on next login (optional)
                # pwpolicy -u "$username" -setpolicy "newPasswordRequired=1"
            else
                echo "Failed to change password"
                return 1
            fi
            ;;
        "expire")
            echo "Expiring password for user: $username"
            if pwpolicy -u "$username" -setpolicy "newPasswordRequired=1"; then
                echo "Password expired - user must change on next login"
            else
                echo "Failed to expire password"
                return 1
            fi
            ;;
        "unlock")
            echo "Unlocking account for user: $username"
            if pwpolicy -u "$username" -setpolicy "isDisabled=0"; then
                echo "Account unlocked successfully"
            else
                echo "Failed to unlock account"
                return 1
            fi
            ;;
        *)
            echo "Unknown password action: $action"
            echo "Available actions: change, expire, unlock"
            return 1
            ;;
    esac
}

# Usage
manage_user_password "daniel" "change" "NewSecurePassword123!"

Group Management

#!/bin/bash

# User group management
manage_user_groups() {
    local username="$1"
    local action="$2"
    local group_name="$3"
    
    if ! id "$username" &>/dev/null; then
        echo "User '$username' does not exist"
        return 1
    fi
    
    case "$action" in
        "add")
            echo "Adding user '$username' to group '$group_name'"
            if dseditgroup -o edit -a "$username" -t user "$group_name"; then
                echo "✓ User added to group successfully"
            else
                echo "✗ Failed to add user to group"
                return 1
            fi
            ;;
        "remove")
            echo "Removing user '$username' from group '$group_name'"
            if dseditgroup -o edit -d "$username" -t user "$group_name"; then
                echo "✓ User removed from group successfully"
            else
                echo "✗ Failed to remove user from group"
                return 1
            fi
            ;;
        "list")
            echo "Groups for user '$username':"
            groups "$username"
            ;;
        *)
            echo "Unknown group action: $action"
            echo "Available actions: add, remove, list"
            return 1
            ;;
    esac
}

# Usage
manage_user_groups "daniel" "add" "developers"
manage_user_groups "daniel" "list"

Important Notes

  • Admin privileges required for user creation and modification
  • Password policies should enforce strong passwords for security
  • User validation - Always verify inputs before creating accounts
  • Home directory permissions - Ensure proper ownership and permissions
  • Backup user data before deletion operations
  • Test scripts on individual accounts before fleet deployment
  • Monitor user activities for security compliance

Tutorial

Nuevas actualizaciones y mejoras para Macfleet.

Configurando un Runner de GitHub Actions en un Mac Mini (Apple Silicon)

Runner de GitHub Actions

GitHub Actions es una plataforma poderosa de CI/CD que te permite automatizar tus flujos de trabajo de desarrollo de software. Aunque GitHub ofrece runners hospedados, los runners auto-hospedados proporcionan mayor control y personalización para tu configuración de CI/CD. Este tutorial te guía a través de la configuración y conexión de un runner auto-hospedado en un Mac mini para ejecutar pipelines de macOS.

Prerrequisitos

Antes de comenzar, asegúrate de tener:

  • Un Mac mini (regístrate en Macfleet)
  • Un repositorio de GitHub con derechos de administrador
  • Un gestor de paquetes instalado (preferiblemente Homebrew)
  • Git instalado en tu sistema

Paso 1: Crear una Cuenta de Usuario Dedicada

Primero, crea una cuenta de usuario dedicada para el runner de GitHub Actions:

# Crear la cuenta de usuario '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

# Establecer la contraseña para el usuario
sudo dscl . -passwd /Users/gh-runner tu_contraseña

# Agregar 'gh-runner' al grupo 'admin'
sudo dscl . -append /Groups/admin GroupMembership gh-runner

Cambia a la nueva cuenta de usuario:

su gh-runner

Paso 2: Instalar Software Requerido

Instala Git y Rosetta 2 (si usas Apple Silicon):

# Instalar Git si no está ya instalado
brew install git

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

Paso 3: Configurar el Runner de GitHub Actions

  1. Ve a tu repositorio de GitHub
  2. Navega a Configuración > Actions > Runners

Runner de GitHub Actions

  1. Haz clic en "New self-hosted runner" (https://github.com/<username>/<repository>/settings/actions/runners/new)
  2. Selecciona macOS como imagen del runner y ARM64 como arquitectura
  3. Sigue los comandos proporcionados para descargar y configurar el runner

Runner de GitHub Actions

Crea un archivo .env en el directorio _work del runner:

# archivo _work/.env
ImageOS=macos15
XCODE_15_DEVELOPER_DIR=/Applications/Xcode.app/Contents/Developer
  1. Ejecuta el script run.sh en tu directorio del runner para completar la configuración.
  2. Verifica que el runner esté activo y escuchando trabajos en la terminal y revisa la configuración del repositorio de GitHub para la asociación del runner y el estado Idle.

Runner de GitHub Actions

Paso 4: Configurar Sudoers (Opcional)

Si tus acciones requieren privilegios de root, configura el archivo sudoers:

sudo visudo

Agrega la siguiente línea:

gh-runner ALL=(ALL) NOPASSWD: ALL

Paso 5: Usar el Runner en Flujos de Trabajo

Configura tu flujo de trabajo de GitHub Actions para usar el runner auto-hospedado:

name: Flujo de trabajo de muestra

on:
  workflow_dispatch:

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

El runner está autenticado en tu repositorio y etiquetado con self-hosted, macOS, y ARM64. Úsalo en tus flujos de trabajo especificando estas etiquetas en el campo runs-on:

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

Mejores Prácticas

  • Mantén tu software del runner actualizado
  • Monitorea regularmente los logs del runner para problemas
  • Usa etiquetas específicas para diferentes tipos de runners
  • Implementa medidas de seguridad apropiadas
  • Considera usar múltiples runners para balanceo de carga

Solución de Problemas

Problemas comunes y soluciones:

  1. Runner no conectando:

    • Verifica conectividad de red
    • Verifica validez del token de GitHub
    • Asegúrate de permisos apropiados
  2. Fallas de construcción:

    • Verifica instalación de Xcode
    • Verifica dependencias requeridas
    • Revisa logs del flujo de trabajo
  3. Problemas de permisos:

    • Verifica permisos de usuario
    • Verifica configuración de sudoers
    • Revisa permisos del sistema de archivos

Conclusión

Ahora tienes un runner auto-hospedado de GitHub Actions configurado en tu Mac mini. Esta configuración te proporciona más control sobre tu entorno de CI/CD y te permite ejecutar flujos de trabajo específicos de macOS de manera eficiente.

Recuerda mantener regularmente tu runner y mantenerlo actualizado con los últimos parches de seguridad y versiones de software.

Aplicación Nativa

Aplicación nativa de Macfleet

Guía de Instalación de Macfleet

Macfleet es una solución poderosa de gestión de flota diseñada específicamente para entornos de Mac Mini alojados en la nube. Como proveedor de hosting en la nube de Mac Mini, puedes usar Macfleet para monitorear, gestionar y optimizar toda tu flota de instancias Mac virtualizadas.

Esta guía de instalación te llevará a través de la configuración del monitoreo de Macfleet en sistemas macOS, Windows y Linux para asegurar una supervisión integral de tu infraestructura en la nube.

🍎 macOS

  • Descarga el archivo .dmg para Mac aquí
  • Haz doble clic en el archivo .dmg descargado
  • Arrastra la aplicación Macfleet a la carpeta Aplicaciones
  • Expulsa el archivo .dmg
  • Abre Preferencias del Sistema > Seguridad y Privacidad
    • Pestaña Privacidad > Accesibilidad
    • Marca Macfleet para permitir el monitoreo
  • Inicia Macfleet desde Aplicaciones
  • El seguimiento comienza automáticamente

🪟 Windows

  • Descarga el archivo .exe para Windows aquí
  • Haz clic derecho en el archivo .exe > "Ejecutar como administrador"
  • Sigue el asistente de instalación
  • Acepta los términos y condiciones
  • Permite en Windows Defender si se solicita
  • Concede permisos de monitoreo de aplicaciones
  • Inicia Macfleet desde el Menú Inicio
  • La aplicación comienza el seguimiento automáticamente

🐧 Linux

  • Descarga el paquete .deb (Ubuntu/Debian) o .rpm (CentOS/RHEL) aquí
  • Instala usando tu gestor de paquetes
    • Ubuntu/Debian: sudo dpkg -i Macfleet-linux.deb
    • CentOS/RHEL: sudo rpm -ivh Macfleet-linux.rpm
  • Permite permisos de acceso X11 si se solicita
  • Agrega el usuario a los grupos apropiados si es necesario
  • Inicia Macfleet desde el menú de Aplicaciones
  • La aplicación comienza el seguimiento automáticamente

Nota: Después de la instalación en todos los sistemas, inicia sesión con tus credenciales de Macfleet para sincronizar datos con tu panel de control.