From 34b33c5011e1c39a12c88e42b9601f47bf7e9877 Mon Sep 17 00:00:00 2001 From: Simone Date: Sun, 10 May 2026 15:58:57 +0200 Subject: [PATCH] =?UTF-8?q?fix(winrm-https):=20PS=205.1=20Test-WSMan=20has?= =?UTF-8?q?=20no=20-SessionOption=20=E2=80=94=20remove=20from=20all=20call?= =?UTF-8?q?=20sites?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Test-WSMan in Windows PowerShell 5.1 does not support -SessionOption (WSManSessionOption), causing "Cannot find a parameter matching the name 'SessionOption'" at runtime. Prepare-WinBuild2025.ps1: - Remove Test-WSMan connectivity check step entirely - Open New-PSSession directly (handles -SkipCACheck via PSSessionOption) - Wrap New-PSSession in try/catch with the same actionable error message - Remove $wsmOpt (WSManSessionOption) — no longer needed Wait-GuestWinRMReady: replace Test-WSMan probe with New-PSSession probe + Remove-PSSession Wait-VMReady.ps1: - Remove $wsmOpt entirely - Replace Test-WSMan -UseSSL -SessionOption with Test-NetConnection -Port 5986 (TCP open on 5986 = HTTPS listener up = VM ready; credentials not available here) Co-Authored-By: Claude Sonnet 4.6 --- TODO.md | 112 +++++++++++++++++++----------- scripts/Wait-VMReady.ps1 | 14 ++-- template/Prepare-WinBuild2025.ps1 | 51 ++++++-------- 3 files changed, 101 insertions(+), 76 deletions(-) diff --git a/TODO.md b/TODO.md index 1a6d090..1657057 100644 --- a/TODO.md +++ b/TODO.md @@ -16,7 +16,35 @@ > - **P3** — estensioni nice-to-have --- +## Summary +_Last updated: 2026-05-10 (post §7.4 e2e + tag v1.2)_ + +**Stato generale**: infrastruttura base e refactor Deploy↔Setup (§7) completi. Sicurezza sprint 1 in corso (HTTPS/5986 done, IP regex done, hash pinning struttura done — valori da riempire). Backlog operatività/perf/qualità intatto. + +| Area | Done | Open | Note | +| ------------------------------- | ---: | ---: | ----------------------------------------------------------------- | +| Setup & Infrastructure | all | 0 | Gitea + runner + dirs + rete tutti operativi | +| Template VM (Fasi A→D) | all | 0 | Snapshot `BaseClean` preso, credenziali in Credential Manager | +| Scripts Verification | all | 0 | e2e-008/009 SUCCESS, cleanup orfani + retry deleteVM ok | +| Runner Configuration | all | 0 | `config.yaml`, capacity 4, `BuildVMGuest` | +| Gitea Workflow Integration | 4 | 1 | manca solo §P3 generalizzazione workflow | +| §1 Sicurezza & hardening | 2 | 6 | 1.1, 1.4 done; 1.2/1.3 parzialmente; 1.5/1.6/1.7/1.8 da fare | +| §2 Affidabilità & resilienza | 0 | 7 | tutto backlog (race IP, cleanup schedulato, snapshot versionato…) | +| §3 Performance & throughput | 0 | 6 | nessuna ottimizzazione applicata; baseline §3.6 prerequisito | +| §4 Osservabilità & manutenzione | 0 | 5 | log JSONL, metriche, runbook tutti aperti | +| §5 Qualità codice & test | 0 | 5 | Pester, modulo `_Common.psm1`, regole PSScriptAnalyzer custom | +| §6 Scalabilità & estensioni | 0 | 6 | Linux VM, composite action, toolchain Tier-1 | +| §7 Refactor Deploy ↔ Setup | 4 | 1 | 7.1/7.2/7.3/7.4 done; 7.5 (rinomina) opzionale | +| In-VM Git Clone (§3.3) | 0 | 4 | dipende da §6.6 (Git+7-Zip nel template) | +| Linux Build VM (§6.1) | 0 | 4 | bozza in `docs/LINUX-TEMPLATE-SETUP.md` | + +**Prossimi passi consigliati** (vedi anche "Suggerimento di sequencing" in fondo): +1. Chiudere §1.3 — riempire hash SHA256 in `Setup-WinBuild2025.ps1` prima del prossimo refresh snapshot. +2. Audit §1.2 (TrustedHosts `*` su host), poi §1.7 (rotazione password guest). +3. Sprint 2 operatività — §2.2 (cleanup schedulato), §2.3 (retention), §2.5 (snapshot versionato). + +--- ## Setup & Infrastructure - [x] **Gitea Server** — già in esecuzione su `http://10.10.20.11:3100` (e `https://gitea.emulab.it`) @@ -148,7 +176,7 @@ ## 1. Sicurezza & hardening -### 1.1 [P0] Migrare WinRM da HTTP/Basic a HTTPS/5986 — COMPLETATO 2026-05-10 +### 1.1 [P0] [x] Migrare WinRM da HTTP/Basic a HTTPS/5986 — COMPLETATO 2026-05-10 **Azioni**: - [x] Generare cert self-signed nel template *prima* dello snapshot (già in Deploy post-install.ps1). @@ -160,7 +188,7 @@ - [x] `Prepare-WinBuild2025.ps1`: preflight TCP/5986, host non imposta più `AllowUnencrypted`; solo `TrustedHosts` viene salvato/ripristinato. - [x] `Validate-DeployState.ps1`, `Validate-SetupState.ps1`: connessione HTTPS/5986, check `AllowUnencrypted=false`. -### 1.2 [P0] Restringere `TrustedHosts` lato host (audit-only — già coperto) +### 1.2 [P0] [ ] Restringere `TrustedHosts` lato host (audit-only — residuo: audit host pre-esistenti) File: nessuno script imposta `*` sull'host. Stato corrente: - `Setup-Host.ps1` non tocca TrustedHosts (verificato 2026-05-10) - [template/Prepare-WinBuild2025.ps1](template/Prepare-WinBuild2025.ps1) appende `$VMIPAddress` ai `TrustedHosts` e ripristina nel `finally` (post-§1.1: solo TrustedHosts, no AllowUnencrypted) @@ -172,7 +200,7 @@ sostituire con la subnet build: Set-Item WSMan:\localhost\Client\TrustedHosts -Value '192.168.79.*' -Force -Concatenate ``` -### 1.3 [P0] Pinning hash SHA256 degli installer — STRUTTURA AGGIUNTA 2026-05-10 +### 1.3 [P0] [ ] Pinning hash SHA256 degli installer — STRUTTURA AGGIUNTA 2026-05-10 (valori da riempire) `$script:Hashes` + `Assert-Hash` aggiunti a [template/Setup-WinBuild2025.ps1](template/Setup-WinBuild2025.ps1). `Assert-Hash` viene chiamato dopo ogni download (dotnet-install.ps1, python installer, vs_buildtools.exe). @@ -188,14 +216,14 @@ Se l'hash è `''` viene emesso un warning ma l'esecuzione continua (non-breaking ``` - [ ] Verificare che `Assert-Hash` throwi correttamente su hash errato (test con hash fake). -### 1.4 [P1] Validazione IP per-ottetto — COMPLETATO 2026-05-10 +### 1.4 [P1] [x] Validazione IP per-ottetto — COMPLETATO 2026-05-10 Regex per-ottetto sostituita in tutti e 4 i file: `'^((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)\.){3}(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)$'` Estrazione in `scripts/_Common.psm1` — vedi §5.2 (P2, backlog). -### 1.5 [P1] PAT mai persistito quando si abilita `-UseGitClone` +### 1.5 [P1] [ ] PAT mai persistito quando si abilita `-UseGitClone` Requisiti di sicurezza per l'implementazione del clone in-VM. La sequenza operativa (quando, dove, come) è dettagliata nella sezione "In-VM Git Clone (Ottimizzazione) — riferimento §3.3". @@ -207,7 +235,7 @@ Vincoli da rispettare in qualsiasi implementazione di `-UseGitClone`: `transcript.txt`, marcare la build come fallita e ruotare il PAT (regola di safety net, non sostituisce le precedenti). -### 1.6 [P2] Defender + Firewall + UAC tutti disattivati nel template — documentare il modello di minaccia +### 1.6 [P2] [ ] Defender + Firewall + UAC tutti disattivati nel template — documentare il modello di minaccia File: [template/Deploy-WinBuild2025.ps1:485-551](template/Deploy-WinBuild2025.ps1) (UAC, ServerManager, DisableCAD, OOBE — set da Deploy), [template/Setup-WinBuild2025.ps1:176-336](template/Setup-WinBuild2025.ps1) (Firewall Step 1, Defender Step 2 validation-only post-refactor 2026-05-09, WinRM Step 3, User Step 4, UAC Step 4b, Dirs Step 5). Stato attuale (post-refactor §7): @@ -226,11 +254,11 @@ Le scelte sono ragionevoli per un template lab efimero, ma vanno raccolte in un' Senza questa nota, future modifiche possono accumulare ulteriori riduzioni di sicurezza senza tracciamento. -### 1.7 [P2] Rotazione password guest VM +### 1.7 [P2] [ ] Rotazione password guest VM - [ ] Trimestrale. Aggiornare credenziale `BuildVMGuest` in Credential Manager + password effettiva nel template (richiede refresh snapshot — coordinare con §2.5). -### 1.8 [P2] Verifica Get-StoredCredential +### 1.8 [P2] [ ] Verifica Get-StoredCredential - [ ] Confermare che `Get-StoredCredential` funzioni correttamente in tutti gli script che lo usano (post-migrazione HTTPS). @@ -238,7 +266,7 @@ senza tracciamento. ## 2. Affidabilità & resilienza -### 2.1 [P0] Race su IP allocation con `capacity: 4` +### 2.1 [P0] [ ] Race su IP allocation con `capacity: 4` File: [runner/config.yaml:17](runner/config.yaml), [scripts/Invoke-CIJob.ps1:244-253](scripts/Invoke-CIJob.ps1). **Stato osservato**: race non riprodotta in e2e-008/009 (un job alla volta). `capacity: 4` @@ -259,7 +287,7 @@ rilevata in fase di Wait-VMReady — apparirà come "WinRM risponde ma è la VM L'opzione A è la più portabile e si integra con il pre-warm pool (§3.4). -### 2.2 [P1] Cleanup orfani schedulato +### 2.2 [P1] [ ] Cleanup orfani schedulato File: [scripts/Cleanup-OrphanedBuildVMs.ps1](scripts/Cleanup-OrphanedBuildVMs.ps1) — script pronto, manca lo scheduling. Estendere `Setup-Host.ps1` per registrare un Task Scheduler: @@ -273,7 +301,7 @@ Register-ScheduledTask -TaskName 'CI-CleanupOrphans' -Action $action -Trigger $t Aggiungere anche un trigger `AtStartup` per gestire crash dell'host. Suggerito: ogni 6 ore, `-MaxAgeHours 4`. -### 2.3 [P1] Retention artifact + log automatica +### 2.3 [P1] [ ] Retention artifact + log automatica File: [docs/OPTIMIZATION.md:160-181](docs/OPTIMIZATION.md) — la logica c'è solo come snippet, non eseguita. Stessa pattern di §2.2 ma su `F:\CI\Artifacts` con `-AddDays(-30)` e su `F:\CI\Logs` con la @@ -281,13 +309,13 @@ finestra già configurata in `Invoke-CIJob.ps1`. Aggiungere `Get-PSDrive F | Where-Object { $_.Free -lt 50GB }` come *guard*: se libero < 50 GB, retention più aggressiva (7 giorni) e log warning. -### 2.4 [P1] `Remove-BuildVM.ps1` — supportare `-WhatIf` +### 2.4 [P1] [ ] `Remove-BuildVM.ps1` — supportare `-WhatIf` File: [scripts/Remove-BuildVM.ps1:28](scripts/Remove-BuildVM.ps1). Aggiungere `[CmdletBinding(SupportsShouldProcess)]` come fatto in `Cleanup-OrphanedBuildVMs.ps1`. Permette debug e dry-run senza forkare un secondo script. -### 2.5 [P1] Snapshot versionato `BaseClean_` +### 2.5 [P1] [ ] Snapshot versionato `BaseClean_` File: [docs/BEST-PRACTICES.md:142-145](docs/BEST-PRACTICES.md), [scripts/Invoke-CIJob.ps1:100](scripts/Invoke-CIJob.ps1). **Motivazione**: quando si refresha il template (KMS lease semestrale, update toolchain), il @@ -303,13 +331,13 @@ e non c'è rollback. Si lega al task: refresh semestrale snapshot template VM (KMS lease = 180 giorni). Boot template su VMnet8 (NAT) → `slmgr /ato` → nuovo snapshot. -### 2.6 [P2] Backup automatico VMDK template +### 2.6 [P2] [ ] Backup automatico VMDK template File: [docs/BEST-PRACTICES.md:130-138](docs/BEST-PRACTICES.md) — solo come snippet manuale. Pre-snapshot: copia atomica del `parent` VMDK in `F:\CI\Backups\Template_\`. Su errore di refresh (es. installer rotto), rollback in 1 minuto. -### 2.7 [P2] Health check del runner + monitoraggio Event Log +### 2.7 [P2] [ ] Health check del runner + monitoraggio Event Log File: [docs/BEST-PRACTICES.md:101-115](docs/BEST-PRACTICES.md) — script presente in doc, non operativo. Schedulare ogni 15 min: query `gitea/api/v1/admin/runners`, se `local-windows-runner` non @@ -322,7 +350,7 @@ EventLog query schedulata o webhook). ## 3. Performance & throughput -### 3.1 [P1] NuGet/pip cache su shared folder +### 3.1 [P1] [ ] NuGet/pip cache su shared folder File: [docs/OPTIMIZATION.md:93-128](docs/OPTIMIZATION.md), [scripts/Invoke-RemoteBuild.ps1:158-194](scripts/Invoke-RemoteBuild.ps1). **Motivazione**: `F:\CI\Cache\NuGet` esiste come dir, non viene mai usata. @@ -343,7 +371,7 @@ $env:PIP_CACHE_DIR = '\\vmware-host\Shared Folders\pip-cache' ``` Dopo lo snapshot refresh la cache va riscaldata una volta — accettabile. -### 3.2 [P1] Sostituire `Compress-Archive` con 7-Zip o robocopy +### 3.2 [P1] [ ] Sostituire `Compress-Archive` con 7-Zip o robocopy File: [scripts/Invoke-RemoteBuild.ps1:112,148,185](scripts/Invoke-RemoteBuild.ps1) (3 chiamate `Compress-Archive`). Prerequisito: 7-Zip nel template — vedi §6.6 e sezione "In-VM Git Clone". @@ -361,12 +389,12 @@ può prendere 20-40 s. Misurare con un repo reale: probabile risparmio 10-20 s/build su `nsis-plugin-nsinnounp`. -### 3.3 [P2] In-VM clone (`-UseGitClone`) +### 3.3 [P2] [ ] In-VM clone (`-UseGitClone`) Implementazione disegnata di seguito (sezione "In-VM Git Clone (Ottimizzazione)"). Vincoli sicurezza PAT: vedi §1.5. Tool prerequisiti (Git, 7-Zip): vedi §6.6. Beneficio reale solo per repo > 200 MB con submoduli grandi; misurare prima. -### 3.4 [P3] Pre-warm pool di cloni +### 3.4 [P3] [ ] Pre-warm pool di cloni File: [docs/OPTIMIZATION.md:133-156](docs/OPTIMIZATION.md). Solo se profilo dimostra che `New-BuildVM` + `Wait-VMReady` (~30-60 s) è il collo di bottiglia. @@ -376,7 +404,7 @@ Implementazione minima: scheduled task ogni 5 min mantiene 2 cloni avviati in `F:\CI\WarmPool\`; `Invoke-CIJob` fa `Move-Item` di un clone caldo nel suo job dir e parte da Phase 4 saltando Phase 2-3. -### 3.5 [P2] vCPU/RAM tuning per workload +### 3.5 [P2] [ ] vCPU/RAM tuning per workload File: [docs/OPTIMIZATION.md:82-89](docs/OPTIMIZATION.md), VMX template. `numvcpus=4`, `memsize=6144` è ragionevole ma non ottimo per ogni build. Per @@ -386,14 +414,14 @@ Considerare: - VMX pinning: 6 vCPU per build C++ pesanti, 2 vCPU per build .NET piccoli. - Esporre `-VMCpu` / `-VMMemory` a `Invoke-CIJob.ps1` con override via workflow. -### 3.6 [P2] Benchmark baseline +### 3.6 [P2] [ ] Benchmark baseline - [ ] Tempo creazione clone + tempo WinRM readiness (per stabilire baseline prima di §3.1/3.2/3.4). --- ## 4. Osservabilità & manutenzione -### 4.1 [P1] Log strutturati per parsing +### 4.1 [P1] [ ] Log strutturati per parsing File: [scripts/Invoke-CIJob.ps1:178-187](scripts/Invoke-CIJob.ps1). **Motivazione**: i log attuali sono `Write-Host` testuale. Per dashboard / alerting servono @@ -416,7 +444,7 @@ function Write-JobEvent { Emettere in ogni transizione di fase. Permette grafici (durata media per fase, tasso di fallimento) con `jq` o Loki/Grafana se in futuro. -### 4.2 [P2] Metriche su Prometheus textfile +### 4.2 [P2] [ ] Metriche su Prometheus textfile Generare `F:\CI\Metrics\runner.prom` da uno scheduled task ogni 60s: ``` ci_runner_orphan_vms 0 @@ -427,13 +455,13 @@ ci_runner_active_jobs 1 Se l'homelab ha già Prometheus + node_exporter, basta `--collector.textfile.directory=F:\CI\Metrics`. -### 4.3 [P1] Disk space alert +### 4.3 [P1] [ ] Disk space alert File: estendere `Setup-Host.ps1` o creare `scripts/Watch-DiskSpace.ps1`. `F:` riempito = build silenziosamente fallite (linked clone fallirà su `vmrun clone` con messaggi criptici). Alert via `eventcreate` o webhook Gitea/Discord quando libero < 50 GB. -### 4.4 [P2] Runbook per incident comuni +### 4.4 [P2] [ ] Runbook per incident comuni File: nuovo `docs/RUNBOOK.md`. Documentare con copy-pasta: @@ -444,7 +472,7 @@ Documentare con copy-pasta: Ogni voce: sintomo, comando di triage, fix, escalation. -### 4.5 [P3] Dashboard read-only +### 4.5 [P3] [ ] Dashboard read-only Una pagina HTML statica generata da `Invoke-CIJob.ps1` (append a `F:\CI\dashboard.html`) con ultime 50 build, durata, esito, link agli artifact. Servita da IIS Express o solo file:// — utile per debug a colpo d'occhio senza aprire Gitea UI. @@ -453,7 +481,7 @@ file:// — utile per debug a colpo d'occhio senza aprire Gitea UI. ## 5. Qualità codice & test -### 5.1 [P1] Pester smoke tests sugli script +### 5.1 [P1] [ ] Pester smoke tests sugli script File: nuovo `tests/` directory. **Motivazione**: manca un livello di test sotto l'e2e. @@ -467,7 +495,7 @@ Pester può coprire: Eseguire in CI tramite il runner stesso (workflow `lint.yml` esiste già — espandere). -### 5.2 [P2] Modulo PowerShell condiviso `scripts/_Common.psm1` +### 5.2 [P2] [ ] Modulo PowerShell condiviso `scripts/_Common.psm1` **Duplicazioni da estrarre**: - `New-PSSessionOption -SkipCACheck -SkipCNCheck -SkipRevocationCheck` (3 file). - `ValidatePattern` IP (4 file — vedi §1.4). @@ -477,7 +505,7 @@ Eseguire in CI tramite il runner stesso (workflow `lint.yml` esiste già — esp Risultato: meno LoC, fix in un punto solo, più facile da testare. -### 5.3 [P2] Esecuzione `vmrun` con check exit code uniforme +### 5.3 [P2] [ ] Esecuzione `vmrun` con check exit code uniforme Pattern attuale ripetuto in tutti gli script che invocano `vmrun`: ```powershell $out = & $VmrunPath ... 2>&1 @@ -486,7 +514,7 @@ if ($LASTEXITCODE -ne 0) { throw "..." } Wrapping in `Invoke-VmrunCommand -Operation 'clone' -Args @(...)` riduce errori di copy-paste e centralizza retry/log. -### 5.4 [P2] PSScriptAnalyzer rules custom +### 5.4 [P2] [ ] PSScriptAnalyzer rules custom File: [gitea/workflows/lint.yml](gitea/workflows/lint.yml) (già esiste). Aggiungere regole specifiche progetto (`PSScriptAnalyzerSettings.psd1` in root): @@ -495,7 +523,7 @@ Aggiungere regole specifiche progetto (`PSScriptAnalyzerSettings.psd1` in root): - `PSUseShouldProcessForStateChangingFunctions`. - Regole custom: vietare hardcoded `F:\CI\` fuori da config (forzare param/env). -### 5.5 [P3] Type hints nei param block +### 5.5 [P3] [ ] Type hints nei param block Già parzialmente fatto. Estendere a tutti gli script per migliorare IntelliSense e validazione runtime. @@ -503,7 +531,7 @@ validazione runtime. ## 6. Scalabilità & estensioni -### 6.1 [P2] Linux Build VM +### 6.1 [P2] [ ] Linux Build VM **Documento di pianificazione dedicato**: [docs/LINUX-TEMPLATE-SETUP.md](docs/LINUX-TEMPLATE-SETUP.md) — bozza completa con fasi A→H, decisioni di design, differenze rispetto al template Windows. @@ -517,7 +545,7 @@ Sostituire WinRM con SSH key-based; `Invoke-Command` non funziona — usare `ssh Aggiungere `scripts/_Transport.psm1` con due implementazioni (`WinRM`, `SSH`) dietro la stessa interfaccia. `Invoke-CIJob.ps1` sceglie dal parametro `-GuestOS`. -### 6.2 [P3] Workflow generico riutilizzabile (composite action) +### 6.2 [P3] [ ] Workflow generico riutilizzabile (composite action) File: [gitea/workflow-example.yml](gitea/workflow-example.yml). Trasformare in *composite action* Gitea (`.gitea/actions/local-ci-build/action.yml`) @@ -531,7 +559,7 @@ richiamabile da qualsiasi repo: ``` Riduce la duplicazione su nuovi repo e centralizza l'evoluzione del wrapper. -### 6.3 [P3] Multi-host runner federation +### 6.3 [P3] [ ] Multi-host runner federation Quando 4 VM in parallelo non bastano, l'opzione naturale è un secondo host Windows con stesso `Setup-Host.ps1` registrato come secondo runner Gitea (label `windows-build:host-2`). Già supportato lato Gitea, basta replicare il setup. @@ -539,7 +567,7 @@ Già supportato lato Gitea, basta replicare il setup. **Premessa**: prima di scalare orizzontale, profilare se il collo di bottiglia è CPU (i9-10900X 20T è abbondante) o I/O (NVMe). Se è I/O, una seconda NVMe sullo stesso host basta. -### 6.4 [P3] Build matrix nel workflow +### 6.4 [P3] [ ] Build matrix nel workflow File: [gitea/workflows/build-nsis.yml](gitea/workflows/build-nsis.yml). Attualmente single job. Quando arriverà la VM Linux: @@ -550,11 +578,11 @@ strategy: runs-on: ${{ matrix.target }}-build ``` -### 6.5 [P3] Secret injection workflow-level +### 6.5 [P3] [ ] Secret injection workflow-level Per chiavi di firma (Authenticode, GPG), usare i Gitea secrets nel workflow e passarli a `Invoke-CIJob.ps1` come param + env, mai loggati. Stesso modello di §1.5 per il PAT. -### 6.6 [P2] Toolchain Tier-1 in Setup-WinBuild2025 +### 6.6 [P2] [ ] Toolchain Tier-1 in Setup-WinBuild2025 File: [template/Setup-WinBuild2025.ps1](template/Setup-WinBuild2025.ps1). **Motivazione**: toolchain attuale (`.NET SDK`, `Python`, `VS Build Tools`) copre solo C#/Python/MSBuild. @@ -612,7 +640,7 @@ duplicazioni; ogni concern ha **una sola** sorgente di verità. **Stato attuale (duplicati)**: UAC, Explorer LaunchTo, Server Manager off, DisableCAD, OOBE telemetry, WU services disable — entrambi gli script li toccano. -### 7.1 [P1] Spostare base OS hardening da Setup a Deploy +### 7.1 [P1] [x] Spostare base OS hardening da Setup a Deploy File: [template/Deploy-WinBuild2025.ps1](template/Deploy-WinBuild2025.ps1), [template/Setup-WinBuild2025.ps1](template/Setup-WinBuild2025.ps1). @@ -627,7 +655,7 @@ File: [template/Deploy-WinBuild2025.ps1](template/Deploy-WinBuild2025.ps1), - [x] Setup Step 5c (Server Manager / DisableCAD / OOBE) → Assert-Step only - [x] E2e validation — completata §7.4 (2026-05-10) -### 7.2 [P1] WU lifecycle — strategia B (Deploy: GPO + Manual; Setup: lifecycle) +### 7.2 [P1] [x] WU lifecycle — strategia B (Deploy: GPO + Manual; Setup: lifecycle) File: [template/Deploy-WinBuild2025.ps1](template/Deploy-WinBuild2025.ps1), [template/Setup-WinBuild2025.ps1](template/Setup-WinBuild2025.ps1). @@ -642,13 +670,13 @@ avvia WU via SchTask SYSTEM, poi Step 6b disabilita servizi permanentemente post - [x] Setup Step 6b: già disabilita wuauserv/UsoSvc + GPO keys — nessuna modifica necessaria - [x] E2e validation — completata §7.4 (2026-05-10) -### 7.3 [P2] Update header docs di entrambi gli script +### 7.3 [P2] [x] Update header docs di entrambi gli script - [x] [template/Deploy-WinBuild2025.ps1](template/Deploy-WinBuild2025.ps1) `.DESCRIPTION`: aggiornato con tutte le hardening voci (firewall, WinRM tuning, WU GPO strategy B, lock screen, SM, OOBE) - [x] [template/Setup-WinBuild2025.ps1](template/Setup-WinBuild2025.ps1) `.DESCRIPTION`: Steps 1/3/4b/5b/5c marcati "validation-only — set by Deploy"; step ordering rationale aggiornato - [x] [docs/WINDOWS-TEMPLATE-SETUP.md](docs/WINDOWS-TEMPLATE-SETUP.md): architettura "tre script", VMX path `CI-WinBuild.vmx`, Fase C step list + razionale + tabella validazioni aggiornati -### 7.4 [P2] Test e2e refactor — COMPLETATO 2026-05-10 +### 7.4 [P2] [x] Test e2e refactor — COMPLETATO 2026-05-10 - [x] Deploy stand-alone su VM test → `Get-NetFirewallProfile` tutti `Enabled=False`, `Get-Service wuauserv | Select StartType` → `Manual`, `NoAutoUpdate=1` GPO presente - [x] Prepare dopo Deploy con `-SkipWindowsUpdate` → tutti `Assert-Step` passano `[OK]` senza eseguire Set (log mostra solo validation output) @@ -661,7 +689,7 @@ avvia WU via SchTask SYSTEM, poi Step 6b disabilita servizi permanentemente post - Deploy + Setup: autologin Administrator (`AutoAdminLogon=1`) aggiunto in post-install.ps1 e validato in Assert-Step 5c - Nuovi script: `template/Validate-DeployState.ps1`, `template/Validate-SetupState.ps1` -### 7.5 [P3] Rinomina Setup → Setup-CITools (opzionale, futuro) +### 7.5 [P3] [ ] Rinomina Setup → Setup-CITools (opzionale, futuro) Una volta che Setup fa solo build customization, nome `Setup-WinBuild2025` è impreciso — non setup-a la build VM, **estende** un template OS già pronto con toolchain CI. Rinominare in `Setup-CITools.ps1` o `Install-CIToolchain.ps1` rifletterebbe meglio la diff --git a/scripts/Wait-VMReady.ps1 b/scripts/Wait-VMReady.ps1 index 3e602bc..3a3f6e2 100644 --- a/scripts/Wait-VMReady.ps1 +++ b/scripts/Wait-VMReady.ps1 @@ -68,7 +68,6 @@ $deadline = (Get-Date).AddSeconds($TimeoutSeconds) $attempt = 0 $phase = 'vmrun-state' # tracks current phase for informative output $lastPhase = '' -$wsmOpt = New-WSManSessionOption -SkipCACheck -SkipCNCheck -SkipRevocationCheck Write-Host "[Wait-VMReady] Waiting for VM ready (timeout: ${TimeoutSeconds}s, IP: $IPAddress)..." @@ -108,14 +107,17 @@ while ((Get-Date) -lt $deadline) { } } - # ── Phase 3: WinRM responsive ──────────────────────────────────────── - try { - Test-WSMan -ComputerName $IPAddress -Port 5986 -UseSSL -SessionOption $wsmOpt -ErrorAction Stop | Out-Null - # Success — VM is ready + # ── Phase 3: WinRM port 5986 accepting TCP connections ─────────────── + # Test-WSMan has no -SessionOption in PS 5.1 and fails cert validation for + # self-signed certs. TCP open on 5986 = HTTPS listener up = VM ready. + $winrmUp = Test-NetConnection -ComputerName $IPAddress -Port 5986 ` + -InformationLevel Quiet -WarningAction SilentlyContinue ` + -ErrorAction SilentlyContinue + if ($winrmUp) { Write-Host "[Wait-VMReady] VM ready after ~$([int]($attempt * $PollIntervalSeconds))s (attempt $attempt)." return } - catch { + else { $phase = 'winrm' if ($lastPhase -ne $phase) { Write-Host "[Wait-VMReady] Phase 3/3: ping OK, waiting for WinRM on port 5986 (HTTPS)..." diff --git a/template/Prepare-WinBuild2025.ps1 b/template/Prepare-WinBuild2025.ps1 index 815998f..363f7c6 100644 --- a/template/Prepare-WinBuild2025.ps1 +++ b/template/Prepare-WinBuild2025.ps1 @@ -8,8 +8,9 @@ 1. Pre-flight validation: script presence, IP octet range, TCP/5986 reachable 2. Configures host WinRM client (TrustedHosts only, HTTPS needs no AllowUnencrypted) — restored on exit 3. Validates host WinRM TrustedHosts applied correctly - 4. Tests WinRM HTTPS connectivity (Test-WSMan -UseSSL -Port 5986) — fails fast with actionable message - 5. Opens PSSession to the VM + 4. Opens PSSession -UseSSL -Port 5986 -SkipCACheck — fails fast with actionable message + (PS 5.1 Test-WSMan has no -SessionOption, so PSSession is used as the connectivity probe) + 5. PSSession open — step 4 and 5 are now merged 6. Ensures C:\CI exists on guest; validates creation 7. Copies Setup-WinBuild2025.ps1 into the VM; validates file present + size match 8. Runs Setup-WinBuild2025.ps1 inside the VM with the given parameters @@ -260,7 +261,6 @@ else { } $sessionOptions = New-PSSessionOption -SkipCACheck -SkipCNCheck -SkipRevocationCheck -$wsmOpt = New-WSManSessionOption -SkipCACheck -SkipCNCheck -SkipRevocationCheck # ── Configure HOST-side WinRM client (TrustedHosts for HTTPS Basic auth) ────── # HTTPS/5986 does not require AllowUnencrypted on the host side. Only TrustedHosts @@ -288,16 +288,21 @@ catch { } -Write-Host "[Prepare] Testing WinRM HTTPS connectivity to $VMIPAddress`:5986..." -try { - Test-WSMan -ComputerName $VMIPAddress -Port 5986 -UseSSL ` - -SessionOption $wsmOpt -Credential $credential ` - -Authentication Basic -ErrorAction Stop | Out-Null - Write-Host "[Prepare] WinRM HTTPS reachable." -} -catch { +# ── Open session (Test-WSMan skipped — PS 5.1 Test-WSMan has no -SessionOption for HTTPS) ── +# New-PSSession with -SkipCACheck handles cert validation for self-signed lab cert. +Write-Host "[Prepare] Opening PSSession to $VMIPAddress`:5986 (HTTPS)..." +$session = try { + New-PSSession ` + -ComputerName $VMIPAddress ` + -Credential $credential ` + -SessionOption $sessionOptions ` + -UseSSL ` + -Port 5986 ` + -Authentication Basic ` + -ErrorAction Stop +} catch { Write-Error @" -[Prepare] Cannot reach $VMIPAddress via WinRM HTTPS (port 5986). +[Prepare] Cannot open PSSession to $VMIPAddress via WinRM HTTPS (port 5986). Ensure: - The VM is running and on VMnet8 (NAT) with internet access @@ -311,17 +316,6 @@ Error: $_ exit 1 } -# ── Open session ────────────────────────────────────────────────────────────── -Write-Host "[Prepare] Opening PSSession..." -$session = New-PSSession ` - -ComputerName $VMIPAddress ` - -Credential $credential ` - -SessionOption $sessionOptions ` - -UseSSL ` - -Port 5986 ` - -Authentication Basic ` - -ErrorAction Stop - try { # ── Copy Setup-WinBuild2025.ps1 into the VM ─────────────────────────────── $setupScript = Join-Path $scriptDir 'Setup-WinBuild2025.ps1' @@ -415,11 +409,12 @@ try { while ((Get-Date) -lt $deadline) { Start-Sleep -Seconds 10 try { - $wsm = New-WSManSessionOption -SkipCACheck -SkipCNCheck -SkipRevocationCheck - $r = Test-WSMan -ComputerName $IP -Port 5986 -UseSSL ` - -SessionOption $wsm -Credential $Cred ` - -Authentication Basic -ErrorAction Stop - if ($r) { return $true } + # Test-WSMan has no -SessionOption in PS 5.1 — use New-PSSession as probe. + $probe = New-PSSession -ComputerName $IP -Port 5986 -UseSSL ` + -SessionOption $SessionOptions -Credential $Cred ` + -Authentication Basic -ErrorAction Stop + Remove-PSSession $probe -ErrorAction SilentlyContinue + return $true } catch { } } return $false