Commit graph

18 commits

Author SHA1 Message Date
Viktor Barzin
3d31a39099 kms-website: verify ODT install completion + capture ODT log; reboot-aware after uninstall
Invoke-Odt returned $true unconditionally after setup.exe, so a failed or
not-yet-finished Click-to-Run install surfaced only as a bare "ospp.vbs not
found after install". Root-cause fixes:
- <Logging> in the config XML -> a capture dir, read back on failure so the
  real setup.exe exit code / error is reported (and sent as telemetry).
- setup.exe run with -PassThru; non-zero (not 0/3010) exit -> fail + log tail.
- Wait-OfficeInstalled polls on-disk state (ospp.vbs + ProductReleaseIds)
  instead of trusting setup.exe's early return under Display Level=None.
- After removing incompatible consumer Office (e.g. O365HomePremRetail), a
  pending reboot now stops the run with reboot+re-run guidance rather than
  half-completing the VL install in the same session (idempotent on re-run).
2026-06-01 20:21:58 +00:00
Viktor Barzin
2027d8bcc0 kms-website: uninstall incompatible (retail/M365) Office before VL install
When the Office install path runs and a non-VL Click-to-Run Office is present
(ProductReleaseIds not ending in 'Volume' = retail/M365), it can't coexist with
a VL install of the same suite. Now: detect it, show it in the consent prompt,
ODT /configure <Remove> only those products (VL products of other families
preserved), then proceed with the VL install. Refactored the ODT run into a
shared Invoke-Odt used by both install (<Add>) and uninstall (<Remove>).
Telemetry on the uninstall step.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-01 20:00:54 +00:00
Viktor Barzin
7cfcd73d83 kms-website: anonymous client diagnostics (Send-Diag -> /diag) + FAQ disclosure
Fire-and-forget telemetry so script failures are captured server-side (Loki via
the kms-diag collector). kms-bootstrap.ps1 + setup-kms.ps1 POST a small anonymous
JSON event at each outcome (action, ok/fail, error text + exit codes, EditionID/
build/locale, detected Office products; no hostname/user/keys). 3s timeout,
errors swallowed -- never affects activation. $env:KMS_NO_TELEMETRY=1 opts out;
$env:KMS_DIAG_URL overrides. Version baked at build via Dockerfile sed
(__KMS_VERSION__ -> SCRIPT_VERSION build-arg). FAQ updated to disclose it.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-01 19:46:49 +00:00
Viktor Barzin
b51dc9894c kms-website: self-host the ODT bootstrapper (fix 404 on Office reinstall)
Microsoft's download.microsoft.com ODT URL is build-numbered and rotates every
release; the hardcoded officedeploymenttool_19127-20198.exe now 404s, so the
"install latest VL Office" path failed right after the consent prompt. Serve a
known-good ODT bootstrapper from our own /scripts/odt-setup.exe (carved out of
Anubis already) and point Reinstall-OfficeVL at it. $env:KMS_ODT_URL overrides.
The bootstrapper self-updates the Office payload, so it rarely needs refreshing.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-01 19:37:10 +00:00
Viktor Barzin
06009dae30 kms-website: fix consent prompt suppressed by KMS_AUTO
The activate-windows/office wrappers set $env:KMS_AUTO to pre-select the
product, but Approve() treated any KMS_AUTO as "non-interactive" and skipped the
consequences prompt -- so on a machine needing the ODT/edition install it printed
the consequences then exited without asking. Gate the prompt on a real console
([Environment]::UserInteractive + not IsInputRedirected, guarded) instead of
KMS_AUTO. KMS_AUTO now only selects WHICH products to activate.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-01 19:23:51 +00:00
Viktor Barzin
d3c52b3bf7 kms-website: dedicated activate-windows / activate-office one-liner commands
The two most common operations now have clean, key-free commands (no
$env:KMS_AUTO prefix) that delegate to kms-bootstrap.ps1:
  iwr .../scripts/activate-windows.ps1 | iex
  iwr .../scripts/activate-office.ps1  | iex
activate-office is Office-only (Project/Visio excluded — bundling them would
prompt to *install* products you don't have, given the new install-offer).
Quick Start now leads with these two; the interactive bootstrap stays as the
"activate everything" option. Dropped the redundant KMS_AUTO combo cards.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-01 19:15:10 +00:00
Viktor Barzin
a0c100ab08 kms-website: install the LATEST VL Office, and offer it when none is installed
- Get-LatestOfficeProduct picks the newest ProPlus/ProjectPro/VisioPro VL SKU
  from keys.json by year (data-driven: add a future LTSC to products.yaml and
  the installer follows; no hardcoded 2024). $env:KMS_OFFICE_PRODUCT still wins.
- Activate-Ospp now offers the ODT install in BOTH cases: no Office found at all
  (previously it just skipped with "not found"), and a non-VL/retail/M365 Office
  installed. ODT channel comes from the chosen product's keys.json entry.
Note: KMS can't activate Microsoft 365/retail, so "latest" = latest LTSC VL.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-01 19:02:08 +00:00
Viktor Barzin
e38f34f146 kms-website: consequences-gated edition switch (Windows changepk + Office ODT)
When the installed product can't KMS-activate as-is, offer to fix it after
showing the consequences (default No; non-interactive needs explicit env consent):
- Windows non-VL edition (Home/retail) -> changepk.exe /ProductKey <target GVLK>
  (default Pro, $env:KMS_EDITION override). Warns: reboot required, one-way,
  re-run after reboot to activate.
- No VL Office/Project/Visio installed -> slim ODT setup.exe /configure to the
  target VL product (default ProPlus/ProjectPro/VisioPro 2024,
  $env:KMS_OFFICE_PRODUCT override). Warns: ~3 GB download, closes Office apps.
setup-kms.ps1 stays minimal: a non-VL edition is pointed at the bootstrap
one-liner (which can upgrade) rather than duplicating changepk.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-01 14:35:56 +00:00
Viktor Barzin
cf5f91c303 kms-website: per-product Office license check (multi-product idempotency)
ospp /dstatus lists every installed product, so the blanket '---LICENSED---'
match treated an Office-licensed machine as Project/Visio-licensed too, causing
KMS_AUTO=office,project to skip Project. Add Test-OsppLicensed that parses the
per-SKU LICENSE NAME/STATUS blocks and checks only the requested family.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-01 10:24:34 +00:00
Viktor Barzin
01803ab812 kms-website: ASCII-only comment (em-dash -> colon)
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-01 10:18:43 +00:00
Viktor Barzin
f1440dfcf4 kms-website: fix Office auto-key label filter ($_ shadowing in switch)
Inside `switch ($label) {...}` the automatic $_ is the switch input (the label),
not the Where-Object pipeline item, so the per-product filter always matched and
KMS_AUTO=office would also install Project/Visio keys. Replace with explicit
label/$_ comparisons.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-01 10:18:24 +00:00
Viktor Barzin
9059dbc85b kms-website: auto-fetch + auto-install GVLKs (no manual key lookup)
Scripts now detect the running edition and fetch the matching GVLK from a
published key list instead of requiring the user to copy one from the table.

- data/products.yaml: add editionid to every Windows/Server entry, plus build
  numbers where an EditionID spans releases (LTSC, Server). Azure Edition left
  unmapped on purpose (collides with Datacenter; KMS may fail there anyway).
- /keys.json: Hugo KEYS output format renders products.yaml as JSON
  (single source of truth). layouts/index.keys.json.
- setup-kms.ps1: when no VL key is installed, read registry EditionID
  (+build/ProductType for server) -> fetch /keys.json -> slmgr /ipk the match
  -> activate. Only acts when not already licensed (never clobbers retail).
- kms-bootstrap.ps1: same for Windows; for Office/Project/Visio, read
  Click-to-Run ProductReleaseIds -> ospp /inpkey the matching GVLK -> /act.
- $env:KMS_KEYS_URL overrides the key-list URL.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-01 10:12:03 +00:00
Viktor Barzin
c27077549c kms-website: ASCII-only script output (em-dash -> hyphen)
Em-dashes in the new idempotency status messages render as "?" garbage on
non-UTF-8 Windows consoles (cp437/850). Replace with ASCII hyphens.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-01 09:02:19 +00:00
Viktor Barzin
d11dc8c0ce kms-website: make activation scripts idempotent + harden Office detection
- Replace locale-dependent "License Status: Licensed" regex with a
  locale-independent WMI probe (SoftwareLicensingProduct.LicenseStatus==1).
  Fixes false "not licensed yet" reports on non-English Windows and on re-runs.
- Idempotent: always pin the KMS host, but skip /ato (Windows) and /act
  (Office) when already licensed — report days remaining instead of
  re-contacting the public KMS server.
- Find-Ospp now also checks Click-to-Run \root\Office16\ (+ \root\Office15\)
  layouts, not just the MSI Office16 path.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-01 08:53:20 +00:00
Viktor Barzin
efa1353e6b kms-website: activate against vlmcs.viktorbarzin.me, drop ODT-install + deep-legacy GVLKs
The page advertised kms.viktorbarzin.me:1688 as the KMS host, but that name
is the website (Traefik) — internally it resolves to 10.0.20.203 which has no
:1688 listener, so LAN clients failed with "KMS server cannot be reached".
Split the concern: siteHost (kms.viktorbarzin.me) serves the page + /scripts
downloads; kmsHost is now the dedicated A-only vlmcs.viktorbarzin.me endpoint
that resolves to the vlmcsd MetalLB IP (10.0.20.202) on the LAN (Technitium)
and to the public IP over the internet (Cloudflare -> pfSense WAN NAT :1688).

Moderate cleanup:
- remove the Office-install-via-ODT path from kms-bootstrap.ps1 (activation
  only now; manual ODT install docs stay on the page)
- collapse Windows 8.1/8/7/Vista + Server 2012/2008 GVLK tables into a legacy
  note (those keys still activate; just no longer tabled)
- drop the unused kmsHostLan param

Pairs with the infra /scripts Anubis carve-out that makes `iwr | iex` work.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-01 08:05:31 +00:00
Viktor Barzin
8bcb64bf99 kms-website: 3-up KMS_AUTO quick-start cards + save-as downloads + clean script comments
- Replace single interactive one-liner with three side-by-side cards
  (Windows / Office+Project+Visio / Both) using $env:KMS_AUTO=...; the
  contract is already supported by kms-bootstrap.ps1
- Make Downloads links use the 'download' attribute so browsers prompt
  save-as instead of rendering .ps1 as text
- Strip operator-side framing: kms-bootstrap.ps1 no longer says
  "this activation has been logged" and both scripts now point Source
  at the public mirror instead of forgejo.viktorbarzin.me
2026-05-09 22:12:21 +00:00
Viktor Barzin
5da130be93 kms-website: public scripts + sanitized copy + slack notifier
- static/scripts/{setup-kms.ps1,kms-bootstrap.ps1}: public, internet-friendly
- Drop \\nas.viktorbarzin.lan\\Emo shared\\ refs (internal SMB share, leaks personal name)
- Reframe LAN section as optional auto-discovery for self-hosters
- Add privacy + legality FAQs
- Quick Start uses one-liner: iwr | iex against /scripts/kms-bootstrap.ps1
- bootstrapURL now points at site-relative /scripts/

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-09 17:54:38 +00:00
Viktor Barzin
3fc75b636a Initial commit — Hugo source, Dockerfile, Woodpecker pipeline
Modernized kms.viktorbarzin.me reference page covering every Windows
+ Office Volume License GVLK Microsoft publishes, plus activation
snippets, ODT config, and bootstrap script links.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-07 23:13:25 +00:00