Report the Hyper-V generation from win-detect-nvme-readiness - #155
Edwin Bernal Microsoft (EdwinBernal1) wants to merge 1 commit into
Conversation
NVMe-capable VM sizes are Generation 2 only, so a Generation 1 guest cannot boot on an NVMe controller whatever the stornvme values say - it needs a BIOS/MBR to UEFI/GPT conversion first. The detector had no generation awareness at all, so the flow could reach a repair decision without ever knowing the guest boots BIOS, and a Gen 1 disk with stornvme Start=0 reported bootReadyForNvme true. A caller routing on that field would conclude the VM was fine and go looking for a different fault. Adds partitionStyle, efiSystemPartitionPresent, firmwareType, hyperVGeneration, conversionRequired and mbr2gptAvailable to each finding, plus a top-level signature field. Generation is derived from the disk layout - GPT with an EFI system partition matched by its UEFI-specification GUID, or MBR - because the ARM security profile is not visible from a repair VM, and Trusted Launch would be the wrong signal regardless: it implies Generation 2, but a plain Generation 2 VM does not use it. GPT without an ESP reports Unknown rather than guessing. Claiming V2 would invite a repair that cannot work; claiming V1 would invite an unnecessary conversion. Unreadable disks and partitions report Unknown instead of throwing, so the rest of the stornvme evidence is still collected. Schema version bumped to 1.1.
Edwin Bernal Microsoft (EdwinBernal1)
left a comment
There was a problem hiding this comment.
Reviewed the current head for generation classification and routing safety. The implementation correlates the Windows volume to its owning disk, requires GPT plus an ESP before reporting V2, keeps incomplete layouts as Unknown, and prevents an MBR/V1 installation from reporting bootReadyForNvme=true. The top-level signature precedence also routes conversion before driver repair. I found no blocking correctness or safety issue.
Residual validation gap: GitHub currently reports only the passing CLA check; the added fixture test is not shown as an executed check here. This review is static and did not rerun the script against attached Gen1/Gen2 disks.
|
Note
|
| Category | Score | Notes |
|---|---|---|
| Functional Correctness | 19/20 | All 4 signatures validated on real attached OS disks; core Gen1 fix proven (F4). −1: adjacent GPT-without-ESP false-ready edge (out of PR scope, reproduced in F7b). |
| Code Quality | 19/20 | PSScriptAnalyzer 0 findings; STATUS_ constants, Log-*, try/catch/finally, one-signature if/elseif chain, schema bump. −1: minor dismount GC latency + $null tri-state doc. |
| Safety & Rollback | 19/20 | Provably read-only; robust Dismount-RegistryHive (GC + 5 retries, 3 defensive call sites, try/finally). −1: no explicit before/after partition-table byte-diff run. |
| Telemetry Coverage | 17/20 | Schema-versioned single-line [NVME-EVIDENCE-JSON] contract + .reg evidence bundle + Log-* tee. −3: no runtime event/correlation-id emission (acceptable for a read-only detector). |
| Test Coverage | 18/20 | 7 real-disk fixtures across V1/V2 + edge layouts; PR unit test passes. −2: WS2016/WS2025 not exercised on real disks; unreadable-disk only mocked. |
Fault Injection Results
Fault injection for a read-only classifier = seeding real offline-disk fixtures (SYSTEM-hive stornvme mutation + partition edits) on snapshot copies of real Gen1/Gen2 OS disks, attached to a repair VM.
| Fixture | Disk / Gen | Mutation applied (fault) | Observed signature | bootReadyForNvme | Status |
|---|---|---|---|---|---|
| F3 | fixture-gen2 / V2 (GPT/UEFI) | stornvme Start=0 (stock WS2022 image) | ALREADY_NVME_READY |
true | ✅ PASS |
| F2 | fixture-gen2 / V2 (GPT/UEFI) | stornvme Start=3 (disabled) | NVME_REPAIR_APPLICABLE |
false | ✅ PASS |
| F1 | fixture-gen2 / V2 (GPT/UEFI) | stornvme Start value deleted (absent) | NVME_REPAIR_APPLICABLE |
false | ✅ PASS |
| FDRV | fixture-gen2 / V2 (GPT/UEFI) | stornvme.sys driver file removed | STORNVME_DRIVER_MISSING |
false | ✅ PASS |
| F7 | fixture-gen2 / Unknown (GPT no-ESP) | ESP partition deleted | STORNVME_DRIVER_MISSING (fw=Unknown,gen=Unknown) |
false | ✅ PASS |
| F4 | fixture-gen1 / V1 (MBR/BIOS) | stornvme Start=0 (stock WS2019 default) — misroute case | GEN1_TO_GEN2_CONVERSION_REQUIRED |
false | ✅ PASS |
| F5 | fixture-gen1 / V1 (MBR/BIOS) | stornvme Start=3 | GEN1_TO_GEN2_CONVERSION_REQUIRED |
false | ✅ PASS |
| F7B | fixture-gen2 / Unknown (GPT no-ESP) | driver restored + stornvme Start=0 | ALREADY_NVME_READY |
true |
Regression-guard verdict: CONFIRMED FIXED: real Gen1 disk (F4) with stock stornvme Start=0 yields bootReadyForNvme=false and GEN1_TO_GEN2_CONVERSION_REQUIRED. Old code would have reported bootReadyForNvme=true.
Testing Performed
Strategy: breaker-integrated (offline-disk fixture mutation — no static/dry-run)
Fault Injection: ✅ Real offline SYSTEM-hive mutation + partition edits on real snapshot disks (mutation engine: rvm_mutate_template.ps1)
Region: centralus (eastus2 rejected — Gen1-capable SKUs are NotAvailableForSubscription; all unrestricted eastus2 SKUs are Gen2-only)
Date: 2026-09-16 · Subscription: d4895902-…-f27ef254ebeb (InternalSub-glimoli)
| Dimension | Configuration | Result |
|---|---|---|
| vm_generation V1 | Real WS2019 Gen1 MBR/BIOS disk (F4, F5) | ✅ GEN1_TO_GEN2_CONVERSION_REQUIRED, bootReady=false |
| vm_generation V2 | Real WS2022 Gen2 GPT/UEFI disk (F1, F2, F3, FDRV) | ✅ all signatures correct |
| partition_layout | MBR / GPT+ESP / GPT-without-ESP | ✅ V1 / V2 / Unknown |
| os_sku | WS2019, WS2022 | ✅ (WS2016/WS2025 not on real disks) |
| PR unit test | tests/test-win-detect-nvme-readiness-generation.ps1 (pwsh 7) |
✅ PASS |
| Quorum | 7/7 contract fixtures (required 6) | ✅ MET |
Opportunities for Improvement
8 points recoverable (current 92 → potential 100)
- [Functional / Safety, NON-BLOCKING] Gate
bootReadyForNvmeon the positive fact($finding.hyperVGeneration -eq 'V2')instead of-not $finding.conversionRequired. Empirically reproduced in F7b: a GPT-without-ESP disk (generationUnknown) withstornvme Start=0+ driver present is currently reportedbootReadyForNvme=true/ALREADY_NVME_READY, even though it is not a confirmed Gen2 UEFI disk. The proposed one-liner keeps the Gen1 fix intact and also refusesreadyon ambiguous layouts. - [Code Quality, perf]
Dismount-RegistryHiveruns[gc]::Collect()+WaitForPendingFinalizers()+Start-Sleep 500msbefore the first unload attempt (≈2.5 s avoidable latency ×3 call sites/drive). Try an immediatereg unloadfirst, fall back to the GC path only if the key persists. - [Contract clarity]
efiSystemPartitionPresentis$nullon the unreadable-disk path but$falsewhen evaluated-with-no-ESP. Document the tri-state (or normalize to$false) so strict JSON consumers don't conflate them. - [Test Coverage] Add WS2016 (mbr2gpt.exe absent →
mbr2gptAvailable=false) and WS2025 real-disk fixtures; add a real unreadable-disk fixture.
Validation Evidence
Core fix — real WS2019 Gen1 disk, stock stornvme Start=0 (F4):
partitionStyle=MBR firmwareType=BIOS hyperVGeneration=V1
stornvmeStart=0 stornvmeDriverPresent=True conversionRequired=True
bootReadyForNvme=False <-- FIXED (old code would report True)
signature=GEN1_TO_GEN2_CONVERSION_REQUIRED schemaVersion=1.1 exit=0
Reproduced edge — GPT-without-ESP, driver restored, stornvme Start=0 (F7b):
partitionStyle=GPT efiSystemPartitionPresent=False firmwareType=Unknown hyperVGeneration=Unknown
stornvmeStart=0 stornvmeDriverPresent=True conversionRequired=False
bootReadyForNvme=True <-- false-ready on a NON-Gen2 disk (see Opportunity #1)
signature=ALREADY_NVME_READY
Review Checklist
- Fault injection verified (seed fixture → run detector → assert signature/fields)
- Code quality clean (PSScriptAnalyzer: 0 findings)
- Telemetry coverage reviewed (structured JSON contract; 0 runtime error paths uninstrumented — read-only detector)
- Safety features verified (provably read-only; robust hive unmount)
- Multi-generation tested (Gen2 GPT/EFI + Gen1 MBR/BIOS, both on real disks)
Test Artifacts
- Improvements:
Output/TestReports/PR155-win-detect-nvme-readiness/2026-09-16/Improvements.md - HTML Report:
Output/TestReports/PR155-win-detect-nvme-readiness/2026-09-16/TestReport.html - Execution Manifest:
Output/TestReports/PR155-win-detect-nvme-readiness/2026-09-16/test_execution_manifest.json - Comprehensive ZIP:
Output/TestReports/PR155-win-detect-nvme-readiness/2026-09-16/ComprehensiveTestResults_2026-09-16_1.zip
Note: No SME Tooling WI was resolved for this script during the run (selector tooling errored; ADO lookup deferred). Attach the artifacts above to the SME WI if one exists.
Generated by VMRepairMint Script Testing sub-agent | Test ID: win-detect-nvme-readiness-PR155-20260916 | Head SHA validated: 91e4e8a
Summary
win-detect-nvme-readinessnow reports the Hyper-V generation of the attached Windows installation, and returns a stableGEN1_TO_GEN2_CONVERSION_REQUIREDsignature when it finds a Generation 1 guest.Independent of #154; no dependency in either direction.
The problem
NVMe-capable VM sizes are Generation 2 only. A Generation 1 guest boots BIOS/MBR, so no
stornvmeregistry value can make it boot on an NVMe controller — it needs a BIOS/MBR → UEFI/GPT conversion first.The detector had no generation awareness whatsoever. Its evidence record was
osDrive,systemHiveFound,stornvmeDriverPresent,controlSet, thestornvme*values,storahciStart,cddbNvmeEntries,bootReadyForNvme,problems— nothing about firmware or partition layout. Two consequences:win-enable-nvme-boot-driverwould then write a correct-lookingstornvmeconfiguration to a disk that still cannot boot.stornvme Start=0reportedbootReadyForNvme = true. A caller routing on that field concludes the VM is fine and goes looking for a different fault entirely.Changes
src/windows/win-detect-nvme-readiness.ps1— v1.0.0 → v1.1.0.New per-finding fields:
partitionStyleGet-Diskon the disk hosting the drive letter —MBR/GPT/UnknownefiSystemPartitionPresentGptTypeis the UEFI-specification ESP GUID{c12a7328-f81f-11d2-ba4b-00a0c93ec93b}firmwareTypeBIOS/UEFI/Unknown, derived from the two abovehyperVGenerationV1/V2/UnknownconversionRequiredtruewhenhyperVGenerationisV1mbr2gptAvailableMBR2GPT.exeexists in the attached image — the in-box tool any future conversion would useNew top-level
signaturefield on the evidence record:NVME_REPAIR_APPLICABLE,GEN1_TO_GEN2_CONVERSION_REQUIRED,STORNVME_DRIVER_MISSING, orALREADY_NVME_READY. Free text gets reworded and truncated; a caller should route on this.bootReadyForNvmenow also requires-not conversionRequired, closing the misroute described above.Schema version
1.0→1.1.Two decisions worth reviewing
Generation is derived from the disk layout, not from Trusted Launch. The ARM security profile is not visible from inside a repair VM, and Trusted Launch would be the wrong signal even if it were: it implies Generation 2, but the converse is false — a plain Generation 2 VM does not use it, so treating its absence as Generation 1 would reject valid repair targets. The disk in front of the script is the only honest source.
GPT without an ESP reports
Unknown, not a guess. ClaimingV2there would invite a repair that cannot work; claimingV1would invite an unnecessary and destructive conversion. Same for an unreadable disk or partition —Unknown, and the scan continues so the rest of thestornvmeevidence is still collected rather than lost to an exception.Testing
tests/test-win-detect-nvme-readiness-generation.ps1— new. The detector had no test file at all; this one extractsGet-OfflineWindowsGenerationand drives it against a fixture of the disk cmdlets, so it runs anywhere without an attached disk.Covers: GPT+ESP → V2/UEFI · MBR → V1/BIOS · GPT without ESP → Unknown · missing partition → Unknown, no throw · missing disk → Unknown, no throw. Plus contract assertions that the signature exists, the schema version was bumped,
conversionRequiredis derived from the detected generation,bootReadyForNvmeexcludes Gen 1, and the ESP is matched by its specification GUID rather than a label or size heuristic.Whole repository, after the change:
No live Azure validation was run for this change. The generation derivation is exercised against fixtures only — a live confirmation on a real Generation 1 VM has not been done, and is the obvious thing to ask for before anyone relies on the signature to route a customer.
Behaviour change
Additive for consumers reading individual fields. One semantic change to flag:
bootReadyForNvmenow returnsfalsefor a Generation 1 guest that previously returnedtrue. That previoustruewas wrong — the VM could not boot on NVMe — but a consumer that treatsbootReadyForNvme = falseas "run the repair" should route onsignatureinstead.The script remains read-only. It mounts the SYSTEM hive, reads, and unmounts; the new fields come from
Get-Disk/Get-Partitionand aTest-Path, none of which write.Related
win-convert-gen1-to-gen2) is not in this PR. It is designed but blocked on an open question: whetherMBR2GPT.exe, which is built to convert its own Windows installation, can be driven against a disk attached to a different repair VM. Until that is answered the detector correctly stops at the prerequisite.win-enable-nvme-boot-driverrun id.