Skip to content

NodePilot 1.2.23

Choose a tag to compare

@Sev7eNup Sev7eNup released this 31 Aug 16:01
· 112 commits to main since this release

The Service Switcher became the Engine Switcher in more than its window title, and the utility got three fixes that came out of running it against a real System Center installation.

Changed

The Service Switcher is now the Engine Switcher everywhere. The utility had been called Engine Switcher in its own window for a while, but only there. Everything underneath still said Service Switcher: the project and its namespace, the assembly, the test project, the documentation, the build artifacts, and every name it writes to disk.

All of it was renamed, persisted names included:

Before Now
Configuration file service-switcher.json engine-switcher.json
Data directory %ProgramData%\NodePilot\ServiceSwitcher %ProgramData%\NodePilot\EngineSwitcher
Theme registry key HKCU\Software\NodePilot\ServiceSwitcher HKCU\Software\NodePilot\EngineSwitcher
Installation folder {app}\tools\service-switcher {app}\tools\engine-switcher
Executable NodePilot.ServiceSwitcher.exe NodePilot.EngineSwitcher.exe
Standalone drop NodePilot-ServiceSwitcher-<version>-win-x64.zip NodePilot-EngineSwitcher-<version>-win-x64.zip
CLI profile in the template service-switcher engine-switcher

Upgrading a machine that already ran the switcher takes one manual step. The update places the new files but does not carry the old state over, so the switcher would look for engine-switcher.json while the machine still holds service-switcher.json. After updating:

$old = "$env:ProgramData\NodePilot\ServiceSwitcher"
$new = "$env:ProgramData\NodePilot\EngineSwitcher"
if ((Test-Path $old) -and -not (Test-Path $new)) { Rename-Item -LiteralPath $old -NewName 'EngineSwitcher' }
$config = Join-Path $new 'service-switcher.json'
if (Test-Path $config) { Rename-Item -LiteralPath $config -NewName 'engine-switcher.json' }

A configuration that sits next to the executable needs the same rename in {app}\tools\engine-switcher. The old {app}\tools\service-switcher directory and the previous Start-menu entry are left behind by the update and can be deleted. The theme preference starts over once. docs/engine-switcher.md carries the full migration section.

Names that describe Windows services — ServiceDiscovery, IServiceControlGateway, ServiceRuntimeState — were deliberately left alone. They are about Windows services, not about the old product name.

Fixed

Windows paths in the configuration no longer have to be escaped, and a broken file is caught before the switch. JSON escapes every backslash, so a configuration edited by hand on the machine — "workflowAllowListPath": "D:\Scripts\runbooks.txt" — aborted the switch with 'S' is an invalid escapable character within a JSON string. Worse, the system check had reported success and both engine buttons stayed enabled, because the file was only read once a switch was already under way.

The three path properties now accept single backslashes and restore a UNC prefix written with one backslash per separator, so "\\fileserver\automation\runbooks.txt" loads as UNC. The escaped form is unchanged and remains the correct one; the tolerance is limited to those three properties, and a stray backslash anywhere else — in profile, in a URL — is still an error rather than something silently accepted.

The configuration is now loaded at every system check, not only when a switch starts. An unusable file is reported in the activity history with its path and disables both engine buttons; correcting the file releases them at the next refresh, without restarting the switcher.

A failed SCOrch query no longer stops every managed service. Deactivating the source workload begins by reading the active jobs, but the fail-closed cleanup was armed before that read. A web service that answered a job query with a truncated body under HTTP 200 therefore took down all four managed services, although nothing had been changed yet.

The cleanup is now armed by the first job that is actually stopped. A failure up to that point leaves every service exactly as it was; from the first stopped job onwards the switch is a mutation like any other and the existing fail-closed behaviour is unchanged.

An unreadable SCOrch response now says which call broke. The failure above surfaced as a bare Expected depth to be zero at the end of the JSON payload — no request URL, no status, no hint of what the server had actually sent. A response that is not a readable collection, whether truncated, an error page or an unsupported $filter, is now reported with the request URL and the beginning of the body.

The standalone Engine Switcher ships with its configuration template. The release drop was the bare executable, while the template stayed behind in the server artifact — so the one audience the standalone copy exists for, a machine with no NodePilot installation to take a template from, had nothing to configure and every switch aborted with "Switcher configuration not found". It is now a zip carrying the executable and the template together.

cliPath became optional and resolves through the installation marker HKLM\SOFTWARE\NodePilot\Server and then the machine PATH, because a relative path only points at np.exe while the configuration sits in the install directory. A missing configuration now names every location that was searched instead of only the machine-wide one, which is the single location nothing ever creates.

Verifying this download

Every file below is listed in NodePilot-1.2.23.SHA256SUMS.txt, the publisher certificate included.

Get-FileHash .\NodePilot-1.2.23.zip -Algorithm SHA256

The installers and the standalone switcher are Authenticode-signed with the NodePilot release certificate:

Subject     CN=NodePilot Release Signing
Thumbprint  277EAB317A581C88302CE92BE805938C86B4650D

Compare that thumbprint against nodepilot-release-signing.cer, attached here:

(Get-PfxCertificate .\nodepilot-release-signing.cer).Thumbprint
$sig = Get-AuthenticodeSignature .\NodePilot-Server-Setup-1.2.23.exe
$sig.SignerCertificate.Subject
$sig.SignerCertificate.Thumbprint

Get-AuthenticodeSignature reports Status: UnknownError, and that is the expected result — the certificate is self-signed, so its root is in nobody's trust store and no chain can be built. What carries the meaning is the pair above: the signer's subject, and a thumbprint equal to the certificate shipped alongside. The checksum file proves the download is intact; the thumbprint is what proves who built it.

SmartScreen

Windows SmartScreen warns on first run of a downloaded installer — "Windows protected your PC". That is expected and unrelated to the signature: the release certificate is self-signed and carries no reputation, so signing does not silence it. Choose More info → Run anyway. SmartScreen ignores antivirus exclusion lists entirely; see the deployment guide for the full explanation.