Commit 7604885
committed
Stop a non-elevated run from continuing past the admin guard
Ensure-Admin.ps1 is dot-sourced, and `exit` inside a dot-sourced script
does not terminate the caller. Every exit in that guard was therefore
inert: WinSwift printed "must be run as Administrator" and then carried
on into the apply pipeline.
Reproduced non-elevated with stdin redirected, which is what any
scripted or CI invocation looks like. Read-Host returns an empty string
immediately, the prompt reads as declined, `exit 1` does nothing, and
the run proceeds:
WinSwift must be run as Administrator.
...
[WhatIf] Create registry backup
[WhatIf] Apply 15 registry changes from 'Disable_Telemetry.reg'
[WhatIf] Disable Scheduled Task: ...Microsoft Compatibility Appraiser
exit code 0
Under -DryRun nothing is written. Without it, an unprivileged process
would attempt real registry imports and scheduled task changes, fail
partway through on access denied, and leave a half-applied system.
The same defect breaks the relaunch path: after Start-Process -Verb
RunAs succeeds, `exit 0` does not stop the parent, so the elevated child
and the original non-elevated process run WinSwift concurrently.
Confirmed the mechanism with a minimal repro. A dot-sourced script
invoked with arguments cannot terminate its caller through `exit`, with
or without [CmdletBinding()]; `throw` and caller-side handling both do.
Fix: the guard reports its outcome through $script:ElevationOutcome,
which propagates to the caller because dot-sourcing shares scope, and
WinSwift.ps1 exits on anything other than 'Elevated' before any runtime
module loads. 'Relaunched' exits 0 because the elevated child owns the
run; 'Denied' and 'Failed' exit 1.
Also stop prompting when no console can answer. A redirected read
returned instantly and was indistinguishable from a declined prompt, so
that case now reports why it cannot continue.
Verified after the fix: both the read-only -Verify path and the -DryRun
apply path exit 1 without reaching the pipeline.
Adds source assertions for the outcome contract and its position ahead
of module loading, plus a behavioral test that runs the entry script
unelevated and asserts the pipeline is never reached. That test skips
when already elevated, which is the case on CI runners.1 parent ba6088b commit 7604885
4 files changed
Lines changed: 206 additions & 129 deletions
File tree
- Scripts/Helpers
- Tests/Unit
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
5 | 5 | | |
6 | 6 | | |
7 | 7 | | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
8 | 14 | | |
9 | 15 | | |
10 | 16 | | |
11 | 17 | | |
12 | 18 | | |
13 | 19 | | |
14 | 20 | | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
15 | 32 | | |
16 | 33 | | |
17 | 34 | | |
| |||
55 | 72 | | |
56 | 73 | | |
57 | 74 | | |
58 | | - | |
| 75 | + | |
| 76 | + | |
59 | 77 | | |
60 | 78 | | |
61 | | - | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
62 | 83 | | |
63 | 84 | | |
64 | | - | |
| 85 | + | |
| 86 | + | |
65 | 87 | | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
31 | 31 | | |
32 | 32 | | |
33 | 33 | | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
34 | 76 | | |
35 | 77 | | |
36 | 78 | | |
| |||
Large diffs are not rendered by default.
0 commit comments