refactor(template): rename Setup-TemplateVM.ps1 -> Setup-WinBuild2025.ps1
- git mv Setup-TemplateVM.ps1 Setup-WinBuild2025.ps1
- git mv Prepare-TemplateSetup.ps1 -> Prepare-WinBuild2025.ps1 (name already in place)
- Updated all references across the workspace:
template/Prepare-WinBuild2025.ps1 (script copy, assertions, comments)
template/Setup-WinBuild2025.ps1 (self-references in docblock and final message)
README.md (directory tree)
TODO.md (all inline links and task descriptions)
docs/WINDOWS-TEMPLATE-SETUP.md (table, step descriptions, phase header, troubleshooting)
docs/LINUX-TEMPLATE-SETUP.md (Windows equivalent reference)
This commit is contained in:
@@ -72,8 +72,8 @@ Ogni build gira in una VM Windows Server 2025 **usa e getta**, ripristinata dall
|
|||||||
│ └── Remove-BuildVM.ps1 # Stop + rimozione VM clone
|
│ └── Remove-BuildVM.ps1 # Stop + rimozione VM clone
|
||||||
│
|
│
|
||||||
├── template/
|
├── template/
|
||||||
│ ├── Prepare-TemplateSetup.ps1 # Provisioning automatico template VM (HOST-side)
|
│ ├── Prepare-WinBuild2025.ps1 # Provisioning automatico template VM (HOST-side)
|
||||||
│ └── Setup-TemplateVM.ps1 # Installazione toolchain nella VM (GUEST-side)
|
│ └── Setup-WinBuild2025.ps1 # Installazione toolchain nella VM (GUEST-side)
|
||||||
│
|
│
|
||||||
├── gitea/
|
├── gitea/
|
||||||
│ ├── workflows/
|
│ ├── workflows/
|
||||||
@@ -103,7 +103,7 @@ Ogni build gira in una VM Windows Server 2025 **usa e getta**, ripristinata dall
|
|||||||
```powershell
|
```powershell
|
||||||
# Dalla directory template/, dopo aver installato Windows Server 2025 nella VM
|
# Dalla directory template/, dopo aver installato Windows Server 2025 nella VM
|
||||||
# e annotato il suo IP DHCP su VMnet8:
|
# e annotato il suo IP DHCP su VMnet8:
|
||||||
.\Prepare-TemplateSetup.ps1 -VMIPAddress 192.168.79.x -SkipWindowsUpdate
|
.\Prepare-WinBuild2025.ps1 -VMIPAddress 192.168.79.x -SkipWindowsUpdate
|
||||||
```
|
```
|
||||||
|
|
||||||
Poi spegni la VM e prendi lo snapshot con nome esatto **`BaseClean`**.
|
Poi spegni la VM e prendi lo snapshot con nome esatto **`BaseClean`**.
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
>
|
>
|
||||||
> **Doc di setup operativi**:
|
> **Doc di setup operativi**:
|
||||||
> - [docs/HOST-SETUP.md](docs/HOST-SETUP.md) — bootstrap macchina host (Setup-Host.ps1)
|
> - [docs/HOST-SETUP.md](docs/HOST-SETUP.md) — bootstrap macchina host (Setup-Host.ps1)
|
||||||
> - [docs/WINDOWS-TEMPLATE-SETUP.md](docs/WINDOWS-TEMPLATE-SETUP.md) — provisioning template Windows (Prepare + Setup-TemplateVM)
|
> - [docs/WINDOWS-TEMPLATE-SETUP.md](docs/WINDOWS-TEMPLATE-SETUP.md) — provisioning template Windows (Prepare + Setup-WinBuild2025)
|
||||||
> - [docs/LINUX-TEMPLATE-SETUP.md](docs/LINUX-TEMPLATE-SETUP.md) — bozza/TODO template Linux (non implementato)
|
> - [docs/LINUX-TEMPLATE-SETUP.md](docs/LINUX-TEMPLATE-SETUP.md) — bozza/TODO template Linux (non implementato)
|
||||||
>
|
>
|
||||||
> - **P0** — sicurezza o affidabilità: affrontare prima di estendere il sistema
|
> - **P0** — sicurezza o affidabilità: affrontare prima di estendere il sistema
|
||||||
@@ -84,17 +84,17 @@
|
|||||||
- [x] Dall'host, esegui:
|
- [x] Dall'host, esegui:
|
||||||
```powershell
|
```powershell
|
||||||
cd n:\Code\Workspace\Local-CI-CD-System\template
|
cd n:\Code\Workspace\Local-CI-CD-System\template
|
||||||
.\Prepare-TemplateSetup.ps1 -VMIPAddress 192.168.79.128 -SkipWindowsUpdate
|
.\Prepare-WinBuild2025.ps1 -VMIPAddress 192.168.79.128 -SkipWindowsUpdate
|
||||||
```
|
```
|
||||||
Installa: WinRM config, utente `ci_build`, .NET SDK 10.0, VS Build Tools 2026, Python 3.13.3.
|
Installa: WinRM config, utente `ci_build`, .NET SDK 10.0, VS Build Tools 2026, Python 3.13.3.
|
||||||
Lo script esegue validazione automatica ad ogni passaggio (`Assert-Step`):
|
Lo script esegue validazione automatica ad ogni passaggio (`Assert-Step`):
|
||||||
- Pre-flight: IP ottetti 0-255, TCP/5985 raggiungibile, Setup-TemplateVM.ps1 presente
|
- Pre-flight: IP ottetti 0-255, TCP/5985 raggiungibile, Setup-WinBuild2025.ps1 presente
|
||||||
- Host WinRM: AllowUnencrypted, TrustedHosts
|
- Host WinRM: AllowUnencrypted, TrustedHosts
|
||||||
- Guest prep: `C:\CI` esiste, file copiato, size match
|
- Guest prep: `C:\CI` esiste, file copiato, size match
|
||||||
- Post-setup remoto (9 check): WinRM, user+admin, UAC, firewall, .NET, Python, MSBuild, CI dirs
|
- Post-setup remoto (9 check): WinRM, user+admin, UAC, firewall, .NET, Python, MSBuild, CI dirs
|
||||||
Se qualsiasi check fallisce → script termina con errore → **non prendere lo snapshot**.
|
Se qualsiasi check fallisce → script termina con errore → **non prendere lo snapshot**.
|
||||||
- [x] Setup completato con successo (VS Build Tools 2026 exit code 0).
|
- [x] Setup completato con successo (VS Build Tools 2026 exit code 0).
|
||||||
- [x] `Setup-TemplateVM.ps1` ora esegue validazione `Assert-Step` dopo ogni step interno
|
- [x] `Setup-WinBuild2025.ps1` ora esegue validazione `Assert-Step` dopo ogni step interno
|
||||||
(WinRM, Firewall, User, UAC, Dirs, Defender, .NET, Python, VS Build Tools, Toolchain,
|
(WinRM, Firewall, User, UAC, Dirs, Defender, .NET, Python, VS Build Tools, Toolchain,
|
||||||
Cleanup, Final pre-snapshot gate) — throws se qualsiasi check fallisce (2026-05-09)
|
Cleanup, Final pre-snapshot gate) — throws se qualsiasi check fallisce (2026-05-09)
|
||||||
|
|
||||||
@@ -103,7 +103,7 @@
|
|||||||
- [x] Spegni la VM: Start → Shut down
|
- [x] Spegni la VM: Start → Shut down
|
||||||
- [x] Prendi snapshot: VM → Snapshot → Take Snapshot
|
- [x] Prendi snapshot: VM → Snapshot → Take Snapshot
|
||||||
**Nome esatto: `BaseClean`**
|
**Nome esatto: `BaseClean`**
|
||||||
**Prerequisito: `Prepare-TemplateSetup.ps1` deve essere uscito con exit 0** — tutti
|
**Prerequisito: `Prepare-WinBuild2025.ps1` deve essere uscito con exit 0** — tutti
|
||||||
gli `Assert-Step` passati, incluso il Final pre-snapshot gate nel guest.
|
gli `Assert-Step` passati, incluso il Final pre-snapshot gate nel guest.
|
||||||
- [x] Lascia la VM spenta — non modificarla mai più dopo questo snapshot
|
- [x] Lascia la VM spenta — non modificarla mai più dopo questo snapshot
|
||||||
|
|
||||||
@@ -150,7 +150,7 @@
|
|||||||
## 1. Sicurezza & hardening
|
## 1. Sicurezza & hardening
|
||||||
|
|
||||||
### 1.1 [P0] Migrare WinRM da HTTP/Basic a HTTPS/5986
|
### 1.1 [P0] Migrare WinRM da HTTP/Basic a HTTPS/5986
|
||||||
File: [template/Setup-TemplateVM.ps1:179-198](template/Setup-TemplateVM.ps1), [scripts/Invoke-RemoteBuild.ps1:82-91](scripts/Invoke-RemoteBuild.ps1).
|
File: [template/Setup-WinBuild2025.ps1:179-198](template/Setup-WinBuild2025.ps1), [scripts/Invoke-RemoteBuild.ps1:82-91](scripts/Invoke-RemoteBuild.ps1).
|
||||||
|
|
||||||
**Motivazione**: la combo `AllowUnencrypted=true` + `Auth/Basic=true` invia credenziali del
|
**Motivazione**: la combo `AllowUnencrypted=true` + `Auth/Basic=true` invia credenziali del
|
||||||
`ci_build` (admin) in chiaro su VMnet8. Anche in lab isolato, l'host può essere compromesso
|
`ci_build` (admin) in chiaro su VMnet8. Anche in lab isolato, l'host può essere compromesso
|
||||||
@@ -160,7 +160,7 @@ manca solo l'esecuzione.
|
|||||||
**Azioni**:
|
**Azioni**:
|
||||||
- [ ] Generare cert self-signed nel template *prima* dello snapshot.
|
- [ ] Generare cert self-signed nel template *prima* dello snapshot.
|
||||||
- [ ] Sostituire `New-PSSession -ComputerName $ip` con `-UseSSL -Port 5986` in `Invoke-RemoteBuild.ps1` e `Get-BuildArtifacts.ps1`.
|
- [ ] Sostituire `New-PSSession -ComputerName $ip` con `-UseSSL -Port 5986` in `Invoke-RemoteBuild.ps1` e `Get-BuildArtifacts.ps1`.
|
||||||
- [ ] Rimuovere `AllowUnencrypted=true` dal `Setup-TemplateVM.ps1`.
|
- [ ] Rimuovere `AllowUnencrypted=true` dal `Setup-WinBuild2025.ps1`.
|
||||||
- [ ] Tenere `-SkipCACheck` lato host: per cert lab self-signed è accettabile, ma documentare la motivazione inline.
|
- [ ] Tenere `-SkipCACheck` lato host: per cert lab self-signed è accettabile, ma documentare la motivazione inline.
|
||||||
- [ ] Regole firewall — limitare WinRM alla subnet build VM (`192.168.79.0/24` — VMnet8 NAT).
|
- [ ] Regole firewall — limitare WinRM alla subnet build VM (`192.168.79.0/24` — VMnet8 NAT).
|
||||||
|
|
||||||
@@ -173,7 +173,7 @@ Set-Item WSMan:\localhost\Client\TrustedHosts -Value '192.168.79.*' -Force -Conc
|
|||||||
```
|
```
|
||||||
|
|
||||||
### 1.3 [P0] Pinning hash SHA256 degli installer
|
### 1.3 [P0] Pinning hash SHA256 degli installer
|
||||||
File: [template/Setup-TemplateVM.ps1:332-399](template/Setup-TemplateVM.ps1), [template/Setup-TemplateVM.ps1:401-502](template/Setup-TemplateVM.ps1).
|
File: [template/Setup-WinBuild2025.ps1:332-399](template/Setup-WinBuild2025.ps1), [template/Setup-WinBuild2025.ps1:401-502](template/Setup-WinBuild2025.ps1).
|
||||||
|
|
||||||
**Motivazione**: Python, `dotnet-install.ps1`, `vs_buildtools.exe` vengono scaricati senza
|
**Motivazione**: Python, `dotnet-install.ps1`, `vs_buildtools.exe` vengono scaricati senza
|
||||||
verifica integrità. Un MITM nella rete dell'host (anche temporaneo) può iniettare binari
|
verifica integrità. Un MITM nella rete dell'host (anche temporaneo) può iniettare binari
|
||||||
@@ -206,7 +206,7 @@ Quando arriva il momento di implementare il clone in-VM (vedi §3.3 / sezione "I
|
|||||||
- [ ] Aggiungere un grep automatico nei log job: se il PAT compare grezzo, fallire la build.
|
- [ ] Aggiungere un grep automatico nei log job: se il PAT compare grezzo, fallire la build.
|
||||||
|
|
||||||
### 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/Setup-TemplateVM.ps1:200-329](template/Setup-TemplateVM.ps1).
|
File: [template/Setup-WinBuild2025.ps1:200-329](template/Setup-WinBuild2025.ps1).
|
||||||
|
|
||||||
Attualmente: `Set-NetFirewallProfile ... -Enabled False`, `EnableLUA=0`, `DisableAntiSpyware=1`,
|
Attualmente: `Set-NetFirewallProfile ... -Enabled False`, `EnableLUA=0`, `DisableAntiSpyware=1`,
|
||||||
`DisableRealtimeMonitoring=1`, `LocalAccountTokenFilterPolicy=1`.
|
`DisableRealtimeMonitoring=1`, `LocalAccountTokenFilterPolicy=1`.
|
||||||
@@ -481,7 +481,7 @@ e centralizza retry/log.
|
|||||||
File: [gitea/workflows/lint.yml](gitea/workflows/lint.yml) (già esiste).
|
File: [gitea/workflows/lint.yml](gitea/workflows/lint.yml) (già esiste).
|
||||||
|
|
||||||
Aggiungere regole specifiche progetto (`PSScriptAnalyzerSettings.psd1` in root):
|
Aggiungere regole specifiche progetto (`PSScriptAnalyzerSettings.psd1` in root):
|
||||||
- `PSAvoidUsingPlainTextForPassword` — rilevante per `Setup-TemplateVM.ps1:55`.
|
- `PSAvoidUsingPlainTextForPassword` — rilevante per `Setup-WinBuild2025.ps1:55`.
|
||||||
- `PSAvoidUsingInvokeExpression`.
|
- `PSAvoidUsingInvokeExpression`.
|
||||||
- `PSUseShouldProcessForStateChangingFunctions`.
|
- `PSUseShouldProcessForStateChangingFunctions`.
|
||||||
- Regole custom: vietare hardcoded `F:\CI\` fuori da config (forzare param/env).
|
- Regole custom: vietare hardcoded `F:\CI\` fuori da config (forzare param/env).
|
||||||
@@ -566,7 +566,7 @@ VM avviata → WinRM: git clone --recurse-submodules https://<token>@gitea/...
|
|||||||
**Punti chiave:**
|
**Punti chiave:**
|
||||||
- Il PAT **non deve essere nello snapshot** — viene iniettato a runtime come env var via WinRM
|
- Il PAT **non deve essere nello snapshot** — viene iniettato a runtime come env var via WinRM
|
||||||
(`git clone https://Simone:<pat>@gitea.emulab.it/<repo>.git`) e non viene mai persistito
|
(`git clone https://Simone:<pat>@gitea.emulab.it/<repo>.git`) e non viene mai persistito
|
||||||
- Git deve essere installato nel template (`Setup-TemplateVM.ps1`) — ora è assente per design
|
- Git deve essere installato nel template (`Setup-WinBuild2025.ps1`) — ora è assente per design
|
||||||
- L'implementazione deve essere **non-breaking**: nuovo switch opt-in `-UseGitClone` in `Invoke-CIJob.ps1`
|
- L'implementazione deve essere **non-breaking**: nuovo switch opt-in `-UseGitClone` in `Invoke-CIJob.ps1`
|
||||||
- Si perde il parallelismo parziale (clone host avviene mentre VM boota), ma si elimina
|
- Si perde il parallelismo parziale (clone host avviene mentre VM boota), ma si elimina
|
||||||
tutto l'overhead di zip/transfer (rilevante su repo grandi o con molti submoduli)
|
tutto l'overhead di zip/transfer (rilevante su repo grandi o con molti submoduli)
|
||||||
@@ -574,7 +574,7 @@ VM avviata → WinRM: git clone --recurse-submodules https://<token>@gitea/...
|
|||||||
|
|
||||||
### Task
|
### Task
|
||||||
|
|
||||||
- [ ] **Setup-TemplateVM.ps1 — installare Git for Windows**
|
- [ ] **Setup-WinBuild2025.ps1 — installare Git for Windows**
|
||||||
- [ ] Scaricare e installare Git for Windows (installer silenzioso da git-scm.com)
|
- [ ] Scaricare e installare Git for Windows (installer silenzioso da git-scm.com)
|
||||||
```powershell
|
```powershell
|
||||||
$gitUrl = 'https://github.com/git-for-windows/git/releases/download/v2.47.1.windows.1/Git-2.47.1-64-bit.exe'
|
$gitUrl = 'https://github.com/git-for-windows/git/releases/download/v2.47.1.windows.1/Git-2.47.1-64-bit.exe'
|
||||||
@@ -582,9 +582,9 @@ VM avviata → WinRM: git clone --recurse-submodules https://<token>@gitea/...
|
|||||||
```
|
```
|
||||||
- [ ] Aggiungere `C:\Program Files\Git\cmd` al PATH di sistema nella VM
|
- [ ] Aggiungere `C:\Program Files\Git\cmd` al PATH di sistema nella VM
|
||||||
- [ ] Verificare: `git --version` ritorna exit 0 nella VM
|
- [ ] Verificare: `git --version` ritorna exit 0 nella VM
|
||||||
- [ ] Rimuovere il commento "Git is NOT installed" dal docblock di Setup-TemplateVM.ps1
|
- [ ] Rimuovere il commento "Git is NOT installed" dal docblock di Setup-WinBuild2025.ps1
|
||||||
|
|
||||||
- [ ] **Setup-TemplateVM.ps1 — altri tool utili**
|
- [ ] **Setup-WinBuild2025.ps1 — altri tool utili**
|
||||||
- [ ] **7-Zip**: installer silenzioso — molto più veloce di `Compress-Archive`/`Expand-Archive`
|
- [ ] **7-Zip**: installer silenzioso — molto più veloce di `Compress-Archive`/`Expand-Archive`
|
||||||
per archivi grandi (es. npm/NuGet cache warm). Necessario anche per §3.2.
|
per archivi grandi (es. npm/NuGet cache warm). Necessario anche per §3.2.
|
||||||
- [ ] **curl.exe**: già presente in Windows 11/Server 2025 (v7.x) — verificare disponibilità
|
- [ ] **curl.exe**: già presente in Windows 11/Server 2025 (v7.x) — verificare disponibilità
|
||||||
|
|||||||
@@ -150,7 +150,7 @@ Dentro la VM, come `ci_build`:
|
|||||||
sudo systemctl restart sshd
|
sudo systemctl restart sshd
|
||||||
```
|
```
|
||||||
|
|
||||||
### Fase C — Setup-LinuxTemplateVM.sh (script equivalente a Setup-TemplateVM.ps1)
|
### Fase C — Setup-LinuxTemplateVM.sh (script equivalente a Setup-WinBuild2025.ps1)
|
||||||
|
|
||||||
Da creare: `template/Setup-LinuxTemplateVM.sh` con `set -euo pipefail` + `assert_step()` helper.
|
Da creare: `template/Setup-LinuxTemplateVM.sh` con `set -euo pipefail` + `assert_step()` helper.
|
||||||
|
|
||||||
@@ -226,7 +226,7 @@ Da creare: `template/Setup-LinuxTemplateVM.sh` con `set -euo pipefail` + `assert
|
|||||||
|
|
||||||
### Fase D — Prepare-LinuxTemplateSetup.ps1 (orchestratore host-side)
|
### Fase D — Prepare-LinuxTemplateSetup.ps1 (orchestratore host-side)
|
||||||
|
|
||||||
Equivalente di `Prepare-TemplateSetup.ps1` per Linux. Usa SSH invece di WinRM.
|
Equivalente di `Prepare-WinBuild2025.ps1` per Linux. Usa SSH invece di WinRM.
|
||||||
|
|
||||||
- [ ] **Pre-flight host**:
|
- [ ] **Pre-flight host**:
|
||||||
- SSH key esiste (`F:\CI\keys\ci_linux`)
|
- SSH key esiste (`F:\CI\keys\ci_linux`)
|
||||||
|
|||||||
@@ -13,10 +13,10 @@ credenziali archiviate, ISO Windows Server presente).
|
|||||||
|
|
||||||
| Script | Dove gira | Scopo |
|
| Script | Dove gira | Scopo |
|
||||||
| ---------------------------------------- | --------------- | -------------------------------------------------- |
|
| ---------------------------------------- | --------------- | -------------------------------------------------- |
|
||||||
| `template/Prepare-TemplateSetup.ps1` | **Host** | Orchestratore: copia + esegue lo script in VM |
|
| `template/Prepare-WinBuild2025.ps1` | **Host** | Orchestratore: copia + esegue lo script in VM |
|
||||||
| `template/Setup-TemplateVM.ps1` | **Dentro VM** | Provisioning effettivo (firewall, defender, tool) |
|
| `template/Setup-WinBuild2025.ps1` | **Dentro VM** | Provisioning effettivo (firewall, defender, tool) |
|
||||||
|
|
||||||
`Prepare-TemplateSetup.ps1` apre una WinRM session, copia `Setup-TemplateVM.ps1` in
|
`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.
|
`C:\CI\`, lo esegue, raccoglie l'exit code, valida lo stato del guest.
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -93,25 +93,25 @@ Dall'host (PowerShell elevato):
|
|||||||
```powershell
|
```powershell
|
||||||
cd N:\Code\Workspace\Local-CI-CD-System\template
|
cd N:\Code\Workspace\Local-CI-CD-System\template
|
||||||
# Provisioning completo + registrazione credenziali automatica:
|
# Provisioning completo + registrazione credenziali automatica:
|
||||||
.\Prepare-TemplateSetup.ps1 -VMIPAddress 192.168.79.128 -StoreCredential
|
.\Prepare-WinBuild2025.ps1 -VMIPAddress 192.168.79.128 -StoreCredential
|
||||||
|
|
||||||
# Se WU già applicato in precedenza:
|
# Se WU già applicato in precedenza:
|
||||||
.\Prepare-TemplateSetup.ps1 -VMIPAddress 192.168.79.128 -SkipWindowsUpdate -StoreCredential
|
.\Prepare-WinBuild2025.ps1 -VMIPAddress 192.168.79.128 -SkipWindowsUpdate -StoreCredential
|
||||||
```
|
```
|
||||||
|
|
||||||
### Cosa fa `Prepare-TemplateSetup.ps1` — passo per passo
|
### Cosa fa `Prepare-WinBuild2025.ps1` — passo per passo
|
||||||
|
|
||||||
Ogni step ha validazione `Assert-Step` (throw on failure, `[OK]` su pass):
|
Ogni step ha validazione `Assert-Step` (throw on failure, `[OK]` su pass):
|
||||||
|
|
||||||
1. **Pre-flight**: script dir presente, `Setup-TemplateVM.ps1` presente, IP ottetti 0-255, TCP/5985 reachable
|
1. **Pre-flight**: script dir presente, `Setup-WinBuild2025.ps1` presente, IP ottetti 0-255, TCP/5985 reachable
|
||||||
2. **Configura host WinRM client**: `AllowUnencrypted=true`, aggiunge `$VMIPAddress` ai `TrustedHosts`
|
2. **Configura host WinRM client**: `AllowUnencrypted=true`, aggiunge `$VMIPAddress` ai `TrustedHosts`
|
||||||
- Salva valori precedenti, ripristinati nel `finally` (host posture invariata)
|
- Salva valori precedenti, ripristinati nel `finally` (host posture invariata)
|
||||||
3. **Validazione host WinRM**: `AllowUnencrypted=true`, `TrustedHosts` include IP
|
3. **Validazione host WinRM**: `AllowUnencrypted=true`, `TrustedHosts` include IP
|
||||||
4. **Test connettività**: `Test-WSMan -Authentication Basic` con credenziali admin
|
4. **Test connettività**: `Test-WSMan -Authentication Basic` con credenziali admin
|
||||||
5. **Apre PSSession** verso la VM
|
5. **Apre PSSession** verso la VM
|
||||||
6. **Crea `C:\CI`** in guest, valida creazione
|
6. **Crea `C:\CI`** in guest, valida creazione
|
||||||
7. **Copia `Setup-TemplateVM.ps1`** in `C:\CI\Setup-TemplateVM.ps1`, valida size match
|
7. **Copia `Setup-WinBuild2025.ps1`** in `C:\CI\Setup-WinBuild2025.ps1`, valida size match
|
||||||
8. **Esegue `Setup-TemplateVM.ps1`** dentro la VM (vedi Fase C)
|
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`
|
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`):
|
10. **Post-setup remote validation** (9 check via singola `Invoke-Command`):
|
||||||
- WinRM Running
|
- WinRM Running
|
||||||
@@ -134,13 +134,13 @@ Ogni step ha validazione `Assert-Step` (throw on failure, `[OK]` su pass):
|
|||||||
| `-BuildPassword` | (prompt) | Password per `ci_build` — mai hard-codare |
|
| `-BuildPassword` | (prompt) | Password per `ci_build` — mai hard-codare |
|
||||||
| `-BuildUsername` | ci_build | Account CI dentro la VM |
|
| `-BuildUsername` | ci_build | Account CI dentro la VM |
|
||||||
| `-DotNetSdkVersion` | 10.0 | Channel .NET SDK |
|
| `-DotNetSdkVersion` | 10.0 | Channel .NET SDK |
|
||||||
| `-SkipWindowsUpdate` | (off) | Pass-through a Setup-TemplateVM.ps1 |
|
| `-SkipWindowsUpdate` | (off) | Pass-through a Setup-WinBuild2025.ps1 |
|
||||||
| `-StoreCredential` | (off) | Registra `BuildUsername`/`BuildPassword` in Windows Credential Manager |
|
| `-StoreCredential` | (off) | Registra `BuildUsername`/`BuildPassword` in Windows Credential Manager |
|
||||||
| `-CredentialTarget` | BuildVMGuest | Target Credential Manager (deve corrispondere a quanto usato da Invoke-CIJob) |
|
| `-CredentialTarget` | BuildVMGuest | Target Credential Manager (deve corrispondere a quanto usato da Invoke-CIJob) |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Fase C — Cosa fa `Setup-TemplateVM.ps1` (dentro la VM)
|
## Fase C — Cosa fa `Setup-WinBuild2025.ps1` (dentro la VM)
|
||||||
|
|
||||||
Eseguito automaticamente da Prepare in Fase B. Ordine ottimizzato per ridurre overhead:
|
Eseguito automaticamente da Prepare in Fase B. Ordine ottimizzato per ridurre overhead:
|
||||||
tutti i tweak UI/registro sono raggruppati **prima** di Windows Update (operazione lenta).
|
tutti i tweak UI/registro sono raggruppati **prima** di Windows Update (operazione lenta).
|
||||||
@@ -208,7 +208,7 @@ Final Pre-snapshot gate — 7 check cross-cutting + no installer leftover
|
|||||||
|
|
||||||
## Fase D — Snapshot
|
## Fase D — Snapshot
|
||||||
|
|
||||||
**Solo se `Prepare-TemplateSetup.ps1` exit 0** (tutti gli `Assert-Step` passati):
|
**Solo se `Prepare-WinBuild2025.ps1` exit 0** (tutti gli `Assert-Step` passati):
|
||||||
|
|
||||||
1. **Spegni la VM**: Start → Shut down (graceful, non hard-stop)
|
1. **Spegni la VM**: Start → Shut down (graceful, non hard-stop)
|
||||||
2. **Take snapshot** in VMware Workstation:
|
2. **Take snapshot** in VMware Workstation:
|
||||||
@@ -247,7 +247,7 @@ toolchain (.NET, VS Build Tools, Python).
|
|||||||
**Procedura**:
|
**Procedura**:
|
||||||
1. Power on della template VM (NIC: VMnet8 NAT)
|
1. Power on della template VM (NIC: VMnet8 NAT)
|
||||||
2. Riattiva: `slmgr /ato`
|
2. Riattiva: `slmgr /ato`
|
||||||
3. Re-run `Prepare-TemplateSetup.ps1` per applicare update toolchain (passare flag opportuni)
|
3. Re-run `Prepare-WinBuild2025.ps1` per applicare update toolchain (passare flag opportuni)
|
||||||
4. Shut down + nuovo snapshot **versionato**: `BaseClean_<yyyyMMdd>` (TODO §2.5)
|
4. Shut down + nuovo snapshot **versionato**: `BaseClean_<yyyyMMdd>` (TODO §2.5)
|
||||||
5. Aggiorna `GITEA_CI_SNAPSHOT_NAME` env var in `runner/config.yaml`
|
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
|
6. Tieni i 2 snapshot più recenti, cancella vecchi dopo 1 settimana di uso pulito
|
||||||
@@ -259,7 +259,7 @@ toolchain (.NET, VS Build Tools, Python).
|
|||||||
| Sintomo | Diagnosi / Fix |
|
| Sintomo | Diagnosi / Fix |
|
||||||
| ------------------------------------------- | ----------------------------------------------------------------------- |
|
| ------------------------------------------- | ----------------------------------------------------------------------- |
|
||||||
| `Cannot reach $VMIPAddress via WinRM` | VM non avviata, WinRM non abilitato, IP errato — verifica con ipconfig |
|
| `Cannot reach $VMIPAddress via WinRM` | VM non avviata, WinRM non abilitato, IP errato — verifica con ipconfig |
|
||||||
| `Setup-TemplateVM.ps1 exited with code 3010`| Reboot richiesto post-WU. Re-run con `-SkipWindowsUpdate` |
|
| `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 |
|
| `[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`) |
|
| `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 |
|
| `Python version match` fail | `$PythonVersion` ≠ versione installata. Aggiorna param o reinstalla |
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
#Requires -Version 5.1
|
#Requires -Version 5.1
|
||||||
<#
|
<#
|
||||||
.SYNOPSIS
|
.SYNOPSIS
|
||||||
HOST-side script: delivers and runs Setup-TemplateVM.ps1 inside the template VM.
|
HOST-side script: delivers and runs Setup-WinBuild2025.ps1 inside the template VM.
|
||||||
|
|
||||||
.DESCRIPTION
|
.DESCRIPTION
|
||||||
Automates the template VM provisioning from the host machine:
|
Automates the template VM provisioning from the host machine:
|
||||||
@@ -11,8 +11,8 @@
|
|||||||
4. Tests WinRM connectivity (Test-WSMan) — fails fast with actionable message
|
4. Tests WinRM connectivity (Test-WSMan) — fails fast with actionable message
|
||||||
5. Opens PSSession to the VM
|
5. Opens PSSession to the VM
|
||||||
6. Ensures C:\CI exists on guest; validates creation
|
6. Ensures C:\CI exists on guest; validates creation
|
||||||
7. Copies Setup-TemplateVM.ps1 into the VM; validates file present + size match
|
7. Copies Setup-WinBuild2025.ps1 into the VM; validates file present + size match
|
||||||
8. Runs Setup-TemplateVM.ps1 inside the VM with the given parameters
|
8. Runs Setup-WinBuild2025.ps1 inside the VM with the given parameters
|
||||||
(Setup performs per-step validation internally — aborts on any failure)
|
(Setup performs per-step validation internally — aborts on any failure)
|
||||||
9. Handles the reboot-required case (exit 3010) and optionally re-runs
|
9. Handles the reboot-required case (exit 3010) and optionally re-runs
|
||||||
10. Post-setup remote validation: 9 guest-state checks via a single Invoke-Command
|
10. Post-setup remote validation: 9 guest-state checks via a single Invoke-Command
|
||||||
@@ -67,13 +67,13 @@
|
|||||||
|
|
||||||
.PARAMETER BuildUsername
|
.PARAMETER BuildUsername
|
||||||
Local username for the CI build account inside the VM. Default: ci_build.
|
Local username for the CI build account inside the VM. Default: ci_build.
|
||||||
Passed through to Setup-TemplateVM.ps1 and used in post-setup validation.
|
Passed through to Setup-WinBuild2025.ps1 and used in post-setup validation.
|
||||||
|
|
||||||
.PARAMETER DotNetSdkVersion
|
.PARAMETER DotNetSdkVersion
|
||||||
.NET SDK channel to install in the VM. Default: 10.0 (matches host SDK).
|
.NET SDK channel to install in the VM. Default: 10.0 (matches host SDK).
|
||||||
|
|
||||||
.PARAMETER SkipWindowsUpdate
|
.PARAMETER SkipWindowsUpdate
|
||||||
Pass through to Setup-TemplateVM.ps1 to skip the Windows Update step.
|
Pass through to Setup-WinBuild2025.ps1 to skip the Windows Update step.
|
||||||
|
|
||||||
.PARAMETER SnapshotName
|
.PARAMETER SnapshotName
|
||||||
Name of the snapshot to create. Default: BaseClean (case-sensitive — used by New-BuildVM.ps1).
|
Name of the snapshot to create. Default: BaseClean (case-sensitive — used by New-BuildVM.ps1).
|
||||||
@@ -94,21 +94,21 @@
|
|||||||
|
|
||||||
.EXAMPLE
|
.EXAMPLE
|
||||||
# Fully automated — VMX path only (power-on + IP detection + snapshot automatic):
|
# Fully automated — VMX path only (power-on + IP detection + snapshot automatic):
|
||||||
.\Prepare-TemplateSetup.ps1 `
|
.\Prepare-WinBuild2025.ps1 `
|
||||||
-VMXPath 'F:\CI\Templates\WinBuild\WinBuild.vmx' `
|
-VMXPath 'F:\CI\Templates\WinBuild\WinBuild.vmx' `
|
||||||
-BuildPassword 'StrongCIPass!2026' -StoreCredential
|
-BuildPassword 'StrongCIPass!2026' -StoreCredential
|
||||||
|
|
||||||
# Skip Windows Update (already applied):
|
# Skip Windows Update (already applied):
|
||||||
.\Prepare-TemplateSetup.ps1 `
|
.\Prepare-WinBuild2025.ps1 `
|
||||||
-VMXPath 'F:\CI\Templates\WinBuild\WinBuild.vmx' `
|
-VMXPath 'F:\CI\Templates\WinBuild\WinBuild.vmx' `
|
||||||
-SkipWindowsUpdate -StoreCredential
|
-SkipWindowsUpdate -StoreCredential
|
||||||
|
|
||||||
# Explicit IP (manual start, no VMware Tools required for IP detection):
|
# Explicit IP (manual start, no VMware Tools required for IP detection):
|
||||||
.\Prepare-TemplateSetup.ps1 -VMIPAddress 192.168.79.130 `
|
.\Prepare-WinBuild2025.ps1 -VMIPAddress 192.168.79.130 `
|
||||||
-BuildPassword 'StrongCIPass!2026' -StoreCredential
|
-BuildPassword 'StrongCIPass!2026' -StoreCredential
|
||||||
|
|
||||||
# Both supplied — uses VMXPath for power-on/snapshot, explicit IP skips getGuestIPAddress:
|
# Both supplied — uses VMXPath for power-on/snapshot, explicit IP skips getGuestIPAddress:
|
||||||
.\Prepare-TemplateSetup.ps1 `
|
.\Prepare-WinBuild2025.ps1 `
|
||||||
-VMXPath 'F:\CI\Templates\WinBuild\WinBuild.vmx' -VMIPAddress 192.168.79.130 `
|
-VMXPath 'F:\CI\Templates\WinBuild\WinBuild.vmx' -VMIPAddress 192.168.79.130 `
|
||||||
-BuildPassword 'StrongCIPass!2026' -StoreCredential
|
-BuildPassword 'StrongCIPass!2026' -StoreCredential
|
||||||
#>
|
#>
|
||||||
@@ -217,8 +217,8 @@ $scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
|
|||||||
|
|
||||||
# Pre-flight validation
|
# Pre-flight validation
|
||||||
Assert-Step 'PreFlight' 'script directory resolved' { Test-Path $scriptDir -PathType Container }
|
Assert-Step 'PreFlight' 'script directory resolved' { Test-Path $scriptDir -PathType Container }
|
||||||
Assert-Step 'PreFlight' 'Setup-TemplateVM.ps1 present alongside this script' {
|
Assert-Step 'PreFlight' 'Setup-WinBuild2025.ps1 present alongside this script' {
|
||||||
Test-Path (Join-Path $scriptDir 'Setup-TemplateVM.ps1') -PathType Leaf
|
Test-Path (Join-Path $scriptDir 'Setup-WinBuild2025.ps1') -PathType Leaf
|
||||||
}
|
}
|
||||||
Assert-Step 'PreFlight' "VMIPAddress octets in 0..255" {
|
Assert-Step 'PreFlight' "VMIPAddress octets in 0..255" {
|
||||||
$parts = $VMIPAddress.Split('.') | ForEach-Object { [int]$_ }
|
$parts = $VMIPAddress.Split('.') | ForEach-Object { [int]$_ }
|
||||||
@@ -331,9 +331,9 @@ $session = New-PSSession `
|
|||||||
-ErrorAction Stop
|
-ErrorAction Stop
|
||||||
|
|
||||||
try {
|
try {
|
||||||
# ── Copy Setup-TemplateVM.ps1 into the VM ─────────────────────────────────
|
# ── Copy Setup-WinBuild2025.ps1 into the VM ───────────────────────────────
|
||||||
$setupScript = Join-Path $scriptDir 'Setup-TemplateVM.ps1'
|
$setupScript = Join-Path $scriptDir 'Setup-WinBuild2025.ps1'
|
||||||
$guestScriptPath = 'C:\CI\Setup-TemplateVM.ps1'
|
$guestScriptPath = 'C:\CI\Setup-WinBuild2025.ps1'
|
||||||
|
|
||||||
Write-Host "[Prepare] Ensuring C:\CI exists on guest..."
|
Write-Host "[Prepare] Ensuring C:\CI exists on guest..."
|
||||||
Invoke-Command -Session $session -ScriptBlock {
|
Invoke-Command -Session $session -ScriptBlock {
|
||||||
@@ -345,7 +345,7 @@ try {
|
|||||||
Invoke-Command -Session $session -ScriptBlock { Test-Path 'C:\CI' -PathType Container }
|
Invoke-Command -Session $session -ScriptBlock { Test-Path 'C:\CI' -PathType Container }
|
||||||
}
|
}
|
||||||
|
|
||||||
Write-Host "[Prepare] Copying Setup-TemplateVM.ps1 -> guest $guestScriptPath (UTF-8 BOM)..."
|
Write-Host "[Prepare] Copying Setup-WinBuild2025.ps1 -> guest $guestScriptPath (UTF-8 BOM)..."
|
||||||
# Do NOT use Copy-Item -ToSession: it binary-copies the file.
|
# Do NOT use Copy-Item -ToSession: it binary-copies the file.
|
||||||
# If the source file has no UTF-8 BOM, PowerShell 5.1 on the guest reads it as
|
# If the source file has no UTF-8 BOM, PowerShell 5.1 on the guest reads it as
|
||||||
# Windows-1252, misinterpreting multi-byte UTF-8 sequences (e.g. em dash U+2014
|
# Windows-1252, misinterpreting multi-byte UTF-8 sequences (e.g. em dash U+2014
|
||||||
@@ -375,7 +375,7 @@ try {
|
|||||||
[int64]$remoteSize -ge ([int64]$hostSize - 6) -and [int64]$remoteSize -le ([int64]$hostSize + 6)
|
[int64]$remoteSize -ge ([int64]$hostSize - 6) -and [int64]$remoteSize -le ([int64]$hostSize + 6)
|
||||||
}
|
}
|
||||||
|
|
||||||
# ── Build argument list for Setup-TemplateVM.ps1 ─────────────────────────
|
# ── Build argument list for Setup-WinBuild2025.ps1 ───────────────────────
|
||||||
$setupArgs = @{
|
$setupArgs = @{
|
||||||
BuildPassword = $BuildPassword
|
BuildPassword = $BuildPassword
|
||||||
BuildUsername = $BuildUsername
|
BuildUsername = $BuildUsername
|
||||||
@@ -384,8 +384,8 @@ try {
|
|||||||
if ($SkipWindowsUpdate) { $setupArgs['SkipWindowsUpdate'] = $true }
|
if ($SkipWindowsUpdate) { $setupArgs['SkipWindowsUpdate'] = $true }
|
||||||
if ($SkipCleanup) { $setupArgs['SkipCleanup'] = $true }
|
if ($SkipCleanup) { $setupArgs['SkipCleanup'] = $true }
|
||||||
|
|
||||||
# ── Run Setup-TemplateVM.ps1 inside the VM ────────────────────────────────
|
# ── Run Setup-WinBuild2025.ps1 inside the VM ──────────────────────────────
|
||||||
Write-Host "[Prepare] Running Setup-TemplateVM.ps1 inside VM (this will take a while)..."
|
Write-Host "[Prepare] Running Setup-WinBuild2025.ps1 inside VM (this will take a while)..."
|
||||||
Write-Host "[Prepare] Output from guest:"
|
Write-Host "[Prepare] Output from guest:"
|
||||||
Write-Host "------------------------------------------------------------"
|
Write-Host "------------------------------------------------------------"
|
||||||
|
|
||||||
@@ -412,7 +412,7 @@ try {
|
|||||||
Write-Host ""
|
Write-Host ""
|
||||||
Write-Warning "*** REBOOT REQUIRED after Windows Update. ***"
|
Write-Warning "*** REBOOT REQUIRED after Windows Update. ***"
|
||||||
Write-Warning " The VM will reboot. Wait for it to come back up, then run:"
|
Write-Warning " The VM will reboot. Wait for it to come back up, then run:"
|
||||||
Write-Warning " .\Prepare-TemplateSetup.ps1 -VMIPAddress $VMIPAddress -SkipWindowsUpdate"
|
Write-Warning " .\Prepare-WinBuild2025.ps1 -VMIPAddress $VMIPAddress -SkipWindowsUpdate"
|
||||||
|
|
||||||
# Reboot the VM
|
# Reboot the VM
|
||||||
Write-Host "[Prepare] Sending reboot command to VM..."
|
Write-Host "[Prepare] Sending reboot command to VM..."
|
||||||
@@ -421,7 +421,7 @@ try {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ($result -ne 0) {
|
if ($result -ne 0) {
|
||||||
throw "Setup-TemplateVM.ps1 exited with code $result"
|
throw "Setup-WinBuild2025.ps1 exited with code $result"
|
||||||
}
|
}
|
||||||
|
|
||||||
# ── Post-setup remote validation ──────────────────────────────────────────
|
# ── Post-setup remote validation ──────────────────────────────────────────
|
||||||
@@ -598,7 +598,7 @@ try {
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
Write-Host " 3. Store CI credentials on this HOST (run in elevated PowerShell):"
|
Write-Host " 3. Store CI credentials on this HOST (run in elevated PowerShell):"
|
||||||
Write-Host " .\Prepare-TemplateSetup.ps1 -VMIPAddress $VMIPAddress -StoreCredential"
|
Write-Host " .\Prepare-WinBuild2025.ps1 -VMIPAddress $VMIPAddress -StoreCredential"
|
||||||
Write-Host " (or manually:)"
|
Write-Host " (or manually:)"
|
||||||
Write-Host " New-StoredCredential -Target '$CredentialTarget' ``"
|
Write-Host " New-StoredCredential -Target '$CredentialTarget' ``"
|
||||||
Write-Host " -UserName '$BuildUsername' -Password '<your-build-password>' ``"
|
Write-Host " -UserName '$BuildUsername' -Password '<your-build-password>' ``"
|
||||||
@@ -93,7 +93,7 @@
|
|||||||
Local username for the CI build account. Default: ci_build.
|
Local username for the CI build account. Default: ci_build.
|
||||||
|
|
||||||
.PARAMETER BuildPassword
|
.PARAMETER BuildPassword
|
||||||
Password for the build account. Mandatory — supplied by Prepare-TemplateSetup.ps1
|
Password for the build account. Mandatory — supplied by Prepare-WinBuild2025.ps1
|
||||||
(which prompts interactively). Store the same value in Windows Credential Manager
|
(which prompts interactively). Store the same value in Windows Credential Manager
|
||||||
on the HOST as target "BuildVMGuest".
|
on the HOST as target "BuildVMGuest".
|
||||||
|
|
||||||
@@ -107,10 +107,10 @@
|
|||||||
Skip the Windows Update step (useful if updates were already applied).
|
Skip the Windows Update step (useful if updates were already applied).
|
||||||
|
|
||||||
.NOTES
|
.NOTES
|
||||||
Invoke via Prepare-TemplateSetup.ps1 from the HOST (recommended), or
|
Invoke via Prepare-WinBuild2025.ps1 from the HOST (recommended), or
|
||||||
run manually from an elevated PowerShell session INSIDE the VM:
|
run manually from an elevated PowerShell session INSIDE the VM:
|
||||||
Set-ExecutionPolicy Bypass -Scope Process -Force
|
Set-ExecutionPolicy Bypass -Scope Process -Force
|
||||||
.\Setup-TemplateVM.ps1 -BuildPassword 'YourPassword'
|
.\Setup-WinBuild2025.ps1 -BuildPassword 'YourPassword'
|
||||||
#>
|
#>
|
||||||
[CmdletBinding()]
|
[CmdletBinding()]
|
||||||
param(
|
param(
|
||||||
@@ -118,7 +118,7 @@ param(
|
|||||||
[string] $BuildUsername = 'ci_build',
|
[string] $BuildUsername = 'ci_build',
|
||||||
|
|
||||||
# Password for the build account.
|
# Password for the build account.
|
||||||
# Must be supplied by the caller (Prepare-TemplateSetup.ps1 prompts interactively).
|
# Must be supplied by the caller (Prepare-WinBuild2025.ps1 prompts interactively).
|
||||||
# Store the same password in Windows Credential Manager on the HOST as target "BuildVMGuest".
|
# Store the same password in Windows Credential Manager on the HOST as target "BuildVMGuest".
|
||||||
[Parameter(Mandatory)]
|
[Parameter(Mandatory)]
|
||||||
[string] $BuildPassword,
|
[string] $BuildPassword,
|
||||||
@@ -1125,8 +1125,8 @@ Write-Host "All pre-snapshot checks passed." -ForegroundColor Green
|
|||||||
|
|
||||||
# ── Done ──────────────────────────────────────────────────────────────────────
|
# ── Done ──────────────────────────────────────────────────────────────────────
|
||||||
Write-Host ""
|
Write-Host ""
|
||||||
Write-Host "Setup-TemplateVM.ps1 complete. All Assert-Step checks passed." -ForegroundColor Green
|
Write-Host "Setup-WinBuild2025.ps1 complete. All Assert-Step checks passed." -ForegroundColor Green
|
||||||
# Full next-steps banner is printed by Prepare-TemplateSetup.ps1 on the host.
|
# Full next-steps banner is printed by Prepare-WinBuild2025.ps1 on the host.
|
||||||
# If running this script standalone (manually inside the VM), follow the steps
|
# If running this script standalone (manually inside the VM), follow the steps
|
||||||
# in docs/WINDOWS-TEMPLATE-SETUP.md (shut down → snapshot BaseClean → power off).
|
# in docs/WINDOWS-TEMPLATE-SETUP.md (shut down → snapshot BaseClean → power off).
|
||||||
Write-Host ""
|
Write-Host ""
|
||||||
Reference in New Issue
Block a user