Files
bootstrap_windows_env/test/integration/packer/README.md

168 lines
6.9 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Vagrant box build (Packer + Hyper-V + Windows 11 25H2)
Builds a `bootstrap-win11.box` Vagrant box from a stock Windows 11 25H2 ISO,
ready to use with `test/integration/Vagrantfile`.
## Prerequisites
On the host (must be Windows with Hyper-V):
- Hyper-V role enabled; current user in **Hyper-V Administrators**.
- [HashiCorp Packer](https://developer.hashicorp.com/packer/install) 1.15+ in
`PATH`. HashiCorp does not publish a winget manifest, so use the helper:
```powershell
# from an elevated PowerShell
cd test\integration\packer
.\install-packer.ps1 # installs the pinned default version
.\install-packer.ps1 -Version 1.14.0 # or pick a specific release
```
The script downloads
`https://releases.hashicorp.com/packer/<Version>/packer_<Version>_windows_amd64.zip`,
extracts `packer.exe` to `C:\Program Files\Packer\`, and adds that directory
to the machine-scoped `PATH`. It is idempotent — re-running with the same
version just re-asserts the `PATH` entry. See the `param()` block in
`install-packer.ps1` for available flags.
By default the same script also installs **Windows ADK Deployment Tools**
to get `oscdimg.exe`, which Packer's `hyperv-iso` builder needs to build the
unattended-install secondary ISO from `cd_files`. Only the
`OptionId.DeploymentTools` feature is selected, so the install is small
(~70 MB) and unattended. Pass `-SkipOscdimg` to opt out (e.g. if you already
have `xorriso`/`mkisofs` on `PATH`). After install you may need to open a
fresh shell — or run
`$env:Path = [Environment]::GetEnvironmentVariable('Path','Machine')` — for
`oscdimg.exe` to resolve in the current session.
- [HashiCorp Vagrant](https://developer.hashicorp.com/vagrant/install) 2.4+ in
`PATH` (used for the `vagrant` post-processor and, later, the integration
test itself).
- A Windows 11 client ISO somewhere on disk. Its path is read from `.env`
(see below) and is **not** hardcoded in the Packer config.
- Roughly 90 GB free disk and ~60 minutes of patience for a first build.
- An elevated PowerShell session for the build (`packer build` shells out to
Hyper-V management APIs that require admin).
## Configure the ISO path via `.env`
The Packer config has no default ISO path. Copy the template, fill it in, and
load it into the current shell before building:
```powershell
cd test\integration\packer
Copy-Item .env.example .env
# edit .env so PKR_VAR_iso_path points at your Windows 11 ISO
. .\load-env.ps1
```
`load-env.ps1` reads `.env` line-by-line and exports each `KEY=VALUE` into the
process environment. `.env` is gitignored at the repo root, so your local path
never gets committed.
Packer picks the values up automatically through its `PKR_VAR_<name>` env-var
convention; nothing about the `packer build` invocation changes.
## One-time setup
```powershell
packer init .\windows-11.pkr.hcl
```
That downloads the `hyperv` and `vagrant` Packer plugins.
## Compute and pin the ISO checksum (recommended)
```powershell
Get-FileHash $env:PKR_VAR_iso_path -Algorithm SHA256
```
Set `PKR_VAR_iso_checksum=sha256:<digest>` in `.env` and re-run `load-env.ps1`.
Leaving it as `none` skips validation; fine for local builds but loses the "my
ISO has not been swapped" guarantee.
## Build
```powershell
packer build .\windows-11.pkr.hcl
```
Roughly what happens:
1. Packer creates a Gen 2 Hyper-V VM (Secure Boot + TPM + 24 vCPU + 32 GB RAM
+ 80 GB dynamic VHDX) attached to `Default Switch`. The build VM is
throwaway and intentionally claims most of the host for speed; the
runtime integration VM uses smaller defaults set in
`test/integration/Vagrantfile` (8 vCPU / 16 GB).
2. It mounts the Windows ISO and a tiny `PROVISION` ISO containing
`cd/autounattend.xml` and `cd/scripts/oobe-enable-winrm.ps1`.
3. Windows Setup performs an unattended install (Pro edition, generic
activation key) and creates user `vagrant`:`vagrant`.
4. FirstLogonCommands enable WinRM (HTTP, basic auth) and set
`LocalAccountTokenFilterPolicy=1` so remote admin tokens are not filtered.
5. Packer connects over WinRM and runs the provisioners in `scripts/`:
- `configure-os.ps1` — UAC token policy, DiagTrack off, NTP resync.
- `disable-windows-updates.ps1` — fully disables WU and friends.
- `disable-defender-cloud.ps1` — disables MAPS / cloud lookups.
- `install-vagrant-key.ps1` — drops the vagrant insecure public key.
- `compact.ps1` — cleans caches, zeros free space.
6. Packer shuts the guest down cleanly and the `vagrant` post-processor
packages the VHDX into `bootstrap-win11.box`.
## Register the resulting box with Vagrant
```powershell
vagrant box add bootstrap-win11 .\bootstrap-win11.box
```
Then in `test/integration/Vagrantfile` set:
```powershell
$env:BOOTSTRAP_BOX = "bootstrap-win11"
go run ..\..\test\integration
```
(or just edit the default in the Vagrantfile to `bootstrap-win11`).
## Layout
```
test/integration/packer/
├── README.md ← this file
├── .env.example ← template; copy to .env (gitignored)
├── load-env.ps1 ← dot-source to export PKR_VAR_* into shell
├── install-packer.ps1 ← elevated installer for packer.exe
├── windows-11.pkr.hcl ← Packer HCL2 build definition
├── vagrantfile-template.rb ← baked into the output box
├── cd/
│ ├── autounattend.xml ← Windows Setup answer file
│ └── scripts/
│ └── oobe-enable-winrm.ps1
└── scripts/ ← provisioners run after WinRM is up
├── configure-os.ps1
├── disable-windows-updates.ps1
├── disable-defender-cloud.ps1
├── install-vagrant-key.ps1
└── compact.ps1
```
## Notes and gotchas
- **Run elevated.** `packer build` opens Hyper-V management APIs; non-elevated
shells fail with confusing "access denied" messages midway through.
- **First build is slow.** Windows Setup + updates trimming + cipher /w on a
60 GB volume can take 45–90 min. Subsequent rebuilds reuse the parent VHDX
via linked clone and are much faster.
- **License compliance.** The box uses the public KMS client setup key
(W269N-WFGWX-YVC9B-4J6C9-T83GX) to pick the Pro edition during install. The
resulting VM is not activated; for short-lived integration runs the eval
period is more than sufficient, but redistribute the box only under your
own licensing terms.
- **25H2 OOBE.** The autounattend sets `BypassNRO=1` during `specialize`
because 24H2/25H2 removed the `BypassNRO.cmd` helper. If a future Windows
update changes the OOBE flow again, the symptom will be a hung
`vagrant up` waiting for WinRM; check by opening Hyper-V Manager and
looking for an OOBE screen on the VM console.
- **Secure Boot.** Enabled (`MicrosoftWindows` template). Switch off in the
Packer source if you ever need to install unsigned kernel-mode drivers in
the box.