Skip to content

vm-repair scripts: add read-only win-detect-nvme-readiness detection script - #144

Merged
Edwin Bernal Microsoft (EdwinBernal1) merged 5 commits into
mainfrom
nvme-migration
Sep 8, 2026
Merged

vm-repair scripts: add read-only win-detect-nvme-readiness detection script#144
Edwin Bernal Microsoft (EdwinBernal1) merged 5 commits into
mainfrom
nvme-migration

Conversation

@EdwinBernal1

@EdwinBernal1 Edwin Bernal Microsoft (EdwinBernal1) commented Sep 5, 2026

Copy link
Copy Markdown
Member

Summary

Adds an NVMe-aware disk-discovery helper for Windows repair VMs, and the first script that uses it.

The existing helpers identify attached disks using the SCSI-specific model name Microsoft Virtual Disk.
On repair VMs using an NVMe controller this can return no disks, and dependent repair scripts may then
complete without modifying the attached OS disk while still reporting success. The new helper selects
eligible disks by BusType, supporting SCSI, SAS, RAID and NVMe controllers.

win-detect-nvme-readiness is a read-only detection script built on that helper. It reports whether a
Windows OS disk can boot from an NVMe disk controller: the stornvme Start value, stornvme.sys
presence, NVMe CriticalDeviceDatabase entries, the active ControlSet, and the bus types of attached
disks. It writes an evidence bundle and emits one machine-readable line prefixed
[NVME-EVIDENCE-JSON]. It makes no changes: the SYSTEM hive is mounted, read and unmounted.

Changes

  • Added src/windows/common/helpers/Get-Disk-Partitions-v3.ps1 (Get-Disk-Partitions-v3, Get-Windows-OsDrives-v3).
  • Added src/windows/win-detect-nvme-readiness.ps1.
  • Added map.json run-id win-detect-nvme-readiness.
  • Updated the helpers README with the v3 entry.

Deliberately unchanged

  • Existing v1 and v2 helpers are untouched.
  • Existing repair-script callers are untouched; caller migration will be handled separately with per-script validation.

Reliable hive unload

A reg unload issued straight after a registry read fails with "Access is denied" because the PowerShell
registry provider still holds keys open, leaving the hive mounted and locking the attached disk for later
runs. The detection script retries, verifies with Test-Path HKLM:\<mount>, and logs the manual unload
command rather than suppressing the error.

Live-validated on SCSI and NVMe repair VMs. Two defects were found and fixed during that validation:
the helper returned its own log lines as data, and it returned before Windows had assigned drive
letters to a newly-onlined disk — which would have made the first run against every fresh repair VM
report "no Windows installation found".

@EdwinBernal1 Edwin Bernal Microsoft (EdwinBernal1) changed the title vm-repair scripts: add NVMe-aware Get-Disk-Partitions-v3 helper vm-repair scripts: add read-only win-detect-nvme-readiness detection script Sep 8, 2026
@mvaferreira

Copy link
Copy Markdown

Late to this since it has already merged, but it is worth recording how it landed on my side — it
overlapped with #143 and your validation notes independently caught two defects in my helpers.

I have adopted your BusType selection. Get-OfflineWindowsDisk.ps1 was selecting disks by
FriendlyName -like '*Virtual Disk*', which is SCSI-only, so on an NVMe repair VM it found nothing
and the scenario reported success without ever touching the attached disk. It now selects on
BusType -in @('SCSI','SAS','RAID','NVMe','File Backed Virtual') — the same set
Get-Disk-Partitions-v3 uses. That was your finding and it was a real bug in mine.

Worth adding as a data point: on an Azure-hosted Windows machine I scored the old and new predicates
read-only against real Get-Disk output. That machine reports BusType = SAS, so the model-string
match was fragile in a second way beyond NVMe.

Your validation notes caught two more. Both were real in my code, in a different form:

  • "it returned before Windows had assigned drive letters to a newly-onlined disk" — mine had a
    fixed 500 ms sleep after diskpart rather than a poll. It now polls, and releases the drive letter
    again if the partition never appears.
  • "the helper returned its own log lines as data" — this is precisely why OfflineRepairCommon.ps1
    buffers through Add-OfflineRepairLog and flushes once at script scope. Any helper that both logs
    and returns a value has this problem, so the same pattern may be worth applying to
    Get-Disk-Partitions-v3.

On the hive unload, your "Reliable hive unload" section describes exactly the failure
Use-OfflineRegistryHive.ps1 exists to solve — the provider keeps keys open, reg unload returns
"Access is denied", the hive stays mounted and locks the disk for every later run. Your script
handles it for its own single mount; the helper generalises it, disposing the handles the scriptblock
produced before attempting the unload, retrying, verifying the hive is actually gone, and treating a
failed unload as a failure rather than reporting success.

Where the two disk helpers stand now. #143 has been restructured into three smaller PRs in
response to the review — #143 itself, plus #146 and #147 — all cut from main after this merged, so
they add files alongside Get-Disk-Partitions-v3.ps1 and leave it and its README entry untouched.

They are not quite duplicates: Get-Disk-Partitions-v3 returns every partition of every attached
disk, while Get-OfflineWindowsDisk identifies the Windows installation to repair — scoring it
when a disk carries more than one, locating its boot partition and BCD store, and binding it as an
offline root that a gate then asserts against on every privileged write. I have said as much in the
README rather than leaving a reader to guess which to reach for.

If you would rather they converge properly, I am happy either way: fold Get-OfflineWindowsDisk on
top of Get-Disk-Partitions-v3 so there is one Get-Disk pass, or drop mine and build the
installation-selection logic into yours. Your file, your call. The parts I would want to keep in
either direction are the rescue-VM exclusions — a hard failure rather than a warning when the rescue
VM's own system disk cannot be resolved, an IsBoot/IsSystem exclusion as defence in depth, and
skipping the Azure temporary/resource disk.

One smaller thing: win-detect-nvme-readiness mounts and reads the SYSTEM hive directly. If the hive
helper lands it could use Invoke-WithHive and drop its own mount/unload handling.

Marcus Ferreira (mvaferreira) pushed a commit to mvaferreira/repair-script-library that referenced this pull request Sep 8, 2026
Merging upstream/main auto-resolved src/windows/common/helpers/README.md
to upstream's copy, which dropped all eight helper rows from main. The
three pull request branches were unaffected - each builds its own README
from upstream and adds only its own rows - so this restores main to the
union of the three, in dependency order.

Also resolves the map.json conflict by keeping both sides: upstream's
win-detect-nvme-readiness entry from Azure#144 alongside ours. Verified: 47
entries, no duplicate ids, no upstream id lost, and every entry path
resolves to a file that exists.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants