<#
.SYNOPSIS
    Configure un hôte Windows pour la supervision via WinRM avec le pack windows-by-WinRM__shinken

.DESCRIPTION
    Ce script configure automatiquement un hôte Windows supervisé pour la supervision via WinRM avec le pack windows-by-WinRM__shinken
    
    Le script va effectuer les opérations suivantes :
    
    1. Vérifier si la langue Anglaise ou Française est installé.
    
    2. Créer un utilisateur de supervision et l'ajouter dans les groupes nécessaires
       (Remote Management Users, Performance Monitor Users)
    
    3. Configurer la langue du nouvel utilisateur de supervision (en-US ou fr-FR)
    
    4. Configurer WinRM pour l'authentification Basic ou Negotiate, puis HTTP
    
    5. Configurer l'utilisateur de supervision pour exécuter des commandes WinRM
    
    6. Configurer l'utilisateur de supervision pour récupérer les informations WMI/CIM root\cimv2
    
    7. Configurer l'utilisateur de supervision pour récupérer les informations WMI/CIM root\standardcimv2

    8. Configurer l'utilisateur de supervision pour récupérer les informations du journal de sécurité (Security Event Log)
    
    9. Configurer l'utilisateur de supervision pour récupérer les informations de W32Time 
       (le service NTP de Windows)

    10. Configurer l'utilisateur de supervision pour récupérer les informations de divers services Windows.
    
    11. Redémarrer les services winmgmt et WinRM pour appliquer toutes les modifications

.PARAMETER UserName
    Nom d'utilisateur local à créer pour la supervision.
    Exemple : "shinken_user"

.PARAMETER Password
    Mot de passe de l'utilisateur.
    
.PARAMETER Negotiate
    Active l'authentification Negotiate (true/false).
    Recommandé pour environnements domaines AD
    Plus sécurisé que Basic

.PARAMETER Basic
    Active l'authentification Basic (true/false).
    Nécessite AllowUnencrypted=true

.PARAMETER AllowUnencrypted
    Autorise les connexions non chiffrées (true/false).
    Obligatoire si Basic=true (HTTPS non supporté actuellement)

.PARAMETER ServicesName
    Liste des noms de services (tableaux de string) à autoriser en lecture.
    Exemple : "W32Time", "WinRM"

.PARAMETER ServiceWhiteListPath
    Chemin vers un fichier texte contenant une liste de services à autoriser (un par ligne).

.PARAMETER GrantAll
    Accorde les droits de lecture à TOUS les services présents sur la machine.
    Attention : Cela peut être long et verbeux.

.PARAMETER RevokeUnlisted
    Révoque les droits de lecture pour les services qui ne sont PAS dans la liste (ServicesName ou WhiteList).
    Utile pour nettoyer une configuration précédente.

.PARAMETER Default
    Active le mode par défaut avec les paramètres prédéfinis :
    - UserName: shinken_user
    - Password: Ch4nge_Th1s_P4ssw0rd
    - Negotiate: true
    - Basic: false
    - AllowUnencrypted: false

.PARAMETER Interactive
    Active le mode interactif avec un assistant pas-à-pas.
    Recommandé pour les utilisateurs non familiers avec PowerShell.
    Le mot de passe est saisi de manière masquée.

.PARAMETER Version
    Affiche la version du script

.PARAMETER Help
    Affiche cette aide complète.
    Équivalent à : Get-Help .\Configure-Host.ps1 -Full

.NOTES
    Prérequis :
    - Windows Server 2012 R2+ ou Windows 10+
    - PowerShell 4.0 ou supérieur
    - Droits administrateur
    - Service WinRM installé
    
    Avertissements de sécurité :
    - Negotiate est recommandé
    - Le mode Basic transmet les identifiants en clair ( non chiffré )
    - Le mot de passe par défaut doit être changé immédiatement

.EXAMPLE
    .\Configure-Host.ps1 -Default

    Utilise les paramètres par défaut (Negotiate, pas Basic)

.EXAMPLE
    .\Configure-Host.ps1 -Interactive

    Mode assistant pas-à-pas qui guide l'utilisateur à travers toutes les étapes
    de configuration avec des explications contextuelles.

.EXAMPLE
    $secPass = ConvertTo-SecureString "P@ssw0rd!" -AsPlainText -Force
    .\Configure-Host.ps1 -UserName "shinken_user" -Password $secPass -Negotiate true -Basic false -AllowUnencrypted false

    Configuration manuelle complète avec tous les paramètres spécifiés.
    Note : Le mot de passe doit être converti en SecureString.

.EXAMPLE
    $secPass = ConvertTo-SecureString "P@ssw0rd!" -AsPlainText -Force
    .\Configure-Host.ps1 -UserName "monitoring_user" -Password $secPass -Basic true

    Configuration avec authentification Basic (moins sécurisée).
    AllowUnencrypted est obligatoire avec Basic.
#>
 
param(
    [Parameter(Position=0, HelpMessage="Nom d'utilisateur local à créer pour la supervision (ex: shinken_user)")]
    [string]$UserName,
    
    [Parameter(Position=1, HelpMessage="Mot de passe de l'utilisateur")]
    [object]$Password,
        
    [Parameter(Position=2, HelpMessage="Active l'authentification Negotiate (true/false)")]
    [string]$Negotiate,
    
    [Parameter(Position=3, HelpMessage="Active l'authentification Basic (true/false)")]
    [string]$Basic,

    [Parameter(Position=4, HelpMessage="Autorise les connexions non chiffrées (true/false)")]
    [string]$AllowUnencrypted,

    [Parameter(HelpMessage="Liste des noms de services à autoriser (ex: W32Time, WinRM)")]
    [string[]]$ServicesName = @(),

    [Parameter(HelpMessage="Chemin vers un fichier texte liste blanche de services")]
    [string]$ServiceWhiteListPath = "",

    [Parameter(HelpMessage="Ignore la configuration des services non critiques")]
    [switch]$SkipServicePermissions,

    [Parameter(HelpMessage="Accorde droits lecture à TOUS les services")]
    [switch]$GrantAll,

    [Parameter(HelpMessage="Révoque droits lecture services non listés")]
    [switch]$RevokeUnlisted,

    [Parameter(HelpMessage="Active le mode par défaut avec paramètres prédéfinis")]
    [switch]$Default,
    
    [Parameter(HelpMessage="Active le mode interactif avec assistant pas-à-pas")]
    [switch]$Interactive,
    
    [Parameter(HelpMessage="Affiche cette aide complète")]
    [switch]$Help,

    [Parameter(HelpMessage="Affiche la version du script")]
    [switch]$Version
)



# ==============================================================================
# Constantes - Valeurs par défaut
# ==============================================================================
$DEFAULT_USERNAME = "shinken_user"
$DEFAULT_PASSWORD = "Ch4nge_Th1s_P4ssw0rd"
$SCRIPT_VERSION = "V02.04.00"

# ==============================================================================
# Variable pour le suivi des étapes
# ==============================================================================
$Steps = New-Object System.Collections.ArrayList


function Get-Version {
    Write-Host "Version : $SCRIPT_VERSION" -ForegroundColor Gray
}

# ==============================================================================
# SECTION 1 : FONCTIONS DE VALIDATION
# ==============================================================================

function Test-Prerequisites {
    Write-Host "Vérification des prérequis..." -ForegroundColor Yellow

    $checks = @()

    # 1. Vérifier les droits administrateurs
    $isAdmin = ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
    $checks += @{
        Name = "Droits administrateurs"
        Result = $isAdmin
        Error = "Ce script nécessite des droits administrateur."
    }

    # 2. Vérifier la version de PowerShell
    $psVersion = $PSVersionTable.PSVersion.Major
    $checks += @{
        Name = "Version de PowerShell"
        Result = ($psVersion -ge 4)
        Error = "Ce script nécessite PowerShell 4.0 ou supérieur."
    }

    # 3. WinRM disponible
    $winrmService = Get-Service -Name WinRM -ErrorAction SilentlyContinue
    $checks += @{
        Name = "Service WinRM présent"
        Result = ($null -ne $winrmService)
        Error = "Le service WinRM n'est pas installé"
    }


    $failed = $false
    foreach ($check in $checks) {
        if ($check.Result) {
            Write-Host "[OK] $($check.Name)" -ForegroundColor Green
        } else {
            if ($check.ContainsKey("Warning") -and $check.Warning) {
                Write-Host "[WARN] $($check.Name) : $($check.Error)" -ForegroundColor Yellow
            } else {
                Write-Host "[KO] $($check.Name) : $($check.Error)" -ForegroundColor Red
                $failed = $true
            }
        }
    }

    Write-Host ""

    if ($failed) {
        throw "Pré-requis non satisfaits. Impossible de continuer."
    }
}
function Test-ParameterCoherence {
    param(
        [string]$Basic,
        [string]$Negotiate,
        [string]$AllowUnencrypted
    )

    # Conversion en booléen sécurisée
    if ([string]::IsNullOrWhiteSpace($Basic)) { $Basic = $false } else { $Basic = [System.Convert]::ToBoolean($Basic) }
    if ([string]::IsNullOrWhiteSpace($Negotiate)) { $Negotiate = $false } else { $Negotiate = [System.Convert]::ToBoolean($Negotiate) }
    if ([string]::IsNullOrWhiteSpace($AllowUnencrypted)) { $AllowUnencrypted = $false } else { $AllowUnencrypted = [System.Convert]::ToBoolean($AllowUnencrypted) }

    $errors = @()

    if (-not $Basic -and -not $Negotiate) {
        $errors += "Aucune méthode d'authentification n'est paramétrée. Veuillez choisir Basic ou Negotiate."
    }

    if ($Basic -and -not $AllowUnencrypted) {
        $errors += "La configuration a été interrompue par l'utilisateur.`n  Veuillez choisir une des deux configurations suivante d'authentification :`n   - Basic avec AllowUnencrypted`n   - NTLM (recommandé)"
    }

    if (-not $Basic -and $Negotiate -and $AllowUnencrypted) {
        $errors += "Negotiate ne nécessite pas une connection chiffré (AllowUnencrypted). Il est déconseillé de l'activer."
    }

    if ( -not $Basic -and $AllowUnencrypted) {
        $errors += "AllowUnencrypted ne peut pas être activé si Basic n'est pas activé."
    }

    if ($errors.Count -gt 0) {
        Write-Host "`n ERREURS DE CONFIGURATION :" -ForegroundColor Red
        $errors | ForEach-Object { Write-Host "  $_" -ForegroundColor Red }
        Write-Host "`nUtilisez -Help pour plus d'informations`n" -ForegroundColor Yellow
        exit 1
    }
}
function ConvertTo-Boolean {
    param([string]$value)
    
    try {
        return [System.Convert]::ToBoolean($value.ToString().Trim())
    } catch {
        throw "Paramètre booléen invalide: '$value'. Utilisez 'true' ou 'false'."
    }
}

# ==============================================================================
# SECTION 2 : FONCTIONS DE GESTION DES MODES
# ==============================================================================

function Get-ExecutionMode {
    param(
        [string]$UserNameParam,
        $PasswordParam,
        [string]$BasicParam,
        [string]$NegotiateParam,
        [string]$AllowUnencryptedParam,
        [string[]]$ServicesNameParam,
        [string]$ServiceWhiteListPathParam,
        [bool]$SkipServicePermissionsParam,
        [bool]$GrantAllParam,
        [bool]$RevokeUnlistedParam
    )

    if ($script:Version) {
        return "version"
    }

    if ($script:Help) {
        return "help"
    }

    if ($script:Default) {
        return "default"
    }

    if ($script:Interactive) {
        return "interactive"
    }

    if ((-not [string]::IsNullOrWhiteSpace($UserNameParam)) -or 
        ($null -ne $PasswordParam) -or 
        (-not [string]::IsNullOrWhiteSpace($BasicParam)) -or 
        (-not [string]::IsNullOrWhiteSpace($NegotiateParam)) -or 
        (-not [string]::IsNullOrWhiteSpace($AllowUnencryptedParam)) -or 
        ($ServicesNameParam) -or 
        (-not [string]::IsNullOrWhiteSpace($ServiceWhiteListPathParam)) -or 
        ($SkipServicePermissionsParam) -or 
        ($GrantAllParam) -or 
        ($RevokeUnlistedParam)) {
        return "manual"
    }

    return "none"
}
function Get-DefaultParameters {
    return @{
        UserName = $DEFAULT_USERNAME
        Password = $DEFAULT_PASSWORD
        Basic = $false
        Negotiate = $true
        AllowUnencrypted = $false

        ServicesName = @()
        ServiceWhiteListPath = ""
        SkipServicePermissions = $true
        GrantAll = $false
        RevokeUnlisted = $false
    }
}

# ==============================================================================
# SECTION 3 : FONCTIONS INTERACTIVES
# ==============================================================================

function Read-BoolInteractive {
    param(
        [string]$Prompt,
        [bool]$Default = $false
    )
    
    $defaultText = if ($Default) { "Y/n" } else { "y/N" }
    $response = Read-Host "$Prompt [$defaultText]"
    
    if ([string]::IsNullOrWhiteSpace($response)) {
        return $Default
    }
    
    return ($response -eq "Y" -or $response -eq "y" -or $response -eq "yes")
}
function Read-SecureStringInteractive {
    param([string]$Prompt)
    
    $securePass = Read-Host $Prompt -AsSecureString
    # Convertir en clair (nécessaire pour le script)
    $BSTR = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($securePass)
    $plainPass = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($BSTR)
    [System.Runtime.InteropServices.Marshal]::ZeroFreeBSTR($BSTR)
    
    return $plainPass
}
function Read-PasswordWithConfirmation {
    param(
        [string]$Prompt = "  Mot de passe (saisie masquée)",
        [bool]$ShowHelp = $false
    )
    
    if ($ShowHelp) {
        Write-Host "  Le mot de passe doit respecter la politique de sécurité Windows configurée." -ForegroundColor Gray
        Write-Host "  Recommandation : Utilisez un mot de passe robuste (8+ caractères, majuscules, minuscules, chiffres, symboles)`n" -ForegroundColor Gray
    }
    
    do {
        $password = Read-SecureStringInteractive $Prompt
        if ([string]::IsNullOrWhiteSpace($password)) {
            Write-Host "  Le mot de passe ne peut être vide" -ForegroundColor Red
            exit 1
        }
        
        $confirmPassword = Read-SecureStringInteractive "  Confirmer le mot de passe"
        
        if ($password -ne $confirmPassword) {
            Write-Host "  Les mots de passe ne correspondent pas. Veuillez réessayer.`n" -ForegroundColor Red
        }
    } while ($password -ne $confirmPassword)
    
    Write-Host "  Mot de passe confirmé." -ForegroundColor Green
    return $password
}
function Read-AuthenticationMethods {
    param(
        [string]$BasicParam,
        [string]$NegotiateParam,
        [string]$AllowUnencryptedParam,
        [bool]$Interactive = $false
    )
    
    Write-Host "`n====== Authentification WinRM ======`n" -ForegroundColor Yellow
    Write-Host "  Deux méthodes d'authentification disponibles :" -ForegroundColor Gray
    Write-Host "    - Negotiate (recommandé) - Chiffrement automatique (NTLM)" -ForegroundColor Cyan
    Write-Host "    - Basic - Moins sécurisé, nécessite AllowUnencrypted`n" -ForegroundColor Gray

    if ($Interactive) {
        # Mode interactif : demander Negotiate d'abord
        $parsedNegotiate = Read-BoolInteractive "  Activer Negotiate ?" -Default $true

        if ($parsedNegotiate) {
            # Negotiate activé → Basic et AllowUnencrypted désactivés
            Write-Host "`n  [OK] Negotiate activé" -ForegroundColor Green
            Write-Host "       -> Basic et AllowUnencrypted désactivés automatiquement" -ForegroundColor Cyan
            Write-Host "       -> Configuration sécurisée`n" -ForegroundColor Green
            $parsedBasic = $false
            $parsedAllowUnencrypted = $false
        } else {
            # Negotiate désactivé → demander Basic
            Write-Host "`n  [ATTENTION] Negotiate désactivé" -ForegroundColor Yellow
            Write-Host "              -> Configuration de Basic...`n" -ForegroundColor Gray
            $parsedBasic = Read-BoolInteractive "  Activer Basic ?" -Default $false
            
            if ($parsedBasic) {
                Write-Host "`n  [ATTENTION]`n  L'authentification Basic nécessite d'autoriser`n  la connexion non chiffrée HTTP (AllowUnencrypted).`n" -ForegroundColor Yellow
                $parsedAllowUnencrypted = Read-BoolInteractive "  Voulez-vous authoriser les connexions WinRM non-chiffrées ?" -Default $true
            } else {
                Write-Host "`n  [ERREUR] Aucune méthode d'authentification configurée !" -ForegroundColor Red
                $parsedAllowUnencrypted = $false
            }
        }
    } else {
        # Mode manual (non-interactif)
        if ([string]::IsNullOrWhiteSpace($NegotiateParam)) {
            $NegotiateParam = Read-Host "  Negotiate (true/false)"
        }
        $parsedNegotiate = ConvertTo-Boolean $NegotiateParam
        
        if ($parsedNegotiate) {
            Write-Host "  [OK] Negotiate activé" -ForegroundColor Green
            Write-Host "       -> Basic et AllowUnencrypted désactivés automatiquement`n" -ForegroundColor Cyan
            $parsedBasic = $false
            $parsedAllowUnencrypted = $false
        } else {
            Write-Host "  [ATTENTION] Negotiate désactivé - Configuration de Basic..." -ForegroundColor Yellow
            if ([string]::IsNullOrWhiteSpace($BasicParam)) {
                $BasicParam = Read-Host "  Basic (true/false)"
            }
            $parsedBasic = ConvertTo-Boolean $BasicParam
            
            if ($parsedBasic) {
                if ([string]::IsNullOrWhiteSpace($AllowUnencryptedParam)) {
                    $AllowUnencryptedParam = Read-Host "  AllowUnencrypted (true/false)"
                }
                $parsedAllowUnencrypted = ConvertTo-Boolean $AllowUnencryptedParam
            } else {
                $parsedAllowUnencrypted = $false
            }
        }
    }
    
    # Validation finale
    if (-not $parsedBasic -and -not $parsedNegotiate) {
        Write-Host "`n  [ERREUR] Aucune méthode d'authentification configurée !" -ForegroundColor Red
        throw "Au moins une méthode d'authentification (Basic ou Negotiate) doit être activée."
    }
    
    return @{
        Basic = $parsedBasic
        Negotiate = $parsedNegotiate
        AllowUnencrypted = $parsedAllowUnencrypted
    }
}
function Start-InteractiveMode {
    Write-Host "`n========================================================" -ForegroundColor Cyan
    Write-Host "  MODE INTERACTIF - Configuration guidée" -ForegroundColor Cyan
    Write-Host "========================================================`n" -ForegroundColor Cyan

    Write-Host "====== Utilisateur de supervision ======`n" -ForegroundColor Yellow
    Write-Host "  Le script va créer un nouvel utilisateur de supervision local." -ForegroundColor Gray
    Write-Host "  Si l'utilisateur existe déjà, il sera mis à jour avec les permissions nécessaires pour WinRM.`n" -ForegroundColor Gray
    
    $script:UserName = Read-Host "  Nom d'utilisateur (défaut: $DEFAULT_USERNAME)"
     if ([string]::IsNullOrWhiteSpace($script:UserName)) {
        $script:UserName = $DEFAULT_USERNAME
        Write-Host "  -> Utilisation de la valeur par défaut : $DEFAULT_USERNAME" -ForegroundColor Gray
    }

    Write-Host "`n====== Mot de passe ======`n" -ForegroundColor Yellow
    
    $script:Password = Read-PasswordWithConfirmation -ShowHelp $true

    $authResult = Read-AuthenticationMethods -Interactive $true
    $script:ParsedBasic = $authResult.Basic
    $script:ParsedNegotiate = $authResult.Negotiate
    $script:ParsedAllowUnencrypted = $authResult.AllowUnencrypted

    Test-ParameterCoherence -Basic $script:ParsedBasic -Negotiate $script:ParsedNegotiate -AllowUnencrypted $script:ParsedAllowUnencrypted

    Write-Host "`n====== Permissions des Services ======`n" -ForegroundColor Yellow
    Write-Host "  Par défaut, l'utilisateur n'aura accès qu'aux services critiques (WinRM, W32Time)." -ForegroundColor Gray
    
    $script:SkipServicePermissions = Read-BoolInteractive "  Voulez-vous conserver cette configuration par défaut (Services critiques uniquement) ?" -Default $true

    if (-not $script:SkipServicePermissions) {
        Write-Host "`n  Configuration avancée des services..." -ForegroundColor Cyan
        
        $script:GrantAll = Read-BoolInteractive "  Accorder les droits de lecture sur TOUS les services ?" -Default $false
        
        if (-not $script:GrantAll) {
            $servicesInput = Read-Host "  Liste des services supplémentaires (séparés par des virgules, ex: Service1,Service2)"
            if (-not [string]::IsNullOrWhiteSpace($servicesInput)) {
                $script:ServicesName = $servicesInput -split "," | ForEach-Object { $_.Trim() }
            }

            $whitelistPathInput = Read-Host "  Chemin vers un fichier de liste blanche (optionnel)"
            if (-not [string]::IsNullOrWhiteSpace($whitelistPathInput)) {
                $script:ServiceWhiteListPath = $whitelistPathInput
            }
            
            $script:RevokeUnlisted = Read-BoolInteractive "  Révoquer les droits sur les services non listés (Nettoyage) ?" -Default $false
        } else {
             Write-Host "  -> Droits de lecture accordés à TOUS les services." -ForegroundColor Yellow
             $script:RevokeUnlisted = $false
        }
    } else {
        Write-Host "  -> Configuration par défaut (Services critiques uniquement)." -ForegroundColor Green
    }

    Write-Host "`n========================================================" -ForegroundColor DarkGray
    Write-Host "  RECAPITULATIF DE LA CONFIGURATION" -ForegroundColor Cyan
    Write-Host "========================================================" -ForegroundColor DarkGray
    Write-Host "  UserName         : $script:UserName" -ForegroundColor White
    Write-Host "  Password         : ********" -ForegroundColor White
    Write-Host "  Negotiate        : $script:ParsedNegotiate" -ForegroundColor White
    Write-Host "  Basic            : $script:ParsedBasic" -ForegroundColor White
    Write-Host "  AllowUnencrypted : $script:ParsedAllowUnencrypted" -ForegroundColor White
    
    if (-not $script:SkipServicePermissions) {
        if ($script:GrantAll) {
             Write-Host "  All Services     : Granted" -ForegroundColor White
        } else {
             if ($script:ServicesName.Count -gt 0) {
                 Write-Host "  Extra Services   : $($script:ServicesName -join ', ')" -ForegroundColor White
             }
             if (-not [string]::IsNullOrWhiteSpace($script:ServiceWhiteListPath)) {
                 Write-Host "  Whitelist        : $script:ServiceWhiteListPath" -ForegroundColor White
             }
             Write-Host "  Revoke Unlisted  : $script:RevokeUnlisted" -ForegroundColor White
        }
    } else {
        Write-Host "  Services Config  : Default (Critical Only)" -ForegroundColor White
    }

    Write-Host "========================================================`n" -ForegroundColor DarkGray
        
    $confirm = Read-Host "  Confirmer et lancer la configuration ? (Y/n)"
    if ($confirm -and $confirm -ne "Y" -and $confirm -ne "y") {
        Write-Host "`n    Configuration annulée`n" -ForegroundColor Red
        exit 0
    }
}

# ==============================================================================
# SECTION 4 : FONCTIONS DE GESTION DES ÉTAPES
# ==============================================================================

function Add-StepResult {
    param([string]$Name,[bool]$Ok,[string]$Msg="")
    $icon = if ($Ok) {"OK"} else {"KO"}
    $status = if ($Ok) {"Success"} else {"Failed"}
    [void]$Steps.Add([PSCustomObject]@{ Step=$Name; Status=$status; Message=$Msg })
}
function Invoke-ConfigurationStep {
    param([string]$Name,[scriptblock]$Action)
    try {
        $Output = & $Action
        if ($null -ne $Output -and $Output -is [string] -and $Output.Trim().Length -gt 0) {
             $Msg = $Output
        } else {
             $Msg = "Étape réussie"
        }
        Add-StepResult -Name $Name -Ok $true -Msg $Msg
    } catch {
        Add-StepResult -Name $Name -Ok $false -Msg ("Erreur : " + $_.Exception.Message)
        throw "Étape $Name échouée"
    }
}

# ==============================================================================
# SECTION 5 : FONCTIONS UTILITAIRES
# ==============================================================================

function Resolve-UserSID {
    param([string]$UserName)
    try {
        $sid = (New-Object System.Security.Principal.NTAccount $UserName).Translate([System.Security.Principal.SecurityIdentifier])
        return $sid
    } catch {
        throw "Impossible de résoudre le SID pour l'utilisateur '$UserName' : $_"
    }
}

# ==============================================================================
# SECTION 6 : FONCTIONS DE CONFIGURATION WINDOWS
# ==============================================================================

function Verify-InstalledLanguage {
    param([string[]]$LangCodes)
    Write-Host "[1/11] Vérification des langues installées $LangCodes" -ForegroundColor Yellow
    
    $languages = Get-WinUserLanguageList
    $has_required_lang = $false

    foreach ($lang in $LangCodes) {
        if ($languages.LanguageTag -contains $lang) {
            $has_required_lang = $true
            Write-Host "      Langue $lang disponible." -ForegroundColor Green
        }
    }

    if ($has_required_lang -eq $false) {
            Write-Host "      Aucune langue requise trouvé." -ForegroundColor Red
            Write-Host "      Pour Windows 11, 10 et Windows Server 2025, la commande suivante est disponible :" -ForegroundColor Red
            Write-Host "      Install-Language -Language fr-FR -ExcludeFeatures" -ForegroundColor Gray
            Write-Host ""
            Write-Host "      Pour les autres versions de Windows, veuillez installer la langue par interface et vous référer à la documentation de configuration du pack." -ForegroundColor Red
            Write-Host ""

        throw "Aucune des langues requises pour le pack n'est installé. Veuillez installer l'une des langues suivantes : $LangCodes"
    }
}
 
function Set-WinRMConfiguration {
    Write-Host "[2/11] Configuration rapide de WinRM" -ForegroundColor Yellow
    winrm quickconfig -q
    if ($LASTEXITCODE -ne 0) { throw "WinRM quickconfig a échoué ($LASTEXITCODE)" }
    Write-Host "      WinRM configuré." -ForegroundColor Green
    Write-Host ""
}
 
function Add-UserToExistingGroup {
    param(
        [string]$UserName,
        [string]$PrimaryGroup,
        [string]$FallbackGroup
    )
 
    $groupUsed = $null
 
    foreach ($grp in @($PrimaryGroup,$FallbackGroup)) {
        $output = net localgroup "$grp" 2>$null
        if ($LASTEXITCODE -eq 0) {
            $groupUsed = $grp
            break
        }
    }
 
    if (-not $groupUsed) {
        throw "Aucun des groupes '$PrimaryGroup' ou '$FallbackGroup' n'existe."
    }
 
    if ($output -match "^\s*$UserName\s*$") {
        Write-Host "      Utilisateur $UserName déjà dans le groupe $groupUsed" -ForegroundColor Gray
    } else {
        & net localgroup "$groupUsed" $UserName /ADD | Out-Null
        if ($LASTEXITCODE -ne 0) {
            throw "Échec ajout utilisateur $UserName dans le groupe $groupUsed ($LASTEXITCODE)"
        } else {
            Write-Host "      Utilisateur $UserName ajouté au groupe $groupUsed" -ForegroundColor Green
        }
    }
}
 
function New-LocalUser {
    param([string]$UserName, [string]$Password)
 
    Write-Host "[3/11] Création de l'utilisateur $UserName" -ForegroundColor Yellow
 
    net user $UserName 2>$null | Out-Null
    if ($LASTEXITCODE -ne 0) {
        & net user $UserName $Password /ADD /Y | Out-Null
        if ($LASTEXITCODE -ne 0) {
            throw "Échec création utilisateur via 'net user' ($LASTEXITCODE)"
        }
    } else {
        Write-Host "      Utilisateur déjà existant : $UserName" -ForegroundColor Gray
    }
 
    Add-UserToExistingGroup -UserName $UserName -PrimaryGroup "Remote Management Users" -FallbackGroup "Utilisateurs de gestion à distance"
    Add-UserToExistingGroup -UserName $UserName -PrimaryGroup "Performance Monitor Users" -FallbackGroup "Utilisateurs de l’Analyseur de performances"
    Add-UserToExistingGroup -UserName $UserName -PrimaryGroup "Event Log Readers" -FallbackGroup "Lecteurs des journaux d’événements"
 
    $SecurePassword = ConvertTo-SecureString $Password -AsPlainText -Force
    $Credential = New-Object System.Management.Automation.PSCredential ($UserName, $SecurePassword)
    try {
        Start-Process -FilePath "whoami.exe" -WorkingDirectory "$env:USERPROFILE" -Credential $Credential -WindowStyle Hidden -Wait
    } catch {
        Write-Host "      Impossible de lancer un logon test pour $UserName ($_)" -ForegroundColor Red
    }
 
    Write-Host "      Utilisateur $UserName créé/validé et groupes assignés." -ForegroundColor Green
}

function Set-UserLanguage {
    param(
        [string]$UserName,
        [string[]]$LangCodes
    )
 
    Write-Host "[4/11] Configuration de la langue pour l'utilisateur $UserName" -ForegroundColor Yellow
 
    $Computer = $env:COMPUTERNAME
    $SID = (Get-CimInstance -ClassName Win32_UserAccount -Filter "Name='$UserName' AND Domain='$Computer'").SID
    if (-not $SID) { throw "Impossible de récupérer le SID pour $UserName" }
 
    $UserProfile = Get-CimInstance Win32_UserProfile | Where-Object SID -eq $SID
    if (-not $UserProfile) { throw "Profil introuvable pour $UserName" }
 
    $HivePath = Join-Path $UserProfile.LocalPath "NTUSER.DAT"
    if (-not (Test-Path $HivePath)) { throw "Profil non initialisé (NTUSER.DAT introuvable) : $HivePath" }
 
    $regRelative = "Control Panel\Desktop"
    $valueName = "PreferredUILanguages"
 
    $IsLoaded = Test-Path "Registry::HKEY_USERS\$SID"
    if ($IsLoaded) {
        $fullPath = "Registry::HKEY_USERS\$SID\$regRelative"
        if (-not (Test-Path $fullPath)) { New-Item -Path $fullPath -Force | Out-Null }
        if (-not (Get-ItemProperty -Path $fullPath -Name $valueName -ErrorAction SilentlyContinue)) {
            New-ItemProperty -Path $fullPath -Name $valueName -Value $LangCodes -PropertyType MultiString -Force | Out-Null
        } else {
            Set-ItemProperty -Path $fullPath -Name $valueName -Value $LangCodes
        }
    } else {
        Write-Host "      Utilisateur non connecté. Chargement de la ruche..." -ForegroundColor Gray
        reg load "HKU\TempHive" $HivePath | Out-Null
        try {
            $tempPath = "Registry::HKEY_USERS\TempHive\$regRelative"
            if (-not (Test-Path $tempPath)) { New-Item -Path $tempPath -Force | Out-Null }
            if (-not (Get-ItemProperty -Path $tempPath -Name $valueName -ErrorAction SilentlyContinue)) {
                New-ItemProperty -Path $tempPath -Name $valueName -Value $LangCodes -PropertyType MultiString -Force | Out-Null
            } else {
                Set-ItemProperty -Path $tempPath -Name $valueName -Value $LangCodes
            }
        } finally {
            reg unload "HKU\TempHive" | Out-Null
            Write-Host "      Ruche déchargée." -ForegroundColor Gray
        }
    }
 
    Write-Host "      Langue préférée utilisateur définie sur $LangCodes (REG_MULTI_SZ)." -ForegroundColor Green
    Write-Host ""
}
 
function Set-WinRMConfigurationAuth {
    param([string]$Basic, [string]$Negotiate, [string]$AllowUnencrypted)

    # Conversion sécurisée pour éviter les erreurs sur chaînes vides
    if ([string]::IsNullOrWhiteSpace($Basic)) { $Basic = "False" }
    if ([string]::IsNullOrWhiteSpace($Negotiate)) { $Negotiate = "False" }
    if ([string]::IsNullOrWhiteSpace($AllowUnencrypted)) { $AllowUnencrypted = "False" }

    $BasicBool = [System.Convert]::ToBoolean($Basic)
    $NegotiateBool = [System.Convert]::ToBoolean($Negotiate)
    $AllowUnencryptedBool = [System.Convert]::ToBoolean($AllowUnencrypted)
  
    Write-Host "[5/11] Configuration de l'authentification WinRM" -ForegroundColor Yellow

    if ($BasicBool) {
        winrm set winrm/config/service/auth '@{Basic="true"}'
    }
     
    if ($NegotiateBool) {
        winrm set winrm/config/service/auth '@{Negotiate="true"}'
    }
 
    if ($AllowUnencryptedBool) {
        winrm set winrm/config/service '@{AllowUnencrypted="true"}'
    }
 
    Write-Host "      Configuration d'authentification définie." -ForegroundColor Green
    Write-Host ""
}
 
function Set-WinRMConfigurationSDDL {
    param([string]$UserName)
    Write-Host "[6/11] Attribution des droits WinRM (SDDL)" -ForegroundColor Yellow
  
    $GENERIC_READ = [Int32]0x80000000
    $GENERIC_EXECUTE = 0x20000000
    $user_sid = (New-Object System.Security.Principal.NTAccount $UserName).Translate([System.Security.Principal.SecurityIdentifier])
  
    $sddl = (Get-Item -Path WSMan:\localhost\Service\RootSDDL).Value
    $sd = New-Object System.Security.AccessControl.CommonSecurityDescriptor $false, $false, $sddl
    $sd.DiscretionaryAcl.AddAccess(
        [System.Security.AccessControl.AccessControlType]::Allow,
        $user_sid,
        ($GENERIC_READ -bor $GENERIC_EXECUTE),
        [System.Security.AccessControl.InheritanceFlags]::None,
        [System.Security.AccessControl.PropagationFlags]::None
    )
    $new_sddl = $sd.GetSddlForm([System.Security.AccessControl.AccessControlSections]::All)
    Set-Item -Path WSMan:\localhost\Service\RootSDDL -Value $new_sddl -Force
    Write-Host "      Droits SDDL appliqués." -ForegroundColor Green
    Write-Host ""
}
 
function Set-WinRMPermission {
    param(
        [parameter(Mandatory=$true,Position=0)][string] $namespace,
        [parameter(Mandatory=$true,Position=1)][string] $operation,
        [parameter(Mandatory=$true,Position=2)][string] $account,
        [parameter(Position=3)][string[]] $permissions = $null,
        [bool] $allowInherit = $false,
        [bool] $deny = $false
    )
  
    Write-Host "[7-8/11] Attribution des droits WMI/CIM sur $namespace" -ForegroundColor Yellow
    $prevErrorActionPreference = $ErrorActionPreference
    $ErrorActionPreference = "Stop"
  
    function Get-AccessMaskFromPermission($permissions) {
        $WBEM_ENABLE = 1
        $WBEM_METHOD_EXECUTE = 2
        $WBEM_FULL_WRITE_REP = 4
        $WBEM_PARTIAL_WRITE_REP = 8
        $WBEM_WRITE_PROVIDER = 0x10
        $WBEM_REMOTE_ACCESS = 0x20
        $READ_CONTROL = 0x20000
        $WRITE_DAC = 0x40000
  
        $WBEM_RIGHTS_FLAGS = $WBEM_ENABLE,$WBEM_METHOD_EXECUTE,$WBEM_FULL_WRITE_REP,
            $WBEM_PARTIAL_WRITE_REP,$WBEM_WRITE_PROVIDER,$WBEM_REMOTE_ACCESS,
            $READ_CONTROL,$WRITE_DAC
  
        $WBEM_RIGHTS_STRINGS = "Enable","MethodExecute","FullWrite","PartialWrite",
            "ProviderWrite","RemoteAccess","ReadSecurity","WriteSecurity"
  
        $permissionTable = @{}
        for ($i = 0; $i -lt $WBEM_RIGHTS_FLAGS.Length; $i++) {
            $permissionTable.Add($WBEM_RIGHTS_STRINGS[$i].ToLower(), $WBEM_RIGHTS_FLAGS[$i])
        }
  
        $accessMask = 0
        foreach ($permission in $permissions) {
            if (-not $permissionTable.ContainsKey($permission.ToLower())) {
                throw "Permission inconnue: $permission`nPermissions authorisées: $($permissionTable.Keys)"
            }
            $accessMask += $permissionTable[$permission.ToLower()]
        }
        $accessMask
    }
  
    $invokeparams = @{Namespace=$namespace;Path="__systemsecurity=@"}
    $output = Invoke-WmiMethod @invokeparams -Name GetSecurityDescriptor
    if ($output.ReturnValue -ne 0) {
        throw "GetSecurityDescriptor a échoué: $($output.ReturnValue)"
    }
  
    $acl = $output.Descriptor
    $OBJECT_INHERIT_ACE_FLAG = 0x1
    $CONTAINER_INHERIT_ACE_FLAG = 0x2
    $computerName = (Get-CimInstance -ClassName Win32_ComputerSystem).Name
  
    if ($account.Contains('\')) {
        $domainaccount = $account.Split('\')
        $domain = $domainaccount[0]
        if (($domain -eq ".") -or ($domain -eq "BUILTIN")) {
            $domain = $computerName
        }
        $accountname = $domainaccount[1]
    } elseif ($account.Contains('@')) {
        $domainaccount = $account.Split('@')
        $domain = $domainaccount[1].Split('.')[0]
        $accountname = $domainaccount[0]
    } else {
        $domain = $computerName
        $accountname = $account
    }
  
    $getparams = @{ClassName="Win32_Account";Filter="Domain='$domain' and Name='$accountname'"}
    $win32account = Get-CimInstance @getparams
    if ($null -eq $win32account) {
        throw "Compte utilisateur inconnu: $account"
    }
  
    switch ($operation) {
        "add" {
            if ($null -eq $permissions) {
                throw "Les permissions doivent être spécifié."
            }
  
            $accessMask = Get-AccessMaskFromPermission($permissions)
            $ace = (New-Object System.Management.ManagementClass("win32_Ace")).CreateInstance()
            $ace.AccessMask = $accessMask
            $ace.AceFlags = if ($allowInherit) { $OBJECT_INHERIT_ACE_FLAG + $CONTAINER_INHERIT_ACE_FLAG } else { 0 }
  
            $trustee = (New-Object System.Management.ManagementClass("win32_Trustee")).CreateInstance()
            $trustee.SidString = $win32account.Sid
            $ace.Trustee = $trustee
            $ace.AceType = if ($deny) { 0x1 } else { 0x0 }
  
            $acl.DACL += $ace.psobject.immediateBaseObject
        }
        default {
            throw "Opération inconnue: $operation`nOpérations authorisés : add"
        }
    }
  
    $setparams = @{Name="SetSecurityDescriptor";ArgumentList=$acl.psobject.immediateBaseObject} + $invokeParams
    $output = Invoke-WmiMethod @setparams
    if ($output.ReturnValue -ne 0) {
        throw "SetSecurityDescriptor a échoué: $($output.ReturnValue)"
    }
    $ErrorActionPreference = $prevErrorActionPreference
}
 
function Set-WinEventLogSecurityPermission {
    param([string]$UserName)
    Write-Host "[9/11] Attribution des droits sur WinEventLog Security" -ForegroundColor Yellow
  
    try {
        $Path = "HKLM:\SYSTEM\CurrentControlSet\Services\EventLog\Security"
        $acl = Get-Acl $Path
        $rule = New-Object System.Security.AccessControl.RegistryAccessRule(
            $UserName,
            "ReadKey",
            "Allow"
        )
        $acl.AddAccessRule($rule)
        Set-Acl $Path $acl
        Write-Host "      Droits Registre appliqués." -ForegroundColor Green
    } catch {
        Write-Host "      Erreur permissions EventLog Security: $_" -ForegroundColor Red
        throw
    }
}

function Set-ServicesReadPermissions {
    param(
        [string]$UserName,

        [string[]]$ServicesName = @(),
        [string]$ServiceWhiteListPath = "",
        [switch]$SkipServicePermissions,
        [switch]$GrantAll,
        [switch]$RevokeUnlisted
    )

    if (-not $ServiceWhiteListPath) {
        $ServiceWhiteListPath = Join-Path $PSScriptRoot "services_whitelist.txt"
    }

    # Services critiques obligatoires
    [string[]]$CriticalServices = @("scmanager", "W32Time", "WinRM")

    # Initialisation des listes
    $ServicesNotFound = New-Object 'System.Collections.Generic.List[string]'
    $ServicesAlreadyConfigured = New-Object 'System.Collections.Generic.List[string]'
    $FailedServices = New-Object 'System.Collections.Generic.List[string]'
    $ServicesConfigured = New-Object 'System.Collections.Generic.List[string]'

   

    if ($SkipServicePermissions) {
        Write-Host "[10/11] Attribution des droits de lecture (Limité aux services critiques)" -ForegroundColor Yellow
        $GrantAll = $false
        $RevokeUnlisted = $false
        # En mode skip, on force la liste aux services critiques uniquement
        $WhiteList = New-Object 'System.Collections.Generic.List[string]'
        $WhiteList.AddRange([string[]]$CriticalServices)
    } else {
        Write-Host "[10/11] Attribution des droits de lecture sur les services : $($ServicesName -join ", ")" -ForegroundColor Yellow
        
        $WhiteList = New-Object 'System.Collections.Generic.List[string]'
        # Toujours inclure les services critiques
        $WhiteList.AddRange([string[]]$CriticalServices)
        
        if ($ServicesName) {
            $WhiteList.AddRange([string[]]@($ServicesName))
        }

        if ($ServiceWhiteListPath -and (Test-Path $ServiceWhiteListPath)) {
            $fileContent = Get-Content $ServiceWhiteListPath | ForEach-Object { $_.Trim() } | Where-Object { -not [string]::IsNullOrWhiteSpace($_) -and -not $_.StartsWith("#") }
            if ($fileContent) {
                # Force cast to string array to avoid System.Object[] issues with AddRange
                $WhiteList.AddRange([string[]]@($fileContent))
            }
        }
    }
    
    $UserSID = Resolve-UserSID -UserName $UserName
    $RegistryServicesPath = "HKLM:\SYSTEM\CurrentControlSet\Services\*"
    $GENERIC_READ = [Int32]0x80000000

    $UniqueServicesList = $WhiteList | Select-Object -Unique
        
    if ($GrantAll) {
        $RevokeUnlisted = $false
        # Type 16 = Win32OwnProcess : Programme Win32 qui peut être démarré par le contrôleur de services et qui obéit au protocole de contrôle des services. Ce type de service Win32 s’exécute dans un processus par lui-même.
        # Type 32 = Win32ShareProcess : 	Service Win32 qui peut partager un processus avec d’autres services Win32.
        $ServicesToGrant = Get-ItemProperty -Path $RegistryServicesPath | Where-Object { $_.Type -eq 16 -or $_.Type -eq 32 } | Select-Object -ExpandProperty PSChildName
    } else {
        $ServicesToGrant = $UniqueServicesList
    }

    foreach ($Service in $ServicesToGrant) {
        try {
            Write-Host "      Configuration du service : $Service... " -NoNewline -ForegroundColor Gray

            $currentSddl = sc.exe sdshow $Service 2>&1 | Out-String
            if ($LASTEXITCODE -ne 0) {
                Write-Host "[IGNORÉ - Introuvable]" -ForegroundColor DarkGray
                $ServicesNotFound.Add($Service)
                continue
            }

            $currentSd = New-Object System.Security.AccessControl.CommonSecurityDescriptor $false, $false, $currentSddl.Trim()
            $currentSd.DiscretionaryAcl.AddAccess(
                [System.Security.AccessControl.AccessControlType]::Allow,
                $UserSID,
                $GENERIC_READ,
                [System.Security.AccessControl.InheritanceFlags]::None,
                [System.Security.AccessControl.PropagationFlags]::None
            )
            $newSddl = $currentSd.GetSddlForm([System.Security.AccessControl.AccessControlSections]::All)

            if ($currentSddl.Trim() -eq $newSddl.Trim()) {
                 Write-Host "[DÉJÀ OK]" -ForegroundColor Green
                 $ServicesAlreadyConfigured.Add($Service)
                 continue
            }

            $result = sc.exe sdset $Service $newSddl 2>&1 | Out-String
            if ($LASTEXITCODE -eq 0) {
                Write-Host "[SUCCÈS]" -ForegroundColor Green
                $ServicesConfigured.Add($Service)
            } else {
                Write-Host "[ÉCHEC : $($result.Trim())]" -ForegroundColor Red
                Write-Host "Impossible de configurer le service $Service" -ForegroundColor Red
                $FailedServices.Add($Service)
            }
        } catch {
            Write-Host "      Erreur lors de la configuration du service $Service : $_" -ForegroundColor Red
            $FailedServices.Add($Service)
        }
    }

        Write-Host "      $($ServicesConfigured.Count) services configurés avec succès." -ForegroundColor Green
    if ($ServicesNotFound.Count -gt 0) {
        Write-Host "      Services introuvables : $($ServicesNotFound -join ", ")" -ForegroundColor Yellow
    }

    if ($ServicesAlreadyConfigured.Count -gt 0) {
        Write-Host "      Services déjà configurés : $($ServicesAlreadyConfigured -join ", ")" -ForegroundColor Yellow
    }

    if ($FailedServices.Count -gt 0) {
        Write-Host "      Services en échec : $($FailedServices -join ", ")" -ForegroundColor Red
    }

    if ($RevokeUnlisted -and $UniqueServicesList.Count -gt 0) {
        Write-Host "      Révocation des droits sur les services non listés..." -ForegroundColor Yellow
        $AllServices = Get-ItemProperty -Path $RegistryServicesPath | Where-Object { $_.Type -eq 16 -or $_.Type -eq 32 } | Select-Object -ExpandProperty PSChildName
        $ServicesToRevoke = $AllServices | Where-Object { $_ -notin $UniqueServicesList }

        foreach ($Service in $ServicesToRevoke) {
            try {
                $currentSddl = sc.exe sdshow $Service 2>&1 | Out-String
                if ($LASTEXITCODE -ne 0) {
                    continue
                }

                $sd = New-Object System.Security.AccessControl.CommonSecurityDescriptor $false, $false, $currentSddl.Trim()
                $sd.DiscretionaryAcl.Purge($UserSID)

                $newSddl = $sd.GetSddlForm([System.Security.AccessControl.AccessControlSections]::All)
                
                if ($currentSddl.Trim() -ne $newSddl.Trim()) {
                    $result = sc.exe sdset $Service $newSddl 2>&1 | Out-String
                    if ($LASTEXITCODE -eq 0) {
                        Write-Host "      [RÉVOQUÉ] $Service" -ForegroundColor Green
                    } else {
                        Write-Host "      [ÉCHEC RÉVOCATION] $Service : $result" -ForegroundColor Red
                    }
                }
            } catch {
                Write-Host "      Erreur lors de la révocation du service $Service : $_" -ForegroundColor Red
                # throw 
            }
        } 
    }

    # Construct Summary
    $msgParts = New-Object 'System.Collections.Generic.List[string]'
  
    if ($ServicesConfigured.Count -gt 0) { 
        $msgParts.Add("$($ServicesConfigured.Count) services configurés :")
        foreach ($svc in $ServicesConfigured) {
             $msgParts.Add("   - $svc")
        }
    }

    if ($ServicesAlreadyConfigured.Count -gt 0) { 
        if ($msgParts.Count -gt 0) { $msgParts.Add("") }
        $msgParts.Add("$($ServicesAlreadyConfigured.Count) services déjà OK :")
        foreach ($svc in $ServicesAlreadyConfigured) {
             $msgParts.Add("   - $svc")
        }
    }

    if ($ServicesNotFound.Count -gt 0) { 
        if ($msgParts.Count -gt 0) { $msgParts.Add("") }
        $msgParts.Add("Services Introuvables ({0}) :" -f $ServicesNotFound.Count)
        foreach ($svc in $ServicesNotFound) {
             $msgParts.Add("   - $svc")
        }
    }
    
    if ($FailedServices.Count -gt 0) { 
        if ($msgParts.Count -gt 0) { $msgParts.Add("") }
        $msgParts.Add("ÉCHECS de configuration ({0}) :" -f $FailedServices.Count)
        foreach ($svc in $FailedServices) {
             $msgParts.Add("   - $svc")
        }
    }
  
    if ($msgParts.Count -eq 0) { return "Aucun service traité" }
    return ($msgParts -join "`n")
}
    



function Restart-WinRMServices {
    Write-Host "[11/11] Redémarrage des services WinRM et WinMgmt" -ForegroundColor Yellow
    
    try {
        Write-Host "      Redémarrage du service winmgmt (Windows Management Instrumentation)..." -ForegroundColor Gray
        Restart-Service -Name winmgmt -Force -ErrorAction Stop
        Write-Host "      Service winmgmt redémarré avec succès." -ForegroundColor Green
    } catch {
        Write-Host "      Erreur lors du redémarrage de winmgmt : $_" -ForegroundColor Red
        throw
    }
    
    try {
        Write-Host "      Redémarrage du service WinRM (Windows Remote Management)..." -ForegroundColor Gray
        Restart-Service -Name WinRM -Force -ErrorAction Stop
        Write-Host "      Service WinRM redémarré avec succès." -ForegroundColor Green
    } catch {
        Write-Host "      Erreur lors du redémarrage de WinRM : $_" -ForegroundColor Red
        throw
    }

    try {
        Write-Host "      Redémarrage du service W32Time (Windows Time)..." -ForegroundColor Gray
        Restart-Service -Name w32time -Force -ErrorAction SilentlyContinue
        Write-Host "      Service W32Time redémarré avec succès." -ForegroundColor Green
    } catch {
         Write-Host "      [INFO] Impossible de redémarrer W32Time : $_" -ForegroundColor DarkGray
    }
    
    Write-Host "      Les services ont été redémarrés et sont opérationnels." -ForegroundColor Green
    Write-Host ""
}

# ==============================================================================
# SECTION 7 : ORCHESTRATION
# ==============================================================================

function Invoke-ConfigurationSteps {
    $LangCodes = "en-US", "fr-FR"
    $script:ConfigurationSuccess = $true
 
    try {
        Invoke-ConfigurationStep "Langue $LangCodes" { Verify-InstalledLanguage -LangCodes $LangCodes }
        Invoke-ConfigurationStep "WinRM quickconfig" { Set-WinRMConfiguration }
        Invoke-ConfigurationStep "Création utilisateur + Ajout aux groupes" { New-LocalUser -UserName $script:UserName -Password $script:Password }
        Invoke-ConfigurationStep "Langue UI du profil" { Set-UserLanguage -UserName $script:UserName -LangCodes $LangCodes }
        Invoke-ConfigurationStep "WinRM Auth" { Set-WinRMConfigurationAuth $script:ParsedBasic $script:ParsedNegotiate $script:ParsedAllowUnencrypted }
        Invoke-ConfigurationStep "WinRM RootSDDL" { Set-WinRMConfigurationSDDL -UserName $script:UserName }
        Invoke-ConfigurationStep "WMI/CIM root\cimv2" { Set-WinRMPermission "root/cimv2" add $script:UserName Enable,RemoteAccess }
        Invoke-ConfigurationStep "WMI/CIM root\standardcimv2" { Set-WinRMPermission "root/standardcimv2" add $script:UserName Enable,RemoteAccess }
        Invoke-ConfigurationStep "WinEventLog Security" { Set-WinEventLogSecurityPermission -UserName $script:UserName }
        Invoke-ConfigurationStep "Droits de lecture sur services" { 
            Set-ServicesReadPermissions -UserName $script:UserName `
                                      -ServicesName $script:ServicesName `
                                      -ServiceWhiteListPath $script:ServiceWhiteListPath `
                                      -SkipServicePermissions:$script:SkipServicePermissions `
                                      -GrantAll:$script:GrantAll `
                                      -RevokeUnlisted:$script:RevokeUnlisted
        }
        Invoke-ConfigurationStep "Redémarrage services" { Restart-WinRMServices }
    } catch {
        Write-Host "$($_.Exception.Message)" -ForegroundColor Red
        $script:ConfigurationSuccess = $false
    }
}
function Start-HostConfiguration { 
    Write-Host "========================================================" -ForegroundColor DarkGray
    Write-Host "CONFIGURE PACK [windows-by-WinRM] for supervised host" -ForegroundColor Cyan
    Write-Host "========================================================" -ForegroundColor DarkGray
    Write-Host ""
 
    $script:ConfigurationSuccess = $true
    Invoke-ConfigurationSteps
    
    Write-Host ""
    Write-Host ("=" * 70) -ForegroundColor DarkGray
    Write-Host "RÉSUMÉ DES ÉTAPES" -ForegroundColor Yellow
    Write-Host ("=" * 70) -ForegroundColor DarkGray
    
    foreach ($s in $Steps) {
        if ($s.Status -eq "Success") {
            Write-Host ("[OK] {0} : {1}" -f $s.Step, $s.Message) -ForegroundColor Green
        } else {
            Write-Host ("[KO] {0} : {1}" -f $s.Step, $s.Message) -ForegroundColor Red
            $script:ConfigurationSuccess = $false
        }
    }
    Write-Host ("=" * 70) -ForegroundColor DarkGray
    return $script:ConfigurationSuccess
}

# ==============================================================================
# SECTION 8 : LOGIQUE PRINCIPALE
# ==============================================================================

$ExecutionMode = Get-ExecutionMode -UserNameParam $UserName -PasswordParam $Password -BasicParam $Basic -NegotiateParam $Negotiate -AllowUnencryptedParam $AllowUnencrypted -ServicesNameParam $ServicesName -ServiceWhiteListPathParam $ServiceWhiteListPath -SkipServicePermissionsParam $SkipServicePermissions -GrantAllParam $GrantAll -RevokeUnlistedParam $RevokeUnlisted

switch ($ExecutionMode) {
    "none" {
        Write-Host "`n ERREUR : Aucun paramètre fourni`n" -ForegroundColor Red
        Write-Host "Usage :"
        Write-Host "  .\Configure-Host.ps1 -Default          # Valeurs par défaut"
        Write-Host "  .\Configure-Host.ps1 -Interactive      # Mode assistant"
        Write-Host "  .\Configure-Host.ps1 -Help             # Aide complète"
        Write-Host "  .\Configure-Host.ps1 -UserName ... -Password ... -Basic true ...`n"
        Write-Host "  .\Configure-Host.ps1 -Version"
        exit 1
    }

    "version" {
        Get-Version
        exit 0
    }

    "help" {
        Get-Help $PSCommandPath -Detailed
        exit 0
    }

    "default" {
        Test-Prerequisites

        Write-Host "`n Mode par défaut activé`n" -ForegroundColor Cyan
        $defaults = Get-DefaultParameters
        
        Write-Host "Paramètres utilisés :"
        Write-Host "  UserName         : $($defaults.UserName)"
        Write-Host "  Password         : ********" 
        Write-Host "  Negotiate        : $($defaults.Negotiate)"
        Write-Host "  Basic            : $($defaults.Basic)"
        Write-Host "  AllowUnencrypted : $($defaults.AllowUnencrypted)`n"
        
        $confirm = Read-Host "Continuer avec ces paramètres ? (Y/n)"
        if ($confirm -and $confirm -ne "Y" -and $confirm -ne "y") {
            Write-Host "Configuration annulée" -ForegroundColor Red
            exit 0
        }
        
        
        
        $script:UserName = $defaults.UserName
        $script:Password = $defaults.Password
        $script:ParsedBasic = $defaults.Basic
        $script:ParsedNegotiate = $defaults.Negotiate
        $script:ParsedAllowUnencrypted = $defaults.AllowUnencrypted

        $script:ServicesName = $defaults.ServicesName
        $script:SkipServicePermissions = $defaults.SkipServicePermissions
        $script:ServiceWhiteListPath = $defaults.ServiceWhiteListPath
        $script:GrantAll = $defaults.GrantAll
        $script:RevokeUnlisted = $defaults.RevokeUnlisted

        Test-ParameterCoherence -Basic $script:ParsedBasic -Negotiate $script:ParsedNegotiate -AllowUnencrypted $script:ParsedAllowUnencrypted
    }

    "interactive" {
        Test-Prerequisites
        
        # Valeurs par défaut pour les nouveaux paramètres (vides/false)
        $script:ServicesName = @()
        $script:ServiceWhiteListPath = ""
        $script:SkipServicePermissions = $true
        $script:GrantAll = $false
        $script:RevokeUnlisted = $false
        
        Start-InteractiveMode
    }

    "manual" {
        Test-Prerequisites
        
        Write-Host "`n Mode manuel `n" -ForegroundColor Cyan
        
        if ([string]::IsNullOrWhiteSpace($UserName)) {
            $UserName = Read-Host "Nom d'utilisateur"
            if ([string]::IsNullOrWhiteSpace($UserName)) {
                Write-Host "Le nom d'utilisateur ne peut être vide" -ForegroundColor Red
                exit 1
            }
        }
        
        if ($null -eq $Password) {
            $PlainPassword = Read-PasswordWithConfirmation -ShowHelp $true
        } elseif ($Password -is [SecureString]) {
            # Convertir SecureString en string si nécessaire
            $BSTR = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($Password)
            $PlainPassword = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($BSTR)
            [System.Runtime.InteropServices.Marshal]::ZeroFreeBSTR($BSTR)
        } else {
            $PlainPassword = $Password
        }
        
        $authResult = Read-AuthenticationMethods -BasicParam $Basic -NegotiateParam $Negotiate -AllowUnencryptedParam $AllowUnencrypted -Interactive $false
        $ParsedBasic = $authResult.Basic
        $ParsedNegotiate = $authResult.Negotiate
        $ParsedAllowUnencrypted = $authResult.AllowUnencrypted
        
        Test-ParameterCoherence -Basic $ParsedBasic -Negotiate $ParsedNegotiate -AllowUnencrypted $ParsedAllowUnencrypted
        
        Write-Host "`n==========================================" -ForegroundColor DarkGray
        Write-Host "RÉCAPITULATIF DE LA CONFIGURATION" -ForegroundColor Cyan
        Write-Host "==========================================" -ForegroundColor DarkGray
        Write-Host "  UserName         : $UserName"
        Write-Host "  Password         : ********"
        Write-Host "  Negotiate        : $ParsedNegotiate"
        Write-Host "  Basic            : $ParsedBasic"
        Write-Host "  AllowUnencrypted : $ParsedAllowUnencrypted"
        Write-Host "==========================================" -ForegroundColor DarkGray
        
        $confirm = Read-Host "Confirmer et lancer la configuration ? (Y/n)"
        if ($confirm -and $confirm -ne "Y" -and $confirm -ne "y") {
            Write-Host "Configuration annulée" -ForegroundColor Red
            exit 0
        }
        
        $script:UserName = $UserName
        $script:Password = $PlainPassword
        $script:ParsedBasic = $ParsedBasic
        $script:ParsedNegotiate = $ParsedNegotiate
        $script:ParsedAllowUnencrypted = $ParsedAllowUnencrypted
        
        $script:ServicesName = $ServicesName
        $script:SkipServicePermissions = $SkipServicePermissions
        $script:ServiceWhiteListPath = $ServiceWhiteListPath
        $script:GrantAll = $GrantAll
        $script:RevokeUnlisted = $RevokeUnlisted
    }
}

$ConfigSuccess = Start-HostConfiguration
# ==============================================================================
# AFFICHAGE DES ÉTAPES POST-CONFIGURATION
# ==============================================================================

# Afficher les instructions uniquement si la configuration a réussi
if ($ConfigSuccess -eq $true) {
    Write-Host ""
    Write-Host ("=" * 70) -ForegroundColor Cyan
    Write-Host "  ÉTAPES SUIVANTES - POST-CONFIGURATION" -ForegroundColor Yellow
    Write-Host ("=" * 70) -ForegroundColor Cyan
    Write-Host ""
    Write-Host "  La configuration automatique du poste Windows est terminée avec succès !" -ForegroundColor Green
    Write-Host ""
    Write-Host "  IMPORTANT : Vous devez maintenant effectuer MANUELLEMENT les étapes suivantes" -ForegroundColor Yellow
    Write-Host "              pour valider la configuration et continuer l'installation du pack windows-by-WinRM :" -ForegroundColor Yellow
    Write-Host ""

    # Étape 1 : Test du pare-feu
    Write-Host "  [1] VÉRIFIER LE PARE-FEU WINDOWS" -ForegroundColor Yellow
    Write-Host "      Vérifiez que la règle WinRM autorise le port 5985 :`n" -ForegroundColor Gray
    Write-Host "      Get-NetFirewallRule -Name `"WINRM-HTTP-In-TCP`"`n" -ForegroundColor White
    Write-Host "      Résultat attendu : Enabled=True, Action=Allow`n" -ForegroundColor Gray

    # Étape 2 : Test WinRM local
    Write-Host "  [2] TESTER WINRM EN LOCAL" -ForegroundColor Yellow
    Write-Host "      Testez la connexion WinRM avec l'utilisateur configuré :`n" -ForegroundColor Gray

    if ($script:ParsedNegotiate) {
        Write-Host "      Test-WSMan -ComputerName localhost -Credential (Get-Credential) ``" -ForegroundColor White
        Write-Host "                 -Authentication Negotiate`n" -ForegroundColor White
    } elseif ($script:ParsedBasic) {
        Write-Host "      Test-WSMan -ComputerName localhost -Credential (Get-Credential) ``" -ForegroundColor White
        Write-Host "                 -Authentication Basic`n" -ForegroundColor White
    }

    Write-Host "      Identifiants à saisir :" -ForegroundColor Gray
    Write-Host "        - Utilisateur : $script:UserName" -ForegroundColor Cyan
    Write-Host "        - Mot de passe : (celui défini lors de la configuration)`n" -ForegroundColor Cyan
    Write-Host "      Résultat attendu : Réponse WSMan avec ProductVendor, ProductVersion, etc.`n" -ForegroundColor Gray

    # Étape 3 : Configuration Shinken
    Write-Host "  [3] CONFIGURER DANS LE SYNCHRONIZER" -ForegroundColor Yellow
    Write-Host "      - Accédez au Synchronizer pour choisir, accrocher et paramétrer les modèles d'hôtes fournis dans le pack :" -ForegroundColor Gray
    Write-Host "        * windows-by-WinRM" -ForegroundColor Cyan
    Write-Host "        * windows-by-WinRM__extra " -ForegroundColor Cyan
    Write-Host "        * windows-by-WinRM__advanced " -ForegroundColor Cyan
    Write-Host "      - Testez les données d'authentification" -ForegroundColor Gray
    Write-Host "      - Testez le bon fonctionnement des checks`n" -ForegroundColor Gray
} else {
    Write-Host ""
    Write-Host ("=" * 70) -ForegroundColor Red
    Write-Host "  CONFIGURATION ÉCHOUÉE" -ForegroundColor Red
    Write-Host ("=" * 70) -ForegroundColor Red
    Write-Host ""
    Write-Host "  Une ou plusieurs étapes ont échoué." -ForegroundColor Yellow
    Write-Host "  Consultez le résumé ci-dessus pour identifier les erreurs.`n" -ForegroundColor Yellow
    Write-Host ""
    exit 1
}