feat: Setup-Laptop v4 - Docker Desktop + Swarm auto-join
Stap 9 opt-in via fleet.config: - SWARM_JOIN=false: overgeslagen (standaard laptops) - SWARM_JOIN=true: WSL2 + Docker Desktop download + Phase 2 scheduled task fleet.config: SWARM_JOIN/SWARM_TOKEN/SWARM_MANAGER/PORTAINER_AGENT toegevoegd Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
3479a341be
commit
f8c3ec4ce0
2 changed files with 183 additions and 19 deletions
|
|
@ -1,6 +1,7 @@
|
||||||
# =============================================================
|
# =============================================================
|
||||||
# Atlas HP EliteBook Auto-Setup Script v3
|
# Atlas HP EliteBook Auto-Setup Script v4
|
||||||
# Draait als Administrator via autounattend FirstLogonCommands.
|
# Draait als Administrator via autounattend FirstLogonCommands.
|
||||||
|
# v4: Docker Desktop + Swarm auto-join (opt-in via fleet.config)
|
||||||
# =============================================================
|
# =============================================================
|
||||||
|
|
||||||
$global:AtlasMutex = New-Object System.Threading.Mutex($false, "Global\AtlasSetupOnce")
|
$global:AtlasMutex = New-Object System.Threading.Mutex($false, "Global\AtlasSetupOnce")
|
||||||
|
|
@ -92,12 +93,12 @@ function Export-LogsToUSB {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
||||||
Write-Phase "Atlas HP EliteBook Setup v3 Gestart"
|
Write-Phase "Atlas HP EliteBook Setup v4 Gestart"
|
||||||
Write-Log "Draait als: $([System.Security.Principal.WindowsIdentity]::GetCurrent().Name)" "Green"
|
Write-Log "Draait als: $([System.Security.Principal.WindowsIdentity]::GetCurrent().Name)" "Green"
|
||||||
Write-Log "Transcript: $TranscriptFile" "Green"
|
Write-Log "Transcript: $TranscriptFile" "Green"
|
||||||
|
|
||||||
Export-HardwareInfo
|
Export-HardwareInfo
|
||||||
Add-Content "$DebugDir\setup-phases.log" "[$(Get-Date -f 's')] Setup-Laptop.ps1 gestart"
|
Add-Content "$DebugDir\setup-phases.log" "[$(Get-Date -f 's')] Setup-Laptop.ps1 v4 gestart"
|
||||||
|
|
||||||
try { net user Atlas "" | Out-Null; Write-Log "Atlas wachtwoord verwijderd" "Green" } catch {}
|
try { net user Atlas "" | Out-Null; Write-Log "Atlas wachtwoord verwijderd" "Green" } catch {}
|
||||||
|
|
||||||
|
|
@ -289,9 +290,9 @@ try {
|
||||||
}
|
}
|
||||||
|
|
||||||
# =============================================================
|
# =============================================================
|
||||||
# STAP 7: Tailscale + MeshCentral
|
# STAP 7: Fleet config lezen
|
||||||
# =============================================================
|
# =============================================================
|
||||||
Write-Phase "STAP 7: Fleet enrollment (Tailscale + MeshCentral)"
|
Write-Phase "STAP 7: Fleet config"
|
||||||
$FleetConfig = $null
|
$FleetConfig = $null
|
||||||
foreach ($d in [char[]](65..90)) {
|
foreach ($d in [char[]](65..90)) {
|
||||||
foreach ($sub in @('Scripts','scripts')) {
|
foreach ($sub in @('Scripts','scripts')) {
|
||||||
|
|
@ -301,12 +302,28 @@ foreach ($d in [char[]](65..90)) {
|
||||||
if ($FleetConfig) { break }
|
if ($FleetConfig) { break }
|
||||||
}
|
}
|
||||||
if (-not $FleetConfig -and (Test-Path 'C:\Atlas\fleet.config')) { $FleetConfig = 'C:\Atlas\fleet.config' }
|
if (-not $FleetConfig -and (Test-Path 'C:\Atlas\fleet.config')) { $FleetConfig = 'C:\Atlas\fleet.config' }
|
||||||
|
|
||||||
$TsKey = ""
|
$TsKey = ""
|
||||||
|
$SwarmJoin = $false
|
||||||
|
$SwarmToken = ""
|
||||||
|
$SwarmManager = ""
|
||||||
|
$PortainerAgent = $false
|
||||||
|
|
||||||
if ($FleetConfig) {
|
if ($FleetConfig) {
|
||||||
$TsKey = (Get-Content $FleetConfig -ErrorAction SilentlyContinue |
|
$cfg = Get-Content $FleetConfig -ErrorAction SilentlyContinue
|
||||||
Where-Object { $_ -match '^TAILSCALE_AUTHKEY=' }) -replace '^TAILSCALE_AUTHKEY=',''
|
$TsKey = ($cfg | Where-Object { $_ -match '^TAILSCALE_AUTHKEY=' }) -replace '^TAILSCALE_AUTHKEY=',''
|
||||||
Write-Log "fleet.config: $FleetConfig" "Green"
|
$SwarmJoin = [bool]($cfg | Where-Object { $_ -match '^SWARM_JOIN=true' })
|
||||||
|
$SwarmToken = ($cfg | Where-Object { $_ -match '^SWARM_TOKEN=' }) -replace '^SWARM_TOKEN=',''
|
||||||
|
$SwarmManager = ($cfg | Where-Object { $_ -match '^SWARM_MANAGER=' }) -replace '^SWARM_MANAGER=',''
|
||||||
|
$PortainerAgent = [bool]($cfg | Where-Object { $_ -match '^PORTAINER_AGENT=true' })
|
||||||
|
Write-Log "fleet.config: $FleetConfig SwarmJoin=$SwarmJoin" "Green"
|
||||||
} else { Write-Log "fleet.config niet gevonden" "Yellow" }
|
} else { Write-Log "fleet.config niet gevonden" "Yellow" }
|
||||||
|
Add-Content "$DebugDir\setup-phases.log" "[$(Get-Date -f 's')] Stap 7 OK: config geladen"
|
||||||
|
|
||||||
|
# =============================================================
|
||||||
|
# STAP 8: Tailscale + MeshCentral
|
||||||
|
# =============================================================
|
||||||
|
Write-Phase "STAP 8: Fleet enrollment (Tailscale + MeshCentral)"
|
||||||
|
|
||||||
# Tailscale
|
# Tailscale
|
||||||
try {
|
try {
|
||||||
|
|
@ -322,10 +339,10 @@ try {
|
||||||
}
|
}
|
||||||
[System.IO.File]::Delete($tsInst)
|
[System.IO.File]::Delete($tsInst)
|
||||||
Write-Log "Tailscale OK" "Green"
|
Write-Log "Tailscale OK" "Green"
|
||||||
Add-Content "$DebugDir\setup-phases.log" "[$(Get-Date -f 's')] Stap 7a OK: Tailscale"
|
Add-Content "$DebugDir\setup-phases.log" "[$(Get-Date -f 's')] Stap 8a OK: Tailscale"
|
||||||
} catch {
|
} catch {
|
||||||
Write-Log "Tailscale FAIL: $($_.Exception.Message)" "Red"
|
Write-Log "Tailscale FAIL: $($_.Exception.Message)" "Red"
|
||||||
Add-Content "$DebugDir\setup-phases.log" "[$(Get-Date -f 's')] Stap 7a FAIL: $($_.Exception.Message)"
|
Add-Content "$DebugDir\setup-phases.log" "[$(Get-Date -f 's')] Stap 8a FAIL: $($_.Exception.Message)"
|
||||||
}
|
}
|
||||||
|
|
||||||
# MeshCentral
|
# MeshCentral
|
||||||
|
|
@ -337,16 +354,153 @@ try {
|
||||||
Start-Process $meshInst -ArgumentList "-fullinstall" -Wait
|
Start-Process $meshInst -ArgumentList "-fullinstall" -Wait
|
||||||
[System.IO.File]::Delete($meshInst)
|
[System.IO.File]::Delete($meshInst)
|
||||||
Write-Log "MeshCentral OK" "Green"
|
Write-Log "MeshCentral OK" "Green"
|
||||||
Add-Content "$DebugDir\setup-phases.log" "[$(Get-Date -f 's')] Stap 7b OK: MeshCentral"
|
Add-Content "$DebugDir\setup-phases.log" "[$(Get-Date -f 's')] Stap 8b OK: MeshCentral"
|
||||||
} catch {
|
} catch {
|
||||||
Write-Log "MeshCentral FAIL: $($_.Exception.Message)" "Red"
|
Write-Log "MeshCentral FAIL: $($_.Exception.Message)" "Red"
|
||||||
Add-Content "$DebugDir\setup-phases.log" "[$(Get-Date -f 's')] Stap 7b FAIL: $($_.Exception.Message)"
|
Add-Content "$DebugDir\setup-phases.log" "[$(Get-Date -f 's')] Stap 8b FAIL: $($_.Exception.Message)"
|
||||||
}
|
}
|
||||||
|
|
||||||
# =============================================================
|
# =============================================================
|
||||||
# STAP 8: Afronden
|
# STAP 9: Docker Desktop + Swarm (opt-in via fleet.config)
|
||||||
|
# SWARM_JOIN=true → Docker Desktop installeren + Swarm joinen
|
||||||
|
# SWARM_JOIN=false → overslaan (standaard voor laptops)
|
||||||
# =============================================================
|
# =============================================================
|
||||||
Write-Phase "STAP 8: Afronden"
|
Write-Phase "STAP 9: Docker + Swarm"
|
||||||
|
|
||||||
|
if ($SwarmJoin -and $SwarmToken -and $SwarmManager) {
|
||||||
|
Write-Log "Docker Desktop gevraagd (SWARM_JOIN=true)" "Yellow"
|
||||||
|
|
||||||
|
# Stap 9a: WSL2 inschakelen (vereist herstart - die volgt sowieso)
|
||||||
|
try {
|
||||||
|
Write-Log "WSL2 features inschakelen..." "Yellow"
|
||||||
|
dism.exe /online /enable-feature /featurename:Microsoft-Windows-Subsystem-Linux /all /norestart 2>&1 | Out-Null
|
||||||
|
dism.exe /online /enable-feature /featurename:VirtualMachinePlatform /all /norestart 2>&1 | Out-Null
|
||||||
|
Write-Log "WSL2 features ingeschakeld" "Green"
|
||||||
|
} catch { Write-Log "WSL2 enable fout: $($_.Exception.Message)" "Yellow" }
|
||||||
|
|
||||||
|
# Stap 9b: Docker Desktop installer downloaden
|
||||||
|
$dockerInst = "C:\Atlas\DockerDesktopInstaller.exe"
|
||||||
|
$dockerDownloaded = $false
|
||||||
|
try {
|
||||||
|
Write-Log "Docker Desktop downloaden (~600MB - kan 5-10 min duren)..." "Yellow"
|
||||||
|
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
|
||||||
|
Invoke-WebRequest "https://desktop.docker.com/win/stable/Docker%20Desktop%20Installer.exe" `
|
||||||
|
-OutFile $dockerInst -UseBasicParsing -TimeoutSec 900
|
||||||
|
$dockerDownloaded = (Test-Path $dockerInst) -and ((Get-Item $dockerInst).Length -gt 100MB)
|
||||||
|
Write-Log "Docker Desktop gedownload: $dockerDownloaded" $(if($dockerDownloaded){"Green"}else{"Red"})
|
||||||
|
} catch { Write-Log "Docker download mislukt: $($_.Exception.Message)" "Red" }
|
||||||
|
|
||||||
|
if ($dockerDownloaded) {
|
||||||
|
# Stap 9c: Phase 2 script schrijven (draait na herstart)
|
||||||
|
# Waarden worden nu ingebakken zodat het script standalone werkt
|
||||||
|
$bToken = $SwarmToken
|
||||||
|
$bManager = $SwarmManager
|
||||||
|
$bAgent = $PortainerAgent
|
||||||
|
|
||||||
|
$phase2Lines = @(
|
||||||
|
'# Atlas Docker Phase 2 — draait na herstart via geplande taak',
|
||||||
|
'$DebugDir = "C:\AtlasDebug"',
|
||||||
|
'$null = New-Item -Type Directory -Force $DebugDir -ErrorAction SilentlyContinue',
|
||||||
|
'function Log2 { param($m) $ts = Get-Date -f "s"; Add-Content "$DebugDir\setup-phases.log" "[$ts] Docker-Phase2: $m" -EA SilentlyContinue; Write-Host "[$ts] $m" }',
|
||||||
|
'Log2 "Phase 2 gestart"',
|
||||||
|
'Start-Sleep 45',
|
||||||
|
'',
|
||||||
|
'# Docker Desktop installeren',
|
||||||
|
'$dockerInst = "C:\Atlas\DockerDesktopInstaller.exe"',
|
||||||
|
'if (Test-Path $dockerInst) {',
|
||||||
|
' Log2 "Docker Desktop installeren..."',
|
||||||
|
' try {',
|
||||||
|
' $p = Start-Process $dockerInst -ArgumentList "install --quiet --accept-license --backend=wsl-2" -Wait -PassThru',
|
||||||
|
' Log2 "Docker install exitcode: $($p.ExitCode)"',
|
||||||
|
' } catch { Log2 "Docker install FAIL: $($_.Exception.Message)" }',
|
||||||
|
'} else { Log2 "DockerDesktopInstaller.exe niet gevonden op C:\Atlas\" }',
|
||||||
|
'',
|
||||||
|
'# Wacht tot Docker daemon beschikbaar is (max 5 minuten)',
|
||||||
|
'$dockerOk = $false',
|
||||||
|
'for ($i = 1; $i -le 20; $i++) {',
|
||||||
|
' Start-Sleep 15',
|
||||||
|
' try {',
|
||||||
|
' $info = & docker info 2>$null',
|
||||||
|
' if ($LASTEXITCODE -eq 0) { $dockerOk = $true; Log2 "Docker daemon actief na $($i*15)s"; break }',
|
||||||
|
' } catch {}',
|
||||||
|
' Log2 "Wacht op Docker daemon... poging $i/20"',
|
||||||
|
'}',
|
||||||
|
'',
|
||||||
|
'if ($dockerOk) {',
|
||||||
|
" # Swarm joinen (token ingebakken bij provisioning)",
|
||||||
|
" \$token = '$bToken'",
|
||||||
|
" \$manager = '$bManager'",
|
||||||
|
' Log2 "Swarm joinen op $manager..."',
|
||||||
|
' try {',
|
||||||
|
' $r = docker swarm join --token $token $manager 2>&1',
|
||||||
|
' $r | Out-File "C:\AtlasDebug\swarm-join.log" -Encoding UTF8',
|
||||||
|
' Log2 "Swarm join: $($r -join " ")"',
|
||||||
|
' } catch { Log2 "Swarm join FAIL: $($_.Exception.Message)" }',
|
||||||
|
''
|
||||||
|
)
|
||||||
|
|
||||||
|
if ($bAgent) {
|
||||||
|
$phase2Lines += @(
|
||||||
|
' # Portainer Agent starten',
|
||||||
|
' Log2 "Portainer Agent starten..."',
|
||||||
|
' try {',
|
||||||
|
' $pa = docker run -d -p 9001:9001 --name portainer_agent --restart=always `',
|
||||||
|
' -v /var/run/docker.sock:/var/run/docker.sock `',
|
||||||
|
' -v /var/lib/docker/volumes:/var/lib/docker/volumes `',
|
||||||
|
' portainer/agent:latest 2>&1',
|
||||||
|
' $pa | Out-File "C:\AtlasDebug\portainer-agent.log" -Encoding UTF8',
|
||||||
|
' Log2 "Portainer Agent: $($pa -join " ")"',
|
||||||
|
' } catch { Log2 "Portainer Agent FAIL: $($_.Exception.Message)" }'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
$phase2Lines += @(
|
||||||
|
'} else { Log2 "Docker daemon niet beschikbaar na timeout - handmatig starten via Docker Desktop" }',
|
||||||
|
'',
|
||||||
|
'# Geplande taak zichzelf verwijderen',
|
||||||
|
'Unregister-ScheduledTask -TaskName "AtlasDockerPhase2" -Confirm:$false -ErrorAction SilentlyContinue',
|
||||||
|
'Log2 "Phase 2 klaar"'
|
||||||
|
)
|
||||||
|
|
||||||
|
$phase2Path = "C:\Atlas\AtlasDockerPhase2.ps1"
|
||||||
|
$phase2Lines | Set-Content $phase2Path -Encoding UTF8
|
||||||
|
Write-Log "Phase 2 script geschreven: $phase2Path" "Green"
|
||||||
|
|
||||||
|
# Geplande taak registreren (draait bij eerste aanmelding na herstart)
|
||||||
|
try {
|
||||||
|
$action = New-ScheduledTaskAction -Execute "powershell.exe" `
|
||||||
|
-Argument "-NoProfile -ExecutionPolicy Bypass -WindowStyle Normal -File `"$phase2Path`""
|
||||||
|
$trigger = New-ScheduledTaskTrigger -AtLogOn
|
||||||
|
$settings = New-ScheduledTaskSettingsSet -ExecutionTimeLimit (New-TimeSpan -Hours 2) -MultipleInstances IgnoreNew
|
||||||
|
Register-ScheduledTask -TaskName "AtlasDockerPhase2" -Action $action -Trigger $trigger `
|
||||||
|
-RunLevel Highest -Settings $settings -Force -ErrorAction Stop | Out-Null
|
||||||
|
Write-Log "Geplande taak 'AtlasDockerPhase2' aangemaakt (draait na herstart)" "Green"
|
||||||
|
Add-Content "$DebugDir\setup-phases.log" "[$(Get-Date -f 's')] Stap 9 OK: Docker Phase 2 ingepland"
|
||||||
|
} catch {
|
||||||
|
Write-Log "Geplande taak FAIL: $($_.Exception.Message)" "Red"
|
||||||
|
Add-Content "$DebugDir\setup-phases.log" "[$(Get-Date -f 's')] Stap 9 FAIL: taak=$($_.Exception.Message)"
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Log "" "White"
|
||||||
|
Write-Log "Docker Desktop wordt geinstalleerd NA de herstart." "Yellow"
|
||||||
|
Write-Log "De taak 'AtlasDockerPhase2' draait automatisch bij aanmelding." "Yellow"
|
||||||
|
Write-Log "Logs: C:\AtlasDebug\setup-phases.log" "Cyan"
|
||||||
|
|
||||||
|
} else {
|
||||||
|
Write-Log "Docker installer niet gedownload - Phase 2 overgeslagen" "Red"
|
||||||
|
Add-Content "$DebugDir\setup-phases.log" "[$(Get-Date -f 's')] Stap 9 SKIP: download mislukt"
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
Write-Log "SWARM_JOIN=false (of niet geconfigureerd) - Docker overgeslagen" "DarkGray"
|
||||||
|
Write-Log "Desktop instellen als Swarm-worker? Zet SWARM_JOIN=true in fleet.config" "DarkGray"
|
||||||
|
Add-Content "$DebugDir\setup-phases.log" "[$(Get-Date -f 's')] Stap 9 SKIP: SWARM_JOIN niet true"
|
||||||
|
}
|
||||||
|
|
||||||
|
# =============================================================
|
||||||
|
# STAP 10: Afronden
|
||||||
|
# =============================================================
|
||||||
|
Write-Phase "STAP 10: Afronden"
|
||||||
try { Add-LocalGroupMember -SID 'S-1-5-32-544' -Member 'Atlas' -ErrorAction SilentlyContinue } catch {}
|
try { Add-LocalGroupMember -SID 'S-1-5-32-544' -Member 'Atlas' -ErrorAction SilentlyContinue } catch {}
|
||||||
net user Atlas /passwordchg:no /expires:never | Out-Null
|
net user Atlas /passwordchg:no /expires:never | Out-Null
|
||||||
net user Administrator /active:no | Out-Null
|
net user Administrator /active:no | Out-Null
|
||||||
|
|
@ -364,6 +518,7 @@ Write-Log "============================================" "Cyan"
|
||||||
Write-Log " Account: Atlas (admin, geen wachtwoord)" "Green"
|
Write-Log " Account: Atlas (admin, geen wachtwoord)" "Green"
|
||||||
Write-Log " Naam: $newName" "Green"
|
Write-Log " Naam: $newName" "Green"
|
||||||
Write-Log " Toetsenbord: $GekozenToetsenbord" "Green"
|
Write-Log " Toetsenbord: $GekozenToetsenbord" "Green"
|
||||||
|
Write-Log " Swarm: $(if($SwarmJoin){'wordt NA herstart ingepland'}else{'niet gevraagd'})" "Green"
|
||||||
Write-Log " Logs: $DebugDir\" "Green"
|
Write-Log " Logs: $DebugDir\" "Green"
|
||||||
Write-Log "" "White"
|
Write-Log "" "White"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,13 @@
|
||||||
# Atlas Fleet Config — gelezen door Setup-Laptop.ps1 tijdens Windows-installatie
|
# Atlas Fleet Config — EXAMPLE (geen echte sleutels)
|
||||||
# Hernoem naar fleet.config en vul echte key in
|
# Kopieer naar Scripts/fleet.config en vul in
|
||||||
# Genereer key via: tailscale.com/admin/settings/keys (Reusable, 90 dagen)
|
|
||||||
TAILSCALE_AUTHKEY=tskey-auth-REPLACE_WITH_REAL_KEY
|
# Tailscale auth key (genereer via tailscale.com/admin/settings/keys → Reusable, 90 days)
|
||||||
|
TAILSCALE_AUTHKEY=tskey-auth-XXXXXXXXXXXXXXXXXX
|
||||||
|
|
||||||
|
# Docker Swarm cluster
|
||||||
|
# SWARM_JOIN=false → laptop (geen Docker installatie)
|
||||||
|
# SWARM_JOIN=true → desktop (Docker Desktop + Swarm worker + Portainer Agent)
|
||||||
|
SWARM_JOIN=false
|
||||||
|
SWARM_TOKEN=SWMTKN-1-XXXXXXXXXXXXXXXXXXXXXXXX
|
||||||
|
SWARM_MANAGER=100.68.151.119:2377
|
||||||
|
PORTAINER_AGENT=true
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue