From afa8e06b2de64100f963ae30b3babfcb5d7009f4 Mon Sep 17 00:00:00 2001 From: oliver Date: Fri, 9 Oct 2026 14:55:40 +0800 Subject: [PATCH] Release 0.4.13: elevate all end-user entry points for Program Files installs. CMD and packaging scripts self-elevate via UAC; fix RunAs/WindowStyle clash; logon tray uses Highest scheduled task. Co-authored-by: Cursor --- packaging/README.md | 13 +++-- packaging/_common.ps1 | 95 ++++++++++++++++++++++++++++++- packaging/check_update.ps1 | 4 +- packaging/cmd/NetX-FirstRun.cmd | 17 ++++-- packaging/cmd/NetX-Start.cmd | 12 +++- packaging/cmd/NetX-Stop.cmd | 11 +++- packaging/cmd/NetX-Tray.cmd | 10 +++- packaging/install_autostart.ps1 | 34 ++++++++--- packaging/install_service.ps1 | 7 +-- packaging/install_update_task.ps1 | 8 ++- packaging/installer/netx.iss | 2 +- packaging/launch_shortcut.ps1 | 3 +- packaging/manifest.example.json | 8 +-- packaging/netx_tray.ps1 | 4 +- packaging/repair_venv.ps1 | 3 +- packaging/setup_first_run.ps1 | 3 +- packaging/start_netx_app.ps1 | 3 +- packaging/stop_netx_app.ps1 | 1 + packaging/update_netx.ps1 | 3 +- pyproject.toml | 2 +- 20 files changed, 193 insertions(+), 50 deletions(-) diff --git a/packaging/README.md b/packaging/README.md index ec2353b..847943d 100644 --- a/packaging/README.md +++ b/packaging/README.md @@ -63,6 +63,8 @@ Optional local zip only: `build_release.ps1 -CreateZip` (not for release upload) 5. Data → `%ProgramData%\NetX\` (`.env`, `pgdata`, spool, secrets). 6. Start menu: **Start NetX** / **Stop NetX** / **Open NetX UI** / **Reconfigure database**. +**Elevation (required on fresh PCs):** all end-user entry points (`NetX-Start.cmd`, `NetX-Tray.cmd`, `NetX-Stop.cmd`, `NetX-FirstRun.cmd`, tray, start/stop/setup/update) **self-elevate via UAC**. Program Files installs cannot start reliably as a normal user (`.venv` repair / writes). Approve the UAC prompt once per launch (tray stays elevated afterward). + Silent first install (bundled default): `/SILENT /DbMode=bundled` Silent external: `/SILENT /DbMode=external /DbHost=... /DbPort=5432 /DbUser=... /DbPassword=... /DbName=...` Silent update over existing data: `/VERYSILENT /NORESTART /InstallMode=update` (also `/SkipDbPage=1`) @@ -81,7 +83,7 @@ Existing Windows deploys that only set `NETX_DATABASE_URL` keep working: never s ## Manual update -Preferred: run a newer `NetX-Setup-*.exe` and choose **Update** (or silent `/InstallMode=update`) so ProgramData is kept. Setup (elevated) always relinks `.venv` → `python/runtime` after file copy so tray start works without write access under Program Files. +Preferred: run a newer `NetX-Setup-*.exe` and choose **Update** (or silent `/InstallMode=update`) so ProgramData is kept. Setup (elevated) always relinks `.venv` → `python/runtime` after file copy; runtime scripts also self-elevate so Start/Tray work on locked-down fresh PCs. Legacy/dev zip (only if you built with `-CreateZip`): @@ -155,10 +157,11 @@ Token: `NETX_FORGEJO_TOKEN` (or `FORGEJO_TOKEN`). ## Tray & autostart ```powershell -# System tray: Start / Stop / Open UI / Check updates +# System tray: Start / Stop / Open UI / Check updates (self-elevates) .\packaging\netx_tray.ps1 -StartOnLaunch -# Start tray at Windows logon (current user) +# Start tray at Windows logon — Scheduled Task with RunLevel Highest +# (replaces legacy HKCU\Run which cannot elevate on fresh installs) .\packaging\install_autostart.ps1 # Remove: .\packaging\install_autostart.ps1 -Remove ``` @@ -180,10 +183,10 @@ Uses [WinSW](https://github.com/winsw/winsw) (downloaded on first install into ` ## Silent auto-update ```powershell -# Writes NETX_UPDATE_AUTO=true and registers a daily task (default 03:30) +# Writes NETX_UPDATE_AUTO=true and registers a daily task (default 03:30, RunLevel Highest) .\packaging\install_update_task.ps1 -# Manual silent path (only applies when NETX_UPDATE_AUTO=true) +# Manual silent path (only applies when NETX_UPDATE_AUTO=true; self-elevates) .\packaging\check_update.ps1 -Apply -Quiet -AutoOnly ``` diff --git a/packaging/_common.ps1 b/packaging/_common.ps1 index 0a22f55..194e8f7 100644 --- a/packaging/_common.ps1 +++ b/packaging/_common.ps1 @@ -322,7 +322,8 @@ function Start-NetxPowerShell { [ValidateSet("Hidden", "Normal", "Minimized")] [string]$WindowStyle = "Hidden", [switch]$Wait = $false, - [switch]$PassThru = $false + [switch]$PassThru = $false, + [switch]$RunAs = $false ) $parts = @( "-NoProfile", @@ -333,14 +334,104 @@ function Start-NetxPowerShell { $sp = @{ FilePath = "powershell.exe" ArgumentList = (ConvertTo-NetxProcessArgumentString -Arguments $parts) - WindowStyle = $WindowStyle + } + # -Verb RunAs implies UseShellExecute; cannot combine with -WindowStyle. + if (-not $RunAs) { + $sp.WindowStyle = $WindowStyle } if ($WorkingDirectory) { $sp.WorkingDirectory = $WorkingDirectory } if ($Wait) { $sp.Wait = $true } if ($PassThru -or $Wait) { $sp.PassThru = $true } + if ($RunAs) { $sp.Verb = "RunAs" } return Start-Process @sp } +function Test-NetxIsAdmin { + try { + $id = [Security.Principal.WindowsIdentity]::GetCurrent() + $p = New-Object Security.Principal.WindowsPrincipal($id) + return $p.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator) + } catch { + return $false + } +} + +function ConvertTo-NetxRelaunchArgumentList { + param([System.Collections.IDictionary]$BoundParameters) + $parts = [System.Collections.Generic.List[string]]::new() + if (-not $BoundParameters) { return @() } + foreach ($key in $BoundParameters.Keys) { + $val = $BoundParameters[$key] + if ($val -is [System.Management.Automation.SwitchParameter]) { + if ($val.IsPresent) { [void]$parts.Add("-$key") } + continue + } + if ($val -is [bool]) { + if ($val) { [void]$parts.Add("-$key") } + continue + } + if ($null -eq $val) { continue } + $s = [string]$val + if ($s -eq "") { continue } + [void]$parts.Add("-$key") + [void]$parts.Add($s) + } + return @($parts) +} + +function Assert-NetxAdminOrRelaunch { + <# + .SYNOPSIS + End-user packaged scripts must run elevated (Program Files + ProgramData). + If not admin, re-launch the same script via UAC and exit with child exit code. + #> + param( + [Parameter(Mandatory = $true)][string]$ScriptPath, + [System.Collections.IDictionary]$BoundParameters = @{}, + [string]$WorkingDirectory = "", + [ValidateSet("Hidden", "Normal", "Minimized")] + [string]$WindowStyle = "Normal" + ) + if (Test-NetxIsAdmin) { return } + + if ($env:NETX_ELEVATION_RELAUNCH -eq "1") { + throw "admin_required: still not elevated after UAC. Run NetX-Start / NetX-Tray as Administrator." + } + + if (-not (Test-Path -LiteralPath $ScriptPath)) { + throw "elevation_script_missing: $ScriptPath" + } + $wd = $WorkingDirectory + if (-not $wd) { $wd = Split-Path -Parent $ScriptPath } + + # Window style belongs on powershell.exe argv, not Start-Process (incompatible with -Verb RunAs). + $parts = @( + "-NoProfile", + "-WindowStyle", $WindowStyle, + "-ExecutionPolicy", "Bypass", + "-File", $ScriptPath + ) + (ConvertTo-NetxRelaunchArgumentList -BoundParameters $BoundParameters) + + $prevRel = $env:NETX_ELEVATION_RELAUNCH + $env:NETX_ELEVATION_RELAUNCH = "1" + try { + $p = Start-Process -FilePath "powershell.exe" ` + -ArgumentList (ConvertTo-NetxProcessArgumentString -Arguments $parts) ` + -WorkingDirectory $wd ` + -Verb RunAs -Wait -PassThru + } catch { + if ($null -ne $prevRel) { $env:NETX_ELEVATION_RELAUNCH = $prevRel } else { Remove-Item Env:NETX_ELEVATION_RELAUNCH -ErrorAction SilentlyContinue } + throw ("admin_required: UAC cancelled or elevation failed. Run NetX as Administrator. {0}" -f $_.Exception.Message) + } + if ($null -ne $prevRel) { $env:NETX_ELEVATION_RELAUNCH = $prevRel } else { Remove-Item Env:NETX_ELEVATION_RELAUNCH -ErrorAction SilentlyContinue } + if ($null -eq $p) { + throw "admin_required: elevation failed (no process)" + } + $code = 0 + if ($null -ne $p.ExitCode) { $code = [int]$p.ExitCode } + exit $code +} + function Get-NetxSystemPython { # Prefer a real interpreter; skip the WindowsApps Store stub. $candidates = @() diff --git a/packaging/check_update.ps1 b/packaging/check_update.ps1 index 0d45bf9..7c4f39f 100644 --- a/packaging/check_update.ps1 +++ b/packaging/check_update.ps1 @@ -1,4 +1,4 @@ -param( +param( [string]$ProgramRoot = "", [string]$DataRoot = "", [string]$UpdateUrl = "", @@ -29,6 +29,8 @@ $ErrorActionPreference = "Stop" . "$PSScriptRoot\_common.ps1" +Assert-NetxAdminOrRelaunch -ScriptPath $PSCommandPath -BoundParameters $PSBoundParameters ` + -WindowStyle $(if ($Quiet) { "Hidden" } else { "Normal" }) $prog = Get-NetxProgramRoot -Override $ProgramRoot $data = Get-NetxDataRoot -ProgramRoot $prog -Override $DataRoot diff --git a/packaging/cmd/NetX-FirstRun.cmd b/packaging/cmd/NetX-FirstRun.cmd index 63fa9e5..e5f9887 100644 --- a/packaging/cmd/NetX-FirstRun.cmd +++ b/packaging/cmd/NetX-FirstRun.cmd @@ -1,9 +1,14 @@ @echo off -setlocal +setlocal EnableDelayedExpansion +net session >nul 2>&1 +if not "%errorLevel%"=="0" ( + powershell.exe -NoProfile -ExecutionPolicy Bypass -Command "try { $p = Start-Process -FilePath '%~f0' -Verb RunAs -Wait -PassThru; if ($null -eq $p -or $null -eq $p.ExitCode) { exit 1 }; exit $p.ExitCode } catch { exit 1 }" + exit /b !ERRORLEVEL! +) set "ROOT=%~dp0" if "%ROOT:~-1%"=="\" set "ROOT=%ROOT:~0,-1%" cd /d "%ROOT%" -title NetX — Reconfigure database +title NetX - Reconfigure database echo. echo NetX database reconfigure / 重新配置数据库 echo Prefer the installer wizard for first-time setup. @@ -12,12 +17,12 @@ echo This window is for repair / reconfigure only. echo 本窗口仅用于修复或重新配置。 echo. powershell.exe -NoProfile -ExecutionPolicy Bypass -File "%ROOT%\packaging\setup_first_run.ps1" -ProgramRoot "%ROOT%" -DataRoot "%ProgramData%\NetX" -set "EC=%ERRORLEVEL%" -if not "%EC%"=="0" ( +set "EC=!ERRORLEVEL!" +if not "!EC!"=="0" ( echo. - echo Setup failed / 配置失败 exit=%EC% + echo Setup failed / 配置失败 exit=!EC! pause - exit /b %EC% + exit /b !EC! ) echo. echo Starting NetX tray... / 正在启动托盘... diff --git a/packaging/cmd/NetX-Start.cmd b/packaging/cmd/NetX-Start.cmd index b489f7d..8342f92 100644 --- a/packaging/cmd/NetX-Start.cmd +++ b/packaging/cmd/NetX-Start.cmd @@ -1,7 +1,13 @@ @echo off -setlocal +setlocal EnableDelayedExpansion +REM Always elevate: Program Files install needs admin to start API / repair venv. +net session >nul 2>&1 +if not "%errorLevel%"=="0" ( + powershell.exe -NoProfile -ExecutionPolicy Bypass -Command "try { $p = Start-Process -FilePath '%~f0' -Verb RunAs -Wait -PassThru; if ($null -eq $p -or $null -eq $p.ExitCode) { exit 1 }; exit $p.ExitCode } catch { exit 1 }" + exit /b !ERRORLEVEL! +) set "ROOT=%~dp0" if "%ROOT:~-1%"=="\" set "ROOT=%ROOT:~0,-1%" cd /d "%ROOT%" -start "" powershell.exe -NoProfile -WindowStyle Hidden -ExecutionPolicy Bypass -File "%ROOT%\packaging\launch_shortcut.ps1" -Action start -ProgramRoot "%ROOT%" -DataRoot "%ProgramData%\NetX" -exit /b 0 +powershell.exe -NoProfile -ExecutionPolicy Bypass -File "%ROOT%\packaging\launch_shortcut.ps1" -Action start -ProgramRoot "%ROOT%" -DataRoot "%ProgramData%\NetX" +exit /b !ERRORLEVEL! diff --git a/packaging/cmd/NetX-Stop.cmd b/packaging/cmd/NetX-Stop.cmd index 7722e38..8a225f2 100644 --- a/packaging/cmd/NetX-Stop.cmd +++ b/packaging/cmd/NetX-Stop.cmd @@ -1,7 +1,12 @@ @echo off -setlocal +setlocal EnableDelayedExpansion +net session >nul 2>&1 +if not "%errorLevel%"=="0" ( + powershell.exe -NoProfile -ExecutionPolicy Bypass -Command "try { $p = Start-Process -FilePath '%~f0' -Verb RunAs -Wait -PassThru; if ($null -eq $p -or $null -eq $p.ExitCode) { exit 1 }; exit $p.ExitCode } catch { exit 1 }" + exit /b !ERRORLEVEL! +) set "ROOT=%~dp0" if "%ROOT:~-1%"=="\" set "ROOT=%ROOT:~0,-1%" cd /d "%ROOT%" -start "" powershell.exe -NoProfile -WindowStyle Hidden -ExecutionPolicy Bypass -File "%ROOT%\packaging\launch_shortcut.ps1" -Action stop -ProgramRoot "%ROOT%" -DataRoot "%ProgramData%\NetX" -exit /b 0 +powershell.exe -NoProfile -ExecutionPolicy Bypass -File "%ROOT%\packaging\launch_shortcut.ps1" -Action stop -ProgramRoot "%ROOT%" -DataRoot "%ProgramData%\NetX" +exit /b !ERRORLEVEL! diff --git a/packaging/cmd/NetX-Tray.cmd b/packaging/cmd/NetX-Tray.cmd index 7cdd5af..ac1f46c 100644 --- a/packaging/cmd/NetX-Tray.cmd +++ b/packaging/cmd/NetX-Tray.cmd @@ -1,7 +1,13 @@ @echo off -setlocal +setlocal EnableDelayedExpansion +REM Elevate once, then start tray (inherits admin for Start/Stop/Update). +net session >nul 2>&1 +if not "%errorLevel%"=="0" ( + powershell.exe -NoProfile -ExecutionPolicy Bypass -Command "try { $p = Start-Process -FilePath '%~f0' -Verb RunAs -Wait -PassThru; if ($null -eq $p -or $null -eq $p.ExitCode) { exit 1 }; exit $p.ExitCode } catch { exit 1 }" + exit /b !ERRORLEVEL! +) set "ROOT=%~dp0" if "%ROOT:~-1%"=="\" set "ROOT=%ROOT:~0,-1%" cd /d "%ROOT%" -start "" powershell.exe -NoProfile -WindowStyle Hidden -ExecutionPolicy Bypass -File "%ROOT%\packaging\launch_shortcut.ps1" -Action tray -ProgramRoot "%ROOT%" -DataRoot "%ProgramData%\NetX" -StartOnLaunch +start "" powershell.exe -NoProfile -WindowStyle Hidden -ExecutionPolicy Bypass -File "%ROOT%\packaging\netx_tray.ps1" -ProgramRoot "%ROOT%" -DataRoot "%ProgramData%\NetX" -StartOnLaunch exit /b 0 diff --git a/packaging/install_autostart.ps1 b/packaging/install_autostart.ps1 index 50510df..4cba106 100644 --- a/packaging/install_autostart.ps1 +++ b/packaging/install_autostart.ps1 @@ -1,25 +1,41 @@ -param( +param( [string]$ProgramRoot = "", + [string]$DataRoot = "", [switch]$Remove = $false ) -# Register / unregister NetX tray at current-user logon. +# Register / unregister NetX tray at logon with highest privileges (UAC admin). +# HKCU\Run cannot elevate reliably on fresh PCs; use a Scheduled Task instead. $ErrorActionPreference = "Stop" . "$PSScriptRoot\_common.ps1" +Assert-NetxAdminOrRelaunch -ScriptPath $PSCommandPath -BoundParameters $PSBoundParameters -WindowStyle Normal $prog = Get-NetxProgramRoot -Override $ProgramRoot +$data = Get-NetxDataRoot -ProgramRoot $prog -Override $DataRoot $tray = Join-Path $PSScriptRoot "netx_tray.ps1" $runKey = "HKCU:\Software\Microsoft\Windows\CurrentVersion\Run" -$name = "NetX" +$legacyName = "NetX" +$taskName = "NetXTray" +$taskPath = "\NetX\" + +# Always clear legacy per-user Run key (non-elevated). +Remove-ItemProperty -Path $runKey -Name $legacyName -ErrorAction SilentlyContinue if ($Remove) { - Remove-ItemProperty -Path $runKey -Name $name -ErrorAction SilentlyContinue - Write-Host "==> Removed NetX from startup" + Unregister-ScheduledTask -TaskName $taskName -TaskPath $taskPath -Confirm:$false -ErrorAction SilentlyContinue + Write-Host "==> Removed NetX tray autostart task" exit 0 } -$cmd = "powershell.exe -NoProfile -WindowStyle Hidden -ExecutionPolicy Bypass -File `"$tray`" -ProgramRoot `"$prog`" -StartOnLaunch" -New-ItemProperty -Path $runKey -Name $name -Value $cmd -PropertyType String -Force | Out-Null -Write-Host "==> NetX tray will start at logon" -Write-Host " $cmd" +$arg = "-NoProfile -WindowStyle Hidden -ExecutionPolicy Bypass -File `"$tray`" -ProgramRoot `"$prog`" -DataRoot `"$data`" -StartOnLaunch" +$action = New-ScheduledTaskAction -Execute "powershell.exe" -Argument $arg -WorkingDirectory $prog +$trig = New-ScheduledTaskTrigger -AtLogOn -User $env:USERNAME +$settings = New-ScheduledTaskSettingsSet -AllowStartIfOnBatteries -DontStopIfGoingOnBatteries -StartWhenAvailable +$principal = New-ScheduledTaskPrincipal -UserId $env:USERNAME -LogonType Interactive -RunLevel Highest +Register-ScheduledTask -TaskName $taskName -TaskPath $taskPath ` + -Action $action -Trigger $trig -Settings $settings -Principal $principal -Force | Out-Null + +Write-Host "==> NetX tray will start at logon (Scheduled Task, RunLevel Highest)" -ForegroundColor Green +Write-Host " $taskPath$taskName" +Write-Host " $arg" diff --git a/packaging/install_service.ps1 b/packaging/install_service.ps1 index f9e87f6..02ea09c 100644 --- a/packaging/install_service.ps1 +++ b/packaging/install_service.ps1 @@ -1,4 +1,4 @@ -param( +param( [string]$ProgramRoot = "", [string]$DataRoot = "", [ValidateSet("winsw", "task")] @@ -15,6 +15,7 @@ $ErrorActionPreference = "Stop" . "$PSScriptRoot\_common.ps1" +Assert-NetxAdminOrRelaunch -ScriptPath $PSCommandPath -BoundParameters $PSBoundParameters -WindowStyle Normal $prog = Get-NetxProgramRoot -Override $ProgramRoot $data = Get-NetxDataRoot -ProgramRoot $prog -Override $DataRoot @@ -25,9 +26,7 @@ $winswXml = Join-Path $winswDir "NetX.xml" $cacheDir = Join-Path $PSScriptRoot "cache" function Test-IsAdmin { - $id = [Security.Principal.WindowsIdentity]::GetCurrent() - $p = New-Object Security.Principal.WindowsPrincipal($id) - return $p.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator) + return Test-NetxIsAdmin } function ConvertTo-WinSWPath([string]$Path) { diff --git a/packaging/install_update_task.ps1 b/packaging/install_update_task.ps1 index 07b3ab9..afcf712 100644 --- a/packaging/install_update_task.ps1 +++ b/packaging/install_update_task.ps1 @@ -1,4 +1,4 @@ -param( +param( [string]$ProgramRoot = "", [string]$DataRoot = "", [ValidateSet("Daily", "AtLogOn", "Hourly")] @@ -12,6 +12,7 @@ $ErrorActionPreference = "Stop" . "$PSScriptRoot\_common.ps1" +Assert-NetxAdminOrRelaunch -ScriptPath $PSCommandPath -BoundParameters $PSBoundParameters -WindowStyle Normal $prog = Get-NetxProgramRoot -Override $ProgramRoot $data = Get-NetxDataRoot -ProgramRoot $prog -Override $DataRoot @@ -51,7 +52,8 @@ switch ($Trigger) { } $settings = New-ScheduledTaskSettingsSet -AllowStartIfOnBatteries -StartWhenAvailable -$principal = New-ScheduledTaskPrincipal -UserId $env:USERNAME -LogonType Interactive -RunLevel Limited +# Highest: silent apply must write Program Files / run Setup. +$principal = New-ScheduledTaskPrincipal -UserId $env:USERNAME -LogonType Interactive -RunLevel Highest Register-ScheduledTask -TaskName $taskName -TaskPath $taskPath -Action $action -Trigger $trig -Settings $settings -Principal $principal -Force | Out-Null -Write-Host "==> Scheduled update task: $taskPath$taskName ($Trigger)" -ForegroundColor Green +Write-Host "==> Scheduled update task: $taskPath$taskName ($Trigger, RunLevel Highest)" -ForegroundColor Green Write-Host " Manual run: .\packaging\check_update.ps1 -Apply -Quiet -AutoOnly" diff --git a/packaging/installer/netx.iss b/packaging/installer/netx.iss index 42b836e..fc2feaa 100644 --- a/packaging/installer/netx.iss +++ b/packaging/installer/netx.iss @@ -5,7 +5,7 @@ #define MyAppName "NetX" #ifndef MyAppVersion - #define MyAppVersion "0.4.12" + #define MyAppVersion "0.4.13" #endif #define MyAppPublisher "NetX" #define MyAppURL "https://github.com/hansjone/netx" diff --git a/packaging/launch_shortcut.ps1 b/packaging/launch_shortcut.ps1 index f4ae945..7f13188 100644 --- a/packaging/launch_shortcut.ps1 +++ b/packaging/launch_shortcut.ps1 @@ -1,4 +1,4 @@ -param( +param( [ValidateSet("tray", "start", "stop", "setup", "update")] [string]$Action = "tray", [string]$ProgramRoot = "", @@ -11,6 +11,7 @@ $ErrorActionPreference = "Stop" . "$PSScriptRoot\_common.ps1" +Assert-NetxAdminOrRelaunch -ScriptPath $PSCommandPath -BoundParameters $PSBoundParameters -WindowStyle Hidden Add-Type -AssemblyName System.Windows.Forms diff --git a/packaging/manifest.example.json b/packaging/manifest.example.json index 410b5ee..e8748ef 100644 --- a/packaging/manifest.example.json +++ b/packaging/manifest.example.json @@ -1,11 +1,11 @@ { "channel": "stable", - "latest": "0.4.12", + "latest": "0.4.13", "min_compatible": "0.3.0", - "notes_url": "https://github.com/hansjone/netx/releases/tag/v0.4.12", + "notes_url": "https://github.com/hansjone/netx/releases/tag/v0.4.13", "windows": { - "url": "https://github.com/hansjone/netx/releases/download/v0.4.12/NetX-Setup-0.4.12.exe", - "setup_url": "https://github.com/hansjone/netx/releases/download/v0.4.12/NetX-Setup-0.4.12.exe", + "url": "https://github.com/hansjone/netx/releases/download/v0.4.13/NetX-Setup-0.4.13.exe", + "setup_url": "https://github.com/hansjone/netx/releases/download/v0.4.13/NetX-Setup-0.4.13.exe", "package": "setup", "sha256": "", "size": 0 diff --git a/packaging/netx_tray.ps1 b/packaging/netx_tray.ps1 index 889e65d..bffcc9c 100644 --- a/packaging/netx_tray.ps1 +++ b/packaging/netx_tray.ps1 @@ -7,9 +7,11 @@ ) # System-tray controller for NetX (Windows packaged installs). +# Always elevated: Start/Stop/Update touch Program Files + services. $ErrorActionPreference = "Stop" . "$PSScriptRoot\_common.ps1" +Assert-NetxAdminOrRelaunch -ScriptPath $PSCommandPath -BoundParameters $PSBoundParameters -WindowStyle Hidden Add-Type -AssemblyName System.Windows.Forms Add-Type -AssemblyName System.Drawing @@ -593,7 +595,7 @@ $miUpdate.add_Click({ ) try { $ap = Start-Process -FilePath "powershell.exe" -ArgumentList $arg ` - -WorkingDirectory $prog -WindowStyle Normal -Verb RunAs -PassThru + -WorkingDirectory $prog -Verb RunAs -PassThru } catch { $notify.ShowBalloonTip(4000, "NetX", (T "Update cancelled (UAC)." "已取消更新(UAC)。"), [System.Windows.Forms.ToolTipIcon]::Info) return diff --git a/packaging/repair_venv.ps1 b/packaging/repair_venv.ps1 index 4172d3a..3af0e60 100644 --- a/packaging/repair_venv.ps1 +++ b/packaging/repair_venv.ps1 @@ -3,9 +3,10 @@ param( [string]$DataRoot = "" ) -# Relink shipped .venv to local python/runtime (run elevated after Setup/update). +# Relink shipped .venv to local python/runtime (must be elevated under Program Files). $ErrorActionPreference = "Stop" . "$PSScriptRoot\_common.ps1" +Assert-NetxAdminOrRelaunch -ScriptPath $PSCommandPath -BoundParameters $PSBoundParameters -WindowStyle Hidden $prog = Get-NetxProgramRoot -Override $ProgramRoot $data = Get-NetxDataRoot -ProgramRoot $prog -Override $DataRoot diff --git a/packaging/setup_first_run.ps1 b/packaging/setup_first_run.ps1 index 8c58bf5..0806bb8 100644 --- a/packaging/setup_first_run.ps1 +++ b/packaging/setup_first_run.ps1 @@ -1,4 +1,4 @@ -param( +param( [ValidateSet("bundled", "external", "")] [string]$DbMode = "", [string]$ProgramRoot = "", @@ -15,6 +15,7 @@ $ErrorActionPreference = "Stop" . "$PSScriptRoot\_common.ps1" +Assert-NetxAdminOrRelaunch -ScriptPath $PSCommandPath -BoundParameters $PSBoundParameters -WindowStyle Normal $prog = Get-NetxProgramRoot -Override $ProgramRoot $data = Get-NetxDataRoot -ProgramRoot $prog -Override $DataRoot diff --git a/packaging/start_netx_app.ps1 b/packaging/start_netx_app.ps1 index a795e44..55b8d6d 100644 --- a/packaging/start_netx_app.ps1 +++ b/packaging/start_netx_app.ps1 @@ -1,4 +1,4 @@ -param( +param( [string]$ProgramRoot = "", [string]$DataRoot = "", [switch]$SkipBrowser = $false, @@ -8,6 +8,7 @@ $ErrorActionPreference = "Stop" . "$PSScriptRoot\_common.ps1" +Assert-NetxAdminOrRelaunch -ScriptPath $PSCommandPath -BoundParameters $PSBoundParameters -WindowStyle Normal $prog = Get-NetxProgramRoot -Override $ProgramRoot $data = Get-NetxDataRoot -ProgramRoot $prog -Override $DataRoot diff --git a/packaging/stop_netx_app.ps1 b/packaging/stop_netx_app.ps1 index 5da0525..48d99c1 100644 --- a/packaging/stop_netx_app.ps1 +++ b/packaging/stop_netx_app.ps1 @@ -7,6 +7,7 @@ param( $ErrorActionPreference = "Continue" . "$PSScriptRoot\_common.ps1" +Assert-NetxAdminOrRelaunch -ScriptPath $PSCommandPath -BoundParameters $PSBoundParameters -WindowStyle Hidden $prog = Get-NetxProgramRoot -Override $ProgramRoot $data = Get-NetxDataRoot -ProgramRoot $prog -Override $DataRoot diff --git a/packaging/update_netx.ps1 b/packaging/update_netx.ps1 index db003c6..02c128b 100644 --- a/packaging/update_netx.ps1 +++ b/packaging/update_netx.ps1 @@ -1,4 +1,4 @@ -param( +param( [Parameter(Mandatory = $true)] [string]$PackagePath, [string]$ProgramRoot = "", @@ -9,6 +9,7 @@ $ErrorActionPreference = "Stop" . "$PSScriptRoot\_common.ps1" +Assert-NetxAdminOrRelaunch -ScriptPath $PSCommandPath -BoundParameters $PSBoundParameters -WindowStyle Normal $prog = Get-NetxProgramRoot -Override $ProgramRoot $data = Get-NetxDataRoot -ProgramRoot $prog -Override $DataRoot diff --git a/pyproject.toml b/pyproject.toml index 9263218..1a39136 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "netx-ops" -version = "0.4.12" +version = "0.4.13" description = "netx operations tool: alarm-centric workflows with REST API and stdio MCP" readme = "README.md" requires-python = ">=3.11"