atlas-fleet/Scripts/Setup-Laptop.ps1
Atlas Corp f8c3ec4ce0 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>
2026-06-23 15:33:15 +02:00

540 lines
27 KiB
PowerShell

# =============================================================
# Atlas HP EliteBook Auto-Setup Script v4
# 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")
if (-not $global:AtlasMutex.WaitOne(0)) { exit }
$host.UI.RawUI.WindowTitle = "*** ATLAS LAPTOP SETUP - LEES DIT VENSTER ***"
$DebugDir = "C:\AtlasDebug"
$null = New-Item -Type Directory -Force $DebugDir, "C:\Atlas" -ErrorAction SilentlyContinue
$TranscriptFile = "$DebugDir\setup-transcript_$(Get-Date -Format 'yyyyMMdd_HHmmss').txt"
Start-Transcript -Path $TranscriptFile -Force -ErrorAction SilentlyContinue
$LogFile = "$DebugDir\setup-log.txt"
function Write-Log {
param([string]$Message, [string]$Color = "White")
$ts = Get-Date -Format "HH:mm:ss"
$line = "[$ts] $Message"
Write-Host $line -ForegroundColor $Color
Add-Content -Path $LogFile -Value $line -ErrorAction SilentlyContinue
}
function Write-Phase {
param([string]$Phase)
$ts = Get-Date -Format "s"
Add-Content "$DebugDir\setup-phases.log" "[$ts] $Phase" -ErrorAction SilentlyContinue
Write-Log "=== $Phase ===" "Cyan"
}
function Export-HardwareInfo {
try {
$hw = @("=== Atlas Hardware Dump ===", "Datum: $(Get-Date)", "")
$bios = Get-CimInstance Win32_BIOS -ErrorAction SilentlyContinue
$sys = Get-CimInstance Win32_ComputerSystem -ErrorAction SilentlyContinue
$cpu = Get-CimInstance Win32_Processor -ErrorAction SilentlyContinue | Select-Object -First 1
$os = Get-CimInstance Win32_OperatingSystem -ErrorAction SilentlyContinue
$hw += "Fabrikant : $($sys.Manufacturer)"
$hw += "Model : $($sys.Model)"
$hw += "Serienummer: $($bios.SerialNumber)"
$hw += "BIOS versie: $($bios.SMBIOSBIOSVersion) Datum: $($bios.ReleaseDate)"
$hw += "CPU: $($cpu.Name) Cores: $($cpu.NumberOfCores) LP: $($cpu.NumberOfLogicalProcessors)"
$hw += "RAM: $([math]::Round($sys.TotalPhysicalMemory/1GB,1)) GB totaal"
$hw += "OS: $($os.Caption) $($os.OSArchitecture) build $($os.BuildNumber)"
$editie = (Get-ItemProperty 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion' -ErrorAction SilentlyContinue).EditionID
$hw += "Editie: $editie"
$lic = Get-CimInstance SoftwareLicensingProduct -Filter "Name like 'Windows%'" -ErrorAction SilentlyContinue |
Where-Object { $_.PartialProductKey } | Select-Object -First 1
$hw += "LicenseStatus: $($lic.LicenseStatus) Key(deels): $($lic.PartialProductKey)"
$hw += ""
$hw += "=== Schijven ==="
Get-CimInstance Win32_DiskDrive -ErrorAction SilentlyContinue | ForEach-Object {
$hw += " $($_.Caption) | $([math]::Round($_.Size/1GB,0)) GB | $($_.MediaType)"
}
$hw += ""
$hw += "=== Netwerk adapters ==="
Get-NetAdapter -ErrorAction SilentlyContinue | ForEach-Object {
$hw += " $($_.Name) | $($_.InterfaceDescription) | $($_.Status) | MAC: $($_.MacAddress)"
}
$hw | Set-Content "$DebugDir\hardware-info.txt" -Encoding UTF8
Write-Log "Hardware dump: $DebugDir\hardware-info.txt" "Green"
} catch { Write-Log "Hardware dump fout: $($_.Exception.Message)" "Red" }
}
function Export-LogsToUSB {
param([string]$Label = "OK")
Write-Log "Logs exporteren naar USB..." "Cyan"
$usbDrive = $null
foreach ($d in [char[]](68..90)) {
if ((Test-Path "${d}:\Scripts\Setup-Laptop.ps1") -or
(Test-Path "${d}:\scripts\Setup-Laptop.ps1") -or
(Test-Path "${d}:\autounattend.xml")) {
$usbDrive = "${d}:\"
break
}
}
if (-not $usbDrive) {
Write-Log "USB niet gevonden voor log-export." "Yellow"
return
}
$stamp = Get-Date -Format "yyyyMMdd_HHmmss"
$name = $env:COMPUTERNAME
$destDir = "${usbDrive}AtlasLogs\${name}_${Label}_${stamp}"
$null = New-Item -Type Directory -Force $destDir -ErrorAction SilentlyContinue
Copy-Item "$DebugDir\*" $destDir -Recurse -Force -ErrorAction SilentlyContinue
Write-Log "Logs geexporteerd naar: $destDir" "Green"
Write-Log "USB mag eruit. Logs staan in AtlasLogs\ op de USB." "Green"
}
try {
Write-Phase "Atlas HP EliteBook Setup v4 Gestart"
Write-Log "Draait als: $([System.Security.Principal.WindowsIdentity]::GetCurrent().Name)" "Green"
Write-Log "Transcript: $TranscriptFile" "Green"
Export-HardwareInfo
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 {}
# =============================================================
# STAP 0: Toetsenbord kiezen
# =============================================================
Write-Phase "STAP 0: Toetsenbord kiezen"
function Set-AtlasProfileKeyboard {
param([string]$Keuze)
$hive = "C:\Users\Atlas\NTUSER.DAT"
if (-not (Test-Path $hive)) { return }
reg load "HKU\AtlasTemp" "$hive" | Out-Null
if ($LASTEXITCODE -ne 0) { return }
Start-Sleep -Milliseconds 500
if ($Keuze -eq "AZERTY") {
reg add "HKU\AtlasTemp\Keyboard Layout\Preload" /v "1" /t REG_SZ /d "0000080c" /f | Out-Null
reg add "HKU\AtlasTemp\Keyboard Layout\Preload" /v "2" /t REG_SZ /d "00020409" /f | Out-Null
} else {
reg add "HKU\AtlasTemp\Keyboard Layout\Preload" /v "1" /t REG_SZ /d "00020409" /f | Out-Null
reg add "HKU\AtlasTemp\Keyboard Layout\Preload" /v "2" /t REG_SZ /d "0000080c" /f | Out-Null
}
[gc]::Collect(); Start-Sleep -Seconds 1; reg unload "HKU\AtlasTemp" | Out-Null
}
function Set-KeyboardLayout {
Write-Host ""
Write-Host " =============================================" -ForegroundColor Cyan
Write-Host " KIES HET STANDAARD TOETSENBORD" -ForegroundColor Cyan
Write-Host " =============================================" -ForegroundColor Cyan
Write-Host " [1] = AZERTY (Belgisch) [2] = QWERTY (US-Internationaal)" -ForegroundColor White
Write-Host " Geen keuze binnen 60 sec = QWERTY" -ForegroundColor DarkGray
Write-Host ""
$keuze = $null
try {
$deadline = (Get-Date).AddSeconds(60)
while (-not $keuze -and (Get-Date) -lt $deadline) {
if ($Host.UI.RawUI.KeyAvailable) {
$k = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
switch ($k.VirtualKeyCode) {
49 { $keuze = "AZERTY" }; 97 { $keuze = "AZERTY" }
50 { $keuze = "QWERTY" }; 98 { $keuze = "QWERTY" }
}
}
Start-Sleep -Milliseconds 150
}
} catch {}
if (-not $keuze) { $keuze = "QWERTY" }
try {
$az = "080C:0000080C"; $qw = "0409:00020409"
$list = New-WinUserLanguageList -Language "nl-NL"
$list[0].InputMethodTips.Clear()
if ($keuze -eq "AZERTY") {
$list[0].InputMethodTips.Add($az); $list[0].InputMethodTips.Add($qw); $def = $az
} else {
$list[0].InputMethodTips.Add($qw); $list[0].InputMethodTips.Add($az); $def = $qw
}
Set-WinUserLanguageList $list -Force
Set-WinDefaultInputMethodOverride -InputTip $def -ErrorAction SilentlyContinue
} catch { Write-Log "Toetsenbord fout: $($_.Exception.Message)" "Red" }
return $keuze
}
$GekozenToetsenbord = Set-KeyboardLayout
Write-Log "Toetsenbord: $GekozenToetsenbord" "Green"
Set-AtlasProfileKeyboard -Keuze $GekozenToetsenbord
Add-Content "$DebugDir\setup-phases.log" "[$(Get-Date -f 's')] Stap 0 OK: kb=$GekozenToetsenbord"
# =============================================================
# STAP 1: WiFi
# =============================================================
Write-Phase "STAP 1: WiFi"
$WifiNaam = "MET_Wifi"; $WifiWW = "Metmet2021"
$WifiXml = "<?xml version=`"1.0`"?><WLANProfile xmlns=`"http://www.microsoft.com/networking/WLAN/profile/v1`"><name>$WifiNaam</name><SSIDConfig><SSID><name>$WifiNaam</name></SSID></SSIDConfig><connectionType>ESS</connectionType><connectionMode>auto</connectionMode><MSM><security><authEncryption><authentication>WPA2PSK</authentication><encryption>AES</encryption><useOneX>false</useOneX></authEncryption><sharedKey><keyType>passPhrase</keyType><protected>false</protected><keyMaterial>$WifiWW</keyMaterial></sharedKey></security></MSM></WLANProfile>"
$pf = "C:\Windows\Temp\MET_Wifi.xml"; $WifiXml | Out-File $pf -Encoding ASCII
$wifiOk = $false
try {
Set-Service WlanSvc -StartupType Automatic -ErrorAction SilentlyContinue
Start-Service WlanSvc -ErrorAction SilentlyContinue
Start-Sleep 3
$wa = Get-NetAdapter -ErrorAction SilentlyContinue |
Where-Object { $_.PhysicalMediaType -match 'Native 802.11|Wireless' -or $_.InterfaceDescription -match 'Wi-Fi|Wireless|WLAN' }
if ($wa) { Write-Log "WiFi adapter: $($wa.InterfaceDescription)" "Green" }
else { Write-Log "GEEN WiFi adapter gevonden" "Red" }
netsh wlan add profile filename="$pf" | Out-Null
for ($i=1; $i -le 6 -and -not $wifiOk; $i++) {
netsh wlan connect name="$WifiNaam" | Out-Null; Start-Sleep 8
$wifiOk = [bool](Get-NetConnectionProfile -ErrorAction SilentlyContinue |
Where-Object { $_.IPv4Connectivity -eq "Internet" })
if (-not $wifiOk) { Write-Log "WiFi poging $i: geen internet" "Yellow" }
}
Write-Log "WiFi: $(if($wifiOk){'verbonden'}else{'MISLUKT'})" $(if($wifiOk){"Green"}else{"Red"})
} catch { Write-Log "WiFi fout: $($_.Exception.Message)" "Red" }
if (Test-Path $pf) { [System.IO.File]::Delete($pf) }
Add-Content "$DebugDir\setup-phases.log" "[$(Get-Date -f 's')] Stap 1: WiFi=$wifiOk"
# =============================================================
# STAP 2: Windows Update
# =============================================================
Write-Phase "STAP 2: Windows Update"
Set-Service wuauserv -StartupType Automatic -ErrorAction SilentlyContinue
Start-Service wuauserv -ErrorAction SilentlyContinue
Write-Log "Windows Update actief" "Green"
Add-Content "$DebugDir\setup-phases.log" "[$(Get-Date -f 's')] Stap 2 OK"
# =============================================================
# STAP 3: HP Image Assistant
# =============================================================
Write-Phase "STAP 3: HP Image Assistant"
$HPIAPath = "C:\Windows\Temp\HPIA"
New-Item -Type Directory -Force $HPIAPath | Out-Null
$HPIALocs = @('C:\Atlas\HPImageAssistant.exe')
foreach ($d in [char[]](68..90)) {
$HPIALocs += "${d}:\Scripts\HPImageAssistant.exe"
$HPIALocs += "${d}:\scripts\HPImageAssistant.exe"
}
$HPIALauncher = $HPIALocs | Where-Object { $_ -and (Test-Path $_) } | Select-Object -First 1
if ($HPIALauncher) {
Write-Log "HPIA gevonden: $HPIALauncher" "Green"
Start-Process $HPIALauncher -ArgumentList "/s /e /f `"$HPIAPath`"" -Wait
} else {
Write-Log "HPIA downloaden van HP..." "Yellow"
try {
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
Invoke-WebRequest "https://ftp.hp.com/pub/caps-softpaq/cmit/HPIA.exe" -OutFile "$HPIAPath\HPIA_installer.exe" -UseBasicParsing -TimeoutSec 120
Start-Process "$HPIAPath\HPIA_installer.exe" -ArgumentList "/s /e /f `"$HPIAPath`"" -Wait
} catch { Write-Log "HPIA download mislukt: $($_.Exception.Message)" "Red" }
}
$HPIAExe = (Get-ChildItem $HPIAPath -Filter "HPImageAssistant.exe" -Recurse -ErrorAction SilentlyContinue |
Sort-Object Length -Descending | Select-Object -First 1).FullName
if ($HPIAExe) {
Write-Log "HPIA uitvoeren (10-20 min)..." "Yellow"
$rpt = "$HPIAPath\Report"; New-Item -Type Directory -Force $rpt | Out-Null
$p = Start-Process $HPIAExe -ArgumentList @("/Operation:Analyze","/Action:Install","/Selection:All",
"/Silent","/Category:Drivers","/ReportFolder:`"$rpt`"") -Wait -PassThru -NoNewWindow
Write-Log "HPIA exitcode: $($p.ExitCode)" $(if($p.ExitCode -le 1){"Green"}else{"Yellow"})
Copy-Item $rpt "$DebugDir\HPIA-report" -Recurse -Force -ErrorAction SilentlyContinue
Add-Content "$DebugDir\setup-phases.log" "[$(Get-Date -f 's')] Stap 3 OK: HPIA=$($p.ExitCode)"
} else {
Write-Log "HPIA niet gevonden - install drivers handmatig via hp.com/support" "Red"
Add-Content "$DebugDir\setup-phases.log" "[$(Get-Date -f 's')] Stap 3 FAIL: HPIA niet gevonden"
}
# =============================================================
# STAP 4: Windows activering
# =============================================================
Write-Phase "STAP 4: Windows activering"
$lic = Get-CimInstance SoftwareLicensingProduct -Filter "Name like 'Windows%'" -ErrorAction SilentlyContinue |
Where-Object { $_.PartialProductKey } | Select-Object -First 1
if ($lic.LicenseStatus -eq 1) { Write-Log "Geactiveerd (digitale licentie)" "Green" }
else {
Write-Log "Activeren via HWID..." "Yellow"
Start-Process cscript.exe -ArgumentList "//B //Nologo $env:windir\System32\slmgr.vbs /ato" -Wait -WindowStyle Hidden
$lic2 = Get-CimInstance SoftwareLicensingProduct -Filter "Name like 'Windows%'" -ErrorAction SilentlyContinue |
Where-Object { $_.PartialProductKey } | Select-Object -First 1
Write-Log "Activering: $($lic2.LicenseStatus) (1=OK)" $(if($lic2.LicenseStatus -eq 1){"Green"}else{"Yellow"})
}
Add-Content "$DebugDir\setup-phases.log" "[$(Get-Date -f 's')] Stap 4 OK: lic=$($lic.LicenseStatus)"
# =============================================================
# STAP 5: Systeem optimaliseren
# =============================================================
Write-Phase "STAP 5: Systeem optimaliseren"
reg add "HKLM\SOFTWARE\Policies\Microsoft\Windows\Windows Search" /v "AllowCortana" /t REG_DWORD /d 0 /f | Out-Null
reg add "HKLM\SOFTWARE\Policies\Microsoft\Windows\DataCollection" /v "AllowTelemetry" /t REG_DWORD /d 0 /f | Out-Null
reg add "HKLM\SOFTWARE\Policies\Microsoft\Windows\OneDrive" /v "DisableFileSyncNGSC" /t REG_DWORD /d 1 /f | Out-Null
Write-Log "Cortana/telemetrie/OneDrive uitgeschakeld" "Green"
Add-Content "$DebugDir\setup-phases.log" "[$(Get-Date -f 's')] Stap 5 OK"
# =============================================================
# STAP 6: Computernaam via serienummer
# =============================================================
Write-Phase "STAP 6: Computernaam"
$newName = "ATLAS-UNKNOWN"
try {
$serial = (Get-CimInstance Win32_BIOS -ErrorAction SilentlyContinue).SerialNumber -replace '[^A-Z0-9]',''
$suffix = if ($serial -and $serial.Length -ge 4) {
$serial.Substring([Math]::Max(0, $serial.Length - 6))
} else {
-join ((65..90) | Get-Random -Count 6 | ForEach-Object { [char]$_ })
}
$newName = "ATLAS-$suffix"
Rename-Computer -NewName $newName -Force -ErrorAction Stop
Write-Log "Naam: $newName (serial: $serial)" "Green"
Add-Content "$DebugDir\setup-phases.log" "[$(Get-Date -f 's')] Stap 6 OK: naam=$newName"
} catch {
Write-Log "Naam instellen mislukt: $($_.Exception.Message)" "Red"
Add-Content "$DebugDir\setup-phases.log" "[$(Get-Date -f 's')] Stap 6 FAIL: $($_.Exception.Message)"
}
# =============================================================
# STAP 7: Fleet config lezen
# =============================================================
Write-Phase "STAP 7: Fleet config"
$FleetConfig = $null
foreach ($d in [char[]](65..90)) {
foreach ($sub in @('Scripts','scripts')) {
$p = "${d}:\${sub}\fleet.config"
if (Test-Path $p) { $FleetConfig = $p; break }
}
if ($FleetConfig) { break }
}
if (-not $FleetConfig -and (Test-Path 'C:\Atlas\fleet.config')) { $FleetConfig = 'C:\Atlas\fleet.config' }
$TsKey = ""
$SwarmJoin = $false
$SwarmToken = ""
$SwarmManager = ""
$PortainerAgent = $false
if ($FleetConfig) {
$cfg = Get-Content $FleetConfig -ErrorAction SilentlyContinue
$TsKey = ($cfg | Where-Object { $_ -match '^TAILSCALE_AUTHKEY=' }) -replace '^TAILSCALE_AUTHKEY=',''
$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" }
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
try {
$tsInst = "C:\Windows\Temp\tailscale-setup.exe"
Write-Log "Tailscale downloaden..." "Yellow"
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
Invoke-WebRequest "https://pkgs.tailscale.com/stable/tailscale-setup-latest.exe" -OutFile $tsInst -UseBasicParsing -TimeoutSec 120
Start-Process $tsInst -ArgumentList "/install /quiet /norestart" -Wait
Start-Sleep 8
if ($TsKey) {
& "C:\Program Files\Tailscale\tailscale.exe" up --authkey=$TsKey --hostname="$newName" --accept-routes 2>&1 |
ForEach-Object { Write-Log " TS: $_" "Cyan" }
}
[System.IO.File]::Delete($tsInst)
Write-Log "Tailscale OK" "Green"
Add-Content "$DebugDir\setup-phases.log" "[$(Get-Date -f 's')] Stap 8a OK: Tailscale"
} catch {
Write-Log "Tailscale FAIL: $($_.Exception.Message)" "Red"
Add-Content "$DebugDir\setup-phases.log" "[$(Get-Date -f 's')] Stap 8a FAIL: $($_.Exception.Message)"
}
# MeshCentral
try {
$meshUrl = "http://100.93.16.81:4433/meshagents?id=3&meshid=@OfhMz3DBvRqrV8eZLhEi5PaRSBuMG5DHdwkY9A9oqXfzT3oNz1UOH3TLPRxIc0Ix&installflags=0&meshinstall=6"
$meshInst = "C:\Windows\Temp\meshagent-install.exe"
Write-Log "MeshCentral downloaden..." "Yellow"
Invoke-WebRequest $meshUrl -OutFile $meshInst -UseBasicParsing -TimeoutSec 60
Start-Process $meshInst -ArgumentList "-fullinstall" -Wait
[System.IO.File]::Delete($meshInst)
Write-Log "MeshCentral OK" "Green"
Add-Content "$DebugDir\setup-phases.log" "[$(Get-Date -f 's')] Stap 8b OK: MeshCentral"
} catch {
Write-Log "MeshCentral FAIL: $($_.Exception.Message)" "Red"
Add-Content "$DebugDir\setup-phases.log" "[$(Get-Date -f 's')] Stap 8b FAIL: $($_.Exception.Message)"
}
# =============================================================
# 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 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 {}
net user Atlas /passwordchg:no /expires:never | Out-Null
net user Administrator /active:no | Out-Null
Write-Log "Administrator uitgeschakeld" "Green"
reg add "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon" /v "AutoAdminLogon" /t REG_SZ /d "0" /f | Out-Null
reg delete "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon" /v "DefaultPassword" /f 2>$null | Out-Null
try { Unregister-ScheduledTask -TaskName "AtlasSetup" -Confirm:$false -ErrorAction SilentlyContinue } catch {}
Add-Content "$DebugDir\setup-phases.log" "[$(Get-Date -f 's')] SETUP VOLTOOID"
Write-Log "" "White"
Write-Log "============================================" "Cyan"
Write-Log " SETUP VOLTOOID" "Green"
Write-Log "============================================" "Cyan"
Write-Log " Account: Atlas (admin, geen wachtwoord)" "Green"
Write-Log " Naam: $newName" "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 "" "White"
Export-LogsToUSB -Label "OK"
} catch {
$em = $_.Exception.Message; $st = $_.ScriptStackTrace
Write-Log "!!! SCRIPT CRASH: $em" "Red"
Write-Log $st "Red"
Add-Content "$DebugDir\setup-phases.log" "[$(Get-Date -f 's')] CRASH: $em"
"$($PSVersionTable.PSVersion)`n$(Get-Date)`n$em`n$st" | Set-Content "$DebugDir\setup-crash.txt"
Export-LogsToUSB -Label "CRASH"
Write-Log "Crash logs op USB. Stuur AtlasLogs map door." "Yellow"
Start-Sleep 30
}
Stop-Transcript -ErrorAction SilentlyContinue
Start-Sleep 15
Restart-Computer -Force