103 lines
4.2 KiB
PowerShell
103 lines
4.2 KiB
PowerShell
<#
|
|
.SYNOPSIS
|
|
Registers the two v2 Windows services on a node: OtOpcUa (main server, net10) and
|
|
OtOpcUaGalaxyHost (out-of-process Galaxy COM host, net48 x86).
|
|
|
|
.DESCRIPTION
|
|
Phase 2 Stream D.2 — replaces the v1 single-service install (TopShelf-based OtOpcUa.Host).
|
|
Installs both services with the correct service-account SID + per-process shared secret
|
|
provisioning per `driver-stability.md §"IPC Security"`. Galaxy.Host depends on OtOpcUa
|
|
(Galaxy.Host must be reachable when OtOpcUa starts; service dependency wiring + retry
|
|
handled by OtOpcUa.Server NodeBootstrap).
|
|
|
|
.PARAMETER InstallRoot
|
|
Where the binaries live (typically C:\Program Files\OtOpcUa).
|
|
|
|
.PARAMETER ServiceAccount
|
|
Service account SID or DOMAIN\name. Both services run under this account; the
|
|
Galaxy.Host pipe ACL only allows this SID to connect (decision #76).
|
|
|
|
.PARAMETER GalaxySharedSecret
|
|
Per-process secret passed to Galaxy.Host via env var. Generated freshly per install.
|
|
|
|
.PARAMETER ZbConnection
|
|
Galaxy ZB SQL connection string (passed to Galaxy.Host via env var).
|
|
|
|
.EXAMPLE
|
|
.\Install-Services.ps1 -InstallRoot 'C:\Program Files\OtOpcUa' -ServiceAccount 'OTOPCUA\svc-otopcua'
|
|
#>
|
|
[CmdletBinding()]
|
|
param(
|
|
[Parameter(Mandatory)] [string]$InstallRoot,
|
|
[Parameter(Mandatory)] [string]$ServiceAccount,
|
|
[string]$GalaxySharedSecret,
|
|
[string]$ZbConnection = 'Server=localhost;Database=ZB;Integrated Security=True;TrustServerCertificate=True;Encrypt=False;',
|
|
[string]$GalaxyClientName = 'OtOpcUa-Galaxy.Host',
|
|
[string]$GalaxyPipeName = 'OtOpcUaGalaxy'
|
|
)
|
|
|
|
$ErrorActionPreference = 'Stop'
|
|
|
|
if (-not (Test-Path "$InstallRoot\OtOpcUa.Server.exe")) {
|
|
Write-Error "OtOpcUa.Server.exe not found at $InstallRoot — copy the publish output first"
|
|
exit 1
|
|
}
|
|
if (-not (Test-Path "$InstallRoot\Galaxy\OtOpcUa.Driver.Galaxy.Host.exe")) {
|
|
Write-Error "OtOpcUa.Driver.Galaxy.Host.exe not found at $InstallRoot\Galaxy — copy the publish output first"
|
|
exit 1
|
|
}
|
|
|
|
# Generate a fresh shared secret per install if not supplied. Stored in DPAPI-protected file
|
|
# rather than the registry so the service account can read it but other local users cannot.
|
|
if (-not $GalaxySharedSecret) {
|
|
$bytes = New-Object byte[] 32
|
|
[System.Security.Cryptography.RandomNumberGenerator]::Create().GetBytes($bytes)
|
|
$GalaxySharedSecret = [Convert]::ToBase64String($bytes)
|
|
}
|
|
|
|
# Resolve the SID — the IPC ACL needs the SID, not the down-level name.
|
|
$sid = if ($ServiceAccount.StartsWith('S-1-')) {
|
|
$ServiceAccount
|
|
} else {
|
|
(New-Object System.Security.Principal.NTAccount $ServiceAccount).Translate([System.Security.Principal.SecurityIdentifier]).Value
|
|
}
|
|
|
|
# --- Install OtOpcUaGalaxyHost first (OtOpcUa starts after, depends on it being up).
|
|
$galaxyEnv = @(
|
|
"OTOPCUA_GALAXY_PIPE=$GalaxyPipeName"
|
|
"OTOPCUA_ALLOWED_SID=$sid"
|
|
"OTOPCUA_GALAXY_SECRET=$GalaxySharedSecret"
|
|
"OTOPCUA_GALAXY_BACKEND=mxaccess"
|
|
"OTOPCUA_GALAXY_ZB_CONN=$ZbConnection"
|
|
"OTOPCUA_GALAXY_CLIENT_NAME=$GalaxyClientName"
|
|
) -join "`0"
|
|
$galaxyEnv += "`0`0"
|
|
|
|
Write-Host "Installing OtOpcUaGalaxyHost..."
|
|
& sc.exe create OtOpcUaGalaxyHost binPath= "`"$InstallRoot\Galaxy\OtOpcUa.Driver.Galaxy.Host.exe`"" `
|
|
DisplayName= 'OtOpcUa Galaxy Host (out-of-process MXAccess)' `
|
|
start= auto `
|
|
obj= $ServiceAccount | Out-Null
|
|
|
|
# Set per-service environment variables via the registry — sc.exe doesn't expose them directly.
|
|
$svcKey = "HKLM:\SYSTEM\CurrentControlSet\Services\OtOpcUaGalaxyHost"
|
|
$envValue = $galaxyEnv.Split("`0") | Where-Object { $_ -ne '' }
|
|
Set-ItemProperty -Path $svcKey -Name 'Environment' -Type MultiString -Value $envValue
|
|
|
|
# --- Install OtOpcUa (depends on Galaxy host being installed; doesn't strictly require it
|
|
# started — OtOpcUa.Server NodeBootstrap retries on the IPC connect path).
|
|
Write-Host "Installing OtOpcUa..."
|
|
& sc.exe create OtOpcUa binPath= "`"$InstallRoot\OtOpcUa.Server.exe`"" `
|
|
DisplayName= 'OtOpcUa Server' `
|
|
start= auto `
|
|
depend= 'OtOpcUaGalaxyHost' `
|
|
obj= $ServiceAccount | Out-Null
|
|
|
|
Write-Host ""
|
|
Write-Host "Installed. Start with:"
|
|
Write-Host " sc.exe start OtOpcUaGalaxyHost"
|
|
Write-Host " sc.exe start OtOpcUa"
|
|
Write-Host ""
|
|
Write-Host "Galaxy shared secret (record this offline — required for service rebinding):"
|
|
Write-Host " $GalaxySharedSecret"
|