Problem
Set-TargetPath (Windows-Path-Repair-Full.ps1, ~line 296) uses [Environment]::SetEnvironmentVariable('Path', $value, $Scope), which writes the registry value as REG_SZ. The stock Machine Path (and often the User Path) is REG_EXPAND_SZ.
Consequences:
- Entries containing unexpanded variables like
%SystemRoot% or %USERPROFILE% — which the script deliberately preserves verbatim — stop expanding after any apply, silently breaking those entries system-wide.
-RestoreBackup restores the string but not the original value type, so even recovery does not undo the downgrade.
Proposed fix
- Write the value via the registry directly with an explicit kind:
RegistryKey.SetValue('Path', $value, [Microsoft.Win32.RegistryValueKind]::ExpandString) against HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager\Environment (Machine) and HKCU:\Environment (User).
- Broadcast
WM_SETTINGCHANGE manually afterward (currently SetEnvironmentVariable does this implicitly).
- Read back with
GetValue(..., [Microsoft.Win32.RegistryValueOptions]::DoNotExpandEnvironmentNames) in Assert-TargetPath so verification compares the unexpanded value; otherwise %-containing entries would spuriously fail read-back.
- Extend the backup schema to record the original value kind for each scope so
-RestoreBackup is fully faithful (bump SchemaVersion; keep reading v1 backups, restoring them as ExpandString).
- Add regression tests using the injectable
SetPathAction/AssertPathAction seams.
Related: rollback flag must be set before the setter runs
In Invoke-PathUpdate (~line 341), $machineWritten/$userWritten are set only after the setter returns. A setter that mutates the registry and then throws skips rollback for that scope, while the final error message still claims all changes were rolled back. This is unlikely with the current single-call SetEnvironmentVariable, but becomes a real hazard once this issue replaces it with a multi-step write (registry set + broadcast). Fix as part of this change:
- Set the written flag before invoking the setter (conservative: rollback may rewrite an unchanged value, which is harmless).
- Add a seam-based test where the setter records the mutation and then throws, asserting rollback still runs for that scope.
Priority
Highest — correctness issue that affects every -Apply run, in a tool whose whole purpose is safe writes.
Problem
Set-TargetPath(Windows-Path-Repair-Full.ps1, ~line 296) uses[Environment]::SetEnvironmentVariable('Path', $value, $Scope), which writes the registry value asREG_SZ. The stock MachinePath(and often the UserPath) isREG_EXPAND_SZ.Consequences:
%SystemRoot%or%USERPROFILE%— which the script deliberately preserves verbatim — stop expanding after any apply, silently breaking those entries system-wide.-RestoreBackuprestores the string but not the original value type, so even recovery does not undo the downgrade.Proposed fix
RegistryKey.SetValue('Path', $value, [Microsoft.Win32.RegistryValueKind]::ExpandString)againstHKLM:\SYSTEM\CurrentControlSet\Control\Session Manager\Environment(Machine) andHKCU:\Environment(User).WM_SETTINGCHANGEmanually afterward (currentlySetEnvironmentVariabledoes this implicitly).GetValue(..., [Microsoft.Win32.RegistryValueOptions]::DoNotExpandEnvironmentNames)inAssert-TargetPathso verification compares the unexpanded value; otherwise%-containing entries would spuriously fail read-back.-RestoreBackupis fully faithful (bumpSchemaVersion; keep reading v1 backups, restoring them asExpandString).SetPathAction/AssertPathActionseams.Related: rollback flag must be set before the setter runs
In
Invoke-PathUpdate(~line 341),$machineWritten/$userWrittenare set only after the setter returns. A setter that mutates the registry and then throws skips rollback for that scope, while the final error message still claims all changes were rolled back. This is unlikely with the current single-callSetEnvironmentVariable, but becomes a real hazard once this issue replaces it with a multi-step write (registry set + broadcast). Fix as part of this change:Priority
Highest — correctness issue that affects every
-Applyrun, in a tool whose whole purpose is safe writes.