Files
local-ci-cd-system/docs/WINDOWS-TEMPLATE-SETUP.md
T
Simone 90a4396443 feat: enhance documentation and scripts for in-VM Git cloning and template setup
- Updated README.md to reflect the new in-VM git clone feature with `-UseGitClone`.
- Modified Setup-Host.ps1 to correct VMX path references.
- Revised various documentation files (ARCHITECTURE.md, CI-FLOW.md, HOST-SETUP.md, WINDOWS-TEMPLATE-SETUP.md) to include updated paths and features.
- Added Setup-GiteaSSH.md for SSH configuration instructions.
- Archived outdated documentation and updated README.md for clarity on current resources.
2026-05-10 23:03:56 +02:00

16 KiB

Windows Template VM Setup

Procedura di provisioning della template VM Windows Server 2025 che alimenta i linked clone usati per ogni job CI. Il template viene creato una volta; lo snapshot BaseClean è la base immutabile per tutte le build successive.

Prerequisito: aver eseguito HOST-SETUP.md (F:\CI\ esiste, credenziali archiviate, ISO Windows Server presente).


Architettura: tre script

Script Dove gira Scopo
template/Deploy-WinBuild2025.ps1 Host Opzionale: crea VM e installa Windows unattended da ISO
template/Prepare-WinBuild2025.ps1 Host Orchestratore: copia + esegue Setup nel guest via WinRM
template/Setup-WinBuild2025.ps1 Dentro VM CI toolchain (user, .NET, Python, VS) + validazione hardening Deploy
template/Validate-DeployState.ps1 Host Valida stato post-Deploy prima di eseguire Prepare
template/Validate-SetupState.ps1 Host Valida stato post-Setup (Deploy + Setup) prima dello snapshot

Confine Deploy / Setup (refactor §7, 2026-05-10):

  • Deploy-WinBuild2025.ps1 si occupa dell'OS hardening (Firewall, WinRM, UAC, Defender, UX tweaks, autologin Administrator, WU GPO locks). Se usato, Setup valida questi come Assert-Step senza re-applicarli.
  • Setup-WinBuild2025.ps1 si occupa della CI customization (utente ci_build, cartelle C:\CI, toolchain .NET/Python/VS, Windows Update lifecycle, cleanup, final gate).

Prepare-WinBuild2025.ps1 apre una WinRM session, copia Setup-WinBuild2025.ps1 in C:\CI\, lo esegue, raccoglie l'exit code, valida lo stato del guest.


Specifiche VM

Parametro Valore
OS Windows Server 2025 Standard/Datacenter (Core o Desktop OK)
vCPU 4
RAM 6144 MB (6 GB)
Disco 80 GB thin provisioned
NIC VMnet8 (NAT) — internet richiesto per WU + installer
VMX path F:\CI\Templates\WinBuild2025\WinBuild2025.vmx
ISO Windows Server 2025 (da F:\CI\ISO\)

Fase A — Crea la VM e installa Windows

A.1 Crea VM in VMware Workstation

  • File → New Virtual Machine → Custom
  • Hardware: 4 vCPU, 6144 MB, 80 GB thin
  • Network: VMnet8 (NAT)
  • VMX: F:\CI\Templates\WinBuild2025\WinBuild2025.vmx
  • CD/DVD: monta ISO Windows Server 2025

A.2 Installa Windows Server 2025

  • Edition: Standard o Datacenter (Server Core o con Desktop)
  • Activation: vedi A.4 (deve essere fatto prima dello snapshot)

A.3 Abilita WinRM dentro la VM

Dentro la VM, come Administrator:

winrm quickconfig -q
Enable-PSRemoting -Force -SkipNetworkProfileCheck
Set-Item WSMan:\localhost\Service\Auth\Basic $true -Force
# AllowUnencrypted left false — Deploy post-install.ps1 creates HTTPS/5986 listener
# Basic auth is secure over HTTPS; host connects on port 5986 with -SkipCACheck
Set-Item WSMan:\localhost\Client\TrustedHosts -Value '*' -Force

A.4 Attiva Windows Server 2025

IMPORTANTE: deve essere fatto prima dello snapshot. I linked clone ereditano l'attivazione.

slmgr /dli

Se non attivato, scegli il metodo:

Verifica: slmgr /xpr — deve mostrare attivazione permanente o scadenza lontana.

A.5 Annota IP DHCP

Dentro la VM:

ipconfig

Annota l'IP 192.168.79.x assegnato dal DHCP di VMnet8.


Fase B — Provisioning automatico dall'host

Dall'host (PowerShell elevato):

cd N:\Code\Workspace\Local-CI-CD-System\template
# Provisioning completo + registrazione credenziali automatica:
.\Prepare-WinBuild2025.ps1 -VMIPAddress 192.168.79.128 -StoreCredential

# Se WU già applicato in precedenza:
.\Prepare-WinBuild2025.ps1 -VMIPAddress 192.168.79.128 -SkipWindowsUpdate -StoreCredential

Cosa fa Prepare-WinBuild2025.ps1 — passo per passo

Ogni step ha validazione Assert-Step (throw on failure, [OK] su pass):

  1. Pre-flight: script dir presente, Setup-WinBuild2025.ps1 presente, IP ottetti 0-255, TCP/5986 reachable
  2. Configura host WinRM client: aggiunge $VMIPAddress ai TrustedHosts (no AllowUnencrypted — HTTPS non lo richiede)
    • Salva valore precedente, ripristinato nel finally (host posture invariata)
  3. Validazione host WinRM: TrustedHosts include IP
  4. Test connettività: Test-WSMan -Port 5986 -UseSSL -Authentication Basic con credenziali admin
  5. Apre PSSession -UseSSL -Port 5986 verso la VM
  6. Crea C:\CI in guest, valida creazione
  7. Copia Setup-WinBuild2025.ps1 in C:\CI\Setup-WinBuild2025.ps1, valida size match
  8. Esegue Setup-WinBuild2025.ps1 dentro la VM (vedi Fase C)
  9. Gestisce reboot 3010: se WU richiede reboot, riavvia VM e suggerisce re-run con -SkipWindowsUpdate
  10. Post-setup remote validation (9 check via singola Invoke-Command):
    • WinRM Running
    • User $BuildUsername exists + admin
    • UAC EnableLUA=0
    • Firewall tutti profili Off
    • .NET SDK installato
    • Python C:\Python\python.exe presente
    • MSBuild path presente
    • C:\CI\{build,output,scripts} presenti
  11. Restore host WinRM nel finally (sempre eseguito, anche su failure)

Parametri principali

Parametro Default Note
-VMIPAddress (mandatory) IP DHCP della VM su VMnet8
-AdminUsername Administrator Account admin built-in nella VM
-AdminPassword (prompt) Se vuoto, prompt SecureString
-BuildPassword (prompt) Password per ci_build — mai hard-codare
-BuildUsername ci_build Account CI dentro la VM
-DotNetSdkVersion 10.0 Channel .NET SDK
-SkipWindowsUpdate (off) Pass-through a Setup-WinBuild2025.ps1
-StoreCredential (off) Registra BuildUsername/BuildPassword in Windows Credential Manager
-CredentialTarget BuildVMGuest Target Credential Manager (deve corrispondere a quanto usato da Invoke-CIJob)

Fase C — Cosa fa Setup-WinBuild2025.ps1 (dentro la VM)

Eseguito automaticamente da Prepare in Fase B. Steps 1/2/3/4b/5b/5c sono validation-only — verificano che Deploy abbia già applicato l'hardening OS. Steps 4/5/6/6b/7-10 eseguono la CI customization effettiva. Ogni step ha validazione Assert-Step (throw on failure).

Step 1   Firewall: validation only — Deploy disabled all profiles             [Assert-Step]
Step 2   Defender: validation only — Deploy set DisableAntiSpyware GPO + RTP off [Assert-Step]
Step 3   WinRM: validation only — Deploy set Basic/Unencrypted/MaxMem/Timeout [Assert-Step]
Step 4   Build user account (ci_build, admin, no expire)  ── crea utente CI
Step 4b  UAC: validation only — Deploy set EnableLUA=0 + TokenFilterPolicy    [Assert-Step]
Step 5   CI dirs: C:\CI\{build, output, scripts}          ── C:\CI deve esistere prima di WU
Step 5b  Explorer LaunchTo=1: validation only — Deploy set HKCU + Default hive [Assert-Step]
Step 5c  CI UX hardening: validation only — Deploy set lock screen, SM policy/task,
         DisableCAD, OOBE, telemetry, autologin Administrator                  [Assert-Step]
Step 6   Windows Update via Scheduled Task SYSTEM         ── clears Deploy GPO locks, runs WU
Step 6b  Windows Update permanently disabled (post-update lockdown)
Step 7   .NET SDK install (channel via dotnet-install.ps1)
Step 8   Python install (3.13.3, all-users, C:\Python)
Step 9   VS Build Tools 2026 via Scheduled Task SYSTEM
Step 10  Toolchain cross-check (dotnet, python, msbuild)
Cleanup  cleanmgr /sagerun:1 + DISM /StartComponentCleanup /ResetBase
Final    Pre-snapshot gate — 7 check cross-cutting + no installer leftover

Razionale dell'ordine

  • Steps 1-3 (validazioni) — verificano prima le precondizioni Deploy (firewall off, Defender off, WinRM pronto) in modo che i failure emergano subito, non a metà toolchain.
  • User + UAC (4/4b) — crea ci_build; valida UAC off (set da Deploy); UAC off prima di dir/tool evita prompt di elevazione negli step 7-9.
  • CI dirs prima di WU (Step 5) — il worker WU scrive file temp in C:\CI\ (wu_worker.ps1, wu_result.txt, ecc.); la directory deve esistere prima.
  • UI tweaks (5b/5c) — validazioni registro rapide; raggruppate prima di WU (lento).
  • WU (Step 6) — clears i GPO lock di Deploy (Step A), avvia COM API via SYSTEM task, poi Step 6b re-disabilita tutto → snapshot cattura WU permanentemente off.
  • Toolchain (7-9) last — WU completato, nessun scan su payload installer.

Validazioni per step (sintesi)

Step Natura Check chiave
1 Assert Get-NetFirewallProfile -Profile Domain/Private/Public → Enabled=False
2 Assert GPO DisableAntiSpyware=1 (set da Deploy)
3 Assert WinRM Running+Automatic, AllowUnencrypted=false (HTTPS-only), Auth/Basic=true, MaxMem≥2048
4 Operativo User exists, enabled, PasswordNeverExpires, member of Administrators
4b Assert EnableLUA=0, LocalAccountTokenFilterPolicy=1
5 Operativo Ogni dir Test-Path -PathType Container
5b Assert HKCU LaunchTo=1
5c Assert+Op NoLockScreen=1, SM policy DoNotOpenAtLogon=1, SM task Disabled, DisableCAD=1, OOBE DisablePrivacyExperience=1, AllowTelemetry=0; AutoAdminLogon=1+DefaultUserName=Administrator re-affermati se assenti (Windows OOBE può resettarli al primo boot)
6 Operativo ResultCode ∈ {0,2,3}, no reboot required (else exit 3010)
6b Operativo wuauserv StartType=Disabled, NoAutoUpdate=1, DisableWindowsUpdateAccess=1
7 Operativo dotnet --version channel match, machine PATH contiene C:\dotnet
8 Operativo C:\Python\python.exe esiste, version match esatto, PATH contiene C:\Python
9 Operativo MSBuild.exe esiste, esegue, PATH, \VC\ dir presente
10 Operativo dotnet+python+msbuild tutti risolvibili (throw)
Final Cross-cut WinRM, firewall, user+admin, UAC, WU disabled, tutti tool, no leftover installer in C:\CI

Fase D — Snapshot

Solo se Prepare-WinBuild2025.ps1 exit 0 (tutti gli Assert-Step passati):

  1. Spegni la VM: Start → Shut down (graceful, non hard-stop)
  2. Take snapshot in VMware Workstation:
    • VM → Snapshot → Take Snapshot
    • Nome esatto: BaseClean (case-sensitive, usato da New-BuildVM.ps1)
  3. Lascia la VM spenta — non modificarla mai più dopo lo snapshot
  4. Verifica runner/config.yaml: GITEA_CI_TEMPLATE_PATH=F:\CI\Templates\WinBuild2025\WinBuild2025.vmx

Validation scripts standalone

Due script per validare il guest in punti specifici del flusso, indipendentemente da Prepare. Utili per debug, re-verifica dopo modifiche manuali, e CI automatizzata.

Dopo Deploy — prima di Prepare

.\template\Validate-DeployState.ps1 -VMIPAddress 192.168.79.129

Controlla: Firewall off, Defender GPO, WinRM (Running/Automatic/AllowUnencrypted/Basic/MaxMem), UAC off, Explorer LaunchTo, NoLockScreen, Server Manager (policy+HKLM+task+HKCU), DisableCAD, OOBE, AllowTelemetry, AutoAdminLogon=1, WU GPO, wuauserv/UsoSvc=Manual.

Dopo Prepare — prima di snapshot

.\template\Validate-SetupState.ps1 -VMIPAddress 192.168.79.129

Tutti i check Deploy + ci_build (exists/enabled/admin/PasswordNeverExpires), C:\CI\{build,output,scripts}, wuauserv/UsoSvc=Disabled, WU GPO, .NET SDK channel match, Python version match, MSBuild present, no leftover installer files.

Exit 0 = tutto OK. Exit 1 = almeno un check fallito (output indica quale).


Fase E — Verifica finale

Dall'host:

# Test creazione clone manuale
cd N:\Code\Workspace\Local-CI-CD-System\scripts
.\New-BuildVM.ps1 -JobId 'smoke-test'

# Verifica WinRM raggiungibile sul clone
.\Wait-VMReady.ps1 -JobId 'smoke-test' -TimeoutSec 120

# Cleanup
.\Remove-BuildVM.ps1 -JobId 'smoke-test'

Se i 3 step exit 0 → template pronto per produzione.


Maintenance — refresh semestrale

Il template va rinfrescato ogni ~180 giorni (KMS lease) o quando serve aggiornare la toolchain (.NET, VS Build Tools, Python).

Procedura:

  1. Power on della template VM (NIC: VMnet8 NAT)
  2. Riattiva: slmgr /ato
  3. Re-run Prepare-WinBuild2025.ps1 per applicare update toolchain (passare flag opportuni)
  4. Shut down + nuovo snapshot versionato: BaseClean_<yyyyMMdd> (TODO §2.5)
  5. Aggiorna GITEA_CI_SNAPSHOT_NAME env var in runner/config.yaml
  6. Tieni i 2 snapshot più recenti, cancella vecchi dopo 1 settimana di uso pulito

Troubleshooting

Sintomo Diagnosi / Fix
Cannot reach $VMIPAddress via WinRM VM non avviata, WinRM non abilitato, IP errato — verifica con ipconfig
Setup-WinBuild2025.ps1 exited with code 3010 Reboot richiesto post-WU. Re-run con -SkipWindowsUpdate
[Defender] Validation failed: GPO key Defender riattivato da Windows Update — disabilita via gpedit + reboot
VS Build Tools installation timed out Network slow o cache corrotta. Re-run con cache pulita (C:\ProgramData\Microsoft\VisualStudio\Packages)
Python version match fail $PythonVersion ≠ versione installata. Aggiorna param o reinstalla
Post-setup MSBuild not found VS install fallita silenziosa. Check C:\CI\vs_log.txt
Pre-snapshot Final check fail Stato VM rotto — non prendere snapshot. Re-run o ricomincia da zero

Backlog correlato (TODO.md)

  • §1.1 [P0] Migrare WinRM da HTTP/Basic a HTTPS/5986 con cert self-signed nel template
  • §1.3 [P0] Pinning hash SHA256 degli installer (Python, dotnet-install.ps1, vs_buildtools.exe)
  • §1.6 [P2] Documentare threat model per Defender/Firewall/UAC tutti off
  • §2.5 [P1] Snapshot versionato BaseClean_<yyyyMMdd> (rollback in caso di refresh rotto)
  • §2.6 [P2] Backup automatico VMDK template pre-snapshot
  • In-VM Git Clone — installare Git for Windows + 7-Zip nel template per ottimizzare flusso