<#
.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 de W32Time 
       (le service NTP de Windows)
    
    9. 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 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="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.00.00-RC000.11"

# ==============================================================================
# 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(
        [bool]$Basic,
        [bool]$Negotiate,
        [bool]$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 += "L'authentification Basic nécessite d'autoriser la connection non chiffré (AllowUnencrypted). Le support HTTPS n'est pas disponible pour le moment."
    }

    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
    )

    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))) {
        return "manual"
    }

    return "none"
}
function Get-DefaultParameters {
    return @{
        UserName = $DEFAULT_USERNAME
        Password = $DEFAULT_PASSWORD
        Basic = $false
        Negotiate = $true
        AllowUnencrypted = $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  [IMPORTANT] Basic nécessite AllowUnencrypted=true" -ForegroundColor Yellow
                $parsedAllowUnencrypted = Read-BoolInteractive "  Activer AllowUnencrypted ?" -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========================================================" -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
    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="$icon $Msg" })
}
function Invoke-ConfigurationStep {
    param([string]$Name,[scriptblock]$Action)
    try {
        & $Action
        Add-StepResult -Name $Name -Ok $true -Msg "Étape réussie"
    } catch {
        Add-StepResult -Name $Name -Ok $false -Msg ("Erreur : " + $_.Exception.Message)
        throw "Étape $Name échouée"
    }
}

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

function Verify-InstalledLanguage {
    param([string[]]$LangCodes)
    Write-Host "[1/9] 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/9] 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/9] 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"
 
    $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/9] Configuration de la langue pour l'utilisateur $UserName" -ForegroundColor Yellow
 
    $Computer = $env:COMPUTERNAME
    $SID = (Get-WmiObject 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 $LangArray -PropertyType MultiString -Force | Out-Null
            } else {
                Set-ItemProperty -Path $tempPath -Name $valueName -Value $LangArray
            }
        } 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([bool]$Basic, [bool]$Negotiate, [bool]$AllowUnencrypted)
  
    Write-Host "[5/9] Configuration de l'authentification WinRM" -ForegroundColor Yellow

    if ($Basic) {
        winrm set winrm/config/service/auth '@{Basic="true"}'
    }
     
    if ($Negotiate) {
        winrm set winrm/config/service/auth '@{Negotiate="true"}'
    }
 
    if ($AllowUnencrypted) {
        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/9] Attribution des droits WinRM (SDDL)" -ForegroundColor Yellow
  
    $GENERIC_READ = 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,
        [string] $computerName = ".",
        [System.Management.Automation.PSCredential] $credential = $null
    )
  
    Write-Host "[7/9] Attribution des droits WMI/CIM" -ForegroundColor Yellow
    $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
    }
  
    if ($PSBoundParameters.ContainsKey("Credential")) {
        $remoteparams = @{ComputerName=$computerName;Credential=$credential}
    } else {
        $remoteparams = @{}
    }
  
    $invokeparams = @{Namespace=$namespace;Path="__systemsecurity=@"} + $remoteParams
    $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-WmiObject @remoteparams 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 = @{Class="Win32_Account";Filter="Domain='$domain' and Name='$accountname'"} + $remoteParams
    $win32account = Get-WmiObject @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)"
    }
}
 
function Set-W32TimePermission {
    param([string]$UserName)
    Write-Host "[8/9] Attribution des droits sur W32Time" -ForegroundColor Yellow
  
    $sid = (New-Object System.Security.Principal.NTAccount($UserName)).Translate([System.Security.Principal.SecurityIdentifier]).Value
    $currentSddl = & sc.exe sdshow w32time
    $newAce = "(A;;CCLCLO;;;${sid})"
    $newSddl = $currentSddl + $newAce
    sc.exe sdset w32time "$newSddl"
    Restart-Service w32time
  
    Write-Host "      Droits W32Time appliqués pour $UserName." -ForegroundColor Green
    Write-Host ""
}

function Restart-WinRMServices {
    Write-Host "[9/9] 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
    }
    
    Write-Host "      Les services ont été redémarrés et sont opérationnels." -ForegroundColor Green
    Write-Host ""
}

# ==============================================================================
# SECTION 6 : 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 "W32Time SDDL" { Set-W32TimePermission -UserName $script:UserName }
        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 7 : LOGIQUE PRINCIPALE
# ==============================================================================

$ExecutionMode = Get-ExecutionMode -UserNameParam $UserName -PasswordParam $Password -BasicParam $Basic -NegotiateParam $Negotiate -AllowUnencryptedParam $AllowUnencrypted

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

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

    "interactive" {
        Test-Prerequisites

        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
    }
}

$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 "      - 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
}