Skip to content

Fix various win-toggle-safe-mode errors and confirm gen2 compatible#106

Open
Vorsku wants to merge 2 commits into
Azure:mainfrom
Vorsku:main
Open

Fix various win-toggle-safe-mode errors and confirm gen2 compatible#106
Vorsku wants to merge 2 commits into
Azure:mainfrom
Vorsku:main

Conversation

@Vorsku

@Vorsku Vorsku commented Nov 26, 2025

Copy link
Copy Markdown

Hi,

Thanks for this project!

I've encountered various issues with the win-toggle-safe-mode script which this PR fixes:

  1. Missing comments on line 48-49 which stop the script starting entirely
  2. AZ CLI always passes parameters as strings so the current DC switch does not work
  3. Any partitions without a drive letter get ignored (which includes the EFI partition we care about for safe mode which normally doesn't have a drive letter) so refactored to also check access paths
  4. Script error if it can't start up the ProblemVM - I've found by default my repair VM doesn't have enough memory to power up the nested VM, but we don't need the ProblemVM to be started to perform the safe mode changes so I've changed the error action to SilentlyContinue

I've tested this updated version successfully against a 2016 domain controller running in Azure as a Gen2:

az vm repair create -g rg-adrestore-tst01 -n vm-adrestore-tst01 --yes --repair-username local_admin --repair-password 'password!234' --enable-nested --verbose

az vm repair run -g rg-adrestore-tst01 -n vm-adrestore-tst01 --preview "https://github.com/Vorsku/repair-script-library/blob/main/map.json" --run-id win-toggle-safe-mode --parameters safeModeSwitch=on DC=yes --verbose --run-on-repair

az vm repair restore -g rg-adrestore-tst01 -n vm-adrestore-tst01 --verbose

Thanks,
Josh

@Vorsku

Vorsku commented Nov 26, 2025

Copy link
Copy Markdown
Author

@microsoft-github-policy-service agree

@Vorsku

Vorsku commented Nov 26, 2025

Copy link
Copy Markdown
Author

@Sandido hoping you can review please? The current script doesn't work anyway due to the missing comments

@EdwinBernal1 EdwinBernal1 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Summary

Fixes four issues in win-toggle-safe-mode.ps1:

  1. Broken comment syntax (lines 48-49) — Missing # on version history lines causes PowerShell parse failure, making the entire script unusable.
  2. [switch]$DC incompatible with AZ CLIaz vm repair run --parameters passes all values as strings; [switch] never activates. Changed to [ValidateSet("Yes","No")][string].
  3. Gen2 EFI partition not detected — EFI System Partition has no drive letter. New code falls back to AccessPaths (volume GUID) for partition scanning.
  4. Error handling adjustmentsStart-VM changed to SilentlyContinue; catch block simplified.

What's Good

Area Detail
Comment syntax fix (lines 48-49) Critical fix. The current main has v0.4: and v0.3: without # — PowerShell treats these as statements and the script fails to parse. This alone justifies the PR
$DC switch → string Correct. az vm repair run --parameters DC=$true passes "$true" as a literal string, not a boolean. [switch] never activates. ValidateSet("Yes","No") is the right pattern
Volume GUID access paths Gen2 VMs have an EFI System Partition without a drive letter. The new $driveCandidates logic correctly falls back to AccessPaths (e.g., \\?\Volume{...}\), enabling BCD discovery at \efi\microsoft\boot\bcd
$osDrive tracking Fixes a real bug — the old code used $drive (loop variable) for registry operations after the loop, meaning it would reference the last iterated partition, not the one containing winload.exe
$root normalization Clean handling of both "C:" and \\?\Volume{...}\ path formats for BCD/OS path construction

Issues Found

🔴 Bug: $osDrive used with drive-letter syntax for registry paths

After the loop, the code uses $osDrive with drive-letter syntax:

# Line 167 (PR)
$regPath = $osDrive + ':\Windows\System32\config\'

# Line 176 (PR)
reg load "HKLM\BROKENSYSTEM" "$($osDrive):\Windows\System32\config\SYSTEM"

If $osDrive is a volume GUID path (e.g., \\?\Volume{abc}\), appending :\Windows\... produces an invalid path like \\?\Volume{abc}\:\Windows\....

In practice this is low-risk because winload.exe lives on the OS partition which almost always has a drive letter (the letterless partition is typically just EFI). But for correctness, the fix should store a normalized root alongside $osDrive:

if ($isOsPath) {
    $osDrive = $drive
    $osRoot = $root   # <-- store the normalized root too
}

Then use $osRoot for all path construction after the loop:

$regPath = "${osRoot}\Windows\System32\config\"
reg load "HKLM\BROKENSYSTEM" "${osRoot}\Windows\System32\config\SYSTEM"

🟡 Concern: Start-VM with -ErrorAction SilentlyContinue

start-vm $guestHyperVVirtualMachine -ErrorAction SilentlyContinue
#Sometimes the repair VM doesn't have enough memory to power it on

This silently swallows the failure, then returns $STATUS_SUCCESS. The user sees "success" but the nested VM is still stopped. A better approach:

try {
    Start-VM $guestHyperVVirtualMachine -ErrorAction Stop
}
catch {
    Log-Output "WARNING: Could not start nested VM (may need more memory). BCD changes were applied successfully." |
        Tee-Object -FilePath $logFile -Append
}

This still doesn't block the script but gives the user visibility.


🟡 Concern: Catch block no longer restarts the VM

The old catch block attempted to restart the nested VM after an error. The PR removes this:

# REMOVED:
# Start Hyper-V VM again
# Log-Output "#06 - Starting VM"
# start-vm $guestHyperVVirtualMachine -ErrorAction Stop

If the script fails mid-operation, the nested VM is left stopped with its disk offline. The old behavior at least tried to restore the VM to a running state. Consider keeping this (with SilentlyContinue or a try/catch) so the user's nested environment isn't left broken.


🟢 Minor: Missing newline at end of file

The diff shows No newline at end of file on the last line. Should add a trailing newline.


🟢 Minor: Catch block log step number

Log-Output "#99 - Bringing disk offline to restart Hyper-V VM"

Changing #05 to #99 is fine for disambiguation but #99 is arbitrary. Consider a naming convention like #ERR-01 to clearly indicate it's an error-path step.


@Vorsku Vorsku requested a review from EdwinBernal1 June 16, 2026 10:09
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.

2 participants