Installation
Build Toolchain
The project uses the .NET 10 SDK with the Microsoft.NET.Sdk.Worker project type. Deterministic builds with locked NuGet restore (packages.lock.json).
Build & Publish
# Restore (locked mode — requires packages.lock.json)
dotnet restore -p:RestoreLockedMode=true
# Run tests
dotnet test -c Release
# Publish optimized self-contained single-file executable
dotnet publish src/JenkinsAsService `
--nologo --configuration Release `
-p:RestoreLockedMode=true `
--runtime win-x64 --self-contained true `
--output publish/x64/ `
-p:PublishSingleFile=true `
-p:IncludeNativeLibrariesForSelfExtract=true `
-p:EnableCompressionInSingleFile=true `
-p:PublishReadyToRun=true `
-p:OptimizationPreference=Speed `
-p:UseSharedCompilation=true `
-p:DebuggerSupport=false `
-p:MetadataUpdaterSupport=false `
-p:Deterministic=true `
-p:DebugType=Embedded `
-p:DebugSymbols=true `
-p:InformationalVersion="1.0.0" `
/v:q /clp:ErrorsOnly
# Build MSI installer (requires WiX v5 SDK — auto-restored via NuGet)
dotnet build src/JenkinsAsService.Installer -c Release -p:PublishDir=../../publish/x64/ -p:Version=1.0.0
Publish Flags
| Flag | Purpose |
|---|---|
PublishSingleFile |
Single .exe output |
IncludeNativeLibrariesForSelfExtract |
Bundles native libs inside the single file |
EnableCompressionInSingleFile |
Compresses the bundle |
PublishReadyToRun |
AOT pre-compilation (R2R) for faster startup |
OptimizationPreference=Speed |
Optimize for speed over size |
DebuggerSupport=false |
Strip debugger attach points (production service) |
MetadataUpdaterSupport=false |
Strip hot-reload metadata |
Deterministic=true |
Same source → identical binary |
DebugType=Embedded |
PDB symbols embedded in .exe (stack traces with file/line info, no separate .pdb) |
InformationalVersion |
Set from git tag in CI |
The published output:
JenkinsAsService.exe— Self-contained executable (~42MB, no .NET runtime needed)appsettings.json— Configuration template
NuGet Dependencies
Main Project
| Package | Version | Purpose |
|---|---|---|
Microsoft.Extensions.Hosting.WindowsServices |
10.0.9 | Windows Service integration |
Microsoft.Extensions.Http |
10.0.9 | IHttpClientFactory for jar download |
Microsoft.Extensions.Http.Resilience |
10.7.0 | Polly retry, circuit breaker, timeout |
Serilog.Extensions.Hosting |
9.0.0 | Serilog integration with .NET hosting |
Serilog.Sinks.File |
7.0.0 | Rolling file log sink |
Serilog.Sinks.EventLog |
4.0.0 | Windows Event Log sink |
Serilog.Enrichers.Environment |
3.0.1 | MachineName and EnvironmentName enrichment |
Serilog.Enrichers.Process |
3.0.0 | ProcessId enrichment |
Serilog.Formatting.Compact |
3.0.0 | CLEF JSON formatter |
AdysTech.CredentialManager |
3.1.0 | Windows Credential Manager access |
System.Security.Cryptography.ProtectedData |
10.0.9 | DPAPI encryption |
OpenTelemetry.Extensions.Hosting |
1.16.0 | OTel hosting integration |
OpenTelemetry.Exporter.OpenTelemetryProtocol |
1.16.0 | OTLP exporter |
OpenTelemetry.Instrumentation.Runtime |
1.15.1 | .NET runtime metrics |
Test Project
| Package | Version | Purpose |
|---|---|---|
xunit |
2.9.3 | Test framework |
xunit.runner.visualstudio |
3.1.4 | VS Test adapter |
NSubstitute |
5.3.0 | Mocking library |
FluentAssertions |
8.10.0 | Fluent assertion syntax |
Microsoft.NET.Test.Sdk |
18.6.0 | Test platform SDK |
coverlet.collector |
10.0.1 | Code coverage collection |
All versions are pinned (no floating ranges). Both projects include packages.lock.json for deterministic restores via RestoreLockedMode=true.
MSI Installer
The project includes a WiX v5 MSI installer (src/JenkinsAsService.Installer/) that:
- Installs to
C:\Program Files\Jenkins(customizable via install directory dialog orINSTALLFOLDERproperty) - Registers the
JenkinsWindows Service (LocalSystem, Automatic start) - Configures Windows-level service recovery automatically (
util:ServiceConfig— restart on all 3 failures after 10s, reset daily) - Starts the service after install
- Stops and removes the service on uninstall
- Supports in-place upgrades (same
UpgradeCodeacross versions) - Shows BSD 3-Clause license agreement during install
- Default secret protection mode:
EnvironmentVariable(reads fromJENKINS_SECRET)
MSI Dialog Flow
LicenseAgreementDlg → InstallDirDlg → JenkinsConfigDlg → SecurityOptionsDlg → VerifyReadyDlg
MSI Structure
| File | Purpose |
|---|---|
JenkinsAsService.Installer.wixproj |
WiX v5 project — references WixToolset.UI.wixext and WixToolset.Util.wixext |
Package.wxs |
Package metadata, UI (WixUI_InstallDir), icon, features |
Folders.wxs |
Install directory definition (ProgramFiles6432Folder\Jenkins) |
Service.wxs |
File components + ServiceInstall / ServiceControl + util:ServiceConfig (recovery) |
ConfigDialog.wxs |
Custom dialogs: JenkinsConfigDlg (URL/secret/name/Java) + SecurityOptionsDlg (secret mode radio group) |
License.rtf |
BSD 3-Clause license in RTF format for the WixUI dialog |
The installer project is excluded from the solution build (Build=false). Build it explicitly after publishing.
Installation
MSI (Recommended)
- Download the
.msifor your architecture from Releases - Run the installer — it walks through install path, Jenkins URL, agent secret, and secret protection mode
- Done — the service registers and starts automatically
Silent Install
For automated deployments, use msiexec with public properties:
msiexec /i JenkinsAsService_1.0.4_x64.msi /qn `
INSTALLFOLDER="D:\Jenkins" `
JENKINS_URL="https://jenkins.example.com:8443" `
JENKINS_SECRET="your-secret" `
JENKINS_SECRET_MODE="EnvironmentVariable" `
JENKINS_AGENT_NAME="" `
JENKINS_JAVA_PATH=""
| Property | Required | Default | Description |
|---|---|---|---|
INSTALLFOLDER |
No | C:\Program Files\Jenkins |
Installation directory |
JENKINS_URL |
Yes | — | Jenkins controller URL with explicit port |
JENKINS_SECRET |
Yes | — | JNLP agent secret |
JENKINS_SECRET_MODE |
No | EnvironmentVariable |
EnvironmentVariable, Dpapi, CredentialManager, or Unprotected |
JENKINS_AGENT_NAME |
No | Hostname | Agent node name in Jenkins |
JENKINS_JAVA_PATH |
No | JAVA_HOME |
Path to JDK bin folder |
Portable (Archive)
For environments where MSI installation isn't possible, download the .7z or .rar archive from Releases:
- Extract to a folder of your choice (e.g.
D:\Jenkins) - Edit
appsettings.json— fill inJenkinsURL,AgentSecret, and any other settings - Register and start the service:
sc.exe create Jenkins binPath= "D:\Jenkins\JenkinsAsService.exe" start= auto obj= LocalSystem
sc.exe failure Jenkins reset= 86400 actions= restart/10000/restart/10000/restart/10000
sc.exe start Jenkins
To configure secret protection, run the CLI before starting:
.\JenkinsAsService.exe update-secret --secret "your-secret" --url "https://jenkins:8443" --mode Dpapi --silent
To uninstall:
sc.exe stop Jenkins
sc.exe delete Jenkins
Automated Release
The GitHub Actions release workflow (.github/workflows/release.yml):
- Push a tag matching
v*(e.g.,v1.0.4) - Runs tests, publishes optimized self-contained executables for x64 and x86
- Builds MSI installers for both architectures via WiX v5
- Creates
.7z(LZMA2, max compression) and.rar(RAR5 with 5% recovery record) archives - Generates
checksums.jsonwith SHA256 hashes for all artifacts - Creates GitHub Release with auto-generated release notes
Release Artifacts
For a tag v1.0.4:
| File | Description |
|---|---|
JenkinsAsService_1.0.4_x64.msi |
64-bit MSI installer |
JenkinsAsService_1.0.4_x86.msi |
32-bit MSI installer |
JenkinsAsService_1.0.4_x64.7z |
64-bit archive (7z) |
JenkinsAsService_1.0.4_x64.rar |
64-bit archive (RAR5 + recovery) |
JenkinsAsService_1.0.4_x86.7z |
32-bit archive (7z) |
JenkinsAsService_1.0.4_x86.rar |
32-bit archive (RAR5 + recovery) |
JenkinsAsService_1.0.4_checksums.json |
SHA256 hashes |
Service Recovery (Windows-Level)
The MSI installer configures Windows service recovery automatically via util:ServiceConfig:
- First / Second / Third failure: Restart the Service (after 10 seconds)
- Reset fail count after: 1 day
The built-in watchdog handles Java process crashes. Windows-level recovery covers full service host crashes (the .NET process itself dying) — rare but covered automatically.