1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
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
76
|
<#
.SYNOPSIS
Elevated helper: set up (or tear down) service mode in ONE UAC prompt,
not two.
.DESCRIPTION
"Run as a background service" is two things -- the boot-time Scheduled
Task and the firewall rules -- and needs one elevation, not one each.
build/installer.nsh runs this single script via ExecShellWait "runas"
for both the install-time choice and the uninstaller's cleanup, instead
of elevating service.ps1 and firewall.ps1 separately.
Each stays a script of its own rather than being folded together, so both
remain independently callable and testable -- the CLI does, through
meshbay-node service, and so does a later "just fix the firewall rules"
retry that has nothing to do with the service task.
Logs to the same file firewall.ps1 already uses, so both are visible in
one place: %TEMP%\meshbay-firewall.log.
.PARAMETER Action
install service.ps1 install, then firewall.ps1 add, then service.ps1 run
remove service.ps1 remove, then firewall.ps1 remove
#>
[CmdletBinding()]
param(
[ValidateSet("install", "remove")]
[string]$Action = "install"
)
$here = $PSScriptRoot
$log = Join-Path $env:TEMP "meshbay-firewall.log"
$firewallAction = if ($Action -eq "install") { "add" } else { "remove" }
$failed = $false
"[{0}] service-mode {1}" -f (Get-Date -Format s), $Action | Add-Content $log
try {
& (Join-Path $here "service.ps1") $Action
}
catch {
" service $Action failed: $_" | Add-Content $log
$failed = $true
}
try {
& (Join-Path $here "firewall.ps1") $firewallAction
}
catch {
" firewall $firewallAction failed: $_" | Add-Content $log
$failed = $true
}
# Register-ScheduledTask with -Trigger AtStartup does exactly that -- it does
# not launch the task now. Every caller of this script (the installer's own
# "background service" choice, and the Node page's later toggle) expects the
# node to actually be running by the time the one UAC prompt they were shown
# returns; without this, nothing is listening until the next reboot, with no
# error and no indication that anything is still needed. `run` needs no
# further elevation (Task Scheduler grants the owning user that much once the
# task exists) -- doing it here, inside the same elevated pass, is only about
# timing: the daemon comes up before this script's own exit code reaches the
# caller, not because starting it needs the admin token this script is
# holding. A no-op, harmlessly, if the task is already running (2026-09-14).
if ($Action -eq "install" -and -not $failed) {
try {
& (Join-Path $here "service.ps1") "run"
}
catch {
" service run failed: $_" | Add-Content $log
$failed = $true
}
}
if ($failed) { exit 1 }
exit 0
|