Guide

Nouvelles mises à jour et améliorations de Macfleet.

Gestion Entreprise du Sommeil et de l'Alimentation pour macOS

Implémentez une gestion de sommeil et d'alimentation de niveau entreprise sur votre déploiement MacFleet avec des politiques d'alimentation automatisées, l'optimisation énergétique, la surveillance de conformité et une gestion complète de la flotte. Ce tutoriel fournit des solutions pour maintenir une efficacité énergétique optimale tout en respectant les exigences de sécurité et opérationnelles.

Comprendre la Gestion de l'Alimentation macOS

macOS fournit plusieurs outils et mécanismes de gestion de l'alimentation :

  • pmset - Outil principal de paramètres de gestion d'alimentation
  • caffeinate - Empêcher le sommeil du système pour des opérations spécifiques
  • systemsetup - Configuration d'alimentation à l'échelle du système
  • Économiseur d'énergie - Interface de gestion d'alimentation via GUI
  • Assertions d'alimentation - Prévention du sommeil au niveau application

Opérations de Gestion d'Alimentation de Base

Configurer le Minuteur de Sommeil Système

#!/bin/bash

# Définir le minuteur de sommeil système à 15 minutes
sudo pmset sleep 15

Configurer le Minuteur de Sommeil d'Écran

#!/bin/bash

# Définir le minuteur de sommeil d'écran à 15 minutes
sudo pmset displaysleep 15

Programmer les Événements de Réveil

#!/bin/bash

# Programmer le réveil tous les jours à 9h00
sudo pmset repeat wakeorpoweron MTWRFSU 9:00:00

Empêcher le Sommeil pour une Période Spécifique

#!/bin/bash

# Empêcher le sommeil du système pendant 300 secondes
caffeinate -u -t 300

Vérifier les Paramètres de Sommeil Système

#!/bin/bash

# Vérifier le temps d'inactivité de sommeil actuel
sudo systemsetup -getcomputersleep

Désactiver le Sommeil Système

#!/bin/bash

# Désactiver le sommeil système
sudo systemsetup -setcomputersleep Never

Activer le Redémarrage en Cas de Blocage

#!/bin/bash

# Redémarrer automatiquement en cas de blocage système
systemsetup -setrestartfreeze on

Système de Gestion d'Alimentation Entreprise

Outil de Gestion d'Alimentation Complet

#!/bin/bash

# Outil de Gestion du Sommeil et de l'Alimentation Entreprise MacFleet
# Politiques d'alimentation avancées et optimisation énergétique

# Configuration
CONFIG_FILE="/etc/macfleet/power_policy.conf"
LOG_FILE="/var/log/macfleet_power.log"
POLICIES_DIR="/Library/MacFleet/PowerPolicies"
AUDIT_LOG="/var/log/macfleet_power_audit.log"

# Créer les répertoires
mkdir -p "$(dirname "$CONFIG_FILE")" "$(dirname "$LOG_FILE")" "$POLICIES_DIR" "$(dirname "$AUDIT_LOG")"

# Politique de gestion d'alimentation par défaut
cat > "$CONFIG_FILE" 2>/dev/null << 'EOF' || true
# Politique de Gestion d'Alimentation Entreprise MacFleet
# Version : 2.0

# Application des Politiques d'Alimentation
ENFORCE_POWER_POLICIES=true
AUTO_APPLY_POLICIES=true
POWER_PROFILE="corporate_standard"
ENERGY_OPTIMIZATION=true
COMPLIANCE_MONITORING=true

# Paramètres de Sommeil (minutes)
SYSTEM_SLEEP_AC=30
SYSTEM_SLEEP_BATTERY=15
DISPLAY_SLEEP_AC=15
DISPLAY_SLEEP_BATTERY=5
DISK_SLEEP_AC=10
DISK_SLEEP_BATTERY=5

# Événements de Réveil et d'Alimentation
WAKE_ON_LAN=true
WAKE_ON_ADMINISTRATIVE_ACCESS=true
AUTOMATIC_RESTART_ON_POWER_LOSS=true
AUTOMATIC_RESTART_ON_FREEZE=true
SCHEDULED_WAKE_ENABLED=true
SCHEDULED_SLEEP_ENABLED=true

# Configuration des Heures de Bureau
BUSINESS_HOURS_START="09:00"
BUSINESS_HOURS_END="18:00"
BUSINESS_DAYS="MTWRF"
WEEKEND_POWER_PROFILE="energy_saver"
AFTER_HOURS_POWER_PROFILE="security_focused"
EOF

# Charger la configuration
source "$CONFIG_FILE" 2>/dev/null || true

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

# Fonction de journalisation d'audit
audit_log() {
    local action="$1"
    local result="$2"
    local details="$3"
    echo "$(date '+%Y-%m-%d %H:%M:%S') - ACTION:$action RESULT:$result DETAILS:$details USER:$(whoami)" >> "$AUDIT_LOG"
}

# Obtenir l'état actuel de l'alimentation
get_power_status() {
    echo "=== État Actuel de la Gestion d'Alimentation ==="
    
    # Paramètres d'alimentation à l'échelle du système
    echo "Paramètres d'Alimentation Système :"
    pmset -g 2>/dev/null || echo "  Paramètres d'alimentation indisponibles"
    
    echo -e "\nSource d'Alimentation Actuelle :"
    pmset -g ps 2>/dev/null | head -1
    
    echo -e "\nMinuteurs de Sommeil :"
    echo "  Sommeil Système (AC) : $(pmset -g | grep -E '^\s*sleep\s' | awk '{print $2}') minutes"
    echo "  Sommeil Écran (AC) : $(pmset -g | grep -E '^\s*displaysleep\s' | awk '{print $2}') minutes"
    echo "  Sommeil Disque (AC) : $(pmset -g | grep -E '^\s*disksleep\s' | awk '{print $2}') minutes"
    
    echo -e "\nAssertions d'Alimentation :"
    pmset -g assertions 2>/dev/null | grep -E "(PreventUserIdleSystemSleep|PreventUserIdleDisplaySleep)" | head -5
    
    echo -e "\nÉtat Thermique :"
    pmset -g thermstate 2>/dev/null | head -3
    
    return 0
}

# Appliquer un profil d'alimentation entreprise
apply_power_profile() {
    local profile="${1:-$POWER_PROFILE}"
    
    echo "=== Application du Profil d'Alimentation Entreprise : $profile ==="
    
    case "$profile" in
        "corporate_standard")
            apply_corporate_standard_profile
            ;;
        "energy_saver")
            apply_energy_saver_profile
            ;;
        "high_performance")
            apply_high_performance_profile
            ;;
        "security_focused")
            apply_security_focused_profile
            ;;
        "presentation_mode")
            apply_presentation_mode_profile
            ;;
        "kiosk_mode")
            apply_kiosk_mode_profile
            ;;
        *)
            echo "Profil d'alimentation inconnu : $profile"
            echo "Utilisation du profil corporate_standard par défaut"
            apply_corporate_standard_profile
            ;;
    esac
    
    # Appliquer les paramètres de sécurité communs
    apply_security_settings
    
    # Configurer les événements programmés
    configure_scheduled_events
    
    echo "✅ Profil d'alimentation '$profile' appliqué avec succès"
    log_action "Profil d'alimentation appliqué : $profile"
    audit_log "POWER_PROFILE" "APPLIED" "Profil : $profile"
    
    return 0
}

# Profil d'alimentation standard entreprise
apply_corporate_standard_profile() {
    echo "=== Configuration du Profil Standard Entreprise ==="
    
    # Paramètres alimentation secteur
    sudo pmset -c sleep "$SYSTEM_SLEEP_AC" 2>/dev/null
    sudo pmset -c displaysleep "$DISPLAY_SLEEP_AC" 2>/dev/null
    sudo pmset -c disksleep "$DISK_SLEEP_AC" 2>/dev/null
    
    # Paramètres batterie (si applicable)
    sudo pmset -b sleep "$SYSTEM_SLEEP_BATTERY" 2>/dev/null
    sudo pmset -b displaysleep "$DISPLAY_SLEEP_BATTERY" 2>/dev/null
    sudo pmset -b disksleep "$DISK_SLEEP_BATTERY" 2>/dev/null
    
    # Paramètres de réveil
    if [[ "$WAKE_ON_LAN" == "true" ]]; then
        sudo pmset -a womp 1 2>/dev/null
    fi
    
    if [[ "$WAKE_ON_ADMINISTRATIVE_ACCESS" == "true" ]]; then
        sudo pmset -a acwake 1 2>/dev/null
    fi
    
    echo "Profil standard entreprise configuré"
    log_action "Profil d'alimentation standard entreprise appliqué"
}

# Profil économiseur d'énergie
apply_energy_saver_profile() {
    echo "=== Configuration du Profil Économiseur d'Énergie ==="
    
    # Économie d'énergie agressive
    sudo pmset -c sleep 10 2>/dev/null
    sudo pmset -c displaysleep 5 2>/dev/null
    sudo pmset -c disksleep 5 2>/dev/null
    
    sudo pmset -b sleep 5 2>/dev/null
    sudo pmset -b displaysleep 2 2>/dev/null
    sudo pmset -b disksleep 3 2>/dev/null
    
    # Activer les fonctionnalités d'économie d'énergie
    sudo pmset -a reducebright 1 2>/dev/null
    sudo pmset -a lessbright 1 2>/dev/null
    
    echo "Profil économiseur d'énergie configuré"
    log_action "Profil d'alimentation économiseur d'énergie appliqué"
}

# Profil haute performance
apply_high_performance_profile() {
    echo "=== Configuration du Profil Haute Performance ==="
    
    # Paramètres de sommeil minimaux
    sudo pmset -c sleep 60 2>/dev/null
    sudo pmset -c displaysleep 30 2>/dev/null
    sudo pmset -c disksleep 30 2>/dev/null
    
    sudo pmset -b sleep 30 2>/dev/null
    sudo pmset -b displaysleep 15 2>/dev/null
    sudo pmset -b disksleep 15 2>/dev/null
    
    # Désactiver les fonctionnalités d'économie d'énergie
    sudo pmset -a reducebright 0 2>/dev/null
    sudo pmset -a lessbright 0 2>/dev/null
    
    echo "Profil haute performance configuré"
    log_action "Profil d'alimentation haute performance appliqué"
}

# Profil axé sécurité
apply_security_focused_profile() {
    echo "=== Configuration du Profil Axé Sécurité ==="
    
    # Minuteurs de sommeil courts pour la sécurité
    sudo pmset -c sleep 5 2>/dev/null
    sudo pmset -c displaysleep 3 2>/dev/null
    sudo pmset -c disksleep 5 2>/dev/null
    
    sudo pmset -b sleep 3 2>/dev/null
    sudo pmset -b displaysleep 1 2>/dev/null
    sudo pmset -b disksleep 3 2>/dev/null
    
    echo "Profil axé sécurité configuré"
    log_action "Profil d'alimentation axé sécurité appliqué"
}

# Profil mode présentation
apply_presentation_mode_profile() {
    echo "=== Configuration du Profil Mode Présentation ==="
    
    # Empêcher le sommeil pendant les présentations
    sudo pmset -c sleep 0 2>/dev/null
    sudo pmset -c displaysleep 0 2>/dev/null
    
    # Maintenir le système actif
    sudo pmset -a lidwake 1 2>/dev/null
    sudo pmset -a acwake 1 2>/dev/null
    
    echo "Profil mode présentation configuré"
    log_action "Profil d'alimentation mode présentation appliqué"
}

# Profil mode kiosque
apply_kiosk_mode_profile() {
    echo "=== Configuration du Profil Mode Kiosque ==="
    
    # Paramètres jamais en sommeil pour les appareils kiosque
    sudo pmset -c sleep 0 2>/dev/null
    sudo pmset -c displaysleep 0 2>/dev/null
    sudo pmset -c disksleep 0 2>/dev/null
    
    # Assurer que le système reste actif
    sudo pmset -a womp 1 2>/dev/null
    sudo pmset -a autorestart 1 2>/dev/null
    
    echo "Profil mode kiosque configuré"
    log_action "Profil d'alimentation mode kiosque appliqué"
}

# Appliquer les paramètres de sécurité
apply_security_settings() {
    echo "=== Application des Paramètres de Sécurité d'Alimentation ==="
    
    # Mode d'hibernation sécurisé
    sudo pmset -a hibernatemode 3 2>/dev/null
    echo "✅ Mode d'hibernation défini à 3"
    
    # Redémarrage automatique
    if [[ "$AUTOMATIC_RESTART_ON_POWER_LOSS" == "true" ]]; then
        sudo pmset -a autorestart 1 2>/dev/null
        echo "✅ Redémarrage automatique en cas de perte d'alimentation activé"
    fi
    
    if [[ "$AUTOMATIC_RESTART_ON_FREEZE" == "true" ]]; then
        sudo systemsetup -setrestartfreeze on 2>/dev/null
        echo "✅ Redémarrage automatique en cas de blocage activé"
    fi
    
    log_action "Paramètres de sécurité d'alimentation appliqués"
}

# Configurer les événements programmés
configure_scheduled_events() {
    echo "=== Configuration des Événements d'Alimentation Programmés ==="
    
    # Effacer les événements programmés existants
    sudo pmset repeat cancel 2>/dev/null
    
    if [[ "$SCHEDULED_WAKE_ENABLED" == "true" ]]; then
        # Programmer le réveil pour les heures de bureau
        sudo pmset repeat wakeorpoweron "$BUSINESS_DAYS" "$BUSINESS_HOURS_START:00" 2>/dev/null
        echo "✅ Réveil programmé configuré pour les heures de bureau"
        log_action "Réveil programmé configuré : $BUSINESS_DAYS à $BUSINESS_HOURS_START"
    fi
    
    if [[ "$SCHEDULED_SLEEP_ENABLED" == "true" ]]; then
        # Programmer le sommeil après les heures de bureau
        local sleep_time="${BUSINESS_HOURS_END}:30:00"
        sudo pmset repeat sleep "$BUSINESS_DAYS" "$sleep_time" 2>/dev/null
        echo "✅ Sommeil programmé configuré pour après les heures"
        log_action "Sommeil programmé configuré : $BUSINESS_DAYS à $sleep_time"
    fi
}

# Vérifier la conformité de la gestion d'alimentation
check_power_compliance() {
    echo "=== Vérification de Conformité de la Gestion d'Alimentation ==="
    
    local compliance_issues=()
    local compliance_score=100
    
    # Vérifier si la gestion d'alimentation est correctement configurée
    local current_settings
    current_settings=$(pmset -g 2>/dev/null)
    
    if [[ -z "$current_settings" ]]; then
        compliance_issues+=("Impossible de lire les paramètres de gestion d'alimentation")
        compliance_score=$((compliance_score - 50))
    fi
    
    # Vérifier les minuteurs de sommeil
    local system_sleep
    system_sleep=$(echo "$current_settings" | grep -E '^\s*sleep\s' | awk '{print $2}')
    
    if [[ "$system_sleep" == "0" ]] && [[ "$POWER_PROFILE" != "kiosk_mode" ]] && [[ "$POWER_PROFILE" != "presentation_mode" ]]; then
        compliance_issues+=("Sommeil système désactivé (risque de sécurité)")
        compliance_score=$((compliance_score - 20))
    fi
    
    # Vérifier le sommeil d'écran
    local display_sleep
    display_sleep=$(echo "$current_settings" | grep -E '^\s*displaysleep\s' | awk '{print $2}')
    
    if [[ "$display_sleep" == "0" ]] && [[ "$POWER_PROFILE" != "kiosk_mode" ]] && [[ "$POWER_PROFILE" != "presentation_mode" ]]; then
        compliance_issues+=("Sommeil d'écran désactivé (gaspillage d'énergie)")
        compliance_score=$((compliance_score - 15))
    fi
    
    # Rapporter l'état de conformité
    echo "Score de Conformité : $compliance_score/100"
    
    if [[ ${#compliance_issues[@]} -eq 0 ]]; then
        echo "✅ La configuration de gestion d'alimentation est conforme"
        audit_log "COMPLIANCE_CHECK" "PASSED" "Score : $compliance_score/100"
        return 0
    else
        echo "❌ Problèmes de conformité trouvés :"
        printf '  - %s\n' "${compliance_issues[@]}"
        audit_log "COMPLIANCE_CHECK" "FAILED" "Problèmes : ${#compliance_issues[@]} Score : $compliance_score/100"
        
        # Auto-remédiation si activée
        if [[ "$AUTO_APPLY_POLICIES" == "true" ]]; then
            echo "🔧 Auto-remédiation activée, application du profil d'alimentation correct..."
            apply_power_profile "$POWER_PROFILE"
        fi
        
        return 1
    fi
}

# Empêcher le sommeil système pour des opérations critiques
prevent_sleep_for_operation() {
    local operation_name="$1"
    local duration_seconds="$2"
    local prevent_display="${3:-false}"
    
    echo "=== Empêcher le Sommeil pour l'Opération : $operation_name ==="
    
    local caffeinate_options="-i"
    
    if [[ "$prevent_display" == "true" ]]; then
        caffeinate_options="$caffeinate_options -d"
    fi
    
    if [[ -n "$duration_seconds" ]]; then
        caffeinate_options="$caffeinate_options -t $duration_seconds"
    fi
    
    echo "Empêchement du sommeil système pour $operation_name..."
    log_action "Prévention de sommeil démarrée pour l'opération : $operation_name (durée : ${duration_seconds:-indéfinie}s)"
    
    # Exécuter caffeinate en arrière-plan et retourner le PID
    caffeinate $caffeinate_options &
    local caffeinate_pid=$!
    
    echo "Prévention de sommeil active (PID : $caffeinate_pid)"
    echo "$caffeinate_pid" > "/tmp/macfleet_caffeinate_$operation_name.pid"
    
    audit_log "SLEEP_PREVENTION" "STARTED" "Opération : $operation_name PID : $caffeinate_pid"
    
    return 0
}

# Arrêter la prévention de sommeil pour une opération
stop_sleep_prevention() {
    local operation_name="$1"
    local pid_file="/tmp/macfleet_caffeinate_$operation_name.pid"
    
    if [[ -f "$pid_file" ]]; then
        local caffeinate_pid
        caffeinate_pid=$(cat "$pid_file")
        
        if kill -0 "$caffeinate_pid" 2>/dev/null; then
            kill "$caffeinate_pid"
            echo "Prévention de sommeil arrêtée pour $operation_name (PID : $caffeinate_pid)"
            log_action "Prévention de sommeil arrêtée pour l'opération : $operation_name"
            audit_log "SLEEP_PREVENTION" "STOPPED" "Opération : $operation_name PID : $caffeinate_pid"
        else
            echo "Processus de prévention de sommeil non trouvé pour $operation_name"
        fi
        
        rm -f "$pid_file"
    else
        echo "Aucune prévention de sommeil active trouvée pour $operation_name"
    fi
}

# Fonction principale avec gestion d'arguments
main() {
    log_action "=== Outil de Gestion d'Alimentation MacFleet Démarré ==="
    
    case "${1:-status}" in
        "status")
            get_power_status
            ;;
        "profile")
            apply_power_profile "$2"
            ;;
        "compliance")
            check_power_compliance
            ;;
        "prevent-sleep")
            prevent_sleep_for_operation "$2" "$3" "$4"
            ;;
        "allow-sleep")
            stop_sleep_prevention "$2"
            ;;
        "schedule")
            configure_scheduled_events
            ;;
        *)
            echo "Outil de Gestion d'Alimentation Entreprise MacFleet"
            echo "Usage : $0 [commande] [options]"
            echo ""
            echo "Commandes :"
            echo "  status                        - Afficher l'état actuel de la gestion d'alimentation"
            echo "  profile [nom]                 - Appliquer un profil d'alimentation spécifique"
            echo "  compliance                    - Vérifier la conformité de la gestion d'alimentation"
            echo "  prevent-sleep [nom] [durée] [écran] - Empêcher le sommeil pour une opération"
            echo "  allow-sleep [nom]             - Arrêter la prévention de sommeil pour une opération"
            echo "  schedule                      - Configurer les événements d'alimentation programmés"
            echo ""
            echo "Profils d'Alimentation :"
            echo "  corporate_standard            - Gestion d'alimentation d'entreprise standard (défaut)"
            echo "  energy_saver                  - Efficacité énergétique maximale"
            echo "  high_performance              - Paramètres axés performance"
            echo "  security_focused              - Gestion d'alimentation optimisée sécurité"
            echo "  presentation_mode             - Empêcher le sommeil pendant les présentations"
            echo "  kiosk_mode                    - Toujours actif pour les appareils kiosque"
            ;;
    esac
    
    log_action "=== Opération de gestion d'alimentation terminée ==="
}

# Exécuter la fonction principale
main "$@"

Notes de Configuration Importantes

Architecture de Gestion d'Alimentation macOS

  • Unité de Gestion d'Alimentation (PMU) - Contrôle d'alimentation au niveau matériel
  • IOPMrootDomain - Gestion d'alimentation du noyau
  • PowerManagement.framework - APIs d'alimentation espace utilisateur
  • pmset - Outil de gestion d'alimentation en ligne de commande
  • Économiseur d'Énergie - Interface d'alimentation Préférences Système

Points d'Intégration Entreprise

  • Profils de Configuration MDM - Déployer les politiques d'alimentation de manière centralisée
  • Systèmes de Surveillance Énergétique - Intégration avec la gestion des installations
  • Suivi d'Empreinte Carbone - Rapports de conformité environnementale
  • Intelligence d'Affaires - Analytiques et optimisation de l'utilisation d'énergie

Bonnes Pratiques pour la Gestion d'Alimentation Entreprise

  1. Stratégie d'Efficacité Énergétique

    • Implémenter des profils d'alimentation échelonnés basés sur les modèles d'utilisation
    • Surveiller et optimiser la consommation d'énergie à travers la flotte
    • S'aligner avec les initiatives de développement durable d'entreprise
    • Suivre les économies de coûts des politiques de gestion d'alimentation
  2. Considérations de Sécurité

    • Activer la destruction des clés FileVault en veille pour les données sensibles
    • Configurer des modes d'hibernation appropriés pour la sécurité
    • Implémenter des modes de sommeil sécurisés pour les appareils non surveillés
    • Équilibrer les exigences de sécurité avec les besoins opérationnels
  3. Optimisation des Performances

    • Utiliser des profils haute performance pour les tâches intensives en ressources
    • Implémenter des modes présentation pour les scénarios de réunion
    • Configurer la gestion thermique pour les charges de travail soutenues
    • Surveiller la santé de la batterie et optimiser les modèles de charge
  4. Conformité et Rapports

    • Générer des rapports d'utilisation d'énergie pour la conformité réglementaire
    • Suivre l'adhérence aux politiques de gestion d'alimentation
    • Documenter les initiatives d'optimisation d'alimentation
    • Surveiller les métriques d'impact environnemental

N'oubliez pas de tester minutieusement les configurations de gestion d'alimentation dans votre environnement avant le déploiement à l'échelle de la flotte pour vous assurer qu'elles répondent aux exigences opérationnelles, de sécurité et d'efficacité énergétique de votre organisation.

Gestion Entreprise de l'Arrêt et du Redémarrage pour macOS

Implémentez une gestion d'arrêt et de redémarrage de niveau entreprise sur votre déploiement MacFleet avec la planification automatisée de maintenance, les procédures d'arrêt en douceur, la validation de sécurité et la gestion complète de l'alimentation de la flotte. Ce tutoriel fournit des solutions pour maintenir la continuité opérationnelle tout en assurant des opérations d'alimentation système sécurisées et efficaces.

Comprendre la Gestion d'Arrêt et de Redémarrage macOS

macOS fournit plusieurs mécanismes et outils de contrôle d'alimentation :

  • shutdown - Outil principal en ligne de commande pour le contrôle d'alimentation système
  • reboot - Commande alternative de redémarrage
  • halt - Arrêt du système sans extinction
  • Menu Apple - Interface d'arrêt via GUI
  • Bouton d'alimentation - Contrôle d'alimentation au niveau matériel

Opérations d'Arrêt de Base

Arrêt Instantané

#!/bin/bash

# Arrêter le Mac instantanément
sudo shutdown -h now

Redémarrage Programmé

#!/bin/bash

# Redémarrer le Mac dans 5 minutes
sudo shutdown -r +5

Arrêt à une Heure Spécifique

#!/bin/bash

# Arrêt à une heure spécifique : 18 octobre, 16:11:00 2022
sudo shutdown -h 2210181611

Redémarrage avec Message d'Avertissement

#!/bin/bash

# Redémarrer avec message d'avertissement
sudo shutdown -r +2 "le système redémarrera dans 2 minutes"

Veille d'Écran et Verrouillage

#!/bin/bash

# Verrouiller l'appareil et éteindre l'écran
sudo shutdown -s

Système de Gestion d'Arrêt et de Redémarrage Entreprise

Outil de Gestion d'Alimentation Complet

#!/bin/bash

# Outil de Gestion d'Arrêt et de Redémarrage Entreprise MacFleet
# Contrôle d'alimentation avancé et planification de maintenance

# Configuration
CONFIG_FILE="/etc/macfleet/shutdown_policy.conf"
LOG_FILE="/var/log/macfleet_shutdown.log"
SCHEDULES_DIR="/Library/MacFleet/ShutdownSchedules"
AUDIT_LOG="/var/log/macfleet_shutdown_audit.log"

# Créer les répertoires
mkdir -p "$(dirname "$CONFIG_FILE")" "$(dirname "$LOG_FILE")" "$SCHEDULES_DIR" "$(dirname "$AUDIT_LOG")"

# Politique de gestion d'arrêt par défaut
cat > "$CONFIG_FILE" 2>/dev/null << 'EOF' || true
# Politique de Gestion d'Arrêt et de Redémarrage Entreprise MacFleet
# Version : 2.0

# Application des Politiques d'Arrêt
ENFORCE_SHUTDOWN_POLICIES=true
GRACEFUL_SHUTDOWN_ENABLED=true
SAVE_WORK_BEFORE_SHUTDOWN=true
FORCE_SHUTDOWN_TIMEOUT=300
WARNING_NOTIFICATION_TIME=300

# Sécurité et Sûreté
REQUIRE_ADMIN_APPROVAL=false
VALIDATE_USER_SESSIONS=true
CHECK_RUNNING_PROCESSES=true
BACKUP_BEFORE_SHUTDOWN=false
ENCRYPTION_KEY_PROTECTION=true

# Fenêtres de Maintenance
MAINTENANCE_WINDOW_ENABLED=true
MAINTENANCE_START_TIME="02:00"
MAINTENANCE_END_TIME="06:00"
MAINTENANCE_DAYS="MTWRF"
WEEKEND_MAINTENANCE_ENABLED=true
HOLIDAY_MAINTENANCE_DISABLED=true

# Protection des Heures de Bureau
BUSINESS_HOURS_START="09:00"
BUSINESS_HOURS_END="18:00"
PREVENT_SHUTDOWN_BUSINESS_HOURS=true
EMERGENCY_SHUTDOWN_OVERRIDE=true
CRITICAL_SYSTEM_PROTECTION=true

# Notification et Communication
USER_NOTIFICATION_ENABLED=true
ADMIN_NOTIFICATION_ENABLED=true
SLACK_WEBHOOK_URL=""
EMAIL_NOTIFICATION_ENABLED=false
NOTIFICATION_LEAD_TIME=600

# Planification Automatique
AUTO_REBOOT_ENABLED=true
AUTO_REBOOT_FREQUENCY="weekly"
AUTO_REBOOT_DAY="sunday"
AUTO_REBOOT_TIME="03:00"
PATCH_REBOOT_REQUIRED=true
EOF

# Charger la configuration
source "$CONFIG_FILE" 2>/dev/null || true

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

# Fonction de journalisation d'audit
audit_log() {
    local action="$1"
    local result="$2"
    local details="$3"
    echo "$(date '+%Y-%m-%d %H:%M:%S') - ACTION:$action RESULT:$result DETAILS:$details USER:$(whoami)" >> "$AUDIT_LOG"
}

# Vérifier si l'arrêt est autorisé
check_shutdown_allowed() {
    local operation="$1"
    local force="${2:-false}"
    
    echo "=== Validation de l'Autorisation d'Arrêt ==="
    
    # Vérifier la protection des heures de bureau
    if [[ "$PREVENT_SHUTDOWN_BUSINESS_HOURS" == "true" && "$force" != "true" ]]; then
        local current_hour
        current_hour=$(date +%H)
        local start_hour
        start_hour=$(echo "$BUSINESS_HOURS_START" | cut -d':' -f1)
        local end_hour
        end_hour=$(echo "$BUSINESS_HOURS_END" | cut -d':' -f1)
        
        if [[ $current_hour -ge $start_hour && $current_hour -lt $end_hour ]]; then
            echo "❌ Arrêt bloqué : Actuellement en heures de bureau ($BUSINESS_HOURS_START - $BUSINESS_HOURS_END)"
            log_action "ARRÊT BLOQUÉ : Protection des heures de bureau active"
            audit_log "SHUTDOWN_BLOCKED" "BUSINESS_HOURS" "Opération : $operation Heure : $(date '+%H:%M')"
            return 1
        fi
    fi
    
    # Vérifier les sessions utilisateur actives
    if [[ "$VALIDATE_USER_SESSIONS" == "true" ]]; then
        local active_users
        active_users=$(who | wc -l)
        
        if [[ $active_users -gt 0 && "$force" != "true" ]]; then
            echo "⚠️  Avertissement : $active_users session(s) utilisateur active(s) détectée(s)"
            log_action "AVERTISSEMENT : Sessions utilisateur actives pendant $operation"
            
            if [[ "$GRACEFUL_SHUTDOWN_ENABLED" != "true" ]]; then
                echo "❌ Arrêt bloqué : Utilisateurs actifs et arrêt en douceur désactivé"
                audit_log "SHUTDOWN_BLOCKED" "ACTIVE_USERS" "Utilisateurs : $active_users Opération : $operation"
                return 1
            fi
        fi
    fi
    
    # Vérifier les processus critiques en cours
    if [[ "$CHECK_RUNNING_PROCESSES" == "true" ]]; then
        local critical_processes=(
            "backupd"
            "softwareupdate"
            "installer"
            "diskutil"
            "fsck"
        )
        
        for process in "${critical_processes[@]}"; do
            if pgrep -f "$process" >/dev/null 2>&1; then
                echo "⚠️  Processus critique en cours : $process"
                
                if [[ "$force" != "true" ]]; then
                    echo "❌ Arrêt bloqué : Le processus critique $process est en cours"
                    log_action "ARRÊT BLOQUÉ : Processus critique $process en cours"
                    audit_log "SHUTDOWN_BLOCKED" "CRITICAL_PROCESS" "Processus : $process Opération : $operation"
                    return 1
                else
                    echo "🚨 Arrêt forcé : Terminera le processus critique $process"
                    log_action "ARRÊT FORCÉ : Termination du processus critique $process"
                fi
            fi
        done
    fi
    
    echo "✅ Autorisation d'arrêt validée"
    audit_log "SHUTDOWN_AUTHORIZED" "APPROVED" "Opération : $operation"
    return 0
}

# Envoyer une notification avant l'arrêt
send_shutdown_notification() {
    local operation="$1"
    local delay_minutes="$2"
    local message="$3"
    
    echo "=== Envoi des Notifications d'Arrêt ==="
    
    local notification_title="Notification $operation Système MacFleet"
    local notification_message="${message:-$operation système programmé dans $delay_minutes minutes}"
    
    # Notification utilisateur
    if [[ "$USER_NOTIFICATION_ENABLED" == "true" ]]; then
        # Afficher la notification à tous les utilisateurs connectés
        local logged_users
        logged_users=$(who | awk '{print $1}' | sort -u)
        
        for user in $logged_users; do
            if [[ -n "$user" ]]; then
                sudo -u "$user" osascript -e "display notification \"$notification_message\" with title \"$notification_title\"" 2>/dev/null || true
                echo "📱 Notification envoyée à l'utilisateur : $user"
            fi
        done
        
        # Notification terminal
        wall "$notification_title : $notification_message" 2>/dev/null || true
    fi
    
    log_action "Notifications d'arrêt envoyées pour $operation (délai : $delay_minutes minutes)"
}

# Arrêt en douceur avec gestion des sessions utilisateur
graceful_shutdown() {
    local operation="$1"
    local delay_minutes="$2"
    local message="$3"
    
    echo "=== Initiation de l'$operation en Douceur ==="
    
    # Envoyer la notification initiale
    send_shutdown_notification "$operation" "$delay_minutes" "$message"
    
    # Sauvegarder le travail utilisateur si activé
    if [[ "$SAVE_WORK_BEFORE_SHUTDOWN" == "true" ]]; then
        echo "💾 Tentative de sauvegarde du travail utilisateur..."
        
        # Essayer de sauvegarder le travail dans les applications courantes
        local save_commands=(
            "osascript -e 'tell application \"System Events\" to keystroke \"s\" using command down'"
            "pkill -USR1 TextEdit"  # Signal TextEdit pour sauvegarder
        )
        
        for cmd in "${save_commands[@]}"; do
            eval "$cmd" 2>/dev/null || true
        done
        
        log_action "Tentative de sauvegarde du travail utilisateur avant $operation"
    fi
    
    # Protection des clés FileVault
    if [[ "$ENCRYPTION_KEY_PROTECTION" == "true" ]]; then
        echo "🔐 Assurance de la sécurité des clés FileVault..."
        sudo pmset -a destroyfvkeyonstandby 1 2>/dev/null || true
        log_action "Protection des clés FileVault activée avant $operation"
    fi
    
    # Attendre la période de délai avec compte à rebours
    if [[ $delay_minutes -gt 0 ]]; then
        echo "⏱️  Attente de $delay_minutes minutes avant $operation..."
        
        local remaining_seconds=$((delay_minutes * 60))
        local notification_intervals=(300 120 60 30 10)  # 5min, 2min, 1min, 30s, 10s
        
        while [[ $remaining_seconds -gt 0 ]]; do
            # Envoyer des rappels de notification à des intervalles spécifiques
            for interval in "${notification_intervals[@]}"; do
                if [[ $remaining_seconds -eq $interval ]]; then
                    local remaining_minutes=$((remaining_seconds / 60))
                    if [[ $remaining_minutes -gt 0 ]]; then
                        send_shutdown_notification "$operation" "$remaining_minutes" "Avertissement final : $operation système dans $remaining_minutes minute(s)"
                    else
                        send_shutdown_notification "$operation" "0" "Avertissement final : $operation système dans $remaining_seconds secondes"
                    fi
                    break
                fi
            done
            
            sleep 1
            remaining_seconds=$((remaining_seconds - 1))
        done
    fi
    
    echo "✅ Préparation de l'$operation en douceur terminée"
    log_action "Préparation de l'$operation en douceur terminée"
}

# Arrêt entreprise avec validation complète
enterprise_shutdown() {
    local delay="${1:-now}"
    local message="$2"
    local force="${3:-false}"
    
    echo "=== Arrêt Entreprise Initié ==="
    
    # Valider l'autorisation d'arrêt
    if ! check_shutdown_allowed "arrêt" "$force"; then
        return 1
    fi
    
    # Analyser le délai
    local delay_minutes=0
    if [[ "$delay" != "now" ]]; then
        if [[ "$delay" =~ ^\+([0-9]+)$ ]]; then
            delay_minutes="${BASH_REMATCH[1]}"
        else
            echo "❌ Format de délai invalide. Utilisez 'now' ou '+minutes'"
            return 1
        fi
    fi
    
    # Arrêt en douceur si activé
    if [[ "$GRACEFUL_SHUTDOWN_ENABLED" == "true" ]]; then
        graceful_shutdown "arrêt" "$delay_minutes" "$message"
    fi
    
    # Journaliser l'action d'arrêt
    log_action "ARRÊT ENTREPRISE : Exécution de l'arrêt avec délai : $delay"
    audit_log "SHUTDOWN" "INITIATED" "Délai : $delay Message : ${message:-Aucun} Force : $force"
    
    # Exécuter l'arrêt
    if [[ "$delay" == "now" ]]; then
        echo "🔌 Exécution de l'arrêt immédiat..."
        sudo shutdown -h now "$message"
    else
        echo "🔌 Programmation de l'arrêt dans $delay_minutes minutes..."
        sudo shutdown -h +"$delay_minutes" "$message"
    fi
    
    audit_log "SHUTDOWN" "EXECUTED" "Commande terminée avec succès"
    return 0
}

# Redémarrage entreprise avec validation complète
enterprise_reboot() {
    local delay="${1:-now}"
    local message="$2"
    local force="${3:-false}"
    
    echo "=== Redémarrage Entreprise Initié ==="
    
    # Valider l'autorisation de redémarrage
    if ! check_shutdown_allowed "redémarrage" "$force"; then
        return 1
    fi
    
    # Analyser le délai
    local delay_minutes=0
    if [[ "$delay" != "now" ]]; then
        if [[ "$delay" =~ ^\+([0-9]+)$ ]]; then
            delay_minutes="${BASH_REMATCH[1]}"
        else
            echo "❌ Format de délai invalide. Utilisez 'now' ou '+minutes'"
            return 1
        fi
    fi
    
    # Redémarrage en douceur si activé
    if [[ "$GRACEFUL_SHUTDOWN_ENABLED" == "true" ]]; then
        graceful_shutdown "redémarrage" "$delay_minutes" "$message"
    fi
    
    # Journaliser l'action de redémarrage
    log_action "REDÉMARRAGE ENTREPRISE : Exécution du redémarrage avec délai : $delay"
    audit_log "REBOOT" "INITIATED" "Délai : $delay Message : ${message:-Aucun} Force : $force"
    
    # Exécuter le redémarrage
    if [[ "$delay" == "now" ]]; then
        echo "🔄 Exécution du redémarrage immédiat..."
        sudo shutdown -r now "$message"
    else
        echo "🔄 Programmation du redémarrage dans $delay_minutes minutes..."
        sudo shutdown -r +"$delay_minutes" "$message"
    fi
    
    audit_log "REBOOT" "EXECUTED" "Commande terminée avec succès"
    return 0
}

# Programmer un redémarrage de maintenance
schedule_maintenance_reboot() {
    local schedule_time="$1"
    local reason="$2"
    
    echo "=== Programmation d'un Redémarrage de Maintenance ==="
    
    if [[ -z "$schedule_time" ]]; then
        echo "❌ Heure de programmation requise (format : AAMMJJHHMM)"
        return 1
    fi
    
    # Valider le format de l'heure de programmation
    if [[ ! "$schedule_time" =~ ^[0-9]{10}$ ]]; then
        echo "❌ Format d'heure de programmation invalide. Utilisez AAMMJJHHMM"
        return 1
    fi
    
    # Vérifier si l'heure programmée est dans la fenêtre de maintenance
    if [[ "$MAINTENANCE_WINDOW_ENABLED" == "true" ]]; then
        local schedule_hour
        schedule_hour=$(echo "$schedule_time" | cut -c 7-8)
        local maintenance_start_hour
        maintenance_start_hour=$(echo "$MAINTENANCE_START_TIME" | cut -d':' -f1)
        local maintenance_end_hour
        maintenance_end_hour=$(echo "$MAINTENANCE_END_TIME" | cut -d':' -f1)
        
        if [[ $schedule_hour -lt $maintenance_start_hour || $schedule_hour -ge $maintenance_end_hour ]]; then
            echo "⚠️  Avertissement : Heure programmée en dehors de la fenêtre de maintenance ($MAINTENANCE_START_TIME - $MAINTENANCE_END_TIME)"
        fi
    fi
    
    # Programmer le redémarrage
    local message="Redémarrage de maintenance programmé : ${reason:-Maintenance système}"
    
    log_action "REDÉMARRAGE DE MAINTENANCE PROGRAMMÉ : Heure : $schedule_time Raison : ${reason:-Maintenance système}"
    audit_log "MAINTENANCE_SCHEDULED" "CREATED" "Heure : $schedule_time Raison : ${reason:-Maintenance système}"
    
    echo "🗓️  Programmation du redémarrage de maintenance..."
    sudo shutdown -r "$schedule_time" "$message"
    
    echo "✅ Redémarrage de maintenance programmé pour $(date -j -f "%Y%m%d%H%M" "20$schedule_time" "+%Y-%m-%d %H:%M")"
    
    return 0
}

# Annuler les opérations programmées
cancel_scheduled_operation() {
    echo "=== Annulation des Opérations Programmées ==="
    
    # Obtenir la liste des opérations programmées
    local scheduled_ops
    scheduled_ops=$(ps aux | grep "shutdown" | grep -v grep | wc -l)
    
    if [[ $scheduled_ops -eq 0 ]]; then
        echo "ℹ️  Aucune opération d'arrêt/redémarrage programmée trouvée"
        return 0
    fi
    
    # Annuler les opérations d'arrêt
    if sudo pkill -f "shutdown"; then
        echo "✅ Opérations d'arrêt/redémarrage programmées annulées"
        log_action "Opérations d'arrêt/redémarrage programmées annulées"
        audit_log "SCHEDULE_CANCELLED" "SUCCESS" "Opérations annulées par $(whoami)"
        
        # Notifier les utilisateurs de l'annulation
        send_shutdown_notification "annulation" "0" "L'opération système programmée a été annulée"
    else
        echo "❌ Échec de l'annulation des opérations programmées"
        log_action "ÉCHEC : Impossible d'annuler les opérations programmées"
        audit_log "SCHEDULE_CANCELLED" "FAILED" "Tentative d'annulation par $(whoami)"
        return 1
    fi
    
    return 0
}

# Arrêt d'urgence (contourne toutes les vérifications)
emergency_shutdown() {
    local reason="$1"
    
    echo "🚨 ARRÊT D'URGENCE INITIÉ 🚨"
    
    if [[ -z "$reason" ]]; then
        echo "❌ Raison d'urgence requise"
        return 1
    fi
    
    log_action "ARRÊT D'URGENCE : Raison : $reason"
    audit_log "EMERGENCY_SHUTDOWN" "INITIATED" "Raison : $reason Utilisateur : $(whoami)"
    
    # Envoyer une notification d'urgence
    send_shutdown_notification "ARRÊT D'URGENCE" "0" "URGENCE : Arrêt système initié - $reason"
    
    # Exécuter l'arrêt immédiat forcé
    echo "🔌 Exécution de l'arrêt d'urgence (forcé)..."
    sudo shutdown -h now "ARRÊT D'URGENCE : $reason"
    
    audit_log "EMERGENCY_SHUTDOWN" "EXECUTED" "Arrêt immédiat terminé"
}

# Vérifier l'état du système pour la préparation à l'arrêt
check_system_status() {
    echo "=== Vérification de l'État du Système ==="
    
    local status_issues=()
    local status_warnings=()
    
    # Vérifier le temps de fonctionnement
    local uptime_seconds
    uptime_seconds=$(uptime | awk '{print $3}' | cut -d',' -f1)
    echo "Temps de Fonctionnement Système : $uptime_seconds"
    
    # Vérifier la charge moyenne
    local load_average
    load_average=$(uptime | awk -F'load average:' '{print $2}' | awk '{print $1}' | tr -d ',')
    if (( $(echo "$load_average > 5.0" | bc -l) )); then
        status_warnings+=("Charge système élevée : $load_average")
    fi
    
    # Vérifier l'espace disque
    local disk_usage
    disk_usage=$(df / | tail -1 | awk '{print $5}' | sed 's/%//')
    if [[ $disk_usage -gt 90 ]]; then
        status_warnings+=("Espace disque faible : ${disk_usage}% utilisé")
    fi
    
    # Vérifier les mises à jour en attente
    if softwareupdate -l 2>/dev/null | grep -q "Software Update found"; then
        status_warnings+=("Mises à jour logicielles en attente disponibles")
    fi
    
    # Rapporter l'état
    if [[ ${#status_issues[@]} -eq 0 && ${#status_warnings[@]} -eq 0 ]]; then
        echo "✅ État du système : Prêt pour arrêt/redémarrage"
        return 0
    else
        if [[ ${#status_issues[@]} -gt 0 ]]; then
            echo "❌ Problèmes d'état du système :"
            printf '  - %s\n' "${status_issues[@]}"
        fi
        
        if [[ ${#status_warnings[@]} -gt 0 ]]; then
            echo "⚠️  Avertissements d'état du système :"
            printf '  - %s\n' "${status_warnings[@]}"
        fi
        
        return 1
    fi
}

# Fonction principale avec gestion d'arguments
main() {
    log_action "=== Outil de Gestion d'Arrêt MacFleet Démarré ==="
    
    case "${1:-status}" in
        "shutdown")
            enterprise_shutdown "$2" "$3" "$4"
            ;;
        "reboot")
            enterprise_reboot "$2" "$3" "$4"
            ;;
        "schedule")
            schedule_maintenance_reboot "$2" "$3"
            ;;
        "cancel")
            cancel_scheduled_operation
            ;;
        "emergency")
            emergency_shutdown "$2"
            ;;
        "status")
            check_system_status
            ;;
        *)
            echo "Outil de Gestion d'Arrêt et de Redémarrage Entreprise MacFleet"
            echo "Usage : $0 [commande] [options]"
            echo ""
            echo "Commandes :"
            echo "  shutdown [délai] [message] [force]  - Arrêter le système avec délai optionnel"
            echo "  reboot [délai] [message] [force]    - Redémarrer le système avec délai optionnel"
            echo "  schedule [heure] [raison]           - Programmer un redémarrage de maintenance (AAMMJJHHMM)"
            echo "  cancel                              - Annuler les opérations programmées"
            echo "  emergency [raison]                  - Arrêt d'urgence (contourne les vérifications)"
            echo "  status                              - Vérifier l'état du système pour préparation à l'arrêt"
            echo ""
            echo "Formats de Délai :"
            echo "  now                                 - Opération immédiate"
            echo "  +minutes                            - Délai en minutes (ex : +5)"
            echo ""
            echo "Exemples :"
            echo "  $0 shutdown now                     - Arrêt immédiat"
            echo "  $0 reboot +10 \"Maintenance système\" - Redémarrer dans 10 minutes avec message"
            echo "  $0 schedule 2501020300 \"Patch Tuesday\" - Programmer redémarrage 2 jan, 3h00"
            echo "  $0 emergency \"Incident de sécurité\" - Arrêt d'urgence"
            ;;
    esac
    
    log_action "=== Opération de gestion d'arrêt terminée ==="
}

# Exécuter la fonction principale
main "$@"

Notes de Configuration Importantes

Options de Commande d'Arrêt macOS

  • -h - Arrêter le système (shutdown)
  • -r - Redémarrer le système (reboot)
  • -s - Mettre le système en veille (écran éteint + verrouillage)
  • Formats d'heure - now, +minutes, AAMMJJHHMM
  • Messages d'avertissement - Texte supplémentaire affiché aux utilisateurs

Points d'Intégration Entreprise

  • Systèmes de Gestion des Changements - Intégration avec les plateformes ITSM
  • Systèmes de Surveillance - Suivi en temps réel des événements d'arrêt
  • Solutions de Sauvegarde - Automatisation de sauvegarde pré-arrêt
  • Cadres de Sécurité - Conformité avec les politiques d'arrêt

Bonnes Pratiques pour la Gestion d'Arrêt Entreprise

  1. Continuité Opérationnelle

    • Implémenter des procédures d'arrêt en douceur avec notifications utilisateur
    • Valider la préparation du système avant les opérations d'arrêt
    • Maintenir des capacités de contournement d'urgence pour les situations critiques
    • Programmer les opérations de maintenance pendant les fenêtres désignées
  2. Sécurité et Conformité

    • Activer la journalisation d'audit complète pour toutes les opérations d'alimentation
    • Implémenter la protection des clés FileVault pendant l'arrêt
    • Valider les sessions utilisateur et les processus en cours avant l'arrêt
    • Maintenir la conformité avec les exigences réglementaires d'arrêt
  3. Gestion des Changements

    • Exiger l'approbation pour les opérations d'arrêt non programmées
    • Documenter tous les arrêts liés à la maintenance
    • Intégrer avec les plateformes ITSM pour le suivi des changements
    • Maintenir les informations de contact d'urgence pour les situations critiques
  4. Expérience Utilisateur

    • Fournir un avertissement adéquat avant les opérations d'arrêt
    • Tenter de sauvegarder le travail utilisateur avant l'arrêt système
    • Envoyer des notifications via plusieurs canaux (GUI, email, Slack)
    • Permettre l'annulation des opérations programmées le cas échéant

Dépannage des Problèmes Courants

  • Erreurs de permissions - S'assurer des privilèges administrateur pour les commandes d'arrêt
  • Conflits d'opérations programmées - Vérifier les arrêts programmés existants
  • Échecs de notification réseau - Vérifier les URLs webhook et la connectivité réseau
  • Échecs de sauvegarde - Vérifier l'espace disque et la disponibilité de destination de sauvegarde
  • Violations de fenêtre de maintenance - Examiner les heures de bureau et les horaires de maintenance

N'oubliez pas de tester minutieusement les procédures d'arrêt dans un environnement contrôlé avant l'implémentation sur l'ensemble de votre MacFleet pour assurer la continuité des activités et la protection des données.

Gestion d'Entreprise des Utilisateurs de Partage sur macOS

Gérez les comptes utilisateurs de partage uniquement sur vos appareils MacFleet en utilisant des commandes dscl avancées. Ce tutoriel couvre la création d'utilisateurs, les politiques de sécurité, le déploiement en masse et la gestion du cycle de vie des utilisateurs en entreprise.

Comprendre la Gestion d'Utilisateurs macOS

macOS utilise l'utilitaire de ligne de commande Directory Service (dscl) pour la gestion des utilisateurs :

  • dscl - Utilitaire de ligne de commande Directory Service
  • Répertoire Local - /var/db/dslocal/nodes/Default
  • Enregistrements Utilisateur - Stockés dans le chemin /Users/
  • Utilisateurs de Partage Uniquement - Comptes d'accès limité pour le partage de fichiers

Création d'Utilisateur de Partage de Base

Utilisateur de Partage Simple

#!/bin/bash

# Créer un compte utilisateur de partage uniquement de base
USERNAME="UtilisateurPartage"
DISPLAY_NAME="Compte de Partage"
PASSWORD="MotDePasseSecurise123"
USER_ID="550"

# Créer l'utilisateur
sudo dscl . create /Users/"$USERNAME"

# Définir le nom d'affichage
sudo dscl . create /Users/"$USERNAME" RealName "$DISPLAY_NAME"

# Définir le mot de passe
sudo dscl . passwd /Users/"$USERNAME" "$PASSWORD"

# Définir l'ID unique
sudo dscl . create /Users/"$USERNAME" UniqueID "$USER_ID"

# Définir l'ID de groupe (groupe staff)
sudo dscl . create /Users/"$USERNAME" PrimaryGroupID 20

# Refuser l'accès shell
sudo dscl . create /Users/"$USERNAME" UserShell /usr/bin/false

# Aucun répertoire home
sudo dscl . create /Users/"$USERNAME" NFSHomeDirectory /dev/null

echo "Utilisateur de partage '$USERNAME' créé avec succès"

Utilisateur de Partage Amélioré avec Options

#!/bin/bash

# Création d'utilisateur de partage améliorée avec options supplémentaires
create_sharing_user() {
    local username="$1"
    local display_name="$2"
    local password="$3"
    local hint="$4"
    local picture_path="$5"
    local user_id="$6"
    
    echo "Création de l'utilisateur de partage : $username"
    
    # Créer l'utilisateur
    sudo dscl . create /Users/"$username"
    
    # Définir le nom d'affichage
    sudo dscl . create /Users/"$username" RealName "$display_name"
    
    # Définir le mot de passe
    sudo dscl . passwd /Users/"$username" "$password"
    
    # Définir l'indice de mot de passe (optionnel)
    if [[ -n "$hint" ]]; then
        sudo dscl . create /Users/"$username" hint "$hint"
    fi
    
    # Définir l'image de profil (optionnel)
    if [[ -n "$picture_path" && -f "$picture_path" ]]; then
        sudo dscl . create /Users/"$username" picture "$picture_path"
    fi
    
    # Définir l'ID unique
    sudo dscl . create /Users/"$username" UniqueID "$user_id"
    
    # Définir l'ID de groupe
    sudo dscl . create /Users/"$username" PrimaryGroupID 20
    
    # Refuser l'accès shell
    sudo dscl . create /Users/"$username" UserShell /usr/bin/false
    
    # Aucun répertoire home
    sudo dscl . create /Users/"$username" NFSHomeDirectory /dev/null
    
    echo "✅ Utilisateur de partage '$username' créé avec succès"
    return 0
}

# Exemples d'utilisation
create_sharing_user "PartagerFichiers" "Compte de Partage de Fichiers" "FichierPass123" "Accès fichiers uniquement" "" "551"
create_sharing_user "AccesInvite" "Utilisateur Invité" "InvitePass456" "Accès temporaire" "/System/Library/User Pictures/Animals/Butterfly.tif" "552"

Catégories d'Utilisateurs d'Entreprise

Classifications de Types d'Utilisateurs

#!/bin/bash

# Catégories d'utilisateurs d'entreprise avec configurations spécifiques
declare -A USER_CATEGORIES=(
    ["partage_standard"]="Accès de partage de fichiers standard"
    ["partage_securise"]="Partage haute sécurité avec restrictions"
    ["invite_temporaire"]="Accès invité temporaire avec expiration"
    ["compte_service"]="Comptes de service pour applications"
    ["partage_departemental"]="Comptes partagés spécifiques au département"
    ["partenaire_externe"]="Accès limité partenaire externe"
    ["kiosque_public"]="Comptes d'accès kiosque public"
)

# Politiques de sécurité pour chaque catégorie
declare -A SECURITY_POLICIES=(
    ["partage_standard"]="politique_mot_de_passe:standard,niveau_audit:basique,delai_session:8h"
    ["partage_securise"]="politique_mot_de_passe:fort,niveau_audit:complet,delai_session:2h,mfa_requis:true"
    ["invite_temporaire"]="politique_mot_de_passe:basique,niveau_audit:complet,delai_session:1h,expiration_auto:24h"
    ["compte_service"]="politique_mot_de_passe:service,niveau_audit:systeme,non_interactif:true"
    ["partage_departemental"]="politique_mot_de_passe:departement,niveau_audit:departement,restrictions_groupe:true"
    ["partenaire_externe"]="politique_mot_de_passe:externe,niveau_audit:complet,restrictions_reseau:true"
    ["kiosque_public"]="politique_mot_de_passe:public,niveau_audit:minimal,delai_session:30m,reinitialisation_deconnexion:true"
)

# Définitions de contrôle d'accès
declare -A ACCESS_CONTROLS=(
    ["partage_standard"]="partage_fichiers:lecture_ecriture,acces_impression:oui,acces_reseau:local"
    ["partage_securise"]="partage_fichiers:lecture_seule,acces_impression:restreint,acces_reseau:vpn_seulement"
    ["invite_temporaire"]="partage_fichiers:dossier_invite,acces_impression:non,acces_reseau:wifi_invite"
    ["compte_service"]="partage_fichiers:repertoires_service,acces_impression:non,acces_reseau:ports_service"
    ["partage_departemental"]="partage_fichiers:repertoires_departement,acces_impression:departement,acces_reseau:vlan_departement"
    ["partenaire_externe"]="partage_fichiers:repertoires_partenaire,acces_impression:non,acces_reseau:dmz_partenaire"
    ["kiosque_public"]="partage_fichiers:documents_publics,acces_impression:public,acces_reseau:wifi_public"
)

print_user_categories() {
    echo "=== Catégories d'Utilisateurs Disponibles ==="
    for category in "${!USER_CATEGORIES[@]}"; do
        echo "Catégorie : $category"
        echo "  Description : ${USER_CATEGORIES[$category]}"
        echo "  Sécurité : ${SECURITY_POLICIES[$category]}"
        echo "  Accès : ${ACCESS_CONTROLS[$category]}"
        echo ""
    done
}

# Afficher les catégories disponibles
print_user_categories

Politiques de Gestion d'Utilisateurs

Moteur de Politique de Mot de Passe

#!/bin/bash

# Définitions de politiques de mot de passe pour différents types d'utilisateurs
generate_password_policy() {
    local policy_type="$1"
    
    case "$policy_type" in
        "standard")
            echo "longueur_min:8,complexite:moyenne,expiration:90j,historique:5"
            ;;
        "fort")
            echo "longueur_min:12,complexite:haute,expiration:60j,historique:10,caracteres_speciaux:requis"
            ;;
        "basique")
            echo "longueur_min:6,complexite:faible,expiration:jamais,historique:3"
            ;;
        "service")
            echo "longueur_min:16,complexite:haute,expiration:180j,historique:20,genere_machine:true"
            ;;
        "departement")
            echo "longueur_min:10,complexite:moyenne,expiration:120j,historique:8,prefixe_departement:requis"
            ;;
        "externe")
            echo "longueur_min:14,complexite:haute,expiration:30j,historique:15,validation_externe:requise"
            ;;
        "public")
            echo "longueur_min:4,complexite:aucune,expiration:quotidienne,historique:1,reinitialisation_auto:true"
            ;;
        *)
            echo "longueur_min:8,complexite:moyenne,expiration:90j,historique:5"
            ;;
    esac
}

# Générer un mot de passe sécurisé basé sur la politique
generate_secure_password() {
    local policy="$1"
    local length
    local complexity
    
    # Analyser la politique
    length=$(echo "$policy" | grep -o 'longueur_min:[0-9]*' | cut -d: -f2)
    complexity=$(echo "$policy" | grep -o 'complexite:[a-z]*' | cut -d: -f2)
    
    case "$complexity" in
        "haute")
            # Haute complexité : majuscules, minuscules, chiffres, caractères spéciaux
            openssl rand -base64 $((length * 2)) | tr -d "=+/" | cut -c1-"$length" | sed 's/./&@1A/4'
            ;;
        "moyenne")
            # Complexité moyenne : majuscules, minuscules, chiffres
            openssl rand -base64 "$length" | tr -d "=+/" | cut -c1-"$length"
            ;;
        "faible")
            # Faible complexité : alphanumérique
            openssl rand -hex "$((length/2))" | cut -c1-"$length"
            ;;
        *)
            # Complexité moyenne par défaut
            openssl rand -base64 "$length" | tr -d "=+/" | cut -c1-"$length"
            ;;
    esac
}

# Valider le mot de passe contre la politique
validate_password() {
    local password="$1"
    local policy="$2"
    local min_length complexity
    
    min_length=$(echo "$policy" | grep -o 'longueur_min:[0-9]*' | cut -d: -f2)
    complexity=$(echo "$policy" | grep -o 'complexite:[a-z]*' | cut -d: -f2)
    
    # Vérifier la longueur
    if [[ ${#password} -lt $min_length ]]; then
        echo "❌ Mot de passe trop court (minimum $min_length caractères)"
        return 1
    fi
    
    # Vérifier la complexité
    case "$complexity" in
        "haute")
            if ! [[ "$password" =~ [A-Z] && "$password" =~ [a-z] && "$password" =~ [0-9] && "$password" =~ [^A-Za-z0-9] ]]; then
                echo "❌ Le mot de passe doit contenir majuscules, minuscules, chiffres et caractères spéciaux"
                return 1
            fi
            ;;
        "moyenne")
            if ! [[ "$password" =~ [A-Z] && "$password" =~ [a-z] && "$password" =~ [0-9] ]]; then
                echo "❌ Le mot de passe doit contenir majuscules, minuscules et chiffres"
                return 1
            fi
            ;;
    esac
    
    echo "✅ Le mot de passe respecte les exigences de la politique"
    return 0
}

Profils de Déploiement d'Entreprise

Modèles de Configuration de Déploiement

#!/bin/bash

# Profils de déploiement d'entreprise pour différents besoins organisationnels
declare -A DEPLOYMENT_PROFILES=(
    ["entreprise_standard"]="Déploiement d'entreprise standard avec sécurité de base"
    ["haute_securite_finance"]="Déploiement haute sécurité pour départements financiers"
    ["acces_invite_accueil"]="Déploiement d'accès invité pour zones d'accueil/publiques"
    ["collaboration_partenaire"]="Déploiement de collaboration partenaire externe"
    ["kiosque_public_bibliotheque"]="Déploiement kiosque public pour bibliothèques/espaces publics"
    ["recherche_developpement"]="Déploiement équipe recherche et développement"
    ["executif_securise"]="Déploiement sécurisé niveau exécutif"
)

# Configurations spécifiques aux profils
get_deployment_config() {
    local profile="$1"
    
    case "$profile" in
        "entreprise_standard")
            cat << EOF
{
    "categorie_utilisateur": "partage_standard",
    "politique_mot_de_passe": "standard",
    "niveau_acces": "fichiers_departement",
    "delai_session": "8h",
    "niveau_audit": "basique",
    "appartenance_groupe": ["staff", "partage_fichiers"],
    "restrictions": {
        "acces_shell": false,
        "repertoire_home": false,
        "privileges_admin": false
    },
    "surveillance": {
        "suivi_connexion": true,
        "journal_acces_fichiers": true,
        "tentatives_echec": 5
    }
}
EOF
            ;;
        "haute_securite_finance")
            cat << EOF
{
    "categorie_utilisateur": "partage_securise",
    "politique_mot_de_passe": "fort",
    "niveau_acces": "finance_restreint",
    "delai_session": "2h",
    "niveau_audit": "complet",
    "appartenance_groupe": ["finance", "partage_securise"],
    "restrictions": {
        "acces_shell": false,
        "repertoire_home": false,
        "privileges_admin": false,
        "acces_reseau": "vlan_finance_seulement",
        "restrictions_horaires": "heures_bureau"
    },
    "securite": {
        "mfa_requis": true,
        "chiffrement": "aes256",
        "rotation_cles": "mensuelle"
    },
    "surveillance": {
        "alertes_temps_reel": true,
        "suivi_connexion": true,
        "journal_acces_fichiers": true,
        "tentatives_echec": 3,
        "rapport_conformite": "sox_hipaa"
    }
}
EOF
            ;;
        "acces_invite_accueil")
            cat << EOF
{
    "categorie_utilisateur": "invite_temporaire",
    "politique_mot_de_passe": "basique",
    "niveau_acces": "ressources_invite",
    "delai_session": "1h",
    "niveau_audit": "complet",
    "appartenance_groupe": ["invite", "acces_public"],
    "restrictions": {
        "acces_shell": false,
        "repertoire_home": false,
        "privileges_admin": false,
        "acces_internet": "wifi_invite_seulement",
        "telechargement_fichiers": false
    },
    "automatisation": {
        "expiration_auto": "24h",
        "nettoyage_auto": true,
        "reinitialisation_deconnexion": true
    },
    "surveillance": {
        "enregistrement_session": true,
        "suivi_connexion": true,
        "journal_activite": true,
        "tentatives_echec": 3
    }
}
EOF
            ;;
        *)
            echo "Profil de déploiement inconnu : $profile"
            return 1
            ;;
    esac
}

# Appliquer un profil de déploiement
apply_deployment_profile() {
    local profile="$1"
    local config_file="/tmp/deployment_config.json"
    
    echo "Application du profil de déploiement : $profile"
    
    # Obtenir la configuration
    get_deployment_config "$profile" > "$config_file"
    
    if [[ ! -f "$config_file" ]]; then
        echo "❌ Échec de génération de configuration pour le profil : $profile"
        return 1
    fi
    
    echo "✅ Configuration de déploiement prête"
    echo "Configuration sauvegardée dans : $config_file"
    
    # Analyser et afficher les paramètres clés
    echo "=== Résumé du Profil ==="
    echo "Catégorie Utilisateur : $(jq -r '.categorie_utilisateur' "$config_file")"
    echo "Politique Mot de Passe : $(jq -r '.politique_mot_de_passe' "$config_file")"
    echo "Niveau d'Accès : $(jq -r '.niveau_acces' "$config_file")"
    echo "Délai Session : $(jq -r '.delai_session' "$config_file")"
    echo "Niveau Audit : $(jq -r '.niveau_audit' "$config_file")"
    
    return 0
}

Système de Gestion d'Utilisateurs d'Entreprise

#!/bin/bash

# Système de Gestion d'Utilisateurs d'Entreprise MacFleet
# Création et gestion complètes d'utilisateurs de partage

# Configuration
CONFIG_DIR="/etc/macfleet/users"
LOG_FILE="/var/log/macfleet_gestion_utilisateurs.log"
BACKUP_DIR="/var/backups/macfleet/users"
REPORTS_DIR="/var/reports/macfleet/users"
AUDIT_LOG="/var/log/macfleet_audit_utilisateurs.log"

# Créer les répertoires requis
create_directories() {
    local directories=("$CONFIG_DIR" "$BACKUP_DIR" "$REPORTS_DIR")
    
    for dir in "${directories[@]}"; do
        if [[ ! -d "$dir" ]]; then
            sudo mkdir -p "$dir"
            sudo chmod 755 "$dir"
        fi
    done
}

# Fonctions de journalisation
log_action() {
    echo "$(date '+%Y-%m-%d %H:%M:%S') [INFO] $1" | tee -a "$LOG_FILE"
}

log_error() {
    echo "$(date '+%Y-%m-%d %H:%M:%S') [ERREUR] $1" | tee -a "$LOG_FILE" >&2
}

audit_log() {
    echo "$(date '+%Y-%m-%d %H:%M:%S') [AUDIT] $1" | tee -a "$AUDIT_LOG"
}

# Gestion d'ID utilisateur
get_next_user_id() {
    local start_id="$1"
    local current_id="$start_id"
    
    while dscl . list /Users UniqueID | awk '{print $2}' | grep -q "^${current_id}$"; do
        ((current_id++))
    done
    
    echo "$current_id"
}

# Fonction de création d'utilisateur complète
create_enterprise_user() {
    local username="$1"
    local display_name="$2"
    local user_category="$3"
    local deployment_profile="$4"
    local department="$5"
    local expiry_date="$6"
    
    log_action "Début création utilisateur : $username (Catégorie : $user_category, Profil : $deployment_profile)"
    
    # Valider les entrées
    if [[ -z "$username" || -z "$display_name" || -z "$user_category" ]]; then
        log_error "Paramètres requis manquants pour la création d'utilisateur"
        return 1
    fi
    
    # Vérifier si l'utilisateur existe déjà
    if dscl . read /Users/"$username" &>/dev/null; then
        log_error "L'utilisateur $username existe déjà"
        return 1
    fi
    
    # Obtenir la configuration de déploiement
    local config_file="/tmp/user_config_${username}.json"
    get_deployment_config "$deployment_profile" > "$config_file"
    
    # Analyser la configuration
    local password_policy
    password_policy=$(jq -r '.politique_mot_de_passe' "$config_file")
    
    # Obtenir le prochain ID utilisateur disponible
    local user_id
    user_id=$(get_next_user_id 550)
    
    # Générer un mot de passe sécurisé
    local policy_details
    policy_details=$(generate_password_policy "$password_policy")
    local password
    password=$(generate_secure_password "$policy_details")
    
    # Créer les métadonnées utilisateur
    local metadata_file="$CONFIG_DIR/${username}_metadata.json"
    cat > "$metadata_file" << EOF
{
    "nom_utilisateur": "$username",
    "nom_affichage": "$display_name",
    "categorie_utilisateur": "$user_category",
    "profil_deploiement": "$deployment_profile",
    "departement": "$department",
    "id_utilisateur": $user_id,
    "date_creation": "$(date -Iseconds)",
    "cree_par": "$(whoami)",
    "date_expiration": "$expiry_date",
    "politique_mot_de_passe": "$password_policy",
    "statut": "actif"
}
EOF
    
    # Créer l'utilisateur
    log_action "Création de l'enregistrement utilisateur pour $username"
    sudo dscl . create /Users/"$username" || {
        log_error "Échec de création de l'enregistrement utilisateur pour $username"
        return 1
    }
    
    # Définir les propriétés de base
    sudo dscl . create /Users/"$username" RealName "$display_name"
    sudo dscl . passwd /Users/"$username" "$password"
    sudo dscl . create /Users/"$username" UniqueID "$user_id"
    sudo dscl . create /Users/"$username" PrimaryGroupID 20
    sudo dscl . create /Users/"$username" UserShell /usr/bin/false
    sudo dscl . create /Users/"$username" NFSHomeDirectory /dev/null
    
    # Ajouter des attributs personnalisés
    sudo dscl . create /Users/"$username" Comment "Utilisateur géré MacFleet - $user_category"
    sudo dscl . create /Users/"$username" Keywords "macfleet,$user_category,$deployment_profile,$department"
    
    # Définir la date d'expiration si fournie
    if [[ -n "$expiry_date" ]]; then
        sudo dscl . create /Users/"$username" ExpiryDate "$expiry_date"
    fi
    
    # Appliquer les appartenances de groupe
    local groups
    groups=$(jq -r '.appartenance_groupe[]' "$config_file" 2>/dev/null)
    while IFS= read -r group; do
        if [[ -n "$group" && "$group" != "null" ]]; then
            sudo dseditgroup -o edit -a "$username" -t user "$group" 2>/dev/null || {
                log_action "Le groupe $group n'existe pas, ignoré"
            }
        fi
    done <<< "$groups"
    
    # Stocker le mot de passe sécurisé (chiffré)
    echo "$password" | openssl enc -aes-256-cbc -pbkdf2 -k "macfleet_$(hostname)" -out "$CONFIG_DIR/${username}_password.enc"
    
    # Créer une sauvegarde
    create_user_backup "$username"
    
    # Journalisation d'audit
    audit_log "Utilisateur créé : $username (UID : $user_id, Catégorie : $user_category, Profil : $deployment_profile)"
    
    log_action "✅ Utilisateur $username créé avec succès (UID : $user_id)"
    
    # Retourner le mot de passe pour communication initiale (en production, utiliser une livraison sécurisée)
    echo "INFO_UTILISATEUR_CREE:$username:$password:$user_id"
    
    return 0
}

# Création d'utilisateurs en masse
bulk_create_users() {
    local csv_file="$1"
    local created_count=0
    local failed_count=0
    
    if [[ ! -f "$csv_file" ]]; then
        log_error "Fichier CSV non trouvé : $csv_file"
        return 1
    fi
    
    log_action "Début création en masse d'utilisateurs depuis : $csv_file"
    
    # Traiter le fichier CSV (ignorer l'en-tête)
    tail -n +2 "$csv_file" | while IFS=',' read -r username display_name category profile department expiry; do
        if create_enterprise_user "$username" "$display_name" "$category" "$profile" "$department" "$expiry"; then
            ((created_count++))
        else
            ((failed_count++))
        fi
    done
    
    log_action "Création en masse terminée. Créés : $created_count, Échecs : $failed_count"
    
    # Générer un rapport
    generate_user_report "creation_masse_$(date +%Y%m%d_%H%M%S)"
}

# Fonctions de gestion d'utilisateurs
list_enterprise_users() {
    echo "=== Utilisateurs Gérés MacFleet ==="
    echo "Nom d'utilisateur | Nom d'affichage | Catégorie | Statut | Créé"
    echo "------------------|-----------------|-----------|--------|------"
    
    for metadata_file in "$CONFIG_DIR"/*_metadata.json; do
        if [[ -f "$metadata_file" ]]; then
            local username display_name category status created_date
            username=$(jq -r '.nom_utilisateur' "$metadata_file")
            display_name=$(jq -r '.nom_affichage' "$metadata_file")
            category=$(jq -r '.categorie_utilisateur' "$metadata_file")
            status=$(jq -r '.statut' "$metadata_file")
            created_date=$(jq -r '.date_creation' "$metadata_file" | cut -d'T' -f1)
            
            printf "%-17s | %-15s | %-9s | %-6s | %s\n" "$username" "$display_name" "$category" "$status" "$created_date"
        fi
    done
}

# Suppression d'utilisateur avec nettoyage
remove_enterprise_user() {
    local username="$1"
    local backup_before_removal="$2"
    
    log_action "Début suppression de l'utilisateur : $username"
    
    # Vérifier si l'utilisateur existe
    if ! dscl . read /Users/"$username" &>/dev/null; then
        log_error "L'utilisateur $username n'existe pas"
        return 1
    fi
    
    # Créer une sauvegarde avant suppression
    if [[ "$backup_before_removal" == "true" ]]; then
        create_user_backup "$username"
    fi
    
    # Supprimer l'utilisateur du système
    sudo dscl . delete /Users/"$username" || {
        log_error "Échec de suppression de l'utilisateur $username du système"
        return 1
    }
    
    # Mettre à jour les métadonnées
    local metadata_file="$CONFIG_DIR/${username}_metadata.json"
    if [[ -f "$metadata_file" ]]; then
        jq '.statut = "supprime" | .date_suppression = now | .supprime_par = "'"$(whoami)"'"' "$metadata_file" > "${metadata_file}.tmp" && mv "${metadata_file}.tmp" "$metadata_file"
    fi
    
    # Journalisation d'audit
    audit_log "Utilisateur supprimé : $username par $(whoami)"
    
    log_action "✅ Utilisateur $username supprimé avec succès"
    return 0
}

# Sauvegarde et restauration d'utilisateur
create_user_backup() {
    local username="$1"
    local backup_file="$BACKUP_DIR/${username}_backup_$(date +%Y%m%d_%H%M%S).plist"
    
    log_action "Création de sauvegarde pour l'utilisateur : $username"
    
    # Exporter l'enregistrement utilisateur
    sudo dscl . read /Users/"$username" > "$backup_file"
    
    # Sauvegarder les métadonnées
    local metadata_file="$CONFIG_DIR/${username}_metadata.json"
    if [[ -f "$metadata_file" ]]; then
        cp "$metadata_file" "$BACKUP_DIR/${username}_metadata_$(date +%Y%m%d_%H%M%S).json"
    fi
    
    log_action "✅ Sauvegarde utilisateur créée : $backup_file"
}

# Surveillance de la santé du système
monitor_user_system() {
    echo "=== Vérification de Santé du Système Utilisateur ==="
    
    # Vérifier les utilisateurs expirés
    local expired_users=0
    for metadata_file in "$CONFIG_DIR"/*_metadata.json; do
        if [[ -f "$metadata_file" ]]; then
            local expiry_date username
            expiry_date=$(jq -r '.date_expiration' "$metadata_file")
            username=$(jq -r '.nom_utilisateur' "$metadata_file")
            
            if [[ "$expiry_date" != "null" && "$expiry_date" != "" ]]; then
                if [[ $(date -d "$expiry_date" +%s 2>/dev/null) -lt $(date +%s) ]]; then
                    echo "⚠️  Utilisateur expiré : $username (expiré : $expiry_date)"
                    ((expired_users++))
                fi
            fi
        fi
    done
    
    # Vérifier les enregistrements d'utilisateurs orphelins
    local system_users
    system_users=$(dscl . list /Users | grep -E "^(Partage|Invite|Service|Externe)" || true)
    local orphaned_users=0
    
    while IFS= read -r user; do
        if [[ -n "$user" && ! -f "$CONFIG_DIR/${user}_metadata.json" ]]; then
            echo "⚠️  Utilisateur orphelin (pas de métadonnées) : $user"
            ((orphaned_users++))
        fi
    done <<< "$system_users"
    
    # Résumé
    echo ""
    echo "Résumé de Santé :"
    echo "  Utilisateurs expirés : $expired_users"
    echo "  Utilisateurs orphelins : $orphaned_users"
    
    if [[ $expired_users -eq 0 && $orphaned_users -eq 0 ]]; then
        echo "✅ Le système utilisateur est en bonne santé"
    else
        echo "⚠️  Le système utilisateur nécessite une attention"
    fi
}

# Générer des rapports complets
generate_user_report() {
    local report_name="$1"
    local report_file="$REPORTS_DIR/${report_name}.json"
    
    log_action "Génération du rapport utilisateur : $report_name"
    
    # Collecter les statistiques utilisateur
    local total_users active_users inactive_users
    total_users=$(find "$CONFIG_DIR" -name "*_metadata.json" | wc -l)
    active_users=$(grep -l '"statut": "actif"' "$CONFIG_DIR"/*_metadata.json 2>/dev/null | wc -l)
    inactive_users=$((total_users - active_users))
    
    # Répartition par catégorie
    local categories
    categories=$(jq -r '.categorie_utilisateur' "$CONFIG_DIR"/*_metadata.json 2>/dev/null | sort | uniq -c | awk '{print "{\"categorie\": \"" $2 "\", \"compte\": " $1 "}"}' | jq -s '.')
    
    # Générer le rapport
    cat > "$report_file" << EOF
{
    "nom_rapport": "$report_name",
    "date_generation": "$(date -Iseconds)",
    "genere_par": "$(whoami)",
    "nom_hote": "$(hostname)",
    "statistiques": {
        "total_utilisateurs": $total_users,
        "utilisateurs_actifs": $active_users,
        "utilisateurs_inactifs": $inactive_users
    },
    "repartition_categorie": $categories,
    "info_systeme": {
        "version_macfleet": "2025.07.07",
        "version_os": "$(sw_vers -productVersion)",
        "nom_hote": "$(hostname)"
    }
}
EOF
    
    log_action "✅ Rapport généré : $report_file"
    echo "Rapport sauvegardé dans : $report_file"
}

# Fonctions de déploiement en flotte
deploy_to_fleet() {
    local fleet_config="$1"
    local user_config="$2"
    
    log_action "Début du déploiement en flotte"
    
    if [[ ! -f "$fleet_config" ]]; then
        log_error "Fichier de configuration de flotte non trouvé : $fleet_config"
        return 1
    fi
    
    if [[ ! -f "$user_config" ]]; then
        log_error "Fichier de configuration utilisateur non trouvé : $user_config"
        return 1
    fi
    
    # Lire la configuration de flotte
    local hosts
    hosts=$(jq -r '.hosts[]' "$fleet_config")
    
    # Déployer sur chaque hôte
    while IFS= read -r host; do
        if [[ -n "$host" ]]; then
            log_action "Déploiement sur l'hôte : $host"
            
            # Copier le script de gestion d'utilisateur et la configuration
            scp "$0" "$user_config" "root@${host}:/tmp/" || {
                log_error "Échec de copie des fichiers vers $host"
                continue
            }
            
            # Exécuter le déploiement sur l'hôte distant
            ssh "root@${host}" "chmod +x /tmp/$(basename "$0") && /tmp/$(basename "$0") deploy_from_config /tmp/$(basename "$user_config")" || {
                log_error "Échec d'exécution du déploiement sur $host"
                continue
            }
            
            log_action "✅ Déploiement terminé sur : $host"
        fi
    done <<< "$hosts"
    
    log_action "Déploiement en flotte terminé"
}

# Fonction principale avec routage de commandes
main() {
    local command="$1"
    shift
    
    # Initialiser
    create_directories
    
    case "$command" in
        "creer")
            create_enterprise_user "$@"
            ;;
        "creation_masse")
            bulk_create_users "$@"
            ;;
        "lister")
            list_enterprise_users
            ;;
        "supprimer")
            remove_enterprise_user "$@"
            ;;
        "sauvegarder")
            create_user_backup "$@"
            ;;
        "surveiller")
            monitor_user_system
            ;;
        "rapport")
            generate_user_report "$@"
            ;;
        "deployer_flotte")
            deploy_to_fleet "$@"
            ;;
        "afficher_categories")
            print_user_categories
            ;;
        "afficher_politiques")
            for policy in standard fort basique service departement externe public; do
                echo "Politique : $policy"
                echo "  $(generate_password_policy "$policy")"
                echo ""
            done
            ;;
        *)
            echo "Système de Gestion d'Utilisateurs d'Entreprise MacFleet"
            echo "Utilisation : $0 <commande> [options]"
            echo ""
            echo "Commandes :"
            echo "  creer <nom_utilisateur> <nom_affichage> <categorie> <profil> [departement] [expiration]"
            echo "  creation_masse <fichier_csv>"
            echo "  lister"
            echo "  supprimer <nom_utilisateur> [sauvegarde_avant_suppression]"
            echo "  sauvegarder <nom_utilisateur>"
            echo "  surveiller"
            echo "  rapport <nom_rapport>"
            echo "  deployer_flotte <config_flotte> <config_utilisateur>"
            echo "  afficher_categories"
            echo "  afficher_politiques"
            echo ""
            echo "Exemples :"
            echo "  $0 creer PartagerFichiers 'Compte de Partage de Fichiers' partage_standard entreprise_standard IT"
            echo "  $0 creation_masse utilisateurs.csv"
            echo "  $0 lister"
            echo "  $0 surveiller"
            echo "  $0 rapport audit_mensuel"
            ;;
    esac
}

# Exécuter la fonction principale avec tous les arguments
main "$@"

Exemple de Déploiement en Flotte

Modèle CSV pour Création en Masse

nom_utilisateur,nom_affichage,categorie,profil,departement,expiration
PartagerFichiers01,Compte de Partage de Fichiers 1,partage_standard,entreprise_standard,IT,
InviteAccueil,Accès Invité Accueil,invite_temporaire,acces_invite_accueil,Reception,2025-12-31
PartenaireExt,Accès Partenaire Externe,partage_securise,collaboration_partenaire,Legal,2025-09-30
KiosqueBib,Compte Kiosque Bibliothèque,kiosque_public,kiosque_public_bibliotheque,Public,
PartageFinance,Compte Partagé Finance,partage_securise,haute_securite_finance,Finance,
EquipeDev,Partage Équipe Développement,partage_standard,recherche_developpement,Ingenierie,

Exemple de Configuration de Flotte

{
    "nom_flotte": "MacFleet Entreprise",
    "date_deploiement": "2025-07-07",
    "hotes": [
        "mac-bureau-01.entreprise.com",
        "mac-bureau-02.entreprise.com",
        "mac-conference-01.entreprise.com"
    ],
    "profil_deploiement": "entreprise_standard",
    "politique_securite": "standard_entreprise",
    "surveillance": {
        "active": true,
        "intervalle_rapport": "quotidien",
        "seuil_alerte": "haute"
    }
}

Considérations de Sécurité

Sécurité des Comptes Utilisateur

  • Pas d'Accès Shell - Les utilisateurs de partage ne peuvent pas accéder à la ligne de commande
  • Pas de Répertoire Home - Empêche le stockage de fichiers dans les répertoires utilisateur
  • Appartenance de Groupe Limitée - Restreint l'accès système
  • Politiques de Mot de Passe - Applique des exigences de mot de passe fort
  • Journalisation d'Audit - Suit toutes les activités de gestion d'utilisateur

Conformité d'Entreprise

  • Conformité SOX - Contrôles d'accès utilisateur financier
  • Conformité HIPAA - Protection des données de santé
  • Cadre NIST - Implémentation des contrôles de sécurité
  • ISO 27001 - Gestion de la sécurité de l'information

Guide de Dépannage

Problèmes Courants

Échec de Création d'Utilisateur

  • Vérifier si l'ID utilisateur est déjà utilisé
  • Vérifier les privilèges administratifs
  • S'assurer que les services d'annuaire fonctionnent

Problèmes d'Authentification

  • Vérifier la conformité à la politique de mot de passe
  • Vérifier le statut du compte utilisateur
  • Examiner les journaux d'audit pour les tentatives échouées

Erreurs de Permission

  • Confirmer les appartenances de groupe
  • Vérifier les permissions de partage de fichiers
  • Vérifier l'application de la politique de sécurité

Commandes de Diagnostic

# Vérifier l'existence de l'utilisateur
dscl . read /Users/nom_utilisateur

# Lister tous les utilisateurs
dscl . list /Users

# Vérifier les groupes utilisateur
groups nom_utilisateur

# Voir les propriétés utilisateur
id nom_utilisateur

Notes Importantes

  • Tester minutieusement avant le déploiement en flotte
  • Sauvegarder les données utilisateur avant d'apporter des modifications
  • Surveiller les journaux d'audit pour les événements de sécurité
  • Mettre à jour les politiques selon les exigences de sécurité
  • Documenter les changements pour l'audit de conformité
  • Utiliser des méthodes de livraison de mot de passe sécurisées en production

Exécuter l'Assistant de configuration sur les appareils macOS au prochain redémarrage

Ce guide complet démontre comment déclencher l'Assistant de configuration macOS au prochain redémarrage de l'appareil, permettant la reconfiguration des appareils, l'intégration des utilisateurs et les flux de déploiement d'entreprise.

Aperçu

L'Assistant de configuration est l'assistant de configuration intégré de macOS qui guide les utilisateurs dans la configuration initiale de l'appareil. Il peut être déclenché manuellement pour divers scénarios d'entreprise :

  • Reconfiguration d'appareils : Réinitialiser les appareils à un état proche de l'usine tout en préservant les données
  • Intégration d'utilisateurs : Rationaliser la configuration des appareils pour les nouveaux employés
  • Déploiement de masse : Standardiser la configuration des appareils dans les organisations
  • Dépannage : Réinitialiser les configurations système sans effacement complet de l'appareil
  • Conformité : S'assurer que les appareils répondent aux exigences de configuration organisationnelle

Déclenchement de base de l'Assistant de configuration

Script simple pour l'Assistant de configuration

Créez un script de base pour déclencher l'Assistant de configuration au prochain redémarrage :

#!/bin/bash

# Script de déclenchement de base de l'Assistant de configuration
# Utilisation : ./declencher_assistant_config.sh

declencher_assistant_config() {
    # Vérifier si le script est exécuté en tant que root
    if [ "$(id -u)" != "0" ]; then
        echo "Erreur : Ce script doit être exécuté en tant que root"
        exit 1
    fi
    
    # Vérifier si le fichier .AppleSetupDone existe
    if [ ! -f "/private/var/db/.AppleSetupDone" ]; then
        echo "Fichier marqueur de l'Assistant de configuration non trouvé. L'Assistant de configuration pourrait déjà être programmé pour s'exécuter."
        exit 0
    fi
    
    # Supprimer le fichier .AppleSetupDone
    sudo rm /private/var/db/.AppleSetupDone
    
    if [ $? -eq 0 ]; then
        echo "L'Assistant de configuration s'exécutera au prochain redémarrage."
        echo "Veuillez redémarrer l'appareil pour commencer l'Assistant de configuration."
    else
        echo "Erreur : Impossible de supprimer le fichier marqueur de l'Assistant de configuration."
        exit 1
    fi
}

# Exécuter la fonction
declencher_assistant_config

Assistant de configuration avancé avec validation

#!/bin/bash

# Assistant de configuration avancé avec validation et journalisation
# Utilisation : ./assistant_config_avance.sh

assistant_config_avance() {
    local fichier_log="/var/log/macfleet_assistant_config.log"
    local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
    local fichier_config_termine="/private/var/db/.AppleSetupDone"
    local nom_ordinateur=$(scutil --get ComputerName)
    
    # Vérifier si le script est exécuté en tant que root
    if [ "$EUID" -ne 0 ]; then
        echo "Erreur : Ce script doit être exécuté en tant que root"
        exit 1
    fi
    
    # Créer le répertoire de log s'il n'existe pas
    mkdir -p /var/log
    
    # Enregistrer le début de l'opération
    echo "[$timestamp] Démarrage du déclenchement de l'Assistant de configuration sur $nom_ordinateur" >> "$fichier_log"
    
    # Vérifier la compatibilité de la version macOS
    local version_os=$(sw_vers -productVersion)
    local version_majeure=$(echo "$version_os" | cut -d. -f1)
    
    if [ "$version_majeure" -ge 14 ]; then
        echo "[$timestamp] ATTENTION : macOS $version_os détecté. Le déclenchement de l'Assistant de configuration pourrait ne pas fonctionner sur macOS 14+" >> "$fichier_log"
        echo "Attention : Ce script est pris en charge sur les versions macOS inférieures à 14. Version actuelle : $version_os"
        read -p "Voulez-vous continuer quand même ? (o/N) : " continuer_quand_meme
        if [ "$continuer_quand_meme" != "o" ] && [ "$continuer_quand_meme" != "O" ]; then
            echo "[$timestamp] Opération annulée par l'utilisateur en raison de la compatibilité de version" >> "$fichier_log"
            echo "Opération annulée."
            exit 0
        fi
    fi
    
    # Vérifier si le fichier marqueur de l'Assistant de configuration existe
    if [ ! -f "$fichier_config_termine" ]; then
        echo "[$timestamp] Fichier marqueur de l'Assistant de configuration non trouvé à $fichier_config_termine" >> "$fichier_log"
        echo "Fichier marqueur de l'Assistant de configuration non trouvé. L'Assistant de configuration pourrait déjà être programmé pour s'exécuter."
        echo "Emplacement du fichier : $fichier_config_termine"
        exit 0
    fi
    
    # Obtenir les informations du fichier avant suppression
    local info_fichier=$(ls -la "$fichier_config_termine" 2>/dev/null)
    echo "[$timestamp] Informations actuelles du fichier marqueur : $info_fichier" >> "$fichier_log"
    
    # Créer une sauvegarde du fichier marqueur
    local repertoire_sauvegarde="/var/backups/macfleet"
    mkdir -p "$repertoire_sauvegarde"
    cp "$fichier_config_termine" "$repertoire_sauvegarde/.AppleSetupDone.sauvegarde.$(date +%Y%m%d_%H%M%S)" 2>/dev/null
    
    # Supprimer le fichier .AppleSetupDone
    rm "$fichier_config_termine"
    
    # Vérifier la suppression
    if [ ! -f "$fichier_config_termine" ]; then
        echo "[$timestamp] Fichier marqueur de l'Assistant de configuration supprimé avec succès" >> "$fichier_log"
        echo "L'Assistant de configuration a été configuré pour s'exécuter au prochain redémarrage."
        echo ""
        echo "Informations sur l'appareil :"
        echo "  Nom de l'ordinateur : $nom_ordinateur"
        echo "  Version macOS : $version_os"
        echo "  Horodatage : $timestamp"
        echo ""
        echo "Prochaines étapes :"
        echo "  1. Redémarrer l'appareil pour commencer l'Assistant de configuration"
        echo "  2. Suivre les instructions à l'écran pour configurer l'appareil"
        echo "  3. L'Assistant de configuration vous guidera à travers la langue, la région, les comptes et autres paramètres"
        echo ""
        echo "Note : Toutes les données utilisateur et applications existantes resteront intactes."
    else
        echo "[$timestamp] ERREUR : Impossible de supprimer le fichier marqueur de l'Assistant de configuration" >> "$fichier_log"
        echo "Erreur : Impossible de supprimer le fichier marqueur de l'Assistant de configuration."
        echo "Veuillez vérifier les permissions et réessayer."
        exit 1
    fi
}

# Exécuter la configuration avancée
assistant_config_avance

Gestion avancée de l'Assistant de configuration

Déclenchement conditionnel de l'Assistant de configuration

#!/bin/bash

# Déclenchement conditionnel de l'Assistant de configuration avec plusieurs scénarios
# Utilisation : ./assistant_config_conditionnel.sh [scenario]

assistant_config_conditionnel() {
    local scenario=${1:-"defaut"}
    local fichier_log="/var/log/macfleet_assistant_config.log"
    local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
    
    # Vérifier si le script est exécuté en tant que root
    if [ "$EUID" -ne 0 ]; then
        echo "Erreur : Ce script doit être exécuté en tant que root"
        exit 1
    fi
    
    echo "[$timestamp] Déclenchement conditionnel de l'Assistant de configuration - Scénario : $scenario" >> "$fichier_log"
    
    case $scenario in
        "nouvel_employe")
            declencher_config_nouvel_employe
            ;;
        "actualisation_appareil")
            declencher_config_actualisation_appareil
            ;;
        "reinitialisation_conformite")
            declencher_reinitialisation_conformite
            ;;
        "depannage")
            declencher_config_depannage
            ;;
        "deploiement_masse")
            declencher_config_deploiement_masse
            ;;
        "defaut")
            declencher_config_defaut
            ;;
        *)
            echo "Scénario inconnu : $scenario"
            echo "Scénarios disponibles : nouvel_employe, actualisation_appareil, reinitialisation_conformite, depannage, deploiement_masse, defaut"
            exit 1
            ;;
    esac
}

declencher_config_nouvel_employe() {
    echo "Configuration de l'Assistant de configuration pour l'intégration d'un nouvel employé..."
    
    # Supprimer le marqueur de l'Assistant de configuration
    rm -f /private/var/db/.AppleSetupDone
    
    echo "[$timestamp] Configuration nouvel employé - Assistant de configuration configuré" >> "$fichier_log"
    
    cat << 'EOF'
Assistant de configuration configuré pour l'intégration d'un nouvel employé.

Les éléments suivants seront présentés à l'utilisateur :
• Sélection de la langue et de la région
• Configuration du réseau Wi-Fi
• Connexion avec l'Apple ID
• Création d'un compte utilisateur
• Paramètres de confidentialité et de sécurité
• Configuration de Touch ID (si disponible)
• Préférences d'apparence du bureau

Veuillez redémarrer l'appareil et le fournir au nouvel employé.
EOF
}

declencher_config_actualisation_appareil() {
    echo "Configuration de l'Assistant de configuration pour l'actualisation d'appareil..."
    
    # Vérifier si les données utilisateur doivent être préservées
    local repertoires_utilisateur=$(ls /Users | grep -v "Shared" | grep -v "Guest" | head -5)
    if [ -n "$repertoires_utilisateur" ]; then
        echo "Comptes utilisateur existants détectés :"
        echo "$repertoires_utilisateur"
        echo ""
        read -p "Préserver les données utilisateur existantes ? (O/n) : " preserver_donnees
        
        if [ "$preserver_donnees" = "n" ] || [ "$preserver_donnees" = "N" ]; then
            echo "Attention : Cela supprimera les données utilisateur lors de l'actualisation."
            read -p "Êtes-vous sûr ? (o/N) : " confirmer
            if [ "$confirmer" != "o" ] && [ "$confirmer" != "O" ]; then
                echo "Opération annulée."
                return 1
            fi
        fi
    fi
    
    rm -f /private/var/db/.AppleSetupDone
    echo "[$timestamp] Configuration actualisation appareil - Assistant de configuration configuré" >> "$fichier_log"
    
    echo "Assistant de configuration configuré pour l'actualisation d'appareil."
    echo "Redémarrez l'appareil pour commencer le processus de reconfiguration."
}

declencher_reinitialisation_conformite() {
    echo "Configuration de l'Assistant de configuration pour la réinitialisation de conformité..."
    
    # Enregistrer la réinitialisation de conformité
    echo "[$timestamp] Réinitialisation de conformité initiée - Assistant de configuration déclenché" >> "$fichier_log"
    
    # Supprimer le marqueur de l'Assistant de configuration
    rm -f /private/var/db/.AppleSetupDone
    
    cat << 'EOF'
Assistant de configuration configuré pour la réinitialisation de conformité.

Cela garantira que l'appareil répond aux exigences de conformité organisationnelle :
• Forcer la re-acceptation des termes et politiques
• Vérifier les configurations des comptes utilisateur
• Confirmer les paramètres de sécurité
• Mettre à jour les préférences de confidentialité
• Valider les paramètres organisationnels

Redémarrez l'appareil pour commencer la vérification de conformité.
EOF
}

declencher_config_depannage() {
    echo "Configuration de l'Assistant de configuration pour le dépannage..."
    
    # Créer un rapport de dépannage
    local rapport_depannage="/tmp/rapport_depannage_$(date +%Y%m%d_%H%M%S).txt"
    
    cat > "$rapport_depannage" << EOF
Rapport de dépannage MacFleet
Généré : $(date)
Appareil : $(scutil --get ComputerName)
Version macOS : $(sw_vers -productVersion)

Problèmes que l'Assistant de configuration peut résoudre :
• Problèmes de configuration des comptes utilisateur
• Corruption des préférences système
• Problèmes de configuration réseau
• Problèmes d'authentification Apple ID
• Incohérences des paramètres de confidentialité

L'Assistant de configuration sera déclenché au prochain redémarrage.
EOF
    
    rm -f /private/var/db/.AppleSetupDone
    echo "[$timestamp] Configuration dépannage - Assistant de configuration configuré" >> "$fichier_log"
    
    echo "Assistant de configuration configuré pour le dépannage."
    echo "Rapport de dépannage sauvegardé à : $rapport_depannage"
    echo "Redémarrez l'appareil pour commencer le processus de configuration."
}

declencher_config_deploiement_masse() {
    echo "Configuration de l'Assistant de configuration pour le déploiement de masse..."
    
    # Obtenir le numéro de série de l'appareil pour le suivi
    local numero_serie=$(system_profiler SPHardwareDataType | grep "Serial Number" | awk '{print $4}')
    
    # Enregistrer le déploiement
    echo "[$timestamp] Configuration déploiement de masse - Appareil : $numero_serie" >> "$fichier_log"
    
    rm -f /private/var/db/.AppleSetupDone
    
    cat << EOF
Assistant de configuration configuré pour le déploiement de masse.

Numéro de série de l'appareil : $numero_serie
Date de déploiement : $(date)

La configuration standardisée inclura :
• Langue : Français
• Région : France
• Réseau : Wi-Fi d'entreprise
• Compte : Compte utilisateur standard
• Sécurité : Politiques de sécurité d'entreprise
• Applications : Applications d'entreprise standard

L'appareil est prêt pour le déploiement. Redémarrez pour commencer la configuration.
EOF
}

declencher_config_defaut() {
    echo "Configuration de l'Assistant de configuration avec les paramètres par défaut..."
    
    rm -f /private/var/db/.AppleSetupDone
    echo "[$timestamp] Configuration par défaut - Assistant de configuration configuré" >> "$fichier_log"
    
    echo "Assistant de configuration configuré avec les paramètres par défaut."
    echo "Redémarrez l'appareil pour commencer le processus de configuration."
}

# Exécution principale
if [ $# -eq 0 ]; then
    echo "Utilisation : $0 [scenario]"
    echo "Scénarios disponibles :"
    echo "  nouvel_employe        - Configurer pour l'intégration d'un nouvel employé"
    echo "  actualisation_appareil - Configurer pour l'actualisation/reconfiguration d'appareil"
    echo "  reinitialisation_conformite - Configurer pour la vérification de conformité"
    echo "  depannage             - Configurer pour le dépannage"
    echo "  deploiement_masse     - Configurer pour le déploiement de masse"
    echo "  defaut                - Configurer avec les paramètres par défaut"
    echo ""
    assistant_config_conditionnel "defaut"
else
    assistant_config_conditionnel "$1"
fi

Automatisation et surveillance de l'Assistant de configuration

Gestionnaire d'entreprise de l'Assistant de configuration

#!/bin/bash

# Gestionnaire d'entreprise de l'Assistant de configuration
# Utilisation : ./gestionnaire_entreprise_assistant.sh

gestionnaire_entreprise_assistant() {
    local fichier_config="/etc/macfleet/config_assistant_configuration.conf"
    local fichier_log="/var/log/macfleet_assistant_config.log"
    local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
    
    # Vérifier si le script est exécuté en tant que root
    if [ "$EUID" -ne 0 ]; then
        echo "Erreur : Ce script doit être exécuté en tant que root"
        exit 1
    fi
    
    # Créer le répertoire de configuration
    mkdir -p /etc/macfleet
    
    # Charger ou créer la configuration
    if [ -f "$fichier_config" ]; then
        source "$fichier_config"
    else
        creer_config_entreprise
        source "$fichier_config"
    fi
    
    echo "[$timestamp] Gestionnaire d'entreprise de l'Assistant de configuration démarré" >> "$fichier_log"
    
    # Afficher le menu de configuration
    afficher_menu_entreprise
}

creer_config_entreprise() {
    cat > "/etc/macfleet/config_assistant_configuration.conf" << 'EOF'
# Configuration de l'Assistant de configuration d'entreprise MacFleet

# Informations de l'organisation
NOM_ORGANISATION="Organisation MacFleet"
EMAIL_CONTACT_IT="support@macfleet.com"
TELEPHONE_CONTACT_IT="1-800-MACFLEET"

# Configuration par défaut
LANGUE_DEFAUT="Français"
REGION_DEFAUT="France"
NECESSITER_APPLE_ID="false"
ACTIVER_SERVICES_LOCALISATION="false"
ACTIVER_SIRI="false"
NECESSITER_ACCEPTATION_TERMES="true"

# Paramètres de sécurité
NECESSITER_MOT_PASSE_FORT="true"
ACTIVER_FILEVAULT="true"
NECESSITER_TOUCH_ID="true"

# Paramètres de déploiement
MODE_DEPLOIEMENT="entreprise"
IGNORER_ETAPES_OPTIONNELLES="true"
AUTO_CONFIGURER_RESEAU="true"
EOF
    
    echo "Configuration d'entreprise créée à /etc/macfleet/config_assistant_configuration.conf"
}

afficher_menu_entreprise() {
    while true; do
        clear
        echo "======================================="
        echo "Assistant de configuration d'entreprise MacFleet"
        echo "======================================="
        echo ""
        echo "Organisation : $NOM_ORGANISATION"
        echo "Contact : $EMAIL_CONTACT_IT"
        echo ""
        echo "Actions disponibles :"
        echo "1. Déclencher l'Assistant de configuration (Appareil unique)"
        echo "2. Préparer le déploiement de masse"
        echo "3. Configurer les options de l'Assistant"
        echo "4. Voir le statut de l'Assistant de configuration"
        echo "5. Générer un rapport de déploiement"
        echo "6. Sauvegarder/Restaurer l'état de configuration"
        echo "7. Voir la configuration"
        echo "8. Quitter"
        echo ""
        read -p "Sélectionnez une option (1-8) : " choix
        
        case $choix in
            1)
                declencher_config_appareil_unique
                ;;
            2)
                preparer_deploiement_masse
                ;;
            3)
                configurer_options_assistant
                ;;
            4)
                voir_statut_assistant
                ;;
            5)
                generer_rapport_deploiement
                ;;
            6)
                sauvegarder_restaurer_config
                ;;
            7)
                voir_configuration
                ;;
            8)
                echo "Fermeture du gestionnaire d'entreprise de l'Assistant de configuration."
                exit 0
                ;;
            *)
                echo "Option invalide. Veuillez réessayer."
                ;;
        esac
        
        echo ""
        read -p "Appuyez sur Entrée pour continuer..."
    done
}

declencher_config_appareil_unique() {
    echo "======================================="
    echo "Déclencher l'Assistant de configuration - Appareil unique"
    echo "======================================="
    
    local nom_appareil=$(scutil --get ComputerName)
    local numero_serie=$(system_profiler SPHardwareDataType | grep "Serial Number" | awk '{print $4}')
    
    echo "Appareil : $nom_appareil"
    echo "Numéro de série : $numero_serie"
    echo ""
    
    read -p "Confirmer le déclenchement de l'Assistant de configuration sur cet appareil ? (o/N) : " confirmer
    if [ "$confirmer" = "o" ] || [ "$confirmer" = "O" ]; then
        # Supprimer le marqueur de l'Assistant de configuration
        if rm -f /private/var/db/.AppleSetupDone; then
            echo "[$timestamp] Configuration appareil unique déclenchée - $nom_appareil ($numero_serie)" >> "$fichier_log"
            echo "Assistant de configuration configuré avec succès."
            echo "Veuillez redémarrer l'appareil pour commencer la configuration."
        else
            echo "Erreur : Impossible de configurer l'Assistant de configuration."
        fi
    else
        echo "Opération annulée."
    fi
}

preparer_deploiement_masse() {
    echo "======================================="
    echo "Préparer le déploiement de masse"
    echo "======================================="
    
    read -p "Entrez le nombre d'appareils pour le déploiement : " nombre_appareils
    read -p "Entrez le nom du lot de déploiement : " nom_lot
    
    local repertoire_deploiement="/var/macfleet/deploiements/$nom_lot"
    mkdir -p "$repertoire_deploiement"
    
    # Créer le package de déploiement
    cat > "$repertoire_deploiement/deployer_assistant_config.sh" << 'EOF'
#!/bin/bash
# Déclencheur de l'Assistant de configuration pour déploiement de masse MacFleet
# Script de déploiement auto-généré

# Vérifier si le script est exécuté en tant que root
if [ "$EUID" -ne 0 ]; then
    echo "Erreur : Ce script doit être exécuté en tant que root"
    exit 1
fi

# Supprimer le marqueur de l'Assistant de configuration
rm -f /private/var/db/.AppleSetupDone

# Enregistrer le déploiement
echo "$(date '+%Y-%m-%d %H:%M:%S') - Configuration déploiement de masse déclenchée sur $(scutil --get ComputerName)" >> /var/log/macfleet_deploiement_masse.log

echo "Assistant de configuration configuré pour le déploiement de masse."
echo "Redémarrez l'appareil pour commencer le processus de configuration."
EOF
    
    chmod +x "$repertoire_deploiement/deployer_assistant_config.sh"
    
    # Créer le manifeste de déploiement
    cat > "$repertoire_deploiement/manifeste_deploiement.txt" << EOF
Manifeste de déploiement de masse MacFleet
Nom du lot : $nom_lot
Nombre d'appareils : $nombre_appareils
Créé : $(date)
Organisation : $NOM_ORGANISATION

Instructions de déploiement :
1. Copier deployer_assistant_config.sh sur chaque appareil
2. Exécuter le script en tant que root sur chaque appareil
3. Redémarrer les appareils pour commencer l'Assistant de configuration
4. Suivre les procédures de configuration standard

Contact : $EMAIL_CONTACT_IT
EOF
    
    echo "Package de déploiement de masse créé à : $repertoire_deploiement"
    echo "Script de déploiement : $repertoire_deploiement/deployer_assistant_config.sh"
    echo "Manifeste : $repertoire_deploiement/manifeste_deploiement.txt"
}

configurer_options_assistant() {
    echo "======================================="
    echo "Configurer les options de l'Assistant"
    echo "======================================="
    
    echo "Configuration actuelle :"
    echo "  Langue : $LANGUE_DEFAUT"
    echo "  Région : $REGION_DEFAUT"
    echo "  Nécessiter Apple ID : $NECESSITER_APPLE_ID"
    echo "  Activer les services de localisation : $ACTIVER_SERVICES_LOCALISATION"
    echo "  Activer Siri : $ACTIVER_SIRI"
    echo ""
    
    read -p "Modifier la configuration ? (o/N) : " modifier
    if [ "$modifier" = "o" ] || [ "$modifier" = "O" ]; then
        echo "La modification de la configuration nécessiterait une configuration supplémentaire..."
        echo "Veuillez modifier : /etc/macfleet/config_assistant_configuration.conf"
    fi
}

voir_statut_assistant() {
    echo "======================================="
    echo "Statut de l'Assistant de configuration"
    echo "======================================="
    
    local fichier_config_termine="/private/var/db/.AppleSetupDone"
    local nom_appareil=$(scutil --get ComputerName)
    local version_os=$(sw_vers -productVersion)
    
    echo "Appareil : $nom_appareil"
    echo "Version macOS : $version_os"
    echo "Horodatage : $(date)"
    echo ""
    
    if [ -f "$fichier_config_termine" ]; then
        echo "Statut : Assistant de configuration TERMINÉ"
        echo "Fichier : $fichier_config_termine existe"
        echo "Modifié : $(stat -f "%Sm" "$fichier_config_termine")"
        echo ""
        echo "L'Assistant de configuration ne s'exécutera PAS au prochain redémarrage."
    else
        echo "Statut : Assistant de configuration PROGRAMMÉ"
        echo "Fichier : $fichier_config_termine n'existe pas"
        echo ""
        echo "L'Assistant de configuration s'exécutera au prochain redémarrage."
    fi
}

generer_rapport_deploiement() {
    echo "======================================="
    echo "Générer un rapport de déploiement"
    echo "======================================="
    
    local fichier_rapport="/tmp/rapport_macfleet_assistant_$(date +%Y%m%d_%H%M%S).txt"
    
    cat > "$fichier_rapport" << EOF
Rapport de déploiement de l'Assistant de configuration MacFleet
Généré : $(date)
Organisation : $NOM_ORGANISATION

Informations sur l'appareil :
  Nom de l'ordinateur : $(scutil --get ComputerName)
  Numéro de série : $(system_profiler SPHardwareDataType | grep "Serial Number" | awk '{print $4}')
  Version macOS : $(sw_vers -productVersion)
  Modèle matériel : $(system_profiler SPHardwareDataType | grep "Model Name" | cut -d: -f2 | xargs)

Statut de l'Assistant de configuration :
EOF
    
    if [ -f "/private/var/db/.AppleSetupDone" ]; then
        echo "  Statut : Terminé" >> "$fichier_rapport"
        echo "  Dernière exécution : $(stat -f "%Sm" "/private/var/db/.AppleSetupDone")" >> "$fichier_rapport"
    else
        echo "  Statut : Programmé pour le prochain redémarrage" >> "$fichier_rapport"
    fi
    
    cat >> "$fichier_rapport" << EOF

Configuration :
  Langue par défaut : $LANGUE_DEFAUT
  Région par défaut : $REGION_DEFAUT
  Mode de déploiement : $MODE_DEPLOIEMENT
  Contact : $EMAIL_CONTACT_IT

Entrées de log récentes :
EOF
    
    if [ -f "/var/log/macfleet_assistant_config.log" ]; then
        tail -10 "/var/log/macfleet_assistant_config.log" >> "$fichier_rapport"
    else
        echo "  Aucune entrée de log trouvée" >> "$fichier_rapport"
    fi
    
    echo "Rapport de déploiement généré : $fichier_rapport"
}

sauvegarder_restaurer_config() {
    echo "======================================="
    echo "Sauvegarder/Restaurer l'état de configuration"
    echo "======================================="
    
    echo "1. Sauvegarder l'état actuel de l'Assistant de configuration"
    echo "2. Restaurer l'état de l'Assistant de configuration"
    echo ""
    read -p "Sélectionnez une option (1-2) : " option_sauvegarde
    
    case $option_sauvegarde in
        1)
            sauvegarder_etat_config
            ;;
        2)
            restaurer_etat_config
            ;;
        *)
            echo "Option invalide."
            ;;
    esac
}

sauvegarder_etat_config() {
    local repertoire_sauvegarde="/var/backups/macfleet"
    local timestamp=$(date +%Y%m%d_%H%M%S)
    
    mkdir -p "$repertoire_sauvegarde"
    
    if [ -f "/private/var/db/.AppleSetupDone" ]; then
        cp "/private/var/db/.AppleSetupDone" "$repertoire_sauvegarde/.AppleSetupDone.sauvegarde.$timestamp"
        echo "État de l'Assistant de configuration sauvegardé à : $repertoire_sauvegarde/.AppleSetupDone.sauvegarde.$timestamp"
    else
        echo "Aucun état de l'Assistant de configuration à sauvegarder (fichier n'existe pas)."
    fi
}

restaurer_etat_config() {
    local repertoire_sauvegarde="/var/backups/macfleet"
    
    if [ -d "$repertoire_sauvegarde" ]; then
        echo "Sauvegardes disponibles :"
        ls -la "$repertoire_sauvegarde"/.AppleSetupDone.sauvegarde.* 2>/dev/null || echo "Aucune sauvegarde trouvée."
        echo ""
        read -p "Entrez le nom du fichier de sauvegarde à restaurer : " fichier_sauvegarde
        
        if [ -f "$repertoire_sauvegarde/$fichier_sauvegarde" ]; then
            cp "$repertoire_sauvegarde/$fichier_sauvegarde" "/private/var/db/.AppleSetupDone"
            echo "État de l'Assistant de configuration restauré depuis : $fichier_sauvegarde"
        else
            echo "Fichier de sauvegarde non trouvé."
        fi
    else
        echo "Aucun répertoire de sauvegarde trouvé."
    fi
}

voir_configuration() {
    echo "======================================="
    echo "Configuration actuelle"
    echo "======================================="
    
    if [ -f "/etc/macfleet/config_assistant_configuration.conf" ]; then
        cat "/etc/macfleet/config_assistant_configuration.conf"
    else
        echo "Aucun fichier de configuration trouvé."
    fi
}

# Exécuter le gestionnaire d'entreprise
gestionnaire_entreprise_assistant

Dépannage et bonnes pratiques

Problèmes courants et solutions

1. Compatibilité de version macOS

# Vérifier la version macOS avant l'exécution
version_os=$(sw_vers -productVersion)
version_majeure=$(echo "$version_os" | cut -d. -f1)

if [ "$version_majeure" -ge 14 ]; then
    echo "Attention : Ce script pourrait ne pas fonctionner sur macOS 14 ou ultérieur"
    echo "Version actuelle : $version_os"
fi

2. Problèmes de permissions

# S'assurer que le script s'exécute avec les privilèges appropriés
if [ "$EUID" -ne 0 ]; then
    echo "Erreur : Ce script doit être exécuté en tant que root"
    echo "Veuillez utiliser : sudo $0"
    exit 1
fi

3. Protection du système de fichiers

# Vérifier si la protection d'intégrité du système affecte l'opération
csrutil status | grep -q "enabled"
if [ $? -eq 0 ]; then
    echo "Note : SIP est activé. Cela pourrait affecter le fonctionnement du script."
fi

Bonnes pratiques pour la gestion de l'Assistant de configuration

  1. Compatibilité de version : Toujours vérifier la compatibilité de version macOS avant le déploiement
  2. Communication utilisateur : Notifier les utilisateurs avant de déclencher l'Assistant de configuration
  3. Sauvegarde de données : Créer des sauvegardes avant les changements de configuration majeurs
  4. Tests : Tester les scripts dans des environnements contrôlés avant le déploiement de masse
  5. Journalisation : Maintenir des logs détaillés de toutes les opérations de l'Assistant de configuration
  6. Plans de retour : Préparer des procédures de retour en arrière pour les échecs de déploiement

Considérations de déploiement d'entreprise

  • Planification : Planifier les déploiements pendant les fenêtres de maintenance
  • Impact utilisateur : Considérer les flux de travail des utilisateurs et minimiser les perturbations
  • Exigences réseau : S'assurer d'une connectivité réseau adéquate pour les services Apple
  • Sécurité : Implémenter des mesures de sécurité appropriées pour les déploiements automatisés
  • Conformité : S'assurer que les déploiements respectent les exigences de conformité organisationnelle

Conclusion

La gestion de l'Assistant de configuration est un outil puissant pour l'administration des appareils macOS. Ces scripts fournissent des solutions complètes pour déclencher, gérer et automatiser l'Assistant de configuration dans les flottes Mac. Des déclencheurs simples pour un seul appareil à l'automatisation d'entreprise complexe, ces outils permettent une gestion efficace des appareils tout en maintenant l'expérience utilisateur et la conformité organisationnelle.

N'oubliez pas de tester tous les scripts de manière approfondie dans des environnements contrôlés avant le déploiement en production, et de toujours maintenir des sauvegardes appropriées des configurations système. La surveillance régulière et la journalisation garantissent des déploiements réussis de l'Assistant de configuration et aident à identifier les problèmes potentiels avant qu'ils n'affectent les utilisateurs.

Configurer l'Économiseur d'Écran sur macOS

Apprenez à configurer et déployer des économiseurs d'écran sur Mac à l'aide de scripts. Cela vous permet de définir des styles de diaporama personnalisés, des temps d'inactivité et des sources de photos sur votre flotte Mac.

Configuration Basique d'Économiseur d'Écran

Configurez un économiseur d'écran de diaporama avec paramètres personnalisés :

#!/bin/bash

# Configuration économiseur d'écran
STYLE="Ken Burns"
IDLE_TIME=300  # 5 minutes en secondes
SHUFFLE_PHOTOS=true
PHOTOS_PATH="/System/Library/Screen Savers/Default Collections/1-National Geographic"

# Définir le style d'économiseur d'écran
defaults -currentHost write com.apple.screensaver moduleDict -dict moduleName "$STYLE"

# Définir le temps d'inactivité avant activation
defaults -currentHost write com.apple.screensaver idleTime -int $IDLE_TIME

# Configurer le mélange des photos
defaults -currentHost write com.apple.screensaver ShufflePhotos -bool $SHUFFLE_PHOTOS

# Définir le chemin du dossier photos
defaults -currentHost write com.apple.screensaver PhotosFolderPath "$PHOTOS_PATH"

echo "Économiseur d'écran configuré : Style=$STYLE, TempInactivité=${IDLE_TIME}s"

Styles d'Économiseur d'Écran Disponibles

Choisissez parmi les styles de diaporama intégrés d'Apple :

#!/bin/bash

# Styles d'économiseur d'écran disponibles
STYLES=(
    "Floating"
    "Flip-up"
    "Reflections"
    "Origami"
    "Shifting Tiles"
    "Sliding Panels"
    "Photo Mobile"
    "Holiday Mobile"
    "Photo Wall"
    "Vintage Prints"
    "Ken Burns"
    "Classic"
)

# Fonction pour définir le style d'économiseur d'écran
set_screen_saver_style() {
    local style="$1"
    local idle_time="${2:-600}"  # Défaut 10 minutes
    local photos_path="${3:-/System/Library/Screen Savers/Default Collections}"
    
    echo "Configuration économiseur d'écran : $style"
    
    # Configurer l'économiseur d'écran
    defaults -currentHost write com.apple.screensaver moduleDict -dict moduleName "$style"
    defaults -currentHost write com.apple.screensaver idleTime -int $idle_time
    defaults -currentHost write com.apple.screensaver PhotosFolderPath "$photos_path"
    
    echo "Économiseur d'écran configuré avec succès"
}

# Exemple : Définir style Ken Burns avec temps d'inactivité de 5 minutes
set_screen_saver_style "Ken Burns" 300 "/Users/Shared/ScreenSaver Photos"

Gestionnaire d'Économiseur d'Écran Interactif

Script avec interface conviviale pour la configuration :

#!/bin/bash

# Fonction pour afficher les styles disponibles
show_styles() {
    echo "Styles d'Économiseur d'Écran Disponibles :"
    echo "1. Floating"
    echo "2. Flip-up"
    echo "3. Reflections"
    echo "4. Origami"
    echo "5. Shifting Tiles"
    echo "6. Sliding Panels"
    echo "7. Photo Mobile"
    echo "8. Holiday Mobile"
    echo "9. Photo Wall"
    echo "10. Vintage Prints"
    echo "11. Ken Burns"
    echo "12. Classic"
}

# Fonction pour configurer l'économiseur d'écran
configure_screen_saver() {
    local style="$1"
    local idle_minutes="$2"
    local shuffle="$3"
    local photos_folder="$4"
    
    local idle_seconds=$((idle_minutes * 60))
    
    # Définir toutes les options de configuration
    defaults -currentHost write com.apple.screensaver moduleDict -dict moduleName "$style"
    defaults -currentHost write com.apple.screensaver idleTime -int $idle_seconds
    defaults -currentHost write com.apple.screensaver ShufflePhotos -bool $shuffle
    defaults -currentHost write com.apple.screensaver PhotosFolderPath "$photos_folder"
    
    # Fermer Préférences Système pour forcer la mise à jour
    killall "System Preferences" 2>/dev/null || true
    
    echo "✓ Économiseur d'écran configuré :"
    echo "  Style : $style"
    echo "  Temps d'inactivité : $idle_minutes minutes"
    echo "  Mélanger photos : $shuffle"
    echo "  Dossier photos : $photos_folder"
}

# Configuration par défaut
STYLE="Ken Burns"
IDLE_MINUTES=10
SHUFFLE_PHOTOS=true
PHOTOS_FOLDER="/System/Library/Screen Savers/Default Collections/1-National Geographic"

# Configurer avec les valeurs par défaut
configure_screen_saver "$STYLE" "$IDLE_MINUTES" "$SHUFFLE_PHOTOS" "$PHOTOS_FOLDER"

Déploiement d'Économiseur d'Écran Entreprise

Déployez des paramètres d'économiseur d'écran standardisés sur plusieurs appareils :

#!/bin/bash

# Configuration économiseur d'écran d'entreprise
CORPORATE_CONFIG() {
    # Configuration de marque d'entreprise
    local style="Classic"
    local idle_time=600  # 10 minutes
    local photos_path="/Library/Desktop Pictures/Corporate"
    local shuffle=false
    
    echo "Déploiement des paramètres économiseur d'écran d'entreprise..."
    
    # Créer le répertoire photos d'entreprise s'il n'existe pas
    if [[ ! -d "$photos_path" ]]; then
        sudo mkdir -p "$photos_path"
        echo "Répertoire photos d'entreprise créé : $photos_path"
    fi
    
    # Appliquer les paramètres
    defaults -currentHost write com.apple.screensaver moduleDict -dict moduleName "$style"
    defaults -currentHost write com.apple.screensaver idleTime -int $idle_time
    defaults -currentHost write com.apple.screensaver ShufflePhotos -bool $shuffle
    defaults -currentHost write com.apple.screensaver PhotosFolderPath "$photos_path"
    
    # Désactiver l'exigence de mot de passe pour l'environnement d'entreprise
    defaults write com.apple.screensaver askForPassword -int 0
    
    echo "Configuration économiseur d'écran d'entreprise appliquée"
    echo "Style : $style | Inactivité : ${idle_time}s | Mélange : $shuffle"
}

# Appliquer la configuration d'entreprise
CORPORATE_CONFIG

Statut et Gestion de l'Économiseur d'Écran

Vérifiez les paramètres actuels de l'économiseur d'écran et gérez la configuration :

#!/bin/bash

# Fonction pour afficher les paramètres actuels de l'économiseur d'écran
show_current_settings() {
    echo "=== Paramètres Actuels de l'Économiseur d'Écran ==="
    
    # Obtenir le style actuel
    local current_style=$(defaults -currentHost read com.apple.screensaver moduleDict 2>/dev/null | grep moduleName | cut -d'"' -f4)
    
    # Obtenir le temps d'inactivité
    local idle_time=$(defaults -currentHost read com.apple.screensaver idleTime 2>/dev/null)
    
    # Obtenir le paramètre de mélange
    local shuffle=$(defaults -currentHost read com.apple.screensaver ShufflePhotos 2>/dev/null)
    
    # Obtenir le chemin des photos
    local photos_path=$(defaults -currentHost read com.apple.screensaver PhotosFolderPath 2>/dev/null)
    
    echo "Style : ${current_style:-Non défini}"
    echo "Temps d'inactivité : ${idle_time:-Non défini} secondes"
    echo "Mélanger photos : ${shuffle:-Non défini}"
    echo "Dossier photos : ${photos_path:-Non défini}"
}

# Fonction pour désactiver l'économiseur d'écran
disable_screen_saver() {
    defaults -currentHost write com.apple.screensaver idleTime -int 0
    echo "Économiseur d'écran désactivé (temps d'inactivité défini à 0)"
}

# Fonction pour activer l'économiseur d'écran avec paramètres par défaut
enable_screen_saver() {
    defaults -currentHost write com.apple.screensaver idleTime -int 600
    defaults -currentHost write com.apple.screensaver moduleDict -dict moduleName "Ken Burns"
    echo "Économiseur d'écran activé avec paramètres par défaut"
}

# Afficher les paramètres actuels
show_current_settings

Utilisation avec MacFleet

  1. Choisissez votre style d'économiseur d'écran préféré parmi les options disponibles
  2. Définissez le temps d'inactivité en secondes (0 désactive l'économiseur d'écran)
  3. Configurez le mélange des photos et le chemin du dossier source
  4. Déployez via l'exécution de script distant MacFleet
  5. Surveillez le déploiement dans l'historique des actions

Chemins Photos Communs

EmplacementChemin
Collections par Défaut/System/Library/Screen Savers/Default Collections
Images de Bureau/Library/Desktop Pictures
Images Utilisateur/Users/nomutilisateur/Pictures
Dossier Partagé/Users/Shared/ScreenSaver Photos

Dépannage

Paramètres non appliqués : Fermez Préférences Système et redémarrez pour actualiser les paramètres Photos non affichées : Vérifiez que le chemin du dossier existe et contient des fichiers image Économiseur d'écran ne s'active pas : Vérifiez le paramètre de temps d'inactivité et les préférences de veille du système


Note : Les modifications prennent effet immédiatement mais peuvent nécessiter de redémarrer Préférences Système pour voir dans l'interface graphique. Testez la configuration avant le déploiement en masse.