# run.ps1 — installation & démarrage automatiques (Windows) # - Installe Docker Desktop si absent # - Active WSL2/VirtualMachinePlatform si nécessaire # - Démarre Docker Desktop (headless) et attend le daemon # - Lance `docker compose up -d` # - Enregistre une reprise RunOnce + retourne 3010 si un reboot est requis Param( [switch]$PostReboot ) # --- Sécurité / contexte --- $IsAdmin = ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent() ).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator) if (-not $IsAdmin) { Write-Host "Relance en administrateur..." Start-Process -Verb RunAs -FilePath "powershell.exe" -ArgumentList "-NoProfile", "-ExecutionPolicy", "Bypass", "-File", "`"$PSCommandPath`"" exit } [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 # --- Dossiers / chemins --- $installRoot = Split-Path -Path $MyInvocation.MyCommand.Path -Parent $logDir = Join-Path -Path $installRoot -ChildPath 'logs' if (-not (Test-Path $logDir)) { New-Item -ItemType Directory -Path $logDir | Out-Null } $PsLog = Join-Path $logDir 'install-ps.log' # <— log distinct pour éviter le verrou NSIS Push-Location $installRoot $ProgramFilesDocker = Join-Path $Env:ProgramFiles 'Docker\Docker' $DockerExe = Join-Path $ProgramFilesDocker 'resources\bin\docker.exe' $DockerDesktopExe = Join-Path $ProgramFilesDocker 'Docker Desktop.exe' $DockerCliExe = Join-Path $ProgramFilesDocker 'DockerCli.exe' function Write-Log($msg) { $stamp = (Get-Date).ToString("yyyy-MM-dd HH:mm:ss") try { Add-Content -Path $PsLog -Value "$stamp $msg" -Encoding utf8 -ErrorAction SilentlyContinue } catch { } Write-Host $msg } function Test-PendingReboot { $paths = @( 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Component Based Servicing\RebootPending', 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update\RebootRequired', 'HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager' ) foreach ($p in $paths) { if (Test-Path $p) { if ($p -like '*Session Manager*') { $val = (Get-ItemProperty -Path $p -Name 'PendingFileRenameOperations' -ErrorAction SilentlyContinue) if ($val) { return $true } } else { return $true } } } return $false } function Register-RunOnce { $runOnceKey = 'HKCU:\Software\Microsoft\Windows\CurrentVersion\RunOnce' New-Item -Path $runOnceKey -Force | Out-Null $cmd = "powershell.exe -NoProfile -ExecutionPolicy Bypass -File `"$PSCommandPath`" -PostReboot" Set-ItemProperty -Path $runOnceKey -Name 'KogusPostInstall' -Value $cmd Write-Log "RunOnce enregistré : $cmd" } function Enable-WSLPrereqs { Write-Log "Activation des fonctionnalités Windows (WSL2 / VirtualMachinePlatform) si nécessaire..." $rebootNeeded = $false & dism.exe /online /enable-feature /featurename:Microsoft-Windows-Subsystem-Linux /all /norestart | Out-Null if ($LASTEXITCODE -eq 3010) { $rebootNeeded = $true } & dism.exe /online /enable-feature /featurename:VirtualMachinePlatform /all /norestart | Out-Null if ($LASTEXITCODE -eq 3010) { $rebootNeeded = $true } try { wsl.exe --set-default-version 2 > $null 2>&1 } catch { } return $rebootNeeded } function Install-DockerDesktop { if (Test-Path $DockerExe) { return $false } Write-Log "Docker Desktop absent : installation silencieuse…" $installerUrl = 'https://desktop.docker.com/win/main/amd64/Docker%20Desktop%20Installer.exe' $installerPath = Join-Path -Path $installRoot -ChildPath 'docker-installer.exe' try { Invoke-WebRequest -UseBasicParsing -Uri $installerUrl -OutFile $installerPath } catch { Write-Log "Téléchargement direct échoué, tentative via winget…" try { winget --version > $null 2>&1 winget install --id Docker.DockerDesktop -e --accept-source-agreements --accept-package-agreements return $true } catch { throw "Impossible de télécharger Docker Desktop ($($_.Exception.Message))." } } $InstallerArguments = @('install', '--quiet', '--accept-license', '--backend=wsl-2', '--always-run-service') # flags officiels Start-Process -FilePath $installerPath -ArgumentList $InstallerArguments -Wait Remove-Item -Path $installerPath -Force -ErrorAction SilentlyContinue Write-Log "Installation de Docker Desktop terminée." return $true } function Ensure-UserInDockerUsers { try { & net localgroup docker-users $env:USERNAME /add > $null 2>&1 } catch { } } function Start-DockerDesktop-And-Wait { # 1) s'assurer que le service est en auto + démarré try { Set-Service -Name 'com.docker.service' -StartupType Automatic -ErrorAction SilentlyContinue } catch { } try { Start-Service -Name 'com.docker.service' -ErrorAction SilentlyContinue } catch { } # 2) démarrage headless via Docker Desktop CLI (4.37+) → docker desktop start/status/engine use try { & $DockerExe desktop start > $null 2>&1 } catch { } try { & $DockerExe desktop engine use linux > $null 2>&1 } catch { } # force le moteur Linux # 3) boucle d’attente (statut Desktop + daemon Engine) $deadline = (Get-Date).AddMinutes(10) while ((Get-Date) -lt $deadline) { try { $status = (& $DockerExe desktop status 2>$null).Trim() if ($status -match 'running') { & $DockerExe version --format '{{.Server.Version}}' > $null 2>&1 if ($LASTEXITCODE -eq 0) { Write-Log "Docker Desktop: $status (daemon OK)" return $true } } } catch { } Start-Sleep -Seconds 3 } # 4) fallback : lancer l’UI si nécessaire (premier démarrage/initialisation WSL) try { Start-Process -FilePath $DockerDesktopExe -ErrorAction SilentlyContinue } catch { } $deadline2 = (Get-Date).AddMinutes(10) while ((Get-Date) -lt $deadline2) { try { & $DockerExe version --format '{{.Server.Version}}' > $null 2>&1 if ($LASTEXITCODE -eq 0) { Write-Log "Docker daemon prêt (après lancement UI)."; return $true } } catch { } Start-Sleep -Seconds 3 } Write-Log "Le daemon Docker ne répond pas (timeout)." return $false } # --- Orchestration --- $rebootNeeded = $false if (-not $PostReboot) { if (Enable-WSLPrereqs) { $rebootNeeded = $true } } $installedNow = $false if (-not (Get-Command $DockerExe -ErrorAction SilentlyContinue)) { $installedNow = Install-DockerDesktop } if ($rebootNeeded -or (Test-PendingReboot)) { Write-Log "Un redémarrage Windows est requis. Enregistrement d'une reprise automatique…" Register-RunOnce Pop-Location exit 3010 } Ensure-UserInDockerUsers if (-not (Start-DockerDesktop-And-Wait)) { Write-Log "Docker n'est pas prêt. Un redémarrage peut être requis." Pop-Location exit 1 } # Lancer la stack $composeCmd = "`"$DockerExe`" compose" Write-Log "Lancement de '$composeCmd up -d'…" $runLog = Join-Path -Path $logDir -ChildPath 'run.log' & cmd.exe /c "$composeCmd up -d > `"$runLog`" 2>&1" if ($LASTEXITCODE -ne 0) { Write-Log "Erreur lors du démarrage. Voir le log : $runLog" Pop-Location exit 1 } else { Write-Log "Stack démarrée. Logs : $runLog" } Pop-Location exit 0