-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathrestart-bridge-admin.ps1
More file actions
104 lines (95 loc) · 4.77 KB
/
Copy pathrestart-bridge-admin.ps1
File metadata and controls
104 lines (95 loc) · 4.77 KB
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
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
param(
[switch]$Elevated
)
$ErrorActionPreference = 'Stop'
$identity = [Security.Principal.WindowsIdentity]::GetCurrent()
$principal = [Security.Principal.WindowsPrincipal]::new($identity)
$adminRole = [Security.Principal.WindowsBuiltInRole]::Administrator
$currentShell = (Get-Process -Id $PID).Path
if ([IO.Path]::GetFileName($currentShell) -ne 'pwsh.exe' -or $PSVersionTable.PSVersion.Major -lt 7) {
throw "PowerShell 7 is required. Run this script with C:\Program Files\PowerShell\7\pwsh.exe."
}
if (-not $principal.IsInRole($adminRole)) {
# Re-enter this same script through UAC, then let the elevated child do the
# process ownership check and restart. Nothing else is stopped.
$elevatedProcess = Start-Process -FilePath $currentShell -Verb RunAs -Wait -PassThru -ArgumentList @(
'-NoProfile', '-ExecutionPolicy', 'Bypass', '-File', ('"' + $MyInvocation.MyCommand.Path + '"'), '-Elevated'
)
if ($elevatedProcess.ExitCode -ne 0) { throw "Elevated bridge restart failed with exit code $($elevatedProcess.ExitCode)" }
exit 0
}
$ProjectDir = Split-Path -Parent $MyInvocation.MyCommand.Path
$UserProfileDir = [Environment]::GetFolderPath('UserProfile')
$PythonCandidates = @(
$env:DS5VIBEHUB_PYTHON
(Join-Path $UserProfileDir '.cache\codex-runtimes\codex-primary-runtime\dependencies\python\python.exe')
((Get-Command python.exe -ErrorAction SilentlyContinue).Source)
)
$Python = $PythonCandidates | Where-Object { $_ -and (Test-Path -LiteralPath $_ -PathType Leaf) } | Select-Object -First 1
$Bridge = Join-Path $ProjectDir 'bridge.py'
$Marker = Join-Path $ProjectDir 'bridge-restart-admin.result.json'
function Test-BridgeProcessOwner {
param(
[Parameter(Mandatory)][int]$CandidatePid,
[Parameter(Mandatory)][string]$ExpectedBridge
)
try {
$process = Get-CimInstance Win32_Process -Filter "ProcessId = $CandidatePid" -ErrorAction Stop
} catch {
return $false
}
if (-not $process -or -not $process.ExecutablePath -or -not $process.CommandLine) {
return $false
}
$executableName = [IO.Path]::GetFileName([string]$process.ExecutablePath)
$isPython = $executableName -in @('python.exe', 'pythonw.exe')
$ownsBridge = ([string]$process.CommandLine).Contains(
$ExpectedBridge,
[StringComparison]::OrdinalIgnoreCase
)
return $isPython -and $ownsBridge
}
if (-not $Python) { throw 'Python runtime not found. Set DS5VIBEHUB_PYTHON or add python.exe to PATH.' }
if (-not (Test-Path -LiteralPath $Bridge)) { throw "Bridge not found: $Bridge" }
$listenerPids = @()
for ($attempt = 0; $attempt -lt 3; $attempt++) {
$listeners = @(Get-NetTCPConnection -LocalAddress 127.0.0.1 -LocalPort 37845 -State Listen -ErrorAction SilentlyContinue)
$listenerPids = @($listeners | ForEach-Object { [int]$_.OwningProcess } | Sort-Object -Unique)
$unexpectedPids = @($listenerPids | Where-Object { -not (Test-BridgeProcessOwner -CandidatePid $_ -ExpectedBridge $Bridge) })
if ($unexpectedPids.Count -ne 0) {
throw "Port 37845 is owned by a non-bridge process; refusing to stop PID(s): $($unexpectedPids -join ', ')"
}
foreach ($ownerPid in $listenerPids) {
# Every PID above was verified against this project's absolute bridge path.
Stop-Process -Id $ownerPid -Force -ErrorAction SilentlyContinue
}
Start-Sleep -Milliseconds 700
$remaining = @(Get-NetTCPConnection -LocalAddress 127.0.0.1 -LocalPort 37845 -State Listen -ErrorAction SilentlyContinue)
if ($remaining.Count -eq 0) { break }
}
$remaining = @(Get-NetTCPConnection -LocalAddress 127.0.0.1 -LocalPort 37845 -State Listen -ErrorAction SilentlyContinue)
if ($remaining.Count -ne 0) {
throw "Could not clear existing bridge listeners: $(@($remaining | ForEach-Object OwningProcess) -join ', ')"
}
$startInfo = [Diagnostics.ProcessStartInfo]::new()
$startInfo.FileName = $Python
$startInfo.Arguments = '-B "' + $Bridge + '"'
$startInfo.WorkingDirectory = $ProjectDir
$startInfo.UseShellExecute = $true
$startInfo.WindowStyle = [Diagnostics.ProcessWindowStyle]::Hidden
$proc = [Diagnostics.Process]::Start($startInfo)
Start-Sleep -Seconds 2
$listen = @(Get-NetTCPConnection -LocalAddress 127.0.0.1 -LocalPort 37845 -State Listen -ErrorAction SilentlyContinue)
$result = [ordered]@{
elevated = $true
bridgePid = $proc.Id
listenerPids = @($listen | ForEach-Object OwningProcess)
at = (Get-Date).ToUniversalTime().ToString('o')
}
[IO.File]::WriteAllText($Marker, ($result | ConvertTo-Json -Depth 4), [Text.UTF8Encoding]::new($false))
if ($listen.Count -ne 1 -or $listen[0].OwningProcess -ne $proc.Id) { throw 'Bridge did not bind exactly to 127.0.0.1:37845' }
# Keep the elevated launcher alive for the lifetime of the bridge. In the
# Codex Desktop process tree, an orphaned elevated child can otherwise be
# reclaimed shortly after this script exits even though it bound correctly.
$proc.WaitForExit()
exit $proc.ExitCode