Add win-fix-boot-partition - #158
Marcus Ferreira (mvaferreira) wants to merge 3 commits into
Conversation
Repairs the system partition of an offline Windows disk: the partition the firmware reads before Windows exists, and the boot sectors inside it. Targets a damaged or missing system partition, not the contents of the BCD store.
- Invoke-SectorRepair assembled the sector 0 write from \.MbrRaw, which the detect pass captured before the Set-Partition calls at the top of the same function moved the Active flag. Write-RawDiskSector writes the whole 512 bytes, partition table included, so the stale buffer put the old table back and undid the Active flag repair that had just been reported as successful. Sector 0 is now re-read immediately before the buffer is built, and the repair is abandoned rather than guessed at if that read fails. - Get-PartitionFilesystemFinding read State.FileSystem without checking whether the boot sector had been read at all. A failed read leaves it 'Unknown', which is not FAT, so a transient I/O or sharing error on a perfectly good EFI System Partition would have it reformatted. An unread boot sector is now a distinct non-repairable finding. - The revert manifest is written before the first write instead of after the last one. Several repair paths return early on failure, and a disk that has been modified with no manifest beside it cannot be reverted at all. - Get-UnreadablePartitionTable is the one write that happens before the offline disk has been identified. It now skips the rescue VM's own system, boot and clustered disks, and the caller refuses to act when more than one disk qualifies instead of writing to each in turn. - Added the missing finally: release the drive letters Get-OfflineWindowsDisk assigned and flush the log buffer on the failure paths too. - Replaced references to run ids that do not exist in the library. The filesystem scenario is win-chkdsk-fs-corruption; the boot configuration script is named descriptively because its run id depends on the library version installed. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: b4446db8-dda7-4210-a934-5b9ae9e3fb15
Review findings addressed —
|
| ID | Finding | Change |
|---|---|---|
| C1 | The sector-0 write used a stale in-memory MbrRaw, silently undoing the Set-Partition -IsActive repair performed moments earlier in the same run |
sector 0 is re-read fresh with Read-RawDiskSector immediately before the bootstrap write, and the repair aborts if that read throws |
| W1 | A failed VBR read was treated as an unformatted ESP, sending a readable-but-unlucky partition to Format-Volume |
a null VbrRaw now raises EspUnreadable instead of triggering a format |
| W2 | No finally: drive letters were never released |
finally added |
| W3 | Revert manifest written after the sector repair's early return | the manifest is written before the first write |
| W4 | Dangling run-id references (win-fix-bcd, win-fix-file-system) |
win-fix-file-system corrected to win-chkdsk-fs-corruption |
| W5 | Preflight RAW-disk sector write ran before offline binding with no exclusions | Get-UnreadablePartitionTable now skips IsSystem/IsBoot/IsClustered disks, and the caller refuses when more than one disk qualifies |
Validation
Break → detect → repair → detect → az vm repair restore → confirm the guest boots, all through
the product path with --preview pointing at the candidate branch. Three scenarios, deliberately
spanning both partition layouts and both VM generations:
| Scenario | Image | Generation / layout | Build | Result |
|---|---|---|---|---|
| Active flag cleared | WindowsServer:2016-Datacenter |
Gen1 / MBR | 14393 | 11/11 passed |
| C1 differential | WindowsServer:2022-Datacenter |
Gen1 / MBR | 20348 | 11/11 passed |
| ESP bootstrap zeroed | WindowsServer:2022-datacenter-azure-edition |
Gen2 / GPT | 20348 | 11/11 passed |
The C1 differential deserves a note, because the first scenario did not actually reach the
defect. Clearing the Active flag alone makes the repair take the partition path and return before
it ever writes sector 0. A combined break was needed — clear the Active flag and zero the MBR
bootstrap — to force both repairs in one run. That produced the exact ordering the fix exists for:
Set the Active flag on partition 1
Prepared the Windows MBR bootstrap ... partition table at offset 446 is unchanged
Sector 0 written and read back identical
Under the previous code the stale clone would have replayed the partition table captured before
the Active flag was set, reverting it. Post-repair detect was clean and the VM booted.
The Gen2/GPT run exercised the destructive ESP path end to end and confirmed two of the fixes in
its log — the manifest is written before the format, and the disk is re-read after the partition
change:
Wrote the revert manifest to F:\win-fix-boot-partition-revert.json.
Formatted the EFI System Partition (G:) as FAT32.
Running: bcdboot F:\Windows /s G: /f UEFI
bcdboot: Boot files successfully created.
Restored the EFI System Partition type on partition 3.
Re-reading the disk after the partition change, so the boot sector repair works from the
partition table that is there now rather than the one read before it.
Post-repair detect reported the ESP back as FAT32 and "the system partition and its boot sectors
are consistent with this disk"; the guest booted.
Provenance
- Reviewed head:
8759d95fbd27553252bb96027e4d085dfc69086f - Final tested head:
844a508 - Review prompt:
PR-Review-Agent.md, SHA2565451BA5C325F61E34FE63B9AF99322A17D70E55210CAF23F5CE27E0F839D8F70 - Counts derived from the report tables: 1 Critical, 5 Warnings (6 Info items not itemised here)
- The original agent report is tied to head
8759d95fand is historical: the code has changed since. - Quality gates on the final head: PowerShell 7 and 5.1 parse clean, PSSAnalyzer at parity with the
reviewed head, repository pre-commit hook passing, CRLF line endings preserved.
…rtition # Conflicts: # map.json
What this adds
win-fix-boot-partition— a single repair scenario, 2106 lines, plus its ownmap.jsonentry.Repairs the system partition of an offline Windows disk: the partition the firmware reads before Windows exists, and the boot sectors inside it. Targets a damaged or missing system partition, not the contents of the BCD store.
The catalog entry a support engineer reads when choosing it:
How it works
Runs against the broken OS disk attached to a rescue VM by "az vm repair create". It answers the question "can the firmware reach a boot partition on this disk at all", which is the layer below win-fix-bcd. If there is no system partition, or its boot sectors are damaged, no amount of BCD repair helps, because the firmware never gets far enough to read the store.
The script repairs in two tiers, and which tier runs is decided by the evidence:
Parameters
detectOnlyrevertwindowsDriveConventions followed
.\src\windows\common\setup\init.ps1and returns$STATUS_SUCCESSor$STATUS_ERROR.Write-Host.az vm run-commandkeeps only the last 4096 characters of the output stream, so a summary printed first is the first thing a long run loses.PSUseShouldProcessForStateChangingFunctionson internal helper functions. The script is invoked non-interactively byaz vm repair run, so-WhatIf/-Confirmon an internal function are unreachable; the reporting-only mode is thedetectOnlyparameter instead.Testing
Exercised through the
az vm repair run --previewproduct path against real Azure VMs: a lab VM is broken deliberately to create the fault, the repair is run against the attached disk from a rescue VM, and the VM is confirmed to boot and behave afterwards. Detection, restraint on a healthy image, and the repair itself are each checked.Series
Second wave of four independent scenario PRs, after #149, #150, #151 and #152. The shared helpers
these scripts dot-source are already merged in #143, #146 and #147. This PR adds no helper files and
changes no existing scenario; its only existing-file change is appending this run-id to
map.json,inserted into whatever upstream carries now so every existing entry is preserved byte for byte.