Switch backend startup to interactive session

This commit is contained in:
Space-Banane
2026-05-31 20:43:01 +02:00
parent a521142b89
commit 79c9e98842
7 changed files with 795 additions and 137 deletions

View File

@@ -1,125 +1,84 @@
[CmdletBinding(SupportsShouldProcess = $true)]
param(
[string]$ServiceName = "ScreenJobBackend",
[string]$DisplayName = "ScreenJob Backend",
[string]$Description = "Runs the ScreenJob backend (start_backend.ps1) as a Windows service.",
[ValidateSet("Automatic", "Manual", "Disabled")]
[string]$StartupType = "Automatic",
[switch]$DelayedAutoStart,
[switch]$ForceReinstall,
[switch]$StartAfterInstall
[switch]$Remove,
[switch]$AllUsers,
[switch]$StartNow
)
Set-StrictMode -Version Latest
$ErrorActionPreference = "Stop"
$scriptDir = Split-Path -Parent $PSCommandPath
$backendScript = Join-Path $scriptDir "start_backend.ps1"
$vbsLauncher = Join-Path $scriptDir "start_backend_hidden.vbs"
$shortcutName = "ScreenJob Backend.lnk"
if (-not (Test-Path -LiteralPath $backendScript)) {
throw "Backend launcher script not found: $backendScript"
}
if (-not (Test-Path -LiteralPath $vbsLauncher)) {
throw "Hidden backend launcher file not found: $vbsLauncher"
}
function Test-IsAdministrator {
$identity = [Security.Principal.WindowsIdentity]::GetCurrent()
$principal = New-Object Security.Principal.WindowsPrincipal($identity)
return $principal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
}
if (-not (Test-IsAdministrator)) {
throw "Run this script from an elevated PowerShell session (Run as Administrator)."
}
$scriptDir = Split-Path -Parent $PSCommandPath
$backendScript = Join-Path $scriptDir "start_backend.ps1"
if (-not (Test-Path -LiteralPath $backendScript)) {
throw "Backend launcher script not found: $backendScript"
}
$projectFile = Join-Path $scriptDir "service_host\ScreenJob.WindowsServiceHost\ScreenJob.WindowsServiceHost.csproj"
if (-not (Test-Path -LiteralPath $projectFile)) {
throw "Windows service host project not found: $projectFile"
}
$dotnetCmd = Get-Command dotnet -ErrorAction SilentlyContinue
if ($null -eq $dotnetCmd) {
throw "dotnet SDK was not found in PATH. Install .NET SDK 10+ and retry."
}
$publishDir = Join-Path $scriptDir "service_host\publish"
$serviceExe = Join-Path $publishDir "ScreenJob.WindowsServiceHost.exe"
$logDir = Join-Path $scriptDir "screenjob_runs\service"
$existingService = Get-Service -Name $ServiceName -ErrorAction SilentlyContinue
if ($null -ne $existingService) {
if (-not $ForceReinstall) {
throw "Service '$ServiceName' already exists. Re-run with -ForceReinstall to replace it."
}
if ($PSCmdlet.ShouldProcess($ServiceName, "Remove existing service")) {
if ($existingService.Status -ne "Stopped") {
Stop-Service -Name $ServiceName -Force -ErrorAction Stop
}
& sc.exe delete $ServiceName | Out-Null
if ($LASTEXITCODE -ne 0) {
throw "Failed to delete existing service '$ServiceName' (sc.exe exit code $LASTEXITCODE)."
}
$deadline = (Get-Date).AddSeconds(15)
while ((Get-Date) -lt $deadline) {
$stillThere = Get-Service -Name $ServiceName -ErrorAction SilentlyContinue
if ($null -eq $stillThere) {
break
$legacyService = Get-Service -Name "ScreenJobBackend" -ErrorAction SilentlyContinue
if ($null -ne $legacyService) {
if (Test-IsAdministrator) {
if ($PSCmdlet.ShouldProcess("ScreenJobBackend", "Remove legacy Windows service")) {
if ($legacyService.Status -ne "Stopped") {
Stop-Service -Name "ScreenJobBackend" -Force -ErrorAction Stop
}
Start-Sleep -Milliseconds 300
& sc.exe delete ScreenJobBackend | Out-Null
if ($LASTEXITCODE -ne 0) {
throw "Failed to delete legacy service 'ScreenJobBackend' (sc.exe exit code $LASTEXITCODE)."
}
Write-Host "Removed legacy Windows service: ScreenJobBackend"
}
} else {
Write-Warning "Legacy Windows service 'ScreenJobBackend' is still installed. Run uninstall_backend_service.ps1 from an elevated PowerShell session once to remove it."
}
}
if ($PSCmdlet.ShouldProcess($projectFile, "Publish Windows service host")) {
if (Test-Path -LiteralPath $serviceExe) {
Remove-Item -LiteralPath $serviceExe -Force -ErrorAction SilentlyContinue
}
& $dotnetCmd.Source publish `
$projectFile `
-c Release `
-r win-x64 `
--self-contained false `
-p:PublishSingleFile=true `
-o $publishDir
if ($LASTEXITCODE -ne 0) {
throw "dotnet publish failed with exit code $LASTEXITCODE."
}
$startupFolder = if ($AllUsers) {
[Environment]::GetFolderPath("CommonStartup")
} else {
[Environment]::GetFolderPath("Startup")
}
if (-not (Test-Path -LiteralPath $serviceExe)) {
throw "Published service executable not found: $serviceExe"
}
$shortcutPath = Join-Path $startupFolder $shortcutName
$binaryPath = "`"$serviceExe`" --backend-script `"$backendScript`" --working-dir `"$scriptDir`" --log-dir `"$logDir`""
if ($PSCmdlet.ShouldProcess($ServiceName, "Create service")) {
New-Service `
-Name $ServiceName `
-BinaryPathName $binaryPath `
-DisplayName $DisplayName `
-Description $Description `
-StartupType $StartupType
if ($StartupType -eq "Automatic" -and $DelayedAutoStart) {
& sc.exe config $ServiceName start= delayed-auto | Out-Null
if ($LASTEXITCODE -ne 0) {
throw "Failed to enable delayed auto-start for '$ServiceName' (sc.exe exit code $LASTEXITCODE)."
if ($Remove) {
if (Test-Path -LiteralPath $shortcutPath) {
if ($PSCmdlet.ShouldProcess($shortcutPath, "Remove backend startup shortcut")) {
Remove-Item -LiteralPath $shortcutPath -Force
Write-Host "Removed backend startup shortcut: $shortcutPath"
}
} else {
Write-Host "No backend startup shortcut found at: $shortcutPath"
}
# Restart on first/second/subsequent failure after 5 seconds.
& sc.exe failure $ServiceName reset= 86400 actions= restart/5000/restart/5000/restart/5000 | Out-Null
if ($LASTEXITCODE -ne 0) {
throw "Failed to configure failure actions for '$ServiceName' (sc.exe exit code $LASTEXITCODE)."
}
if ($StartAfterInstall) {
Start-Service -Name $ServiceName -ErrorAction Stop
}
return
}
Write-Host "Service '$ServiceName' installed successfully." -ForegroundColor Green
Write-Host "Check status with: Get-Service -Name $ServiceName"
Write-Host "View logs in: $logDir"
if ($PSCmdlet.ShouldProcess($shortcutPath, "Create backend startup shortcut")) {
$shell = New-Object -ComObject WScript.Shell
$shortcut = $shell.CreateShortcut($shortcutPath)
$shortcut.TargetPath = "$env:SystemRoot\System32\wscript.exe"
$shortcut.Arguments = '"' + $vbsLauncher + '"'
$shortcut.WorkingDirectory = $scriptDir
$shortcut.Description = "Launch ScreenJob backend at sign-in in the current user session."
$shortcut.Save()
Write-Host "Created backend startup shortcut: $shortcutPath"
}
if ($StartNow) {
Start-Process -FilePath "$env:SystemRoot\System32\wscript.exe" -ArgumentList @($vbsLauncher) -WorkingDirectory $scriptDir | Out-Null
Write-Host "Started backend launcher now."
}