# Servy - Full Documentation Context > Auto-generated full documentation context compiled from the Servy Wiki. > Generated on: 2026-10-10T14:18:15Z --- # Document: Home > Source: https://github.com/aelassas/servy/wiki/Home # Servy Servy is a Windows tool that lets you run any executable as a Windows service, with full control over configuration, monitoring, management, and recovery, all via a clean graphical interface, CLI, or PowerShell. The modern build supports **Windows 10 (1809+)**, **Windows 11**, and **Windows Server 2016+**. Legacy systems such as Windows 7 SP1 and Windows Server 2008 R2 are also supported via a dedicated **.NET Framework 4.8 build**. See the [Installation Guide](https://github.com/aelassas/servy/wiki/Installation-Guide#version-comparison) to choose the right version for your OS. Starting from v10.2, Servy provides enterprise-grade per-service isolation between custom accounts, DPAPI, HKDF & AES-256 HMAC authenticated encryption, and automated vault ACL hardening. All releases feature signed binaries, SBOMs, and continuous vulnerability scanning. See [Security.md](https://github.com/aelassas/servy/wiki/Security) and [Architecture.md](https://github.com/aelassas/servy/wiki/Architecture) for details. > [!TIP] > Use the sidebar to browse installation guides, configuration options, and more. ## Why Use a Windows Service Wrapper? Applications written in Node.js, Python, Java, Go, PHP, Ruby, Rust, or similar environments are usually started as ordinary console or desktop programs. They run inside a user session, which causes problems on servers and other unattended machines: * **Logoff:** When the user logs off, Windows ends all processes in that session, including the application. * **Reboot:** After a restart, the application does not run until someone logs in and starts it manually. * **Crashes and hangs:** If the process exits unexpectedly or stops responding, nothing restarts it. * **Output growth:** If console output is redirected to a file, the file grows without limit unless something rotates it. A Windows service wrapper registers an ordinary executable with the Windows Service Control Manager (SCM) and runs it as a service. The application then starts at boot, runs without a logged-in user, and is restarted on failure, without any change to its source code. See [examples and recipes](https://github.com/aelassas/servy/wiki/Examples-&-Recipes) for real-world usage and configurations across different environments. ## Core Problems Servy Solves Servy covers the basics of running an executable as a service, plus the operational tasks that usually come with it. | Problem | How Servy addresses it | | --- | --- | | **Application stops at logoff or does not start after reboot** | Runs the application as a Windows service in Session 0. It starts at boot, before any user logs in, on both x64 and ARM64. | | **Application crashes or hangs** | Monitors the process with health checks and heartbeats, restarts it according to a configurable recovery policy, and sends failure alerts through Windows notifications or email. | | **Child processes left running after a stop** | Stops the application with a `Ctrl+C` or close-window signal, forwards the stop request to its child processes, and terminates any that remain. | | **Log files that grow without limit** | Writes stdout and stderr to files and rotates them by size or by date. | | **Limited visibility into running services** | Servy Manager shows CPU and RAM usage graphs, live console output, the status of service dependencies, and searchable logs. | | **Setup and cleanup around startup and shutdown** | Runs pre-launch, post-launch, pre-stop, and post-stop programs, with configurable retries, timeouts, and failure handling. | | **Process and environment settings** | Supports a working directory, startup parameters, environment variables with expansion, process priority, CPU affinity, and service dependencies. | | **Service accounts and permissions** | Runs services as Local System, a local or domain user, or a Group Managed Service Account (gMSA). | | **Deployment and management** | Provides a desktop app, a CLI (`servy-cli`), a PowerShell module, and service import and export. It supports current Windows versions as well as Windows 7 SP1 and Windows Server 2008 R2 through the .NET Framework 4.8 build. | --- # Document: Overview > Source: https://github.com/aelassas/servy/wiki/Overview ## Table of Contents 1. [Get Started](https://github.com/aelassas/servy/wiki/Overview#get-started) 1. [Quick Example](https://github.com/aelassas/servy/wiki/Overview#quick-example) 1. [Desktop App](https://github.com/aelassas/servy/wiki/Overview#desktop-app) 1. [Service Details](https://github.com/aelassas/servy/wiki/Overview#service-details) 1. [Logging](https://github.com/aelassas/servy/wiki/Overview#logging) 1. [Recovery](https://github.com/aelassas/servy/wiki/Overview#recovery) 1. [Advanced](https://github.com/aelassas/servy/wiki/Overview#advanced) 1. [Log On](https://github.com/aelassas/servy/wiki/Overview#log-on) 1. [Pre-Launch](https://github.com/aelassas/servy/wiki/Overview#pre-launch) 1. [Post-Launch](https://github.com/aelassas/servy/wiki/Overview#post-launch) 1. [Pre-Stop](https://github.com/aelassas/servy/wiki/Overview#pre-stop) 1. [Post-Stop](https://github.com/aelassas/servy/wiki/Overview#post-stop) 1. [Manager App](https://github.com/aelassas/servy/wiki/Overview#manager-app) 1. [Services](https://github.com/aelassas/servy/wiki/Overview#services) 1. [Performance](https://github.com/aelassas/servy/wiki/Overview#performance) 1. [Console](https://github.com/aelassas/servy/wiki/Overview#console) 1. [Dependencies](https://github.com/aelassas/servy/wiki/Overview#dependencies) 1. [Logs](https://github.com/aelassas/servy/wiki/Overview#logs) 1. [CLI / PowerShell](https://github.com/aelassas/servy/wiki/Overview#cli--powershell) 1. [CLI](https://github.com/aelassas/servy/wiki/Overview#cli) 1. [PowerShell](https://github.com/aelassas/servy/wiki/Overview#powershell) 1. [See Also](https://github.com/aelassas/servy/wiki/Overview#see-also) > [!IMPORTANT] > **Console UI Compatibility** > If your app tries to visually update the command prompt (like clearing the screen or moving the cursor), it will crash when running as a background service since services don't have visible windows. To fix this without changing your code, enable the **Enable Console UI** option in the service configuration while installing your service. ## Get Started Servy lets you run any application as a native Windows service with full control over startup, environment, logging, and lifecycle management. You can manage services using the desktop app (GUI), the CLI (`servy-cli`), or PowerShell. > [!IMPORTANT] > **Desktop Interaction and Session 0 Isolation** > > Servy can wrap any executable as a native Windows service, including GUI apps as long as they do not require an interactive desktop session. Like all Windows service wrappers (including NSSM and WinSW), Servy processes execute within **Session 0**, which runs in an isolated environment without interactive desktop access. > > If you attempt to run a GUI application that requires an interactive desktop as a service, it will fail to start or crash at runtime, often throwing errors such as Access Violation (`0xC0000005`) or Null Pointer Exception. If your application requires an active desktop session, use an alternative automation tool (such as **Windows Task Scheduler** configured to run only when a user is logged on) instead. > [!NOTE] > **Before You Begin** > > Servy requires administrator rights to install and manage Windows services. If you are using a modern Windows workstation or server, choose the .NET 10.0+ build. If you need support for older platforms such as Windows 7 SP1 or Windows Server 2008 R2, use the .NET Framework 4.8 build instead. To get started, download the latest release from [GitHub](https://github.com/aelassas/servy/releases/latest) or install via a package manager: **WinGet** ```powershell winget install servy ``` **Chocolatey** ```powershell choco install -y servy ``` **Scoop** ```powershell scoop bucket add extras scoop install servy ``` **Patch My PC** Servy is available in the official [Patch My PC catalog](https://patchmypc.com/supported-products/) for enterprise automated deployment and updates via Microsoft Intune and ConfigMgr (SCCM). After a default installation `servy-cli` is on the system **PATH** - see [Installation Guide](https://github.com/aelassas/servy/wiki/Installation-Guide#add-servy-to-path) for the option that controls this and for the portable package. ## Quick Example You can manage services using the [desktop app (GUI)](https://github.com/aelassas/servy/wiki/Servy-Desktop-App), the [CLI](https://github.com/aelassas/servy/wiki/Servy-CLI), or [PowerShell](https://github.com/aelassas/servy/wiki/Servy-PowerShell-Module). Here's a minimal example using the CLI to run a Node.js app as a Windows service. Run it from an elevated PowerShell prompt: installing, starting and stopping a Windows service all require administrator privileges. ```powershell servy-cli install ` --name="MyService" ` --path="C:\Program Files\nodejs\node.exe" ` --startupDir="C:\MyServer" ` --params="server.js" ` --enableHealth ``` This creates a service named `MyService` that runs your Node.js server in the background, starts automatically with Windows, and has [health monitoring](https://github.com/aelassas/servy/wiki/Health-Monitoring-&-Recovery) enabled. Then start the service: ```powershell servy-cli start --name="MyService" ``` Or from an **elevated** Command Prompt: ```cmd sc.exe start MyService ``` Explore more [examples and recipes](https://github.com/aelassas/servy/wiki/Examples-&-Recipes) for Python, Java, Go, and other popular frameworks. ## Desktop App The [Servy Desktop App](https://github.com/aelassas/servy/wiki/Servy-Desktop-App) provides an intuitive graphical interface to configure, install, and manage individual Windows services. ### Service Details Configure core service properties including name, description, executable path, arguments, working directory, and startup type. See [Servy Desktop App](https://github.com/aelassas/servy/wiki/Servy-Desktop-App#service-details). servy-config-main For more details on CPU affinity, see the [FAQ](https://github.com/aelassas/servy/wiki/FAQ#how-and-why-should-i-use-cpu-affinity-with-servy). ### Logging Configure `stdout` and `stderr` log file redirection, size-based and date-based log rotation, and retention policies. See [Logging & Log Rotation](https://github.com/aelassas/servy/wiki/Logging-&-Log-Rotation). servy-config-logging > [!NOTE] > Enabling the debug option will record sensitive information in the local log file at `%ProgramData%\Servy\logs\services\\Servy.Service.log`. This behavior only occurs when local logging is enabled, which is the default setting. Sensitive data is never recorded in the Windows Event Log. The CLI `show` command and `Show-ServyService` mask the encrypted fields by default; `--decrypt` / `-Decrypt` prints the parameters and environment variables in clear text (the stored password always stays masked). See [Servy CLI](https://github.com/aelassas/servy/wiki/Servy-CLI) and [Servy PowerShell Module](https://github.com/aelassas/servy/wiki/Servy-PowerShell-Module). For detailed information about logging, check out the [Logging & Log Rotation](https://github.com/aelassas/servy/wiki/Logging-&-Log-Rotation) documentation. ### Recovery Configure automated liveness checks, external diagnostic heartbeat pings, and automatic restart behavior. See [Health Monitoring & Recovery](https://github.com/aelassas/servy/wiki/Health-Monitoring-&-Recovery). servy-config-recovery For detailed information about health monitoring and recovery, check out the [Health Monitoring & Recovery](https://github.com/aelassas/servy/wiki/Health-Monitoring-&-Recovery) documentation. ### Advanced Set custom process environment variables and Windows service dependencies. See [Environment Variables](https://github.com/aelassas/servy/wiki/Environment-Variables) and [Service Dependencies](https://github.com/aelassas/servy/wiki/Service-Dependencies). servy-config-advanced For detailed information about environment variables, check out the [Environment Variables](https://github.com/aelassas/servy/wiki/Environment-Variables) documentation. For detailed information about service dependencies, check out the [Service Dependencies](https://github.com/aelassas/servy/wiki/Service-Dependencies) documentation. ### Log On Configure service execution accounts including `LocalSystem`, built-in service accounts, domain accounts, and gMSAs. See [Security](https://github.com/aelassas/servy/wiki/Security). servy-config-logon You can also run the service under: * `NT AUTHORITY\NetworkService` * `NT AUTHORITY\LocalService` * Passwordless accounts servy-config-logon-builtin-accounts ### Pre-Launch Execute custom initialization scripts or executables before the main service process starts. See [Pre-Launch & Post-Launch Actions](https://github.com/aelassas/servy/wiki/Pre-Launch-&-Post-Launch-Actions). servy-config-pre-launch For detailed information about the pre-launch hook, check out the [Pre-Launch & Post-Launch Actions](https://github.com/aelassas/servy/wiki/Pre-Launch-&-Post-Launch-Actions) documentation. ### Post-Launch Run auxiliary tasks immediately after the primary process launches successfully. See [Pre-Launch & Post-Launch Actions](https://github.com/aelassas/servy/wiki/Pre-Launch-&-Post-Launch-Actions). servy-config-post-launch For detailed information about the post-launch hook, check out the [Pre-Launch & Post-Launch Actions](https://github.com/aelassas/servy/wiki/Pre-Launch-&-Post-Launch-Actions) documentation. ### Pre-Stop Run graceful shutdown tasks or resource draining scripts prior to stopping the main service. See [Pre-Stop & Post-Stop Actions](https://github.com/aelassas/servy/wiki/Pre-Stop-&-Post-Stop-Actions). servy-config-pre-stop For detailed information about the pre-stop hook, check out the [Pre-Stop & Post-Stop Actions](https://github.com/aelassas/servy/wiki/Pre-Stop-&-Post-Stop-Actions) documentation. ### Post-Stop Execute post-cleanup tasks after the primary service and all child processes have completely exited. See [Pre-Stop & Post-Stop Actions](https://github.com/aelassas/servy/wiki/Pre-Stop-&-Post-Stop-Actions). servy-config-post-stop For detailed information about the post-stop hook, check out the [Pre-Stop & Post-Stop Actions](https://github.com/aelassas/servy/wiki/Pre-Stop-&-Post-Stop-Actions) documentation. ## Manager App [Servy Manager](https://github.com/aelassas/servy/wiki/Servy-Manager) is a central administrative interface to manage, monitor, and inspect all services installed across the system. ### Services View all registered services, inspect real-time CPU/RAM metrics, and trigger lifecycle actions. See [Servy Manager](https://github.com/aelassas/servy/wiki/Servy-Manager#services). servy-manager-services ### Performance Track real-time CPU and memory utilization using live visual performance graphs. See [Servy Manager](https://github.com/aelassas/servy/wiki/Servy-Manager#performance). servy-manager-performance ### Console Stream unified `stdout` and `stderr` console output in real time with live filtering and tailing controls. See [Servy Manager](https://github.com/aelassas/servy/wiki/Servy-Manager#console). servy-manager-console ### Dependencies Inspect full Windows Service Control Manager (SCM) dependency trees with status color coding. See [Servy Manager](https://github.com/aelassas/servy/wiki/Servy-Manager#dependencies). servy-manager-dependencies ### Logs Inspect Windows Event Log entries directly within the application viewer. See [Servy Manager](https://github.com/aelassas/servy/wiki/Servy-Manager#logs). servy-manager-logs ## CLI / PowerShell Servy includes a command-line interface (`servy-cli`) and a [PowerShell module](https://github.com/aelassas/servy/wiki/Servy-PowerShell-Module) for full automation and CI/CD integration. ### CLI Execute service operations directly via command-line arguments or configuration files. See [Servy CLI](https://github.com/aelassas/servy/wiki/Servy-CLI). servy-cli ### PowerShell Manage services natively using PowerShell cmdlets and pipeline objects. See [Servy PowerShell Module](https://github.com/aelassas/servy/wiki/Servy-PowerShell-Module). servy-powershell ## See Also * [Installation Guide](https://github.com/aelassas/servy/wiki/Installation-Guide) * [Usage](https://github.com/aelassas/servy/wiki/Usage) * [Servy Desktop App](https://github.com/aelassas/servy/wiki/Servy-Desktop-App) * [Servy Manager](https://github.com/aelassas/servy/wiki/Servy-Manager) * [Servy CLI](https://github.com/aelassas/servy/wiki/Servy-CLI) * [Servy PowerShell Module](https://github.com/aelassas/servy/wiki/Servy-PowerShell-Module) * [Examples & Recipes](https://github.com/aelassas/servy/wiki/Examples-&-Recipes) * [Export/Import Services](https://github.com/aelassas/servy/wiki/Export-Import-Services) * [Service Event Notifications](https://github.com/aelassas/servy/wiki/Service-Event-Notifications) --- # Document: Installation Guide > Source: https://github.com/aelassas/servy/wiki/Installation-Guide ## Table of Contents 1. [Introduction](https://github.com/aelassas/servy/wiki/Installation-Guide#introduction) 1. [System Requirements](https://github.com/aelassas/servy/wiki/Installation-Guide#system-requirements) 1. [Version Comparison](https://github.com/aelassas/servy/wiki/Installation-Guide#version-comparison) 1. [Installation Options](https://github.com/aelassas/servy/wiki/Installation-Guide#installation-options) 1. [Quick Install](https://github.com/aelassas/servy/wiki/Installation-Guide#quick-install) 1. [Add Servy to PATH](https://github.com/aelassas/servy/wiki/Installation-Guide#add-servy-to-path) 1. [Manual Installation](https://github.com/aelassas/servy/wiki/Installation-Guide#manual-installation) 1. [Silent Install/Uninstall](https://github.com/aelassas/servy/wiki/Installation-Guide#silent-installuninstall) 1. [Silent Install](https://github.com/aelassas/servy/wiki/Installation-Guide#silent-install) 1. [Custom Silent Install](https://github.com/aelassas/servy/wiki/Installation-Guide#custom-silent-install) 1. [Custom Installation Directory](https://github.com/aelassas/servy/wiki/Installation-Guide#custom-installation-directory) 1. [Silent Uninstall](https://github.com/aelassas/servy/wiki/Installation-Guide#silent-uninstall) 1. [Switches Explained](https://github.com/aelassas/servy/wiki/Installation-Guide#switches-explained) 1. [Security & Antivirus Setup](https://github.com/aelassas/servy/wiki/Installation-Guide#security--antivirus-setup) ## Introduction This guide covers the requirements and various methods for installing Servy on Windows systems. Servy is provided in two distinct builds to ensure compatibility across modern and legacy Windows environments. * **Modern Build (.NET 10.0+):** Best for Windows 10, 11, and modern Windows Server. * **Legacy Build (.NET Framework 4.8):** Best for Windows 7, 8, and older Server editions. ## System Requirements > [!CAUTION] > **Administrator privileges are required** to install Servy and to manage Windows services. ### Version Comparison | Feature | .NET 10.0+ Version (x64) | .NET 10.0+ Version (ARM64) | .NET Framework 4.8 Version (Legacy x64) | | --- | --- | --- | --- | | **Filename** | `servy-x.x-x64-installer.exe` | `servy-x.x-arm64-installer.exe` | `servy-x.x-net48-x64-installer.exe` | | **OS Support** | Windows 10 (1809+), 11, Server 2016+ | Windows 11 on ARM, Windows on ARM | Windows 7 SP1, 8.x, Server 2008 R2+ | | **Dependencies** | None (Self-contained) | None (Self-contained) | [.NET Framework 4.8](https://dotnet.microsoft.com/en-us/download/dotnet-framework/net48) | | **Performance** | Optimized (Modern Runtime) | Native ARM64 (Optimized Runtime) | Standard (Legacy Runtime) | **Note on Legacy OS:** While the .NET 10.0 build may run on Windows 7, it is **unsupported**. For Windows 7 SP1 or Windows Server 2008 R2, you must use the **.NET Framework 4.8** build to ensure stability. ## Installation Options You have two paths to install Servy: use a package manager if your environment supports it, or [download the installer](https://github.com/aelassas/servy/releases/latest) and install it manually when you need full control over the setup process. ### Quick Install **WinGet** ```powershell winget install servy ``` **Chocolatey** ```powershell choco install -y servy ``` **Scoop** ```powershell scoop bucket add extras scoop install servy ``` **Patch My PC** Servy is available in the official [Patch My PC catalog](https://patchmypc.com/supported-products/) for enterprise automated deployment and updates via Microsoft Intune and ConfigMgr (SCCM). > [!NOTE] > **Legacy OS Support (Windows 7 SP1 / 8.x / Server 2008 R2):** Package managers carry the self-contained modern build. For older platforms, download `servy-x.x-net48-x64-installer.exe` or `servy-x.x-net48-x64-portable.7z` directly from [GitHub Releases](https://github.com/aelassas/servy/releases/latest) (requires .NET Framework 4.8). ### Add Servy to PATH The installer's **Add Servy to PATH** option (Additional Options page, enabled by default, requires the CLI component) adds the Servy directory to the system **PATH**, so `servy-cli` runs from any elevated Command Prompt or PowerShell session. Clear it to leave `PATH` untouched; uninstalling removes the entry only if the installer added it. The portable package makes no `PATH` change - add its directory yourself, or use Scoop, which puts `servy-cli` on `PATH` through its own shim. ### Manual Installation 1. [Download the latest release](https://github.com/aelassas/servy/releases/latest). 2. Run the installer (you will be prompted for admin rights). 3. Launch Servy from the Start Menu or desktop shortcut. ### Silent Install/Uninstall #### Silent Install You can install Servy silently (without any UI) from an administrator command prompt using the following commands: ```powershell # For .NET 10.0+ (x64) .\servy--x64-installer.exe /VERYSILENT /NORESTART /SUPPRESSMSGBOXES /SP- /CLOSEAPPLICATIONS /NOCANCEL # For .NET 10.0+ (ARM64) .\servy--arm64-installer.exe /VERYSILENT /NORESTART /SUPPRESSMSGBOXES /SP- /CLOSEAPPLICATIONS /NOCANCEL # For .NET Framework 4.8 .\servy--net48-x64-installer.exe /VERYSILENT /NORESTART /SUPPRESSMSGBOXES /SP- /CLOSEAPPLICATIONS /NOCANCEL ``` Using PowerShell: ```powershell # For .NET 10.0+ (x64) Start-Process -FilePath ".\servy--x64-installer.exe" -ArgumentList '/VERYSILENT /SUPPRESSMSGBOXES /NORESTART /SP- /CLOSEAPPLICATIONS /NOCANCEL' -Verb RunAs -Wait # For .NET 10.0+ (ARM64) Start-Process -FilePath ".\servy--arm64-installer.exe" -ArgumentList '/VERYSILENT /SUPPRESSMSGBOXES /NORESTART /SP- /CLOSEAPPLICATIONS /NOCANCEL' -Verb RunAs -Wait # For .NET Framework 4.8 Start-Process -FilePath ".\servy--net48-x64-installer.exe" -ArgumentList '/VERYSILENT /SUPPRESSMSGBOXES /NORESTART /SP- /CLOSEAPPLICATIONS /NOCANCEL' -Verb RunAs -Wait # Refresh PATH in current session $env:Path = ((( [Environment]::GetEnvironmentVariable('Path', 'Machine'), [Environment]::GetEnvironmentVariable('Path', 'User') ) -join ';').Split(';', [StringSplitOptions]::RemoveEmptyEntries) | Select-Object -Unique) -join ';' ``` You need to wait a little while for Servy to finish installing. If you face any issues, enable logging by adding the following option: ```text /LOG="servy-install.log" ``` #### Custom Silent Install To install the CLI only, use these options: ```text /SetupType=custom /Components=install_cli ``` To install the desktop app only, use these options: ```text /SetupType=custom /Components=install_main_app ``` To install the manager app only, use these options: ```text /SetupType=custom /Components=install_manager ``` To install the desktop app and CLI only, use these options: ```text /SetupType=custom /Components=install_main_app,install_cli ``` To install the manager app and CLI only, use these options: ```text /SetupType=custom /Components=install_manager,install_cli ``` #### Custom Installation Directory To specify a custom installation directory, use the `/DIR` parameter from the command line: ```powershell .\servy--x64-installer.exe /VERYSILENT /DIR="C:\Your\Custom\Path" /NORESTART /SUPPRESSMSGBOXES /SP- /CLOSEAPPLICATIONS /NOCANCEL ``` Using a custom path will not allow you to bypass the need for administrative rights. The installer executable is compiled with `PrivilegesRequired=admin`, which causes Windows to automatically trigger a UAC prompt and require elevated credentials before execution starts. Beyond writing files, the setup routine performs system-level configuration such as updating `HKLM` registry keys and setting strict ACLs on the `%ProgramData%\Servy` directory via `icacls.exe`. If you also want to prevent the installer from modifying the system `PATH` environment variable, you can explicitly deselect the `addpath` task using `/MERGETASKS="!addpath"`. If you want to skip all optional tasks entirely, including both the `PATH` update and desktop shortcuts, you can pass an empty task list using `/TASKS=""`. If you do not have administrative access on the target machine, you will not be able to use the `.exe` installer at all. In that scenario, you should use the portable package instead (`servy--x64-portable.7z`). The portable archive can be extracted and executed directly from any folder where your user account has standard write access, such as `%LOCALAPPDATA%` or a user folder, without requiring elevation or installer scripts. #### Silent Uninstall You can uninstall Servy silently (without any UI) from an administrator command prompt using the following command (PowerShell): ```powershell # Default location; adjust the path if Servy was installed to a custom directory & "$env:ProgramFiles\Servy\unins000.exe" /VERYSILENT /NORESTART /SUPPRESSMSGBOXES ``` #### Switches Explained | Switch | Description | |--------|-------------| | `/VERYSILENT` | Installs completely silently with no wizard or progress windows. | | `/NORESTART` | Prevents automatic system restart after installation. | | `/SUPPRESSMSGBOXES` | Suppresses all message boxes, including errors, during installation. | | `/SP-` | Disables the "This will install..." startup prompt. | | `/CLOSEAPPLICATIONS` | Asks running apps to close if they block files. | | `/NOCANCEL` | Prevents the user from canceling the installation. | ## Security & Antivirus Setup Servy's executables and installers are digitally signed by SignPath (see [Security](https://github.com/aelassas/servy/wiki/Security#supply-chain-and-trust)). It performs only standard installation tasks and does not contain malware, adware, or unwanted software. Release binaries are scanned on VirusTotal, and false-positive reports are submitted to Microsoft Security Intelligence and affected AV vendors. Servy is published in the Windows Package Manager (WinGet), Chocolatey, Scoop, and Patch My PC enterprise catalog. Before running a downloaded installer, you can check its signature under **Properties > Digital Signatures**. To ensure smooth operation of the Servy Windows services, it is recommended to add the following folders to your Microsoft Defender or third-party antivirus exclusion list: ```text %ProgramData%\Servy %ProgramFiles%\Servy ``` This prevents antivirus software from interfering with the execution of service binaries managed by Servy. Starting with v9.1, Servy uses a hybrid single-file execution approach. Managed C# assemblies (like `Servy.CLI.dll`, `Servy.dll`, `Servy.Manager.dll`, `Servy.Service.dll`, and `Servy.Restarter.dll`) are **no longer extracted** to `%TEMP%\.net`. Instead, they are loaded directly into memory from the main executables (`servy-cli.exe`, `Servy.Manager.exe`, etc.), **which are all fully Authenticode signed**. Servy **only** extracts unmanaged native C/C++ binaries to `%TEMP%` (which Windows `LoadLibrary` requires). This prevents security software from intercepting and flagging dynamically extracted DLLs. --- # Document: Quick Start / Usage > Source: https://github.com/aelassas/servy/wiki/Usage ## Table of Contents 1. [Introduction](https://github.com/aelassas/servy/wiki/Usage#introduction) 1. [Quick Start](https://github.com/aelassas/servy/wiki/Usage#quick-start) 1. [Service Configuration](https://github.com/aelassas/servy/wiki/Usage#service-configuration) 1. [Logging & Log Rotation](https://github.com/aelassas/servy/wiki/Usage#logging--log-rotation) 1. [Health Monitoring & Recovery](https://github.com/aelassas/servy/wiki/Usage#health-monitoring--recovery) 1. [Advanced Configuration](https://github.com/aelassas/servy/wiki/Usage#advanced-configuration) 1. [Logon & Security](https://github.com/aelassas/servy/wiki/Usage#logon--security) 1. [Launch & Stop Hooks](https://github.com/aelassas/servy/wiki/Usage#launch--stop-hooks) 1. [Managing Services](https://github.com/aelassas/servy/wiki/Usage#managing-services) 1. [See Also](https://github.com/aelassas/servy/wiki/Usage#see-also) ## Introduction This page provides a comprehensive guide on how to configure, install, and manage services using Servy. Whether you are using the Servy (GUI), CLI, or PowerShell, the underlying principles remain the same. Servy is a service wrapper that transforms any executable, script, or runtime (Node.js, Python, Java, etc.) into a managed Windows Service. It provides enterprise-grade features like automatic recovery, log rotation, CPU and RAM monitoring, and lifecycle hooks that native Windows services lack. ## Quick Start > [!IMPORTANT] > Before installing a service, make sure you are running with administrator rights and that the target account has the required access to `%ProgramData%\Servy` and any application folders it needs to use. 1. **Launch** `Servy.exe` (Servy GUI). 2. **Name your service**: Enter a unique service name in the **Service Name** field. 3. **Select your executable**: Provide the full path to your binary in **Process Path**. 4. **Configure optional settings**: Set **Process Parameters**, **Startup Directory**, or **Description** as needed. 5. **Install**: Click the **Install** button to register it with the Windows Service Control Manager (SCM). 6. **Start**: Click **Start** to bring your service online immediately. ## Service Configuration ### Primary Settings * **Service Name (required)**: The unique service name for Windows. * **Display Name**: The human-readable name shown in `services.msc`. * **Description**: A brief summary of the service's purpose. * **Process Path (required)**: Full path to the executable (e.g., `C:\Program Files\nodejs\node.exe`). Supports environment variable expansion. * **Startup Directory**: The working directory for the process. Defaults to the executable's folder. * **Process Parameters**: Command-line arguments passed to the executable. * **Startup Type**: Choose between `Automatic (default)`, `Automatic (delayed start)`, `Manual`, or `Disabled`. * **Process Priority**: Choose between `Idle`, `Below Normal`, `Normal (default)`, `Above Normal`, `High`, or `Real Time (use with caution)`. * **CPU Affinity**: Logical CPUs the process may run on (e.g., `0-3,8` or `0xFF00`). See this [FAQ](https://github.com/aelassas/servy/wiki/FAQ#how-and-why-should-i-use-cpu-affinity-with-servy) for further details. * **Timeouts**: * **Start Timeout**: Seconds to wait for a successful start (default: `10s`). * **Stop Timeout**: Seconds to wait for the process to exit gracefully before killing it (default: `5s`). * **Enable Console UI**: For interactive console apps; disables stdout/stderr redirection. ## Logging & Log Rotation Servy captures `stdout` (standard output) and `stderr` (error output) and writes them to files. * **Size-based Rotation**: Automatically rolls logs when they reach a specific size (e.g., 10MB). * **Date-based Rotation**: Rolls logs on a `Daily`, `Weekly`, or `Monthly` interval. * **Retention**: Set **Max Rotations** to limit the number of old log files kept on disk. For advanced logging configurations, see [Logging & Log Rotation](https://github.com/aelassas/servy/wiki/Logging-&-Log-Rotation). ## Health Monitoring & Recovery Servy can monitor your application's health and automatically take action if it fails. * **Heartbeat**: Servy checks if the process is still alive at defined intervals. * **Recovery Actions**: Choose **Restart Service** (default), **Restart Process**, **Restart Computer**, or **None** upon failure. * **Heartbeat URL**: An absolute HTTP/HTTPS URL (e.g., `https://hc-ping.com/uuid`) used for sending out-of-band diagnostic heartbeat pings to external monitoring services (such as [healthchecks.io](https://healthchecks.io/) or Uptime Kuma). * **Failure Program**: Specify an external script or app to run specifically when a failure is detected. For detailed setup, see [Health Monitoring & Recovery](https://github.com/aelassas/servy/wiki/Health-Monitoring-&-Recovery). ## Advanced Configuration ### Environment Variables Define process-specific environment variables without polluting the system-wide environment. * **Format**: `KEY=VALUE` (one per line or separated by `;`). * **Expansion**: Supports referencing other variables, e.g., `PATH=%PATH%;C:\CustomBin`. * **Escaping**: Use `\;` for literal semicolons and `\=` for literal equals. See [Environment Variables](https://github.com/aelassas/servy/wiki/Environment-Variables) for the full resolution order. ### Service Dependencies Ensure your service only starts after other required services (like `MSSQLSERVER` or `Docker`) are ready. Use the internal **Service Name**, not the Display Name. See [Service Dependencies](https://github.com/aelassas/servy/wiki/Service-Dependencies). ## Logon & Security Servy allows you to configure the service identity, supporting: * **Local Accounts**: `.\username` * **Domain Accounts**: `DOMAIN\username` * **Managed Service Accounts**: `DOMAIN\gMSA$` **Security Note:** Stored passwords are encrypted using **AES-256**. For technical details on how Servy handles credentials, see the [Security](https://github.com/aelassas/servy/wiki/Security) model. ## Launch & Stop Hooks Servy provides four distinct hook points to manage your service lifecycle: | Hook | Typical Use Case | | :--- | :--- | | **Pre-Launch** | Fetching secrets, generating config files. | | **Post-Launch** | Sending "Started" notifications, initializing DB migrations. | | **Pre-Stop** | Graceful drain of connections, flushing buffers. | | **Post-Stop** | Temporary file cleanup, post-mortem logging. | * Detailed Startup Guide: [Pre-Launch & Post-Launch Actions](https://github.com/aelassas/servy/wiki/Pre-Launch-&-Post-Launch-Actions) * Detailed Shutdown Guide: [Pre-Stop & Post-Stop Actions](https://github.com/aelassas/servy/wiki/Pre-Stop-&-Post-Stop-Actions) ## Managing Services * **Servy Manager**: Use the GUI for real-time status monitoring, log viewing, and configuration updates. See [Servy Manager](https://github.com/aelassas/servy/wiki/Servy-Manager). * **Servy CLI**: Ideal for automation and remote management. See [Servy CLI](https://github.com/aelassas/servy/wiki/Servy-CLI). * **PowerShell**: Use the native module for CI/CD integration. See [Servy PowerShell Module](https://github.com/aelassas/servy/wiki/Servy-PowerShell-Module). * **Portability**: Use the **Export/Import** feature to move service configurations between servers. See [Export/Import Services](https://github.com/aelassas/servy/wiki/Export-Import-Services). **Next Step:** Ready to deploy? Check out the [Examples & Recipes](https://github.com/aelassas/servy/wiki/Examples-&-Recipes) for pre-configured setups for Node.js, Python, and Java applications. ## See Also * [Servy Desktop App](https://github.com/aelassas/servy/wiki/Servy-Desktop-App) * [Servy Manager](https://github.com/aelassas/servy/wiki/Servy-Manager) * [Servy CLI](https://github.com/aelassas/servy/wiki/Servy-CLI) * [PowerShell Module](https://github.com/aelassas/servy/wiki/Servy-PowerShell-Module) * [Examples & Recipes](https://github.com/aelassas/servy/wiki/Examples-&-Recipes) * [Shutdown & Teardown](https://github.com/aelassas/servy/wiki/Shutdown-&-Teardown) * [Service Event Notifications](https://github.com/aelassas/servy/wiki/Service-Event-Notifications) * [Comparison with Alternatives](https://github.com/aelassas/servy/wiki/Comparison-with-Alternatives) * [Troubleshooting](https://github.com/aelassas/servy/wiki/Troubleshooting) * [FAQ](https://github.com/aelassas/servy/wiki/FAQ) --- # Document: Servy Desktop App > Source: https://github.com/aelassas/servy/wiki/Servy-Desktop-App ## Table of Contents 1. [Introduction](https://github.com/aelassas/servy/wiki/Servy-Desktop-App#introduction) 1. [Overview](https://github.com/aelassas/servy/wiki/Servy-Desktop-App#overview) 1. [Service Details](https://github.com/aelassas/servy/wiki/Servy-Desktop-App#service-details) 1. [Logging](https://github.com/aelassas/servy/wiki/Servy-Desktop-App#logging) 1. [Recovery](https://github.com/aelassas/servy/wiki/Servy-Desktop-App#recovery) 1. [Advanced](https://github.com/aelassas/servy/wiki/Servy-Desktop-App#advanced) 1. [Log On](https://github.com/aelassas/servy/wiki/Servy-Desktop-App#log-on) 1. [Pre-Launch](https://github.com/aelassas/servy/wiki/Servy-Desktop-App#pre-launch) 1. [Post-Launch](https://github.com/aelassas/servy/wiki/Servy-Desktop-App#post-launch) 1. [Pre-Stop](https://github.com/aelassas/servy/wiki/Servy-Desktop-App#pre-stop) 1. [Post-Stop](https://github.com/aelassas/servy/wiki/Servy-Desktop-App#post-stop) 1. [Features](https://github.com/aelassas/servy/wiki/Servy-Desktop-App#features) 1. [Availability](https://github.com/aelassas/servy/wiki/Servy-Desktop-App#availability) 1. [Usage](https://github.com/aelassas/servy/wiki/Servy-Desktop-App#usage) 1. [See Also](https://github.com/aelassas/servy/wiki/Servy-Desktop-App#see-also) > [!IMPORTANT] > **Console UI Compatibility** > If your app tries to visually update the command prompt (like clearing the screen or moving the cursor), it will crash when running as a background service since services don't have visible windows. To fix this without changing your code, enable the **Enable Console UI** option in the service configuration while installing your service. ## Introduction Servy is a Windows service wrapper that allows you to transform any executable, script, or batch file into a background service. It bridges the gap between simple console applications and the enterprise-grade management expected from native Windows services. Servy provides an intuitive interface to run any app as a native Windows service with configuration and management options. By using Servy, you can ensure that your applications start automatically when the system boots, restart following unexpected crashes, and maintain detailed logs without modifying a single line of your application code. Whether you are hosting a web server, a background worker, or a database, the Servy Desktop App simplifies the process of deployment and maintenance through a clean, tabbed interface. > [!NOTE] > If you get a blank screen on remote management tools (like MeshCentral, TeamViewer, or AnyDesk), run the desktop app from an admin command prompt with the following command: `Servy.exe --force-sr` ## Overview The following sections illustrate the key components of the Desktop App, showing how you can customize every aspect of your service lifecycle. ### Service Details This tab lets you configure the main service properties such as name, description, executable path, arguments, startup directory, and startup type. servy-config-main For more details on CPU affinity, see the [FAQ](https://github.com/aelassas/servy/wiki/FAQ#how-and-why-should-i-use-cpu-affinity-with-servy). ### Logging This tab lets you configure `stdout` and `stderr` logging, including size-based log rotation, date-based log rotation, the maximum number of rotated log files to retain, and additional options such as enabling debug logs. servy-config-logging > [!NOTE] > Enabling the debug option will record sensitive information in the local log file at `%ProgramData%\Servy\logs\services\\Servy.Service.log`. This behavior only occurs when local logging is enabled, which is the default setting. Sensitive data is never recorded in the Windows Event Log. The CLI `show` command and `Show-ServyService` mask the encrypted fields by default; `--decrypt` / `-Decrypt` prints the parameters and environment variables in clear text (the stored password always stays masked). See [Servy CLI](https://github.com/aelassas/servy/wiki/Servy-CLI) and [Servy PowerShell Module](https://github.com/aelassas/servy/wiki/Servy-PowerShell-Module). For detailed information about logging, check out the [Logging & Log Rotation](https://github.com/aelassas/servy/wiki/Logging-&-Log-Rotation) documentation. ### Recovery This tab lets you configure automated health-monitoring and failure-handling behavior. It enables continuous internal liveness checks, optional out-of-band diagnostic pings to external monitoring platforms (e.g., [healthchecks.io](https://healthchecks.io) or [Uptime Kuma](https://github.com/louislam/uptime-kuma) Push Monitors), and customizable recovery actions to keep your application running reliably without manual intervention. servy-config-recovery For detailed information about health monitoring and recovery, check out the [Health Monitoring & Recovery](https://github.com/aelassas/servy/wiki/Health-Monitoring-&-Recovery) documentation. ### Advanced The advanced tab provides additional configuration options such as environment variables and service dependencies. servy-config-advanced For detailed information about environment variables, check out the [Environment Variables](https://github.com/aelassas/servy/wiki/Environment-Variables) documentation. For detailed information about service dependencies, check out the [Service Dependencies](https://github.com/aelassas/servy/wiki/Service-Dependencies) documentation. ### Log On This tab allows you to configure the service account, including support for local accounts, domain accounts, and gMSA accounts. Servy securely encrypts stored passwords using AES. For more details, see the [Security](https://github.com/aelassas/servy/wiki/Security) page. servy-config-logon You can also run the service under: - `NT AUTHORITY\NetworkService` - `NT AUTHORITY\LocalService` - Passwordless accounts servy-config-logon-builtin-accounts ### Pre-Launch Configure an optional pre-launch program that runs before the main service process starts. This can be used to prepare the environment, set up dependencies, or run initialization scripts. By default, the pre-launch hook runs synchronously with a timeout. If the pre-launch script exits with a non-zero exit code or times out, the service will fail to start unless the **Ignore Failure** option is enabled. Set the timeout to 0 to run the pre-launch hook in fire-and-forget mode. When set to 0, the hook is started and the service is launched immediately without waiting for completion. Use this only for tasks that do not affect the service's ability to start or run correctly. `stdout`/`stderr` redirection and retries are not available in fire-and-forget mode. Orphaned fire-and-forget pre-launch hooks are cleaned up when the service stops. servy-config-pre-launch For detailed information about the pre-launch hook, check out the [Pre-Launch & Post-Launch Actions](https://github.com/aelassas/servy/wiki/Pre-Launch-&-Post-Launch-Actions) documentation. ### Post-Launch Configure an optional post-launch program that runs after the process starts successfully. servy-config-post-launch Orphaned post-launch hooks are cleaned up when the service stops. For detailed information about the post-launch hook, check out the [Pre-Launch & Post-Launch Actions](https://github.com/aelassas/servy/wiki/Pre-Launch-&-Post-Launch-Actions) documentation. ### Pre-Stop Configure an optional script or executable to run before the main service stops. This can be used for graceful shutdown tasks such as notifying external systems or draining resources. The pre-stop process runs synchronously and extends the service stop timeout while it is running. Set the timeout to 0 to run the pre-stop process in fire-and-forget mode. servy-config-pre-stop For detailed information about the pre-stop hook, check out the [Pre-Stop & Post-Stop Actions](https://github.com/aelassas/servy/wiki/Pre-Stop-&-Post-Stop-Actions) documentation. ### Post-Stop Configure an optional script or executable to run after the wrapped process and all of its child processes have exited. The post-stop process is started in fire-and-forget mode and does not block service shutdown. servy-config-post-stop For detailed information about the post-stop hook, check out the [Pre-Stop & Post-Stop Actions](https://github.com/aelassas/servy/wiki/Pre-Stop-&-Post-Stop-Actions) documentation. ## Features - **Run Anything:** Wrap executables, scripts, or batch files as native Windows services. - **Smart Recovery:** Automatically restart services or the entire host machine based on custom health monitoring rules. - **Flexible Lifecycle Hooks:** Execute custom code at every stage (pre-launch, post-launch, pre-stop, and post-stop). - **Log Rotation:** Rotate logs by size or date, with real-time tailing in the Manager console. - **Secure Credentials:** Encrypted storage of service account passwords using industry-standard AES. - **Real-time Monitoring:** Integrated CPU and RAM performance tracking. - **Dependency Mapping:** Visual dependency trees to troubleshoot startup sequences. ## Availability Servy Desktop App is distributed in multiple editions to cover modern and older systems: - **.NET 10.0+ (Recommended)** - Self-contained installer - Does not require any .NET runtime to be pre-installed - **.NET Framework 4.8 (For older systems)** - Standard installer package - Requires .NET Framework 4.8 Runtime ## Usage 1. **Launch:** Run the Servy Desktop App (`Servy.exe`). 1. **Configure:** Enter your application path and service details in the "Service Details" (Main) tab. 1. **Options:** Customize your environment variables, logging preferences, and recovery actions in the respective tabs. 1. **Install:** Click the "Install" button to register the service with the Windows Service Control Manager (SCM). 1. **Manage:** Use Servy Manager to monitor the performance of your new service and browse logs. ## See Also - [Overview](https://github.com/aelassas/servy/wiki/Overview) - [Usage](https://github.com/aelassas/servy/wiki/Usage) - [Servy Manager](https://github.com/aelassas/servy/wiki/Servy-Manager) - [Servy CLI](https://github.com/aelassas/servy/wiki/Servy-CLI) - [Servy PowerShell Module](https://github.com/aelassas/servy/wiki/Servy-PowerShell-Module) --- # Document: Servy Manager > Source: https://github.com/aelassas/servy/wiki/Servy-Manager ## Table of Contents 1. [Overview](https://github.com/aelassas/servy/wiki/Servy-Manager#overview) 1. [Services](https://github.com/aelassas/servy/wiki/Servy-Manager#services) 1. [Performance](https://github.com/aelassas/servy/wiki/Servy-Manager#performance) 1. [Console](https://github.com/aelassas/servy/wiki/Servy-Manager#console) 1. [Dependencies](https://github.com/aelassas/servy/wiki/Servy-Manager#dependencies) 1. [Logs](https://github.com/aelassas/servy/wiki/Servy-Manager#logs) 1. [Features](https://github.com/aelassas/servy/wiki/Servy-Manager#features) 1. [Availability](https://github.com/aelassas/servy/wiki/Servy-Manager#availability) 1. [Usage](https://github.com/aelassas/servy/wiki/Servy-Manager#usage) 1. [Keyboard Shortcuts](https://github.com/aelassas/servy/wiki/Servy-Manager#keyboard-shortcuts) 1. [See Also](https://github.com/aelassas/servy/wiki/Servy-Manager#see-also) > [!NOTE] > If you get a blank screen on remote management tools (like MeshCentral, TeamViewer, or AnyDesk), run the Manager app from an admin command prompt with the following command: `Servy.Manager.exe --force-sr` ## Overview Servy Manager is a central administrative application for managing and monitoring services controlled by Servy. It provides real-time visibility into process health, CPU and memory utilization, live stream console output, dependency trees, and system log files; all interacting directly with Servy's local database and runtime state. ### Services The Manager provides a central place to view all installed services, their status, CPU & RAM usage in real time, and quick actions (start, stop, restart, install, uninstall, remove, edit, copy PID). servy-manager-services ### Performance Monitor CPU & RAM usage in real time from the Performance tab with live graphs. servy-manager-performance ### Console Monitor service `stdout` and `stderr` output in real time from a single, unified console. The Console view automatically loads recent log history, continues tailing live output, and keeps both streams ordered by timestamp for accurate troubleshooting. You can filter logs instantly, pause updates while selecting or copying text, and resume live streaming without losing context. servy-manager-console ### Dependencies The Dependencies tab provides a visual representation of a service dependency tree retrieved from the Service Control Manager (SCM). Each dependency is displayed with its current status, where running services are shown in green, stopped services in red, and cycles in orange. The tree can be refreshed at any time using the Refresh button or by pressing **F5**. This view is especially useful for understanding startup and shutdown order, diagnosing why a service fails to start, and quickly identifying stopped or missing dependencies that may impact service availability. servy-manager-dependencies ### Logs Servy writes logs to both the Windows Event Log and log files in `%ProgramData%\Servy\logs`, and its built-in log viewer lets you inspect them in real time directly from the GUI. servy-manager-logs ## Features - **Service listing:** View all services installed or imported in Servy. - **Service control:** Start, stop, and restart services. - **Service installation:** Install services from configuration files, uninstall/remove services. - **Export:** Save service configuration in XML or JSON. - **Import:** Import configurations into Servy's database without immediate installation - install them later from the UI. - **Configuration editor:** Open and edit service configurations. - **Search:** Quickly find a specific service. - **Monitor:** Track real-time CPU and RAM usage for services. - **Live log tailing:** Stream standard output (`stdout`) and standard error (`stderr`) logs in real time. - **Dependency tree:** Preview and inspect service dependencies. - **Logs:** Quickly search logs by log level, date, and keyword. ## Availability Servy Manager is distributed in multiple editions to cover modern and older systems: - **.NET 10.0+ (Recommended)** - Self-contained installer - Does not require any .NET runtime to be pre-installed - **.NET Framework 4.8 (For older systems)** - Standard installer package - Requires .NET Framework 4.8 Runtime ## Usage 1. Launch Servy Manager (`Servy.Manager.exe`). 1. Browse the list of services already installed or imported. 1. Use the buttons on each row to start, stop or restart a service. 1. Use the row's `⋮` menu to: - Install, uninstall or remove a service - Open/edit its configuration - Export its configuration to XML/JSON - Copy its PID 1. To add a service, use the **Import** menu (XML or JSON) to import its configuration into the database, then install it from the row's `⋮` menu, or use the Servy Desktop App for interactive setup. 1. Select a service to inspect its detailed management tabs: - **Performance:** View real-time CPU and RAM usage graphs. - **Console:** Stream live `stdout` and `stderr` logs in real time. - **Dependencies:** Inspect service dependency trees and relationships. - **Logs:** Search and filter Servy event log entries and diagnostic history. ## Keyboard Shortcuts | Shortcut | Where | What it does | | --- | --- | --- | | `F5` | Services | Refreshes the full service list. Statuses also refresh automatically. | | `F5` | Logs | Re-runs the current log search. | | `F5` | Dependencies | Refreshes the dependency tree. | | `Ctrl` + `A` | Services | Selects every service in the list. Works even when the search box has focus, where it replaces the usual select-all-text behaviour. | `F5` has no effect on the Console tab, which streams continuously. ## See Also - [Overview](https://github.com/aelassas/servy/wiki/Overview) - [Usage](https://github.com/aelassas/servy/wiki/Usage) - [Servy Desktop App](https://github.com/aelassas/servy/wiki/Servy-Desktop-App) - [Servy CLI](https://github.com/aelassas/servy/wiki/Servy-CLI) - [Servy PowerShell Module](https://github.com/aelassas/servy/wiki/Servy-PowerShell-Module) --- # Document: Servy CLI > Source: https://github.com/aelassas/servy/wiki/Servy-CLI ## Table of Contents 1. [Introduction](https://github.com/aelassas/servy/wiki/Servy-CLI#introduction) 1. [Basic Usage](https://github.com/aelassas/servy/wiki/Servy-CLI#basic-usage) 1. [Command Help](https://github.com/aelassas/servy/wiki/Servy-CLI#command-help) 1. [Install Command](https://github.com/aelassas/servy/wiki/Servy-CLI#install-command) 1. [Show Command](https://github.com/aelassas/servy/wiki/Servy-CLI#show-command) 1. [Additional Commands](https://github.com/aelassas/servy/wiki/Servy-CLI#additional-commands) 1. [Tips](https://github.com/aelassas/servy/wiki/Servy-CLI#tips) 1. [See Also](https://github.com/aelassas/servy/wiki/Servy-CLI#see-also) > [!IMPORTANT] > **Console UI Compatibility** > If your app tries to visually update the command prompt (like clearing the screen or moving the cursor), it will crash when running as a background service since services don't have visible windows. To fix this without changing your code, enable the `--enableConsoleUI` option in the service configuration while installing your service. ## Introduction Servy includes a command-line interface (CLI) designed for full scripting, automated deployments, and seamless integration into CI/CD pipelines. The CLI offers a lightweight, script-friendly alternative to the desktop app, focusing on automation and headless use cases while leveraging the same core service management logic as the desktop application. After a default installation `servy-cli` is on the system **PATH** - see [Installation Guide](https://github.com/aelassas/servy/wiki/Installation-Guide#add-servy-to-path) for the option that controls this and for the portable package. > [!NOTE] > In servy-cli, the equals sign (`=`) is not supported when using single-character shortcuts (like `-n` or `-p`). ## Basic Usage To get started, open an elevated Command Prompt or PowerShell window and run: ```text PS> servy-cli help Servy.CLI + Copyright © 2026 Akram El Assas. All rights reserved. install Install a Windows service. uninstall Uninstall a Windows service. start Start a Windows service. stop Stop a Windows service. status Get the current status of a Windows service. Possible results: NotInstalled, Stopped, StartPending, StopPending, Running, ContinuePending, PausePending, Paused, Unknown. restart Restart a Windows service. export Export a Servy Windows service configuration to a configuration file. import Import a Windows service configuration into the Servy database and optionally install the service. show Show a Servy Windows service configuration in a human-readable form, or list all services when no name is given. help Display more information on a specific command. version Display version information. ``` ## Command Help For detailed help on any command, append `--help` after the command name. For example, to get help for the `start` command: ```text PS> servy-cli start --help Servy.CLI + Copyright © 2026 Akram El Assas. All rights reserved. -n, --name Required. Name of the service to start. -q, --quiet Suppress spinner and run in non-interactive mode. --help Display this help screen. --version Display version information. ``` ## Install Command The main command for installing or updating a Windows service is `install`. **Quick Example** The following command installs `MyApp.exe` as a Windows service named `MyService`: ```cmd servy-cli install --name="MyService" --path="C:\path\to\MyApp.exe" ``` **Detailed Usage** Here is its detailed usage: ```text PS> servy-cli install --help Servy.CLI + Copyright © 2026 Akram El Assas. All rights reserved. -n, --name Required. Unique service name to install. --displayName The human-readable name shown in the Windows Services console (services.msc). If left empty, the service name will be used instead. -d, --description Description of the service. -p, --path Required. Path to the executable process. Supports environment variable expansion, example: %JAVA_HOME%\bin\java.exe --startupDir Startup directory for the process. Supports environment variable expansion, example: %PROGRAMDATA%\MyApp --params Additional parameters for the process. Supports environment variable expansion, example: --params="--data %ProgramData%\MyApp --bin %MY_VAR%\bin". SECURITY WARNING: Use the SERVY_PROCESS_PARAMETERS environment variable instead to avoid exposing sensitive parameters in OS process listings. --startupType Service startup type. Options: Automatic, AutomaticDelayedStart, Manual, Disabled. Defaults to Automatic. --priority Process priority level. Options: Idle, BelowNormal, Normal, AboveNormal, High, RealTime. Defaults to Normal. -a, --cpuAffinity Logical CPUs the process may run on (e.g., '0-3,8' or '0xFF00'). --startTimeout Timeout in seconds to wait for the process to start successfully before considering the startup as failed. Must be between 1 and 86400 seconds. Defaults to 10 seconds. --stopTimeout Timeout in seconds to wait for the process to exit. Must be between 1 and 86400 seconds. Defaults to 5 seconds. --enableConsoleUI Enable console user interface for the service. When enabled, stdout/stderr redirection is disabled. --stdout Path to stdout log file. --stderr Path to stderr log file. --enableRotation Deprecated. Enable size-based log rotation. This option is kept only for backward compatibility. Use --enableSizeRotation instead. --enableSizeRotation Enable size-based log rotation. --rotationSize Log rotation size in Megabytes (MB). Must be between 1 and 10240 MB. --enableDateRotation Enable date-based log rotation based on the date interval specified by --dateRotationType. When both size-based and date-based rotation are enabled, size rotation takes precedence. --dateRotationType Date rotation type. Options: Daily, Weekly, Monthly, None (None disables date-based rotation; use when only size rotation is desired). --maxRotations Maximum rotated log files to keep. Must be between 0 and 10000. Set to 0 or leave empty for unlimited. --useLocalTimeForRotation Use local server time for log rotation instead of UTC. Default is false. --debug Whether debug logs are enabled. When enabled, environment variables and process parameters are recorded in the Servy.Service.log file. Not recommended for production environments, as these logs may contain sensitive information. --enableHealth Enable health monitoring. --heartbeatInterval Heartbeat interval in seconds. Must be between 5 and 86400 seconds. Only used when health monitoring is enabled. --maxFailedChecks Maximum allowed failed health checks. Must be between 1 and 100000. Only used when health monitoring is enabled. --recoveryAction Recovery action on failure. Options: None, RestartService, RestartProcess, RestartComputer. RestartService and RestartComputer actions are not available if the service runs under NT AUTHORITY\LocalService, NT AUTHORITY\NetworkService, an IIS AppPool identity (IIS APPPOOL\...), or a user account without the required privileges. Only used when health monitoring is enabled. --recoveryOnCleanExit Enable running recovery action even if the process exits successfully. Default is false. Only used when health monitoring is enabled. --maxRestartAttempts Maximum restart attempts on failure. Must be between 0 and 100000. Set to 0 for unlimited restart attempts. Only used when health monitoring is enabled. --heartbeatUrl Absolute URL for out-of-band diagnostic heartbeat pings. Only used when health monitoring is enabled. SECURITY WARNING: Use the SERVY_HEARTBEAT_URL environment variable instead to avoid exposing sensitive parameters in OS process listings. --heartbeatUrlTimeoutSeconds Timeout in seconds for external heartbeat URL requests. Must be between 2 and 30 seconds. Defaults to 10 seconds. Only used when health monitoring is enabled. --enableHeartbeatUrlFlags Append /start and /fail to the heartbeat URL on service start and failure. Only used when health monitoring is enabled. --failureProgramPath The failure program path. Configure a script or executable to run when the wrapped process exits with a non-zero exit code (recovery disabled) or after all recovery action retries have failed (recovery enabled). It is not run when the process fails to start; that path stops the service. Supports environment variable expansion, example: %JAVA_HOME%\bin\java.exe --failureProgramStartupDir Specifies the directory in which the failure program will start. If not set, defaults to the service working directory. Supports environment variable expansion, example: %PROGRAMDATA%\MyApp --failureProgramParams Additional parameters for the failure program. SECURITY WARNING: Use the SERVY_FAILURE_PROGRAM_PARAMETERS environment variable instead to avoid exposing sensitive parameters in OS process listings. --envVars Environment variables for the process. Enter variables in the format varName=varValue separated by semicolons (;). Use \= to escape '=', \" to escape '"', \; to escape ';', \\ to escape '\', and %% to escape '%' (collapses to a single '%'). Supports environment variable expansion, example: VAR1=%ProgramData%\MyApp; VAR2=%VAR1%\bin. SECURITY WARNING: Use the SERVY_ENVIRONMENT_VARIABLES environment variable instead to avoid exposing sensitive parameters in OS process listings. --allowOverriddenRuntimeVars Allow overriding of protected runtime variables (e.g., JAVA_HOME, JAVA_OPTS, CATALINA_OPTS) by the service's environment variables. --deps Specify one or more Windows service names (not display names) that this service depends on separated with semicolons (;). Each service name must contain only letters, digits, hyphens, underscores, periods, spaces, and dollar signs ($), optionally preceded by '+' to reference a load-order group, and must not exceed 256 characters. Windows starts stopped dependencies automatically when this service starts; if a dependency is disabled or fails to start, this service will not start. --user The service account username (e.g., .\username, DOMAIN\username, DOMAIN\gMSA$, or a built-in identity such as NT AUTHORITY\LocalService, NT AUTHORITY\NetworkService, NT SERVICE\MyService or IIS APPPOOL\MyPool). Leave the --password option or SERVY_PASSWORD environment variable empty for built-in, virtual and gMSA accounts. If this option is not set, the service runs under Local System. --password The service account password. SECURITY WARNING: Use the SERVY_PASSWORD environment variable instead to avoid exposing credentials in OS process listings. --preLaunchPath The pre-launch executable path. Configure an optional script or executable to run before the main service starts. This is useful for preparing configurations, fetching secrets, or other setup tasks. If the pre-launch script fails, the service will not start unless you enable --preLaunchIgnoreFailure. Supports environment variable expansion, example: %JAVA_HOME%\bin\java.exe --preLaunchStartupDir Specifies the directory in which the pre-launch executable will start. If not set, defaults to the service working directory. Supports environment variable expansion, example: %PROGRAMDATA%\MyApp --preLaunchParams Additional parameters for the pre-launch executable. SECURITY WARNING: Use the SERVY_PRE_LAUNCH_PARAMETERS environment variable instead to avoid exposing sensitive parameters in OS process listings. --preLaunchEnv Environment variables for the pre-launch executable. Enter variables in the format varName=varValue separated by semicolons (;). Use \= to escape '=', \" to escape '"', \; to escape ';', \\ to escape '\', and %% to escape '%' (collapses to a single '%'). Supports environment variable expansion, example: VAR1=%ProgramData%\MyApp; VAR2=%VAR1%\bin. SECURITY WARNING: Use the SERVY_PRE_LAUNCH_ENVIRONMENT_VARIABLES environment variable instead to avoid exposing sensitive parameters in OS process listings. --preLaunchStdout Path to stdout log file of the pre-launch executable. --preLaunchStderr Path to stderr log file of the pre-launch executable. --preLaunchTimeout Timeout for the pre-launch executable. Must be between 0 and 86400 seconds. Set the timeout to 0 to run the pre-launch hook in fire-and-forget mode. When set to 0, the hook is started and the service is launched immediately without waiting for completion. Use this only for tasks that do not affect the service's ability to start or run correctly. Stdout/Stderr redirection and retries are not available in fire-and-forget mode. --preLaunchRetryAttempts Number of retry attempts for the pre-launch executable if it fails. Must be between 0 and 100000. --preLaunchIgnoreFailure Ignore failure and start service even if pre-launch executable fails. --postLaunchPath The post-launch executable path. Configure an optional script or executable to run after the process starts successfully. Supports environment variable expansion, example: %JAVA_HOME%\bin\java.exe --postLaunchStartupDir Specifies the directory in which the post-launch executable will start. If not set, defaults to the service working directory. Supports environment variable expansion, example: %PROGRAMDATA%\MyApp --postLaunchParams Additional parameters for the post-launch executable. SECURITY WARNING: Use the SERVY_POST_LAUNCH_PARAMETERS environment variable instead to avoid exposing sensitive parameters in OS process listings. --preStopPath The pre-stop executable path. Configure an optional script or executable to run before the main service stops. This can be used for graceful shutdown tasks such as notifying external systems or draining resources. The pre-stop process runs synchronously and extends the service stop timeout while it is running. Set the timeout to 0 to run the pre-stop process in fire-and-forget mode. Supports environment variable expansion, example: %JAVA_HOME%\bin\java.exe --preStopStartupDir Specifies the directory in which the pre-stop executable will start. If not set, defaults to the service working directory. Supports environment variable expansion, example: %PROGRAMDATA%\MyApp --preStopParams Additional parameters for the pre-stop executable. SECURITY WARNING: Use the SERVY_PRE_STOP_PARAMETERS environment variable instead to avoid exposing sensitive parameters in OS process listings. --preStopTimeout Timeout for the pre-stop executable. Set the timeout to 0 to run the pre-stop process in fire-and-forget mode. Must be between 0 and 86400 seconds. --preStopLogAsError Log pre-stop failure as error. --postStopPath The post-stop executable path. Configure an optional script or executable to run after the wrapped process and all of its child processes have exited. The post-stop process is started in fire-and-forget mode and does not block service shutdown. Supports environment variable expansion, example: %JAVA_HOME%\bin\java.exe --postStopStartupDir Specifies the directory in which the post-stop executable will start. If not set, defaults to the service working directory. Supports environment variable expansion, example: %PROGRAMDATA%\MyApp --postStopParams Additional parameters for the post-stop executable. SECURITY WARNING: Use the SERVY_POST_STOP_PARAMETERS environment variable instead to avoid exposing sensitive parameters in OS process listings. -q, --quiet Suppress spinner and run in non-interactive mode. --help Display this help screen. --version Display version information. ``` > [!NOTE] > If the value of `--params` in `install` command includes arguments that start with `--`, use an equals sign (=) to prevent parsing issues. Example: `--params="--mode=production --port=7008"` Without the equals sign, the CLI might interpret `--mode` or `--port` as its own options instead of part of the service parameters. > [!IMPORTANT] > **Security Best Practice:** Avoid using sensitive flags (e.g., `--password`, `--params`, `--envVars`, `--preLaunchEnv`) in production or scripts. Passing these values as command-line arguments makes them visible to any user or process with access to the Windows Process List or shell history files. Instead, set the corresponding environment variables (e.g., `SERVY_PASSWORD`, `SERVY_PROCESS_PARAMETERS`, `SERVY_ENVIRONMENT_VARIABLES`) before running the install command. See [Security](https://github.com/aelassas/servy/wiki/Security#6-sensitive-command-line-arguments--service-account-credentials) page for more information. Below is the **recommended** way to install a service using the secure environment variable fallback pattern: ```powershell # 1. Set sensitive values in the current process environment $env:SERVY_PASSWORD = "your_secret_password" $env:SERVY_PROCESS_PARAMETERS = "C:\Apps\App\index.js" $env:SERVY_ENVIRONMENT_VARIABLES = "ENV_VAR1=VAL1; ENV_VAR2=VAL2;" # 2. Run the install command without sensitive CLI flags servy-cli install ` --name="My NodeJS Service" ` --description="My NodeJS Server" ` --path="C:\Program Files\nodejs\node.exe" ` --startupDir="C:\Apps\App" ` --startupType="Automatic" ` --priority="Normal" ` --stdout="C:\Apps\App\stdout.log" ` --stderr="C:\Apps\App\stderr.log" ` --enableSizeRotation ` --rotationSize=10 ` --enableHealth ` --heartbeatInterval=10 ` --maxFailedChecks=3 ` --recoveryAction="RestartService" ` --maxRestartAttempts=5 ` --deps="MongoDB; MySQL80" ` --user=".\serviceuser" # 3. Clear sensitive variables from memory immediately after use Remove-Item Env:SERVY_PASSWORD Remove-Item Env:SERVY_PROCESS_PARAMETERS Remove-Item Env:SERVY_ENVIRONMENT_VARIABLES ``` Below is an example usage of the `install` command: ```powershell servy-cli install ` --name="My NodeJS Service" ` --description="My NodeJS Server" ` --path="C:\Program Files\nodejs\node.exe" ` --startupDir="C:\Apps\App" ` --params="C:\Apps\App\index.js" ` --startupType="Automatic" ` --priority="Normal" ` --stdout="C:\Apps\App\stdout.log" ` --stderr="C:\Apps\App\stderr.log" ` --enableSizeRotation ` --rotationSize=10 ` --enableHealth ` --heartbeatInterval=10 ` --maxFailedChecks=3 ` --recoveryAction="RestartService" ` --maxRestartAttempts=5 ` --envVars="ENV_VAR1=VAL1; ENV_VAR2=VAL2;" ` --deps="MongoDB; MySQL80" ``` Below is an example usage of the `install` command with a pre-launch script: ```powershell servy-cli install ` --name="MyLegacyService" ` --description="Runs legacy app with dynamic config" ` --path="C:\Apps\LegacyApp\LegacyApp.exe" ` --startupDir="C:\Apps\LegacyApp" ` --params="--mode=production" ` --preLaunchPath="C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" ` --preLaunchStartupDir="C:\Scripts" ` --preLaunchParams="-File C:\Scripts\GenerateConfig.ps1 -VaultUrl https://vault.example.com -SecretName AppSecrets" ` --preLaunchEnv="ENV=production;API_KEY=abcdef123" ` --preLaunchStdout="C:\Logs\prelaunch_stdout.log" ` --preLaunchStderr="C:\Logs\prelaunch_stderr.log" ` --preLaunchTimeout=60 ` --preLaunchRetryAttempts=2 ` --preLaunchIgnoreFailure ` --enableHealth ` --heartbeatInterval=30 ` --maxFailedChecks=3 ` --recoveryAction="RestartService" ` --maxRestartAttempts=5 ` --stdout="C:\Logs\service_stdout.log" ` --stderr="C:\Logs\service_stderr.log" ` --enableSizeRotation ` --rotationSize=10 ``` For more details on CPU affinity, see the [FAQ](https://github.com/aelassas/servy/wiki/FAQ#how-and-why-should-i-use-cpu-affinity-with-servy). ## Show Command The `show` command prints the service configuration held in Servy's database in a form meant to be read rather than parsed. It is the human-readable counterpart of [`export`](https://github.com/aelassas/servy/wiki/Export-Import-Services), which writes the same records as XML or JSON. `show` requires Administrator privileges: the records live under `%ProgramData%\Servy` and describe how privileged processes are launched. > [!NOTE] > **Encrypted fields are masked by default.** Servy encrypts nine columns at rest - the four parameter fields, both pre/post-stop parameter fields, both environment-variable fields, and the password. `show` prints each of them as `********` unless you ask for the values, and without `--decrypt` it does not even decrypt them, so the plaintext is never produced. A masked row still tells you the field is set: an unset column is left out entirely. > > **`--decrypt` (`-d`) reveals eight of the nine.** The stored password is the exception and stays masked even with the flag, exactly as an exported XML or JSON file never contains it. > > `--decrypt` requires `--name`. The all-services list renders none of the encrypted columns, so there is nothing there to reveal. ```text PS> servy-cli show --help Servy.CLI + Copyright © 2026 Akram El Assas. All rights reserved. -n, --name Name of the service to show. When omitted, all services are listed. -s, --search Filter the service list by a keyword matched against the service name or description. Cannot be combined with --name. -d, --decrypt Show the encrypted fields (parameters and environment variables) in clear text instead of masked. Requires --name. The stored password stays masked. -q, --quiet Suppress spinner and run in non-interactive mode. --help Display this help screen. --version Display version information. ``` ### One service Pass `--name` (or `-n`) to print every stored setting of a single service, grouped by category. The service name comes first, then its live status and process id, then the rest. A category whose section trigger or path is unconfigured is omitted entirely, so features or hooks you never configured cost no screen space. Categories with active feature triggers (such as `Logs`, `Recovery`, and the hook sections) render all of their rows, displaying `-` for unset fields. The categories built only from optional paths and values: `Logs` (when stdout/stderr are blank), `Recovery` (when health monitoring is disabled), `Failure Program`, `Pre-Launch`, `Post-Launch`, `Pre-Stop` and `Post-Stop`, are omitted when inactive. Every on/off setting reads `Yes` or `No`; `Status`, `Startup Type`, `Priority`, `Rotation Period` and `Recovery` are printed as invariant enum names that are never localized, so they stay safe to parse. `Status` uses the same tokens the [`status`](https://github.com/aelassas/servy/wiki/Servy-CLI#additional-commands) command prints. ```text PS> servy-cli show -n telegraf Name : telegraf Status : Running Pid : 7312 Display Name : Telegraf Agent Description : Metrics collection agent Startup Type : AutomaticDelayedStart Priority : Normal Executable : C:\Program Files\telegraf\telegraf.exe Startup Dir : C:\Program Files\telegraf Parameters : ******** Account Local System : No User Account : .\telegraf-svc Password : ******** Logs Stdout : C:\Program Files\telegraf\log\out.log Stderr : C:\Program Files\telegraf\log\err.log Active Stdout : - Active Stderr : - Size Rotation : Yes Rotation Size : 10 MB Date Rotation : Yes Rotation Period : Daily Max Files : 7 Local Time : No Timeouts Start : 10s Stop : 5s Environment Environment Variables : ******** Allow Overridden Runtime Vars : Yes Other Console UI : No Debug Logs : No ``` Pass `--decrypt` (or `-d`) to read the masked fields. Only run it when you actually need the values, and treat the output the way you would treat an export file: ```text PS> servy-cli show -n telegraf --decrypt Name : telegraf Status : Running Pid : 7312 Display Name : Telegraf Agent Description : Metrics collection agent Startup Type : AutomaticDelayedStart Priority : Normal Executable : C:\Program Files\telegraf\telegraf.exe Startup Dir : C:\Program Files\telegraf Parameters : --config telegraf.conf --config-directory telegraf.d Account Local System : No User Account : .\telegraf-svc Password : ******** Logs Stdout : C:\Program Files\telegraf\log\out.log Stderr : C:\Program Files\telegraf\log\err.log Active Stdout : - Active Stderr : - Size Rotation : Yes Rotation Size : 10 MB Date Rotation : Yes Rotation Period : Daily Max Files : 7 Local Time : No Timeouts Start : 10s Stop : 5s Environment Environment Variables : API_TOKEN=9f3c1a; API_HOST=example.internal Allow Overridden Runtime Vars : Yes Other Console UI : No Debug Logs : No ``` The categories are `Account`, `Logs`, `Timeouts`, `Recovery`, `Failure Program`, `Environment`, `Pre-Launch`, `Post-Launch`, `Pre-Stop`, `Post-Stop` and `Other`. When the named service is not in the database the command fails with `The specified service was not found.` and a non-zero exit code. ### All services With no `--name`, `show` lists every service in the database, one line each: ```text PS> servy-cli show NAME DISPLAY NAME DESCRIPTION STARTUP TYPE STATUS PID ------------ ---------------- ------------------------ --------------------- ------- ---- backup-agent Backup Agent Nightly backup job Manual Stopped - nginx Nginx Web Server Reverse proxy Automatic Running 4188 telegraf Telegraf Agent Metrics collection agent AutomaticDelayedStart Running 7312 3 service(s). ``` Use `--search` (or `-s`) to narrow the list by a keyword matched against the service name or description - the same search the [Servy Manager](https://github.com/aelassas/servy/wiki/Servy-Manager) list uses: ```text PS> servy-cli show --search backup NAME DISPLAY NAME DESCRIPTION STARTUP TYPE STATUS PID ------------ ------------ ------------------ ------------ ------- --- backup-agent Backup Agent Nightly backup job Manual Stopped - 1 service(s). ``` `--search` narrows the list, so it cannot be combined with `--name`. When nothing matches, the command prints `No services found.` and succeeds. > [!NOTE] > A dash (`-`) in any field means the value is not set. The `STATUS` column reports `NotInstalled` for a service that is in Servy's database but no longer registered with the Windows Service Control Manager, and `Unknown` for one that is registered but whose status cannot be read. Status and startup-type values are invariant enum names that are never localized, so they stay safe to parse in scripts; the status values are the same tokens the [`status`](https://github.com/aelassas/servy/wiki/Servy-CLI#additional-commands) command prints. ## Additional Commands * `uninstall`: Uninstall an existing service by name. * `start`: Start a Windows service by name. * `stop`: Stop a Windows service by name. * `restart`: Restart a Windows service by name. * `status`: Get a Windows service status by name. * `export`: Export a Servy Windows service configuration to a configuration file. * `import`: Import a Windows service configuration into Servy's database and optionally install it. * `show`: Show a Servy Windows service configuration in a human-readable form, or list all services when no name is given. Encrypted fields are masked unless `--decrypt` is passed. * `--version`: Show CLI version (it's a global flag). ## Tips * Always run the CLI with Administrator privileges when executing commands that modify Windows services. * Use the `--help` flag with any command to display detailed usage information and available options. * When automating with scripts or CI/CD pipelines, rely on the CLI's exit codes: `0` indicates success, any other value indicates failure. * Ensure that log file paths are writable by the user account under which the service runs to avoid permission issues. ## See Also * [PowerShell Module](https://github.com/aelassas/servy/wiki/Servy-PowerShell-Module) * [Servy Automation & CI/CD](https://github.com/aelassas/servy/wiki/Servy-Automation-&-CI-CD) * [Examples & Recipes](https://github.com/aelassas/servy/wiki/Examples-&-Recipes) * [Export/Import Services](https://github.com/aelassas/servy/wiki/Export-Import-Services) --- # Document: Servy PowerShell Module > Source: https://github.com/aelassas/servy/wiki/Servy-PowerShell-Module ## Table of Contents 1. [Introduction](https://github.com/aelassas/servy/wiki/Servy-PowerShell-Module#introduction) 1. [Compatibility & Runtime Requirements](https://github.com/aelassas/servy/wiki/Servy-PowerShell-Module#compatibility--runtime-requirements) 1. [Installation](https://github.com/aelassas/servy/wiki/Servy-PowerShell-Module#installation) 1. [Usage Examples](https://github.com/aelassas/servy/wiki/Servy-PowerShell-Module#usage-examples) 1. [Why use parameter splatting?](https://github.com/aelassas/servy/wiki/Servy-PowerShell-Module#why-use-parameter-splatting) 1. [Install a New Service](https://github.com/aelassas/servy/wiki/Servy-PowerShell-Module#install-a-new-service) 1. [Show Service Configuration](https://github.com/aelassas/servy/wiki/Servy-PowerShell-Module#show-service-configuration) 1. [Export Service Configuration](https://github.com/aelassas/servy/wiki/Servy-PowerShell-Module#export-service-configuration) 1. [Import Service Configuration](https://github.com/aelassas/servy/wiki/Servy-PowerShell-Module#import-service-configuration) 1. [Start, Stop, Restart, and Check Status](https://github.com/aelassas/servy/wiki/Servy-PowerShell-Module#start-stop-restart-and-check-status) 1. [Uninstall a Service](https://github.com/aelassas/servy/wiki/Servy-PowerShell-Module#uninstall-a-service) 1. [Cmdlets Reference](https://github.com/aelassas/servy/wiki/Servy-PowerShell-Module#cmdlets-reference) 1. [Install-ServyService Parameter Reference](https://github.com/aelassas/servy/wiki/Servy-PowerShell-Module#install-servyservice-parameter-reference) 1. [Troubleshooting](https://github.com/aelassas/servy/wiki/Servy-PowerShell-Module#troubleshooting) 1. [See Also](https://github.com/aelassas/servy/wiki/Servy-PowerShell-Module#see-also) 1. [References](https://github.com/aelassas/servy/wiki/Servy-PowerShell-Module#references) > [!IMPORTANT] > **Console UI Compatibility** > If your app tries to visually update the command prompt (like clearing the screen or moving the cursor), it will crash when running as a background service since services don't have visible windows. To fix this without changing your code, enable the `-EnableConsoleUI` option in the service configuration while installing your service. ## Introduction The Servy PowerShell Module provides a lightweight, scriptable interface for managing background services. It is designed to be highly portable, allowing sysadmins to automate deployments across diverse Windows environments. ### Compatibility & Runtime Requirements The PowerShell module (`Servy.psm1`) is authored to be compatible with **PowerShell 2.0 and later**. However, its ability to run on older operating systems depends on which version of the Servy CLI is present: * **For Windows 10 / 11 / Server 2016+**: Use the **Modern CLI (.NET 10.0+)**. This version offers the best performance and utilizes the latest Windows security features. * **For Windows 7 SP1 / 8 / Server 2008 R2**: Use the **Legacy CLI (.NET Framework 4.8)**. When paired with this build, the PowerShell module is fully functional on older distributions. > [!NOTE] > The Task Scheduler hooks shipped under `taskschd/` > (`ServyFailureEmail.ps1`, `ServyFailureNotification.ps1`, `Get-ServyLastErrors.ps1`, > `Servy-Watermark.psm1`) have stricter requirements: > - `Get-WinEvent`-based scripts need **PowerShell 5.1+** (Windows 7 SP1 / Server 2008 R2 SP1+). > - Toast notifications need **PowerShell 5.1+** (Windows 10 1607+). > Only `Servy.psm1` itself is fully PS 2.0 compatible. ## Installation Import the module in your PowerShell session: ```powershell Import-Module "C:\Program Files\Servy\Servy.psm1" -Force ``` Display the version: ```powershell Get-ServyVersion ``` Display help: ```powershell # View general module help and available commands Get-ServyHelp # Get help for other supported commands Get-ServyHelp -Command "install" Get-ServyHelp -Command "start" Get-ServyHelp -Command "stop" ``` ## Usage Examples **Pro Tip:** In PowerShell, switch parameters (like `-Quiet`, `-Install`, or `-EnableHealth`) are toggle flags. When calling a command **inline**, do not pass values like `$true` or `$false`; including the flag enables it, and omitting it leaves it disabled. When using **parameter splatting**, it is correct and idiomatic to set switch parameters to `$true` in the splat hashtable. ### Why use parameter splatting? Parameter splatting makes PowerShell commands easier to read, maintain, and extend. Instead of long command lines with many parameters, options are grouped into a single hashtable that clearly shows intent and defaults. This is especially useful for Servy commands, which support many optional parameters and advanced scenarios such as hooks, logging, and recovery configuration. Splatting also: * Avoids line continuation backticks * Makes it easier to add or remove parameters * Keeps examples readable as the API evolves ### Install a New Service ```powershell # CORRECT: Switch flags are included by presence or set to $true in the splat hashtable $installParams = @{ Name = "WexflowServer" Description = "Wexflow Workflow Engine" Path = "C:\Program Files\dotnet\dotnet.exe" StartupDir = "C:\Program Files\Wexflow Server\Wexflow.Server" Params = "Wexflow.Server.dll" StartupType = "Automatic" EnableHealth = $true RecoveryAction = "RestartService" HeartbeatInterval = 30 MaxFailedChecks = 3 } Install-ServyService @installParams # INCORRECT: Do not do this with inline switches # Install-ServyService -Quiet $true -EnableHealth $true # CORRECT: Use inline switches without values, or use splatting # Inline: Install-ServyService -Quiet -EnableHealth # Splatting: # $params = @{ Quiet = $true; EnableHealth = $true } # Install-ServyService @params ``` ### Show Service Configuration `Show-ServyService` prints every stored setting of one service in a readable, category-grouped form - the name first, then the live status and process id, then the rest. `Show-ServyServices` lists all services instead, one line each, and takes an optional `-Search` keyword matched against the service name or description. Both require an elevated session, and neither ever prints the stored password. > [!NOTE] > **Encrypted fields are masked by default.** `Show-ServyService` prints the parameter and > environment-variable fields as `********`, and without `-Decrypt` it does not decrypt them at all. > Pass `-Decrypt` to read the values. The stored password stays masked either way. > `Show-ServyServices` renders no encrypted column, so it has nothing to mask. ```powershell # One service, full configuration - encrypted fields masked Show-ServyService -Name "WexflowServer" # Same, with the parameters and environment variables in clear text Show-ServyService -Name "WexflowServer" -Decrypt # Every service in the Servy database Show-ServyServices # Only the services whose name or description matches a keyword Show-ServyServices -Search "wexflow" ``` ```text PS> Show-ServyServices NAME DISPLAY NAME DESCRIPTION STARTUP TYPE STATUS PID ------------ ---------------- ------------------------ --------------------- ------- ---- backup-agent Backup Agent Nightly backup job Manual Stopped - nginx Nginx Web Server Reverse proxy Automatic Running 4188 telegraf Telegraf Agent Metrics collection agent AutomaticDelayedStart Running 7312 3 service(s). ``` > [!NOTE] > These two cmdlets are for reading configuration at a console. To consume a service > configuration from a script, use `Export-ServyServiceConfig` and parse the XML or JSON, > which is a stable contract; the `show` layout is not. ### Export Service Configuration ```powershell $exportXmlParams = @{ Name = "WexflowServer" ConfigFileType = "xml" Path = "C:\WexflowServer.xml" } Export-ServyServiceConfig @exportXmlParams $exportJsonParams = @{ Name = "WexflowServer" ConfigFileType = "json" Path = "C:\WexflowServer.json" } Export-ServyServiceConfig @exportJsonParams ``` ### Import Service Configuration ```powershell # CORRECT: Switch flags are included by presence or set to $true in the splat hashtable $importXmlParams = @{ ConfigFileType = "xml" Path = "C:\WexflowServer.xml" Install = $true } Import-ServyServiceConfig @importXmlParams $importJsonParams = @{ ConfigFileType = "json" Path = "C:\WexflowServer.json" } Import-ServyServiceConfig @importJsonParams ``` ### Start, Stop, Restart, and Check Status Servy installs a **standard Windows service** that is fully registered with the Service Control Manager (SCM). Once installed, the service can be managed using **any normal Windows service control mechanism** such as `Start-Service`, `sc.exe`, `services.msc`, or third-party tools. The Servy PowerShell cmdlets shown below are provided as **convenience wrappers** for scripting consistency. They are **not required** to start or stop the service. ```powershell $serviceParams = @{ Name = "WexflowServer" } Start-ServyService @serviceParams Get-ServyServiceStatus @serviceParams Stop-ServyService @serviceParams Restart-ServyService @serviceParams ``` #### Using standard Windows service commands The same service can be controlled using built-in PowerShell and Windows tools: ```powershell Start-Service -Name WexflowServer Get-Service -Name WexflowServer Stop-Service -Name WexflowServer ``` Or from an **elevated** Command Prompt: ```cmd sc.exe start WexflowServer sc.exe stop WexflowServer ``` **Note:** When using PowerShell, invoke `sc.exe` explicitly (for example, `sc.exe start ServiceName`) from an **elevated PowerShell session**. PowerShell defines `sc` as an alias, so omitting the `.exe` may result in unexpected behavior. This is standard PowerShell behavior and not related to Servy. Once installed, the service behaves like any other native Windows service and does not depend on Servy-specific commands to run. ### Uninstall a Service ```powershell $uninstallParams = @{ Name = "WexflowServer" } Uninstall-ServyService @uninstallParams ``` ## Cmdlets Reference | Cmdlet | Parameters | Description | | --- | --- | --- | | `Set-ServyConfig` | `-TimeoutSeconds` (int, optional, Default: 600)
`-MaxBufferChars` (int, optional, **no longer used** since 9.9; accepted for compatibility) | **Configures module-level execution settings for the Servy CLI.**
Sets the execution timeout used by every cmdlet. This is useful for exceptionally long-running operations.

**Example:**
- `Set-ServyConfig -TimeoutSeconds 1200` | | `Install-ServyService` | `-Name` (string, **required**)
`-Path` (string, **required**)
*(See [Install-ServyService Parameters](https://github.com/aelassas/servy/wiki/Servy-PowerShell-Module#install-servyservice-parameter-reference) for the complete parameter list)* | **Installs a new Windows service with advanced configuration.**

Wraps the Servy CLI `install` command to turn any executable into a managed Windows service. It supports complex lifecycle management, logging, and self-healing features.

**Key Features:**
- **Logging:** Redirect output to files with rotation by size or date.
- **Health:** Automated recovery actions (e.g., `RestartService`) based on failed heartbeats.
- **Lifecycle:** Execute tasks *before* (`PreLaunch`) or *after* (`PostLaunch`) startup.

**Examples:**
- `Install-ServyService -Name "MyApp" -Path "C:\App\app.exe"`
- `Install-ServyService -Name "MyApp" -DisplayName "My App" -Path "C:\App\app.exe"`
- `Install-ServyService -Name "LogApp" -Path "C:\App\app.exe" -Stdout "C:\App\stdout.log" -EnableSizeRotation -RotationSize 10`
- `Install-ServyService -Name "SecureApp" -Path "C:\App\app.exe" -EnvVars "API_KEY=12345;DB_PORT=5432"` | | `Uninstall-ServyService` | `-Name` (string, **required**)
`-Quiet` (switch, optional) | **Uninstalls a Windows service by name.**
Completely removes the service entry from the Windows Service Control Manager (SCM) and the Servy internal database.

**Example:**
- `Uninstall-ServyService -Name "MyApp" -Quiet` | | `Start-ServyService` | `-Name` (string, **required**)
`-Quiet` (switch, optional) | **Starts a Windows service.**
Triggers the service start signal. If any `PreLaunch` settings were defined during installation, the pre-launch process will be executed and must succeed before the main service starts (unless `PreLaunchIgnoreFailure` was used).

**Example:**
- `Start-ServyService -Name "MyApp"` | | `Stop-ServyService` | `-Name` (string, **required**)
`-Quiet` (switch, optional) | **Stops a Windows service.**
Sends a termination signal to the service process. It respects the `StopTimeout` value set during installation, allowing the application to shut down gracefully before forcing termination.

**Example:**
- `Stop-ServyService -Name "MyApp" -Quiet` | | `Restart-ServyService` | `-Name` (string, **required**)
`-Quiet` (switch, optional) | **Restarts a Windows service.**
Performs a full stop operation followed by a start operation. This is the recommended way to apply configuration changes after an import.

**Example:**
- `Restart-ServyService -Name "MyApp"` | | `Get-ServyServiceStatus` | `-Name` (string, **required**)
`-Quiet` (switch, optional) | **Retrieves the current status of the service.**
Queries the SCM for the real-time state of the process.

**Possible Results:** `NotInstalled`, `Stopped`, `StartPending`, `StopPending`, `Running`, `ContinuePending`, `PausePending`, `Paused`, `Unknown`.

**Example:**
- `Get-ServyServiceStatus -Name "MyApp"` | | `Show-ServyService` | `-Name` (string, **required**)
`-Decrypt` (switch, optional)
`-Quiet` (switch, optional) | **Shows the full configuration of one service in a human-readable form.**
Wraps the Servy CLI `show` command. Prints the service name, its live status and process id first, then every stored setting grouped by category (`Account`, `Logs`, `Timeouts`, `Recovery`, `Failure Program`, `Environment`, `Pre-Launch`, `Post-Launch`, `Pre-Stop`, `Post-Stop`, `Other`). Categories with nothing configured are omitted. The fields Servy encrypts at rest - parameters and environment variables - are masked as `********` unless `-Decrypt` is passed, and without it they are not decrypted at all. The stored password stays masked either way and is never printed. Requires an elevated session.

**Examples:**
- `Show-ServyService -Name "MyApp"`
- `Show-ServyService -Name "MyApp" -Decrypt` | | `Show-ServyServices` | `-Search` (string, optional)
`-Quiet` (switch, optional) | **Lists every service stored in the Servy database.**
Wraps the Servy CLI `show` command with no service name, printing one line per service with its name, display name, description, startup type, status and process id. Use `-Search` to narrow the list by a keyword matched against the service name or description, the same way the Servy Manager search box does. Requires an elevated session.

**Examples:**
- `Show-ServyServices`
- `Show-ServyServices -Search "web"` | | `Export-ServyServiceConfig` | `-Name` (string, **required**)
`-ConfigFileType` (string, **required**: `xml`, `json`)
`-Path` (string, **required**)
`-Quiet` (switch, optional) | **Exports the service configuration to a file.**
Saves all metadata (paths, timeouts, health checks, etc.) to an external file for backup or template creation.

**Examples:**
- `Export-ServyServiceConfig -Name "MyApp" -ConfigFileType "json" -Path "C:\Backups\MyApp.json"`
- `Export-ServyServiceConfig -Name "MyApp" -ConfigFileType "xml" -Path "C:\Backups\MyApp.xml"` | | `Import-ServyServiceConfig` | `-ConfigFileType` (string, **required**: `xml`, `json`)
`-Path` (string, **required**)
`-Install` (switch, optional)
`-Quiet` (switch, optional) | **Imports a configuration from a file.**
Loads settings from a previously exported file into the Servy database. Use the `-Install` switch to register the service with Windows immediately after import.

**Examples:**
- `Import-ServyServiceConfig -ConfigFileType "json" -Path "C:\Configs\NewApp.json" -Install`
- `Import-ServyServiceConfig -ConfigFileType "xml" -Path "C:\Configs\NewApp.xml"` | | `Get-ServyHelp` | `-Command` (string, optional)
`-Quiet` (switch, optional) | **Displays the Servy CLI help manual.**
Provides global usage instructions or detailed parameter explanations for a specific command if requested.

**Examples:**
- `Get-ServyHelp`
- `Get-ServyHelp -Command "install"` | | `Get-ServyVersion` | `-Quiet` (switch, optional) | **Displays the version of the Servy binary.**
Outputs the version string of the `servy-cli.exe` file being utilized by the module.

**Example:**
- `Get-ServyVersion -Quiet` | ### Install-ServyService Parameter Reference #### Core Configuration | Parameter | Type | Required | Values / Range / Notes | | --- | --- | --- | --- | | `-Name` | string | **Yes** | Service unique identifier name | | `-Path` | string | **Yes** | Path to the executable process | | `-DisplayName` | string | No | Display name in Windows Services (`services.msc`) | | `-Description` | string | No | Descriptive text about the service | | `-StartupDir` | string | No | Working directory for the service process | | `-Params` | string | No | Additional parameters passed to the executable | | `-StartupType` | string | No | Options: `Automatic`, `AutomaticDelayedStart`, `Manual`, `Disabled` | | `-Priority` | string | No | Options: `Idle`, `BelowNormal`, `Normal`, `AboveNormal`, `High`, `RealTime` | | `-CpuAffinity` | string | No | Logical CPUs allowed (e.g., `'0-3,8'` or `'0xFF00'`) | | `-User` | string | No | Service account username (`.\username` or `DOMAIN\username`) | | `-Password` | SecureString | No | Password for the service account | | `-EnvVars` | string | No | Environment variables (`Name=Value;Name=Value`) | | `-AllowOverriddenRuntimeVars` | switch | No | Allow the service's environment variables to override protected runtime variables (e.g., `JAVA_HOME`, `JAVA_OPTS`, `CATALINA_OPTS`) | | `-Deps` | string | No | Windows service dependencies (by service name) | | `-StartTimeout` | int | No | Timeout to wait for successful start (range: `1`-`86400` seconds) | | `-StopTimeout` | int | No | Timeout to wait for process exit (range: `1`-`86400` seconds) | | `-EnableConsoleUI` | switch | No | Enable console UI (disables stdout/stderr redirection) | | `-Quiet` | switch | No | Suppress spinner and run non-interactively | #### Logging | Parameter | Type | Required | Values / Range / Notes | | --- | --- | --- | --- | | `-Stdout` | string | Optional | Log file path for capturing stdout | | `-Stderr` | string | Optional | Log file path for capturing stderr | | `-EnableRotation` | switch | Optional | *Deprecated*: use `-EnableSizeRotation` | | `-EnableSizeRotation` | switch | Optional | Enable size-based log rotation | | `-RotationSize` | int | Optional | Max log file size before rotation (range: `1`-`10240` MB) | | `-EnableDateRotation` | switch | Optional | Enable date-based log rotation | | `-DateRotationType` | string | Optional | Options: `Daily`, `Weekly`, `Monthly`, `None` | | `-MaxRotations` | int | Optional | Rotated logs to keep (range: `0`-`10000`; `0` = unlimited) | | `-UseLocalTimeForRotation` | switch | Optional | Calculate rotation using local server time instead of UTC | | `-EnableDebugLogs` | switch | Optional | Enable debug logging to `Servy.Service.log` | #### Health Monitoring & Self-Healing | Parameter | Type | Required | Values / Range / Notes | | --- | --- | --- | --- | | `-EnableHealth` | switch | Optional | Enable automated health monitoring | | `-HeartbeatInterval` | int | Optional | Heartbeat interval in seconds (range: `5`-`86400` seconds) | | `-MaxFailedChecks` | int | Optional | Failed checks before triggering recovery (range: `1`-`100000`) | | `-RecoveryAction` | string | Optional | Options: `None`, `RestartService`, `RestartProcess`, `RestartComputer` | | `-RecoveryOnCleanExit` | switch | Optional | Run recovery action even if process exits with code 0 | | `-MaxRestartAttempts` | int | Optional | Max restart attempts (range: `0`-`100000`; `0` = unlimited) | | `-HeartbeatUrl` | string | Optional | Out-of-band diagnostic ping URL (e.g., healthchecks.io) | | `-HeartbeatUrlTimeoutSeconds` | int | Optional | Ping response timeout (range: `2`-`30` seconds) | | `-EnableHeartbeatUrlFlags` | switch | Optional | Include heartbeat URL flags (`/start`, `/fail`) | | `-FailureProgramPath` | string | Optional | Path to program/script run upon service failure | | `-FailureProgramStartupDir` | string | Optional | Working directory for failure program | | `-FailureProgramParams` | string | Optional | Parameters for failure program | #### Lifecycle Hooks (Pre/Post Launch & Stop) | Parameter | Type | Required | Values / Range / Notes | | --- | --- | --- | --- | | `-PreLaunchPath` | string | Optional | Executable/script run before service launch | | `-PreLaunchStartupDir` | string | Optional | Working directory for PreLaunch script | | `-PreLaunchParams` | string | Optional | Additional parameters for PreLaunch executable | | `-PreLaunchEnv` | string | Optional | Environment variables for PreLaunch executable | | `-PreLaunchStdout` | string | Optional | File path for PreLaunch stdout log | | `-PreLaunchStderr` | string | Optional | File path for PreLaunch stderr log | | `-PreLaunchTimeout` | int | Optional | PreLaunch timeout (range: `0`-`86400`s; `0` = fire-and-forget) | | `-PreLaunchRetryAttempts` | int | Optional | Retry attempts for PreLaunch executable (range: `0`-`100000`) | | `-PreLaunchIgnoreFailure` | switch | Optional | Proceed with service start even if PreLaunch fails | | `-PostLaunchPath` | string | Optional | Executable/script run after service launch (fire-and-forget) | | `-PostLaunchStartupDir` | string | Optional | Working directory for PostLaunch script | | `-PostLaunchParams` | string | Optional | Additional parameters for PostLaunch executable | | `-PreStopPath` | string | Optional | Executable/script run before service stops | | `-PreStopStartupDir` | string | Optional | Working directory for PreStop script | | `-PreStopParams` | string | Optional | Additional parameters for PreStop executable | | `-PreStopTimeout` | int | Optional | PreStop timeout (range: `0`-`86400`s; `0` = fire-and-forget) | | `-PreStopLogAsError` | switch | Optional | Treat PreStop failures as errors | | `-PostStopPath` | string | Optional | Executable/script run after service stops | | `-PostStopStartupDir` | string | Optional | Working directory for PostStop script | | `-PostStopParams` | string | Optional | Additional parameters for PostStop executable | For more details on CPU affinity, see the [FAQ](https://github.com/aelassas/servy/wiki/FAQ#how-and-why-should-i-use-cpu-affinity-with-servy). ## Troubleshooting 1. Installation Fails When Passing `$true` or `$false` A common mistake in PowerShell is attempting to pass a boolean value to a switch parameter (e.g., `-Quiet $true`). * The Symptom: The command fails with a "Parameter cannot be found" error or, more commonly, PowerShell interprets `$true` as the next positional argument. In `Install-ServyService`, this often results in `$true` being mistakenly assigned to the `-Path` or `-Name` parameters, causing the underlying CLI call to fail. * The Fix: Remove the `$true` or `$false` reference. Use `-Quiet` to turn it on, and omit it to keep it off. 1. "Access Denied" Errors Most Servy operations (install, uninstall, start, stop) interact directly with the Windows Service Control Manager. * Solution: Ensure your PowerShell session is running with Administrator privileges. If you are using an IDE like VS Code, restart it as an Administrator. 1. Service Fails to Start If `Start-ServyService` returns a success message but the service status remains Stopped, the issue is likely within the application executable or the PreLaunch configuration. * Solution: Check your `stdout` and `stderr` logs if you configured them during installation. * Validation: Run the command defined in `-Path` and `-Params` manually in a command prompt to see if it crashes immediately. 1. CLI Executable Not Found In portable mode, the module expects `servy-cli.exe` to be in the same folder as `Servy.psm1`. * Solution: Verify that the files haven't been separated. If you are using the installed version, ensure `%ProgramFiles%\Servy\` is in your System **PATH** or that the files exist in that directory. 1. Issues in Automated Environments (Ansible/CI/CD) Automated runners often hang if a process attempts to draw an interactive progress bar or spinner. * Solution: Always use the `-Quiet` switch in non-interactive scripts. This forces the module to output plain text logs instead of interactive UI elements. 1. Environment Variable Formatting The `-EnvVars` and `-PreLaunchEnv` parameters require a specific string format. * Requirement: Use the `Key=Value` format, separated by semicolons. * Example: `-EnvVars "NODE_ENV=production;PORT=3000"` ## See Also * [Export/Import Services](https://github.com/aelassas/servy/wiki/Export-Import-Services) ## References * [Servy.psm1](https://github.com/aelassas/servy/blob/main/src/Servy.CLI/Servy.psm1) * [servy-module-examples.ps1](https://github.com/aelassas/servy/blob/main/src/Servy.CLI/servy-module-examples.ps1) --- # Document: Advanced Configuration > Source: https://github.com/aelassas/servy/wiki/Advanced-Configuration ## Table of Contents 1. [Introduction](https://github.com/aelassas/servy/wiki/Advanced-Configuration#introduction) 1. [File Locations & Prerequisites](https://github.com/aelassas/servy/wiki/Advanced-Configuration#file-locations--prerequisites) 1. [Prerequisites](https://github.com/aelassas/servy/wiki/Advanced-Configuration#prerequisites) 1. [Where to Find Settings](https://github.com/aelassas/servy/wiki/Advanced-Configuration#where-to-find-settings) 1. [Logging Configuration](https://github.com/aelassas/servy/wiki/Advanced-Configuration#logging-configuration) 1. [Logging Levels (`LogLevel`)](https://github.com/aelassas/servy/wiki/Advanced-Configuration#logging-levels-loglevel) 1. [Log Rolling Interval (`LogRollingInterval`)](https://github.com/aelassas/servy/wiki/Advanced-Configuration#log-rolling-interval-logrollinginterval) 1. [Settings Reference](https://github.com/aelassas/servy/wiki/Advanced-Configuration#settings-reference) 1. [Shared Core Settings](https://github.com/aelassas/servy/wiki/Advanced-Configuration#shared-core-settings) 1. [General Logging](https://github.com/aelassas/servy/wiki/Advanced-Configuration#general-logging) 1. [Servy Windows Service](https://github.com/aelassas/servy/wiki/Advanced-Configuration#servy-windows-service) 1. [Servy Host Service](https://github.com/aelassas/servy/wiki/Advanced-Configuration#servy-host-service) 1. [Restarter Settings](https://github.com/aelassas/servy/wiki/Advanced-Configuration#restarter-settings) 1. [Desktop App Settings](https://github.com/aelassas/servy/wiki/Advanced-Configuration#desktop-app-settings) 1. [Manager App Settings](https://github.com/aelassas/servy/wiki/Advanced-Configuration#manager-app-settings) 1. [CLI Settings](https://github.com/aelassas/servy/wiki/Advanced-Configuration#cli-settings) 1. [Build Configuration Examples](https://github.com/aelassas/servy/wiki/Advanced-Configuration#build-configuration-examples) 1. [Modern Build (.NET 10.0+)](https://github.com/aelassas/servy/wiki/Advanced-Configuration#modern-build-net-100) 1. [Legacy Build (.NET Framework 4.8)](https://github.com/aelassas/servy/wiki/Advanced-Configuration#legacy-build-net-framework-48) 1. [See Also](https://github.com/aelassas/servy/wiki/Advanced-Configuration#see-also) ## Introduction This guide explains how to fine-tune the Servy ecosystem, from application refresh rates to advanced log rotation strategies. ## File Locations & Prerequisites ### Prerequisites * **Administrator Privileges**: You must run your text editor (e.g., VS Code, Notepad++) as an **Administrator** to save changes to `%ProgramFiles%` or `%ProgramData%`. * **Restart Required**: Changes to configuration files do not take effect dynamically. You must restart the associated application (Desktop/Manager) or the Windows Service (via SCM or CLI) for changes to apply. ### Where to Find Settings | Component | Modern Build (.NET 10.0+) | Legacy Build (.NET 4.8) | | :--- | :--- | :--- | | **Windows Service** | `%ProgramData%\Servy\appsettings.service.json` | `...\Servy.Service.Net48.exe.config` | | **Windows Service (CLI)** | `%ProgramData%\Servy\appsettings.service.json` | `...\Servy.Service.CLI.Net48.exe.config` | | **Servy Host Service** | `%ProgramData%\Servy\appsettings.host.json` | `...\Servy.Host.Net48.exe.config` | | **Restarter** | `%ProgramData%\Servy\appsettings.restarter.json` | `...\Servy.Restarter.Net48.exe.config` | | **Desktop App** | `%ProgramFiles%\Servy\appsettings.desktop.json` | `...\Servy.exe.config` | | **Manager App** | `%ProgramFiles%\Servy\appsettings.manager.json` | `...\Servy.Manager.exe.config` | | **CLI** | `%ProgramFiles%\Servy\appsettings.cli.json` | `...\servy-cli.exe.config` | > [!NOTE] > For Servy v8.7 and below, the settings file for the desktop app and service is named `appsettings.json`. For Servy v8.8+, refer to the table above. ## Logging Configuration Servy uses a dual-channel logging engine that writes to both the **Windows Event Log** (for high-level monitoring) and **local flat files** (for detailed diagnostics). **Log Directory:** `%ProgramData%\Servy\logs\` ### Logging Levels (`LogLevel`) Determines output verbosity. Values are case-insensitive. | Level | Target | Description | | :--- | :--- | :--- | | **DEBUG** | **File Only** | Most verbose; logs internal state and heartbeats. Not recommended for production. | | **INFO** | **Both** | **(Default)** Logs major milestones (starts, stops, configuration changes). | | **WARN** | **Both** | Logs non-fatal issues like slow shutdowns or configuration typos. | | **ERROR** | **Both** | Logs critical failures, crashes, or access denied errors. | | **NONE** | **None** | Disables the logging engine entirely. | ### Log Rolling Interval (`LogRollingInterval`) Determines how often a new log file is created. Available from Servy v7.8+. > [!IMPORTANT] > **Size Rotation Precedence**: The `LogRotationSizeMB` limit always takes precedence. If a log reaches the size limit (e.g., 10MB) before the time interval (e.g., `Monthly`), it will rotate immediately to prevent disk overflow. * `Daily`: Rotates at the start of each new calendar day. **Defaults to UTC**; set `UseLocalTimeForRotation: true` to rotate at midnight in the server's local time. * `Weekly`: Rotates when the week number changes, with weeks starting on Monday and week 1 being the first week with at least four days in the new year (.NET `FirstFourDayWeek`). This is close to ISO 8601 but not identical: the last days of December keep week 52 or 53, so a week that spans 1 January also rotates on 1 January. **Defaults to UTC**; set `UseLocalTimeForRotation: true` to use local time. * `Monthly`: Rotates on the first day of every calendar month. **Defaults to UTC**; set `UseLocalTimeForRotation: true` to use local time. * `None`: **(Default)** Files only rotate when they hit the size limit. ## Settings Reference The settings below apply to the Windows service wrapper, restarter, desktop app, manager app, and CLI. Use them when you need to fine-tune logging, refresh behavior, or operational limits for a specific component. ### Shared Core Settings Every Servy component (the Windows service wrapper, the restarter, the desktop app, the manager app and the CLI) uses the same configuration database and the same encryption key. Starting from v10.2 their locations are **fixed and read-only**: they always live in the Servy vault, `%ProgramData%\Servy`, which is the only folder whose permissions Servy hardens (see [Executable Permission Hardening](https://github.com/aelassas/servy/wiki/Security#executable-permission-hardening)). A database or key stored anywhere else would not get those permissions. The keys below were configurable up to v10.1. Since v10.2 Servy **ignores** them if they are present in a settings file (`appsettings.*.json` in the .NET 10 build, `*.exe.config` in the .NET Framework 4.8 build), and logs a warning naming the key and the settings file when one of them is still set. Remove the entry to silence the warning. | Setting (ignored since v10.2) | Fixed value | Description | | :--- | :--- | :--- | | `ConnectionStrings:DefaultConnection` (`DefaultConnection` in `.exe.config`) | `Data Source=%ProgramData%\Servy\db\Servy.db;Busy Timeout=5000;Journal Mode=WAL;Pooling=True;` | SQLite connection string of the configuration database. | | `Security:AESKeyFilePath` | `%ProgramData%\Servy\security\aes_key.dat` | AES encryption key file used to protect sensitive service settings such as passwords. | | `Security:AESIVFilePath` | `%ProgramData%\Servy\security\aes_iv.dat` | **(Legacy)** Static AES Initialization Vector (IV) file used by the v1 cipher format (Servy < 6.5). Unused in current builds (`AllowLegacyV1Decryption = false`). | > [!IMPORTANT] > **Upgrading from v10.1 or earlier with a custom location:** if you moved the database or the key with one of these settings, move the files back before you upgrade. Stop every Servy-managed service, close the desktop and manager apps, copy the database to `%ProgramData%\Servy\db\Servy.db` and the key to `%ProgramData%\Servy\security\aes_key.dat` (keep `aes_iv.dat` next to it if you have one), then upgrade. Otherwise v10.2 creates a new, empty database and a new key in the vault and does not see the services recorded in the old database. The key is bound to the machine, so this works only on the machine that created it; to move services to another machine, use [Backup, Restore & VM Cloning](https://github.com/aelassas/servy/wiki/Backup-Restore-&-VM-Cloning). ### General Logging | Setting | Default | Description | | :--- | :--- | :--- | | `LogLevel` | `INFO` | Verbosity of the output. | | `EnableSizeRotation` | `true` | Enables size-based log rotation for internal log files. When disabled, `LogRotationSizeMB` has no effect (available from v9.4+). | | `LogRotationSizeMB` | `10` | Maximum log file size in MB before a file is archived. Requires `EnableSizeRotation` to be `true`. Must be greater than `0`; `0` or a negative value is silently replaced by the `10` MB default. To disable size-based rotation, set `EnableSizeRotation` to `false` instead. | | `MaxBackupLogFiles` | `10` | Number of archived logs retained. Set to `0` for unlimited. | | `EnableEventLog` | `true` | Controls whether Servy and the Windows Service infrastructure write to the Windows Event Log. | | `UseLocalTimeForRotation` | `false` | Uses local system time instead of UTC when determining date-based log rotation boundaries. | | `LogRollingInterval` | `None` | Date-based rotation interval: `Daily`, `Weekly`, `Monthly`, or `None`. See the Log Rolling Interval section above. Available from Servy v7.8+. | > [!NOTE] > The `EnableEventLog` setting is primarily respected by the **Servy Windows Service** wrapper and **Servy Windows Service Restarter** utility. Setting this in the **CLI**, **Desktop App**, or **Manager App** configuration has no effect. > [!WARNING] > **Side Effect of `EnableEventLog: false` on Service Failure Diagnostics** > > Setting `EnableEventLog` to `false` disables both Servy's event logger and the framework's automatic service state logging (`AutoLog = false`). > > When set to `false`, startup or shutdown failures (such as `SR.StartFailed`, `SR.StopFailed`, or `SR.ShutdownFailed`) will **not** generate entry logs in the Windows Event Viewer. In this state, critical diagnostic entries will only be captured in the local file logs under `%ProgramData%\Servy\logs\`. ### Servy Windows Service | Setting | Default | Description | | :--- | :--- | :--- | | `Timing:WaitChunkMs` | `5000` | Granularity, in milliseconds, of the wait loop used while running synchronous **pre-launch / pre-stop hooks**. It controls how often the wait is sliced to check for cancellation or timeout, and does not control health-check frequency. | | `Timing:ScmAdditionalTimeMs` | `15000` | Additional buffer time, in milliseconds, added to Service Control Manager (SCM) operations to prevent premature timeouts. | ### Servy Host Service The `Servy` service (`Servy.Host.exe`, or `Servy.Host.Net48.exe` in the .NET Framework 4.8 build, see [Architecture](https://github.com/aelassas/servy/wiki/Architecture#servyhost-servy-service)) reads its settings from the file next to its executable, `%ProgramData%\Servy`. The file is optional: when it is missing, every setting takes its default. It has no settings of its own beyond logging; the `Timing:*` settings above belong to the service wrapper and the host ignores them. | Setting | Default | Description | | :--- | :--- | :--- | | `General Logging` | - | Uses the settings from the **General Logging** section above. The host writes `Servy.Host.log` to `%ProgramData%\Servy\logs\`. | ### Restarter Settings | Setting | Default | Description | | :--- | :--- | :--- | | `RestartTimeoutSeconds` | `120` | Maximum time, in seconds, that the Restarter waits for the service to stop and start again before giving up. Bounded to `[1, 86400]`. **Values above 240 are not reachable in practice:** the Servy host service force-kills `Servy.Restarter.exe` after 240 seconds (4 minutes), and the Restarter logs a warning at startup when the configured value exceeds it. | | `General Logging` | - | Uses the settings from the **General Logging** section above. | ### Desktop App Settings | Setting | Default | Description | | :--- | :--- | :--- | | `ManagerAppPublishPath` | `.\Servy.Manager.exe` | Path to the Servy Manager app launched from the Desktop app. Resolved relative to the Desktop app's base directory if not absolute. | | `General Logging` | - | Uses the settings from the **General Logging** section above. | ### Manager App Settings | Setting | Default | Description | | :--- | :--- | :--- | | `RefreshIntervalInSeconds` | `4` | Refresh interval, in seconds, for the main service list. Bounded to `[1, 3600]`. | | `PerformanceRefreshIntervalInMs` | `800` | Frequency, in milliseconds, of CPU/RAM graph updates. Bounded to `[100, 300000]`. | | `ConsoleRefreshIntervalInMs` | `800` | Polling rate, in milliseconds, for `stdout`/`stderr` updates in the Console tab. Bounded to `[100, 300000]`. | | `ConsoleMaxLines` | `20000` | Maximum number of `stdout`/`stderr` lines retained in the Console tab buffer. Bounded to `[100, 40000]`. | | `DependenciesRefreshIntervalInMs` | `800` | Polling rate, in milliseconds, for the Dependencies tab. Bounded to `[100, 300000]`. | | `MaxBulkOperationParallelism` | `8` | Maximum concurrent SCM operations during bulk tasks. Bounded to `[1, 64]`. | | `SearchDebounceDelayMs` | `300` | Debounce window, in milliseconds, before the search box re-runs the filter in the Console tab. Bounded to `[100, 2000]`. | | `LogsWindowDays` | `3` | Number of days of Windows Event Log history shown in the Logs tab. Bounded to `[1, 30]`. | | `DesktopAppPublishPath` | `.\Servy.exe` | Path to the Servy desktop app launched from the Manager. Resolved relative to the Manager's base directory if not absolute. | | `ServicesHiddenColumns` | `""` | Comma-separated list of services-grid column headers hidden in the Manager's Services tab, for example `Description,Log On As`. The Manager rewrites it when a column is shown or hidden from the column-header context menu; an empty value shows every column. Entries are matched case-insensitively against the column header text (Description, Status, Startup Type, Log On As, PID, CPU, RAM). | | `LogsHiddenColumns` | `""` | Comma-separated list of logs-grid column headers hidden in the Manager's Logs tab, for example `Event ID,Level`. The Manager rewrites it when a column is shown or hidden from the column-header context menu; an empty value shows every column. Entries are matched case-insensitively against the column header text (`Time`, `Level`, `Event ID`). | | `General Logging` | - | Uses the settings from the **General Logging** section above. | > [!NOTE] > To prevent SCM contention, the actual bulk-operation parallelism is capped by: `Math.Max(1, Math.Min(Environment.ProcessorCount * 2, MaxBulkOperationParallelism))`. ### CLI Settings | Setting | Default | Description | | :--- | :--- | :--- | | `General Logging` | - | Uses the settings from the **General Logging** section above. | ## Build Configuration Examples ### Modern Build (.NET 10.0+) **File:** `%ProgramData%\Servy\appsettings.service.json` (Servy Windows Service Wrapper) ```json { "Timing": { "WaitChunkMs": 5000, "ScmAdditionalTimeMs": 15000 }, "LogLevel": "INFO", "EnableSizeRotation": true, "LogRotationSizeMB": 10, "LogRollingInterval": "Daily", "MaxBackupLogFiles": 10, "UseLocalTimeForRotation": true, "EnableEventLog": true } ``` > [!TIP] > If you only want to disable logging to the Windows Event Log while keeping local file logging for all Servy services, create a `%ProgramData%\Servy\appsettings.service.json` file with this content: > ```json > { > "EnableEventLog": false > } > ``` ### Legacy Build (.NET Framework 4.8) **File:** `%ProgramData%\Servy\Servy.Service.Net48.exe.config` (Servy Windows Service Wrapper) ```xml ``` ### Servy Host Service (.NET 10.0+ and .NET Framework 4.8) **Modern build file:** `%ProgramData%\Servy\appsettings.host.json` ```json { "LogLevel": "INFO", "EnableSizeRotation": true, "LogRotationSizeMB": 10, "LogRollingInterval": "None", "MaxBackupLogFiles": 10, "UseLocalTimeForRotation": false, "EnableEventLog": true } ``` **Legacy build file:** `%ProgramData%\Servy\Servy.Host.Net48.exe.config` ```xml ``` ## See Also * [Logging & Log Rotation](https://github.com/aelassas/servy/wiki/Logging-&-Log-Rotation) * [Servy Manager](https://github.com/aelassas/servy/wiki/Servy-Manager) * [Installation Guide](https://github.com/aelassas/servy/wiki/Installation-Guide) --- # Document: Logging & Log Rotation > Source: https://github.com/aelassas/servy/wiki/Logging-&-Log-Rotation ## Table of Contents 1. [Introduction](https://github.com/aelassas/servy/wiki/Logging-&-Log-Rotation#introduction) 1. [Logs in Servy Manager](https://github.com/aelassas/servy/wiki/Logging-&-Log-Rotation#logs-in-servy-manager) 1. [Event IDs](https://github.com/aelassas/servy/wiki/Logging-&-Log-Rotation#event-ids) 1. [Logging Settings](https://github.com/aelassas/servy/wiki/Logging-&-Log-Rotation#logging-settings) 1. [CLI Options](https://github.com/aelassas/servy/wiki/Logging-&-Log-Rotation#cli-options) 1. [CLI Example](https://github.com/aelassas/servy/wiki/Logging-&-Log-Rotation#cli-example) 1. [PowerShell Options](https://github.com/aelassas/servy/wiki/Logging-&-Log-Rotation#powershell-options) 1. [PowerShell Example](https://github.com/aelassas/servy/wiki/Logging-&-Log-Rotation#powershell-example) 1. [Internal Servy Logs](https://github.com/aelassas/servy/wiki/Logging-&-Log-Rotation#internal-servy-logs) ## Introduction Servy provides flexible logging to monitor your services in real time, capturing important events in Windows Event Logs, local log files at `%ProgramData%\Servy\logs\` as well as standard output and error streams (`stdout`/`stderr`). Logs can be viewed in Servy Manager, filtered by level, date, or keyword, and optionally rotated to prevent disk space issues. ## Logs in Servy Manager servy-manager-logs - Important events are logged in **Windows Event Viewer** and can be browsed from **Servy Manager**. - **Logs Tab**: Quickly search logs by log level, date, and keyword for easy monitoring and troubleshooting. - **Message Format**: Each log entry starts with `[ServiceName]` followed by the message. - Example: `[MyService] Health monitoring started.` ## Event IDs Servy assigns specific **Event IDs** to distinguish between types of service logs. These IDs are recorded in **Windows Event Viewer** and are useful for filtering, searching, and automation. | Level | Event ID Range | Purpose | |-------|----------------|---------| | Info | 1000-1099 | Lifecycle milestones (start, stop, recovery success) | | Warning | 2000-2099 | Recoverable degradations (retries, fallback paths) | | Error | 3000-3099 | Core errors (DPAPI failures, DB init failures, ...) | | Error | 3100-3199 | Script / scheduled-task errors (`ServyFailureEmail.ps1` etc.) | - 2002 = transient migration warning (pre-escalation; auto-clears on next successful read) - 3001 = key unprotect failed - 3003 = persistent migration failure - 3103 = scheduled-task script error - 3104 = scheduled-task script dependency error > [!NOTE] > Event IDs are per event type, not unique per entry. ## Logging Settings The "Logging" tab in the desktop app lets you configure `stdout` and `stderr` logging, including size-based log rotation, date-based log rotation, the maximum number of rotated log files to retain, and additional options such as enabling debug logs. servy-config-logging > [!NOTE] > If both size-based and date-based rotation are enabled, size-based rotation takes precedence. > [!NOTE] > Enabling the debug option will record sensitive information in the local log file at `%ProgramData%\Servy\logs\services\\Servy.Service.log`. This behavior only occurs when local logging is enabled, which is the default setting. Sensitive data is never recorded in the Windows Event Log. The CLI `show` command and `Show-ServyService` mask the encrypted fields by default; `--decrypt` / `-Decrypt` prints the parameters and environment variables in clear text (the stored password always stays masked). See [Servy CLI](https://github.com/aelassas/servy/wiki/Servy-CLI) and [Servy PowerShell Module](https://github.com/aelassas/servy/wiki/Servy-PowerShell-Module). > [!NOTE] > Enabling **Console UI** (`--enableConsoleUI`) disables stdout/stderr redirection at the OS level - the child process keeps an attached console handle instead of pipes. Servy cannot capture or rotate the output in that mode, so the configured `--stdout` / `--stderr` paths will remain empty. Use one or the other, not both. ## CLI Options - `--stdout` - stdout log path - `--stderr` - stderr log path - `--enableSizeRotation` - `--rotationSize` - size in MB (1-10240) - `--enableDateRotation` - `--dateRotationType` - Daily, Weekly, Monthly, None (None disables date-based rotation; use when only size rotation is desired) - `--useLocalTimeForRotation` - use local time instead of UTC (default: false) - `--maxRotations` - number of files, 0 = unlimited (maximum 10000) - `--debug` - Enable debug logs. Records environment variables and process parameters in `%ProgramData%\Servy\logs\services\\Servy.Service.log`. Not recommended for production. ## CLI Example ```powershell servy-cli install ` --name="My NodeJS Service" ` --description="My NodeJS Server" ` --path="C:\Program Files\nodejs\node.exe" ` --startupDir="C:\Apps\App" ` --params="C:\Apps\App\index.js" ` --startupType="Automatic" ` --priority="Normal" ` --stdout="C:\Apps\App\stdout.log" ` --stderr="C:\Apps\App\stderr.log" ` --enableSizeRotation ` --rotationSize="10" ` --maxRotations="5" ` --debug ``` ## PowerShell Options - `-Stdout` (string) - `-Stderr` (string) - `-EnableSizeRotation` (switch) - `-RotationSize` (int) - `-EnableDateRotation` (switch) - `-DateRotationType` (Daily, Weekly, Monthly, None - None disables date-based rotation; use when only size rotation is desired) - `-UseLocalTimeForRotation` (switch) - `-MaxRotations` (int, 0 = unlimited) - `-EnableDebugLogs` - Enable debug logs. Records environment variables and process parameters in `%ProgramData%\Servy\logs\services\\Servy.Service.log`. Not recommended for production. ## PowerShell Example ```powershell Import-Module "C:\Program Files\Servy\Servy.psm1" -Force $installParams = @{ Quiet = $true Name = "My NodeJS Service" Description = "My NodeJS Server" Path = "C:\Program Files\nodejs\node.exe" StartupDir = "C:\Apps\App" Params = "C:\Apps\App\index.js" StartupType = "Automatic" Priority = "Normal" Stdout = "C:\Apps\App\stdout.log" Stderr = "C:\Apps\App\stderr.log" EnableSizeRotation = $true RotationSize = 10 MaxRotations = 5 EnableDebugLogs = $true } Install-ServyService @installParams ``` ## Internal Servy Logs Servy's own log files are under `%ProgramData%\Servy\logs\`: - `logs\` - the logs of the Desktop App, Servy Manager, `servy-cli` and the `Servy` host service (`Servy.Host.log`). Only `SYSTEM` and `Administrators` can read them. - `logs\services\\` (v10.2+) - one folder per service, holding `Servy.Service.log` (the service wrapper) and `Servy.Restarter.log`. Only that service's account, `SYSTEM` and `Administrators` can reach it. A service name that holds a character a folder name cannot hold is percent-encoded (`My:Service` logs to `logs\services\My%3AService\`); see [Security](https://github.com/aelassas/servy/wiki/Security) for the full rules. Before v10.2, every service wrote to a single shared `logs\Servy.Service.log`. An upgrade leaves that file where it is, untouched; no service writes to it any more, and it can be deleted once it is no longer needed. See [Advanced Configuration](https://github.com/aelassas/servy/wiki/Advanced-Configuration). > [!TIP] > Combine log rotation with health monitoring and pre-launch scripts to avoid disk space issues. --- # Document: Health Monitoring & Recovery > Source: https://github.com/aelassas/servy/wiki/Health-Monitoring-&-Recovery ## Table of Contents 1. [Introduction](https://github.com/aelassas/servy/wiki/Health-Monitoring-&-Recovery#introduction) 1. [Health Monitoring Settings](https://github.com/aelassas/servy/wiki/Health-Monitoring-&-Recovery#health-monitoring-settings) 1. [CLI Options](https://github.com/aelassas/servy/wiki/Health-Monitoring-&-Recovery#cli-options) 1. [CLI Example](https://github.com/aelassas/servy/wiki/Health-Monitoring-&-Recovery#cli-example) 1. [PowerShell Options](https://github.com/aelassas/servy/wiki/Health-Monitoring-&-Recovery#powershell-options) 1. [PowerShell Example](https://github.com/aelassas/servy/wiki/Health-Monitoring-&-Recovery#powershell-example) 1. [How Health Monitoring Works](https://github.com/aelassas/servy/wiki/Health-Monitoring-&-Recovery#how-health-monitoring-works) 1. [Transient Detection (Memory-Based)](https://github.com/aelassas/servy/wiki/Health-Monitoring-&-Recovery#transient-detection-memory-based) 1. [Recovery Orchestration (The Gatekeeper)](https://github.com/aelassas/servy/wiki/Health-Monitoring-&-Recovery#recovery-orchestration-the-gatekeeper) 1. [Stability Verification (Persistence-Based)](https://github.com/aelassas/servy/wiki/Health-Monitoring-&-Recovery#stability-verification-persistence-based) 1. [Reboot Detection (Session Persistence)](https://github.com/aelassas/servy/wiki/Health-Monitoring-&-Recovery#reboot-detection-session-persistence) 1. [The Adaptive Stability Window](https://github.com/aelassas/servy/wiki/Health-Monitoring-&-Recovery#the-adaptive-stability-window) 1. [Heartbeat Ping URL Logic](https://github.com/aelassas/servy/wiki/Health-Monitoring-&-Recovery#heartbeat-ping-url-logic) 1. [Logic Examples & Threshold Scenarios](https://github.com/aelassas/servy/wiki/Health-Monitoring-&-Recovery#logic-examples--threshold-scenarios) 1. [Health Monitoring Logic Flow](https://github.com/aelassas/servy/wiki/Health-Monitoring-&-Recovery#health-monitoring-logic-flow) 1. [Reboot Detection Example](https://github.com/aelassas/servy/wiki/Health-Monitoring-&-Recovery#reboot-detection-example) 1. [Service Restart Detection Example](https://github.com/aelassas/servy/wiki/Health-Monitoring-&-Recovery#service-restart-detection-example) ## Introduction Servy includes **built-in health monitoring** to ensure that your services are running correctly and recover automatically from failures. If you are getting started, here are the core behaviors of the Servy health monitor: - **Heartbeats are Liveness Checks:** Servy checks if your process is running and responding every **30 seconds** (default). - **Consecutive Failures Only:** Recovery is only triggered if the service fails $N$ times **in a row**. A single successful heartbeat resets the transient failure counter to zero. - **The "Flapping" Protection:** Servy doesn't forget failures immediately. The persistent restart counter only resets to zero after the service has been stable (running without issue) for a specific **Probationary Period**. - **Reboot Persistence:** If Servy restarts the computer to fix a service, it **remembers** how many times it has tried to fix it across reboots. This prevents your machine from entering an infinite reboot loop. - **Safety Stop:** Once the `MaxRestartAttempts` limit is reached, Servy stops trying, runs your optional `FailureProgram`, and leaves the service **Stopped** for manual inspection. ## Health Monitoring Settings The "Recovery" tab in the desktop app lets you configure automated health-monitoring and failure-handling behavior. It enables continuous internal liveness checks, optional out-of-band diagnostic pings to external monitoring platforms (e.g., [healthchecks.io](https://healthchecks.io) or [Uptime Kuma](https://github.com/louislam/uptime-kuma) Push Monitors), and customizable recovery actions to keep your application running reliably without manual intervention. servy-config-recovery Here are the available recovery options: - **Heartbeat Interval**: optional, default is 30 seconds. This is the frequency at which Servy checks if the service is responsive. A heartbeat is an internal liveness check (process existence and state), not an application-level health probe. Minimum is 5 seconds, maximum is 86400 seconds (24 hours). - **Max Failed Checks**: optional, default is 3. The number of consecutive failed checks allowed before triggering a recovery action. Minimum is 1, maximum is 100000. - **Recovery Action**: optional. Defines what happens when health checks fail. Options: - `RestartService` (default): restart the service - `RestartProcess`: restart the process without full service restart - `RestartComputer`: restart the host machine - `None`: take no action - **Recovery On Clean Exit**: optional. Triggers the defined recovery action even if the child process exits gracefully with a clean exit code (0). By default, a clean exit stops the service intentionally without triggering recovery. - **Max Restart Attempts**: optional, default is 3. The maximum number of recovery attempts before giving up. Minimum is 0 (set to 0 for unlimited restart attempts), maximum is 100000. - **Heartbeat URL**: optional string. An absolute HTTP/HTTPS URL (e.g., `https://hc-ping.com/uuid`) used for sending out-of-band diagnostic heartbeat pings to external monitoring services (such as healthchecks.io or Uptime Kuma). - **Heartbeat URL Timeout**: optional integer, default is 10 seconds (range: 2-30 seconds). Timeout for the heartbeat HTTP GET request. - **Heartbeat URL Flags**: optional switch/boolean. Appends `/start` when the service starts and `/fail` when recovery fails, to the Heartbeat URL (e.g., transforming `https://hc-ping.com/your-uuid` into `https://hc-ping.com/your-uuid/start` or `https://hc-ping.com/your-uuid/fail`). - **Failure Program Path**: optional failure program to run after all recovery attempts have failed (and, when health-monitoring is disabled, when the child process exits with a non-zero code). - **Failure Startup Directory**: optional failure program startup directory. - **Failure Program Parameters**: optional failure program parameters. If health-monitoring is disabled, the failure program will run when the **child process exits with a non-zero code**. If health-monitoring is enabled, the failure program will only run after all recovery action retries have failed. Note: **start-up failures (e.g. a missing executable path) currently do not trigger the failure program** - check Logs tab in Servy Manager or the Windows Event Log under Source `Servy` for those. **Environment Variables:** the failure program inherits the **main service's** `EnvironmentVariables`. There is no separate `Post-Launch / Pre-Stop / Post-Stop / Failure-Program EnvironmentVariables` setting - only `Pre-Launch` supports a per-hook override. > [!NOTE] > `RestartService` and `RestartComputer` are not available if the service runs under `NT AUTHORITY\LocalService`, `NT AUTHORITY\NetworkService`, an IIS AppPool identity (`IIS APPPOOL\...`), or a user account without the required privileges. > [!WARNING] > Setting Max Restart Attempts to 0 (unlimited retries) bypasses the FailureProgram path, because the "quota reached" condition is never met. ## CLI Options - `--enableHealth`: Enable health monitoring. - `--heartbeatInterval`: Heartbeat interval in seconds. - `--maxFailedChecks`: Maximum allowed failed health checks. - `--recoveryAction`: Recovery action on failure. Options: `None`, `RestartService`, `RestartProcess`, `RestartComputer`. - `--recoveryOnCleanExit`: Enable recovery actions even if the process exits with a clean exit code (0). (*Available starting from Servy 8.4*) - `--maxRestartAttempts`: Maximum restart attempts on failure. - `--heartbeatUrl`: Absolute URL for out-of-band diagnostic heartbeat pings. This is a sensitive option: prefer the `SERVY_HEARTBEAT_URL` environment variable (v10.4+), which takes precedence over `--heartbeatUrl` when both are set (see [Security](https://github.com/aelassas/servy/wiki/Security) for the full list of sensitive fields). - `--heartbeatUrlTimeoutSeconds`: Timeout in seconds for the heartbeat URL request. - `--enableHeartbeatUrlFlags`: Appends `/start` when the service starts and `/fail` when recovery fails, to the Heartbeat URL. - `--failureProgramPath`: Path to an optional program to execute if all recovery attempts fail. - `--failureProgramStartupDir`: Optional working directory for the failure program. - `--failureProgramParams`: Optional parameters to pass to the failure program. > [!NOTE] > Health monitoring (`--enableHealth`) must be enabled to use `--heartbeatUrl` or recovery options. Setting recovery parameters without `--enableHealth` has no effect. ## CLI Example ```powershell servy-cli install ` --name="MyNodeService" ` --description="My NodeJS Server" ` --path="C:\Program Files\nodejs\node.exe" ` --startupDir="C:\Apps\App" ` --params="C:\Apps\App\index.js" ` --startupType="Automatic" ` --enableHealth ` --heartbeatInterval="10" ` --maxFailedChecks="3" ` --recoveryAction="RestartProcess" ` --recoveryOnCleanExit ` --maxRestartAttempts="3" ` --heartbeatUrl="https://hc-ping.com/your-uuid-here" ` --heartbeatUrlTimeoutSeconds="5" ` --enableHeartbeatUrlFlags ` --failureProgramPath="C:\Apps\FailureHandler.exe" ` --failureProgramStartupDir="C:\Apps" ` --failureProgramParams="-log C:\Logs\failure.log" ``` ## PowerShell Options The following parameters are the PowerShell equivalents of the CLI health monitoring options when using `Install-ServyService` with splatting. - `-EnableHealth`: Enables health monitoring for the service. This is a switch parameter. - `-HeartbeatInterval`: Heartbeat interval in seconds. - `-MaxFailedChecks`: Maximum number of consecutive failed health checks allowed before triggering recovery. - `-RecoveryAction`: Recovery action on failure. Valid values: `None`, `RestartService`, `RestartProcess`, `RestartComputer`. - `-RecoveryOnCleanExit`: Switch parameter to trigger recovery actions even on a clean process exit (exit code 0). (*Available starting from Servy 8.4*) - `-MaxRestartAttempts`: Maximum number of recovery attempts before the service is stopped. - `-HeartbeatUrl`: String, optional. Absolute HTTP/HTTPS URL (e.g. `https://hc-ping.com/uuid`) for heartbeat pings. `Install-ServyService` passes it to `servy-cli` (v10.4+) through the `SERVY_HEARTBEAT_URL` environment variable of the child process, not on the command line, so it is not visible in the process list. If `-HeartbeatUrl` is omitted, a `SERVY_HEARTBEAT_URL` already set in the PowerShell session is passed on. - `-HeartbeatUrlTimeoutSeconds`: Timeout in seconds for the heartbeat URL request. - `-EnableHeartbeatUrlFlags`: Switch parameter, optional. Appends `/start` when the service starts and `/fail` when recovery fails, to the Heartbeat URL. - `-FailureProgramPath`: Path to an optional program to execute after all recovery attempts have failed. - `-FailureProgramStartupDir`: Optional working directory for the failure program. - `-FailureProgramParams`: Optional parameters passed to the failure program. > [!NOTE] > Health monitoring (`-EnableHealth`) must be enabled to use `-HeartbeatUrl` or recovery options. Setting recovery parameters without `-EnableHealth` has no effect. ## PowerShell Example ```powershell Import-Module "C:\Program Files\Servy\Servy.psm1" -Force $installParams = @{ Name = "MyNodeService" Description = "My NodeJS Server" Path = "C:\Program Files\nodejs\node.exe" StartupDir = "C:\Apps\App" Params = "C:\Apps\App\index.js" StartupType = "Automatic" EnableHealth = $true HeartbeatInterval = 10 MaxFailedChecks = 3 RecoveryAction = "RestartService" RecoveryOnCleanExit = $true MaxRestartAttempts = 3 HeartbeatUrl = "https://hc-ping.com/your-uuid-here" HeartbeatUrlTimeoutSeconds = 5 EnableHeartbeatUrlFlags = $true FailureProgramPath = "C:\Apps\FailureHandler.exe" FailureProgramStartupDir = "C:\Apps" FailureProgramParams = "-log C:\Logs\failure.log" } Install-ServyService @installParams ``` ## How Health Monitoring Works Servy implements a **Tiered Recovery Architecture** designed to maximize uptime while protecting the host system from an infinite reboot loop. The logic is divided into three primary layers: **Transient Detection (Memory-Based)**, **Recovery Orchestration (The Gatekeeper)**, and **Stability Verification (Persistence-Based)**. ### Transient Detection (Memory-Based) The service monitors the child process using a periodic heartbeat timer to filter out **noise** and transient glitches. - **Failed Checks:** If the process is missing, has crashed, or exited cleanly while `RecoveryOnCleanExit` is enabled, a memory-based counter (`_failedChecks`) increments. (By default, a clean exit code of 0 stops the service intentionally). - **Transient Reset:** If the process returns to a healthy state and the current failure count is greater than 0, the memory counter is immediately reset to `0`. This ensures that occasional missed heartbeats do not accumulate over long periods; recovery is only triggered by **consecutive** failures. - **Persistence Sync:** When the process is healthy, the persistent `restartAttempts` counter is reset to `0` only if it is determined to be **expired**. A counter is considered expired if the time it was last written (the last recorded failure) is longer ago than the calculated **Adaptive Stability Window**. This ensures that the failure history is only cleared after a proven period of consistent uptime, rather than being wiped by a single "lucky" heartbeat from a "flapping" service. - **Threshold:** Recovery is only triggered after the number of consecutive failures reaches `MaxFailedChecks`. This prevents unnecessary restarts due to momentary OS hiccups or slow process responses. - **Purpose:** This dual-reset strategy ensures the watchdog is sensitive to immediate crashes but forgiving of intermittent, non-critical hiccups. ### Recovery Orchestration (The Gatekeeper) When the failure threshold is reached, the system enters a managed **Recovery State**. - **The Gatekeeper Pattern:** A thread-safe flag (`_isRecovering`) blocks any further health checks until the recovery action (Restart Process, Service, or Computer) has completely finished. - **Quota Management:** Before executing recovery, the service checks a persistent counter kept by the Servy host service. If `MaxRestartAttempts` is reached, the service executes the `FailureProgram` and stops the service to allow for manual intervention. The failure program is executed only after the persistent restart counter reaches `MaxRestartAttempts`, never during intermediate recovery attempts. ### Stability Verification (Persistence-Based) This is the most critical layer. It manages the persistent `restartAttempts` counter for each service, which the Servy host service stores in `Servy.db` (the `RestartAttempts` and `RestartAttemptsUpdatedAtTicks` columns). Unlike the transient counter, this is **not** reset immediately upon a successful heartbeat. - **Stability Reset:** The persistent counter is only reset to `0` once the service has been running successfully for longer than the **Adaptive Stability Window**. - **Logic:** If the time the counter was last written is older than the calculated threshold, Servy considers the service **stable** and clears the failure history. #### Reboot Detection (Session Persistence) The watchdog compares the timestamp of the last restart attempt against the **System Boot Time**. - **Logic:** If the counter was last written before the current OS session, the reset is skipped for that evaluation and its timestamp is re-anchored to the current session. The failure count survives the reboot, and the Adaptive Stability Window then starts counting fresh from boot - the counter clears only after the service stays healthy for the full window within the new session. - **Purpose:** This ensures that if the service triggered a `RestartComputer` action, it "remembers" that attempt when the machine boots back up. This prevents a reboot from being used to bypass recovery quotas. #### The Adaptive Stability Window To prevent "Flapping" (where a process crashes shortly after starting), the persistent counter is only reset to `0` after the service survives a calculated **Probationary Period**. The watchdog calculates the required stable uptime before the persistent restart counter is reset to zero. This formula balances high-frequency "flapping" protection with long-term operational sanity. $$Threshold = \begin{cases} D + PreLaunchTimeout & \text{if } D > 3600 \\ \max(\min(D + \max(D, 30), 3600), D) + PreLaunchTimeout & \text{if } D \le 3600 \end{cases}$$ Where: - **Detection Window** ($D$): `HeartbeatInterval` × `MaxFailedChecks`. The minimum time required to detect a service failure. - **Buffer:** $\max(D, 30s)$. An additional safety margin to ensure the service has stabilized past its detection horizon. - **$3600$ (Operator Sanity Cap):** A 1-hour limit (3600 seconds) to ensure administrators do not have to wait indefinitely for a counter reset on slow-pulse services. - **Safety Floor** ($D$): Ensures that the final reset threshold is never shorter than the detection window itself, guaranteeing the service survives at least one full health cycle before clearing its fault history. - **Pre-Launch Timeout:** If pre-launch is enabled, the threshold is extended by `PreLaunchTimeoutInSeconds` to prevent slow initialization cycles from consuming the stability evaluation budget. ### Heartbeat Ping URL Logic When `HeartbeatUrl` is configured and health monitoring is enabled, Servy transmits asynchronous HTTP GET pings to the configured external monitoring endpoint according to the following rules: - **Service Lifecycle Start:** Inside the startup sequence, if extended flags are enabled (`EnableHeartbeatUrlFlags`), Servy appends `/start` to the `HeartbeatUrl` (e.g., `https://hc-ping.com/your-uuid/start`). - **Health Check Loop Pass (steady state):** When a health check finds the process healthy and the consecutive-failure counter is already `0`, Servy pings the exact base `HeartbeatUrl` (e.g., `https://hc-ping.com/your-uuid`). - **Health Check Loop Pass (recovered):** When a health check finds the process healthy after one or more failed checks and extended flags are enabled (`EnableHeartbeatUrlFlags`), Servy sends `/start` instead of the bare URL, signalling that the service came back. With flags disabled, no ping is sent on that check; the bare ping resumes on the next healthy check. - **Health Check Loop Fail / Process Crash:** Right before triggering configured recovery actions, upon process crash, or when all restart attempt quotas have been exhausted, if extended flags are enabled (`EnableHeartbeatUrlFlags`), Servy appends `/fail` to the `HeartbeatUrl` and sends the ping (e.g., `https://hc-ping.com/your-uuid/fail`). ### Logic Examples & Threshold Scenarios The following table demonstrates how the watchdog adapts to different heartbeat configurations: | Heartbeat Interval | Max Failed Checks | Detection Window ($D$) | Buffer (max(D, 30s)) | Final Reset Threshold | Strategy Applied | | --- | --- | --- | --- | --- | --- | | **5 Seconds** | 3 | 15 Seconds | 30 Seconds | **45 Seconds** | **Buffered:** $D$ + 30s minimum safety margin. | | **5 Seconds** | 1 | 5 Seconds | 30 Seconds | **35 Seconds** | **Buffered:** $D$ + 30s minimum safety margin. | | **10 Seconds** | 3 | 30 Seconds | 30 Seconds | **60 Seconds** | **Proportional:** $D$ + 30s minimum safety margin. | | **1 Minute** | 3 | 3 Minutes ($180s$) | 3 Minutes ($180s$) | **6 Minutes** ($360s$) | **Proportional:** Standard $2 \times D$ window. | | **15 Minutes** | 3 | 45 Minutes ($2700s$) | 45 Minutes ($2700s$) | **60 Minutes** ($3600s$) | **Capped:** 1-hour limit for operator sanity. | | **1 Hour** | 3 | 3 Hours ($10800s$) | 3 Hours ($10800s$) | **3 Hours** ($10800s$) | **Floored (not recommended):** Detection window exceeds cap; overrides to $D$. | | **1 Day** | 3 | 3 Days ($259200s$) | 3 Days ($259200s$) | **3 Days** ($259200s$) | **Floored (not recommended):** Detection window exceeds cap; overrides to $D$. | > [!WARNING] > **Floored Configurations:** If `HeartbeatInterval × MaxFailedChecks` exceeds 3600 seconds (1 hour), the detection window itself exceeds the reset cap. Servy falls back to using $D$ as the threshold and logs a warning on every stability evaluation. Keep `HeartbeatInterval × MaxFailedChecks` at or below 3600 seconds to stay within the recommended operational range. **Pre-Launch Considerations:** If a pre-launch script is configured (`PreLaunchExecutablePath` is set), the stability timer does not effectively start until the process has completed its initialization phase. For example, if a service has a **1-minute detection window** ($60\text{s}$), its base stability requirement is **2 minutes** ($120\text{s}$). If it takes **5 minutes** ($300\text{s}$) to load its database dependencies (`PreLaunchTimeout`), the final reset threshold will be **7 minutes** ($420\text{s}$). This configuration architecture insulates the execution paths, ensuring warm-up latency never penalizes stability tracking. ### Health Monitoring Logic Flow For every heartbeat cycle, Servy follows this decision-making process: 1. **The Heartbeat Check** - Servy checks the liveness of the child process (process existence and responsiveness). 2. **IF HEALTHY:** - **Transient Reset:** The memory-based `_failedChecks` counter is immediately reset to `0`. - **Ping URL:** If `HeartbeatUrl` is configured, Servy pings the bare URL when the failure counter was already `0`. When the process has just recovered from one or more failed checks, it sends `/start` instead if `EnableHeartbeatUrlFlags` is enabled, and no ping otherwise (see [Heartbeat Ping URL Logic](https://github.com/aelassas/servy/wiki/Health-Monitoring-&-Recovery#heartbeat-ping-url-logic)). - **Stability Check:** Servy compares the current time against the time the `restartAttempts` counter was last written. - **Persistence Reset:** If the duration exceeds the **Adaptive Stability Window**, the persistent `restartAttempts` counter is reset to `0`. 3. **IF UNHEALTHY:** - **Transient Increment:** The memory-based `_failedChecks` counter increments. - **Threshold Check:** If `_failedChecks < MaxFailedChecks`, the cycle ends (waiting for the next heartbeat). - **Gatekeeper Check:** If the threshold is met, Servy checks if a recovery is already in progress (`_isRecovering`). If true, the cycle ends to prevent overlapping recovery actions. 4. **RECOVERY ORCHESTRATION:** - **Failure Signal:** If `EnableHeartbeatUrlFlags` is enabled, Servy sends a `/fail` HTTP GET ping to `HeartbeatUrl`. - **Quota Check:** Servy reads the persistent `restartAttempts` counter from the Servy host service. - **Failure State:** If `restartAttempts >= MaxRestartAttempts`, the recovery limit is reached. Servy executes the `FailureProgram` (if configured) and **stops the service** to allow for manual intervention. - **Action State:** If the limit is not reached: - Increment the persistent `restartAttempts` counter. The host stamps the write with the current UTC time. - Set `_isRecovering = true`. - Execute the configured `RecoveryAction` (Restart Process, Service, or Computer). - **Reboot Persistence:** If the action was `RestartComputer`, the persistent timestamp is kept in `Servy.db`. Upon system reboot, the "Stability Check" (Step 2) will see the recent timestamp and preserve the failure count, preventing a reboot loop. ### Reboot Detection Example Consider a service configured with: - **Heartbeat Interval**: 10 seconds - **Max Failed Checks**: 3 - **Max Restart Attempts**: 3 - **Recovery Action**: `RestartComputer` - **Failure Program**: `C:\Apps\FailureHandler.exe` #### Timeline **Session 1: First crash sequence** 1. **12:00** Service starts normally. `restartAttempts = 0` 2. **12:05** Service crashes repeatedly and exceeds `MaxFailedChecks` - Servy triggers `RestartComputer` - `restartAttempts` is incremented to 1 and persisted - `restartAttempts` increments before attempting the recovery action 3. **12:06** System reboots **Session 2: Second crash sequence** 4. **12:10** Windows finishes reboot. Servy starts automatically - Loads `restartAttempts = 1` - The counter was last written before the current OS boot time, reboot detection prevents reset 5. **12:15** Service crashes again - Servy triggers `RestartComputer` - `restartAttempts` increments to 2 6. **12:16** System reboots again **Session 3: Third crash sequence** 7. **12:20** Windows finishes reboot. Servy starts automatically - Loads `restartAttempts = 2` 8. **12:25** Service crashes - Servy triggers `RestartComputer` - `restartAttempts` increments to 3 9. **12:26** System reboots again **Session 4: Fourth crash sequence** 10. **12:30** Windows finishes reboot. Servy starts automatically - Loads `restartAttempts = 3` (already reached `MaxRestartAttempts`) 11. **12:35** Service crashes again - Servy sees that `restartAttempts` has reached the `MaxRestartAttempts` limit - Recovery action is not executed - Configured failure program is executed (`C:\Apps\FailureHandler.exe`) - Servy stops the service to prevent infinite reboot loops #### Key Points - `restartAttempts` persists across reboots. Each reboot increments it only once per recovery action - `MaxRestartAttempts` limit prevents endless reboot loops - After reaching the limit, Servy runs the failure program if configured and stops the service - Operators can manually intervene after the fourth crash ### Service Restart Detection Example Consider a service configured with: - **Heartbeat Interval**: 10 seconds - **Max Failed Checks**: 3 - **Max Restart Attempts**: 3 - **Recovery Action**: `RestartService` - **Failure Program**: `C:\Apps\FailureHandler.exe` #### Timeline **Session 1: First crash sequence** 1. **12:00** Service starts normally. `restartAttempts = 0` 2. **12:05** Service crashes repeatedly and exceeds `MaxFailedChecks` - Servy triggers `RestartService` - `restartAttempts` is incremented to 1 and persisted - `restartAttempts` increments before attempting the recovery action 3. **12:06** Service successfully restarts **Session 2: Second crash sequence** 4. **12:10** Service crashes again - Servy triggers `RestartService` - `restartAttempts` increments to 2 5. **12:11** Service successfully restarts **Session 3: Third crash sequence** 6. **12:15** Service crashes again - Servy triggers `RestartService` - `restartAttempts` increments to 3 7. **12:16** Service successfully restarts **Session 4: Fourth crash sequence** 8. **12:20** Service crashes again - Servy sees that `restartAttempts` has reached the `MaxRestartAttempts` limit - Recovery action is **not** executed - Configured failure program is executed (`C:\Apps\FailureHandler.exe`) - Servy stops the service to prevent endless restart loops --- # Document: Environment Variables > Source: https://github.com/aelassas/servy/wiki/Environment-Variables ## Table of Contents 1. [Introduction](https://github.com/aelassas/servy/wiki/Environment-Variables#introduction) 1. [Environment Variable Expansion](https://github.com/aelassas/servy/wiki/Environment-Variables#environment-variable-expansion) 1. [GUI](https://github.com/aelassas/servy/wiki/Environment-Variables#gui) 1. [CLI Option: `--envVars`](https://github.com/aelassas/servy/wiki/Environment-Variables#cli-option---envvars) 1. [CLI Example](https://github.com/aelassas/servy/wiki/Environment-Variables#cli-example) 1. [PowerShell Option: `-EnvVars`](https://github.com/aelassas/servy/wiki/Environment-Variables#powershell-option--envvars) 1. [PowerShell Example](https://github.com/aelassas/servy/wiki/Environment-Variables#powershell-example) 1. [Tips](https://github.com/aelassas/servy/wiki/Environment-Variables#tips) ## Introduction Servy allows you to define **environment variables** for the service process, enabling fine-grained control over the runtime context. **Environment variable expansion** is supported in multiple areas of Servy configuration: - Service **binary paths** (`--path` / `-Path`) - **Startup directories** (`--startupDir` / `-StartupDir`) - **Process parameters** (`--params` / `-Params`) - **Environment variables** (`--envVars` / `-EnvVars`) This makes it possible to reference existing system variables, user-defined variables, or paths dynamically in your configuration. > [!NOTE] > All hooks inherit the **main service's** `EnvironmentVariables` except `Pre-Launch` hook. There is no separate `Post-Launch / Pre-Stop / Post-Stop / Failure-Program EnvironmentVariables` setting - only `Pre-Launch` supports a per-hook override. ## Environment Variable Expansion Servy uses a sophisticated expansion engine that allows variables to reference each other. The resolution follows this specific order: 1. **System Environment:** All current system and process environment variables are loaded first. Since v10.2, the service first brings them up to date with the System variables in the registry (`HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Environment`), so a System variable **added, changed or removed** in Windows is seen without restarting the machine - see the note below. 2. **Custom Overrides:** Variables defined in the **Environment Variables** field (or `--envVars`) are added next. If a custom variable has the same name as a system variable, the **custom value wins**. 3. **Cross-Reference Expansion:** Finally, all variables are scanned for `%VAR%` placeholders. These placeholders are resolved using the final merged set of variables. > [!NOTE] > **New, changed and removed System variables (v10.2+).** Windows gives a process its environment when it starts, and a Windows service inherits the environment of the Service Control Manager, which is only built when the machine starts. Since v10.2, whenever Servy expands a `%VAR%` placeholder - in the paths, startup directories, parameters and environment variables above - it first reads the System variables from the registry and applies what changed. The read is read-only and needs no administrator rights, so it works for the service under any account and for the Desktop App, Servy Manager and the CLI alike. > > - **The service** (`Servy.Service.exe`): every System variable takes its current registry value, so an added, changed or removed variable reaches the service and its process the next time the service (or a hook) starts its process - restarting the service is enough, the machine does not need a restart. A variable also defined as a **User** variable of the service account keeps the User value, as in Windows, and `Path` is the System `Path` followed by the user's. > - **The Desktop App, Servy Manager and the CLI**: the System variables are recorded when the app starts. A variable added later is picked up; a variable changed or removed later is picked up as long as the app still holds the value it started with. A value the app got from a **User** variable, or from the program or console that started it, is kept. > - Variables Windows sets per account (such as `USERNAME`, `USERPROFILE`, `APPDATA`) are never taken from the System key. User variables changed after start are not picked up; restart the app for those. ### Protected Variables For security reasons, Servy restricts `--envVars` / `-EnvVars` and `--preLaunchEnv` / `-PreLaunchEnv` from overriding a core set of variables that would otherwise enable privilege escalation, runtime injection (DLL/JIT profiler hijacking, debugger probes, search-path attacks, etc.), or process hijacking. While a user with sufficient privileges to install services already has full system access, blocking overrides of protected variables provides an additional layer of safety, improves auditability, and helps prevent unintended side effects. If an attacker has enough privileges to compromise the system, they are forced to make changes through standard Windows administration tools that trigger standard system logs and EDR alerts. **They cannot use Servy as a silent, stealthy mechanism for local process injection or persistence.** Variables are divided into two distinct security tiers: 1. **Immutable Core System Variables (Tier 1):** Essential operating system integrity boundaries that **can never be overridden** under any circumstances. 2. **Overridable Runtime Variables (Tier 2):** Application, framework, and diagnostic variables blocked by default to prevent injection, but which can be overridden on a per-service basis if explicitly permitted by configuration policy (`AllowOverriddenRuntimeVars`). The setting applies to the main process and to every hook (pre-launch, post-launch, pre-stop, post-stop and the failure program), including the pre-launch environment variables. Any attempt to override a blocked variable is ignored **each time the service starts** (during environment-variable expansion), and a warning is recorded in `%ProgramData%\Servy\logs\services\\Servy.Service.log`: ```text Security: Blocked an attempt to override protected runtime variable 'JAVA_OPTS'. Custom values for this variable are ignored to prevent runtime injection. Enable 'AllowOverriddenRuntimeVars' in service settings to allow this override. ``` A Tier 1 variable is always ignored, with this warning: ```text Security: Blocked an attempt to override immutable system variable 'PATH'. Custom values for this variable are ignored to prevent core OS instability or privilege escalation. ``` #### Tier 1: Immutable Core System Variables (Never Overridable) These variables protect core Windows operating system paths, shell binaries, profile identity scopes, and security policy boundaries. They remain strictly untouchable regardless of configuration settings: | Category | Environment Variables | Security / Integrity Purpose | | --- | --- | --- | | **System Integrity** | `PATH`, `COMSPEC`, `SYSTEMROOT`, `WINDIR`, `SYSTEMDRIVE`, `TEMP`, `TMP`, `PATHEXT`, `PROGRAMFILES`, `PROGRAMFILES(X86)`, `PROGRAMW6432`, `COMMONPROGRAMFILES`, `COMMONPROGRAMFILES(X86)`, `COMMONPROGRAMW6432` | Protects core operating system paths, shell execution binaries, executable extension resolution rules, and system-wide temporary layout storage areas from redirection or manipulation. | | **Profile & Identity Redirection** | `APPDATA`, `LOCALAPPDATA`, `PUBLIC`, `HOMEDRIVE`, `HOMEPATH`, `HOME`, `USERDOMAIN`, `USERDOMAIN_ROAMINGPROFILE`, `LOGONSERVER` | Prevents the malicious redirection of active user profile locations, local cache repositories, home path scopes, or domain network logons which could allow credential harvesting or state poisoning. | | **User & Profile Integrity** | `USERNAME`, `USERPROFILE`, `ALLUSERSPROFILE`, `PROGRAMDATA`, `PSMODULEPATH` | Safeguards system configuration and initialization boundaries, tracking contexts, and default PowerShell utility module path discovery scopes from arbitrary interference. | | **Windows AppCompat & Symbol Debugging** | `__COMPAT_LAYER`, `SHIM_FILE_LOG`, `SHIM_DEBUG_LEVEL`, `_NT_SYMBOL_PATH`, `_NT_ALT_SYMBOL_PATH`, `_NT_SOURCE_PATH`, `MICROSOFT_TELEMETRY_ENV_OVERRIDE` | Hardens execution trees against debugging diagnostics vectors, system symbol repository redirections, and application compatibility shim injection layer techniques. | | **Global / Unix Compatibility** | `LD_PRELOAD`, `LD_LIBRARY_PATH`, `LD_AUDIT` | Controls dynamic tracking or link-editor behaviors within Unix compatibility frameworks, MinGW subsystems, WSL boundaries, or Cygwin sandboxes to stop arbitrary binary instrumentation. | | **PowerShell Hardening Bypass** | `__PSLockDownPolicy`, `PSExecutionPolicyPreference` | Mitigates unauthorized administrative policy changes at process initialization by blocking programmatic overrides targeting Windows execution restrictions or the system LanguageMode. | #### Tier 2: Overridable Runtime Variables (Blocked by Default) These variables control framework execution options, classpaths, diagnostic attaches, and runtime environments. They are blocked by default to prevent runtime injection, but can be unlocked on a per-service basis: | Category | Environment Variables | Security / Integrity Purpose | | --- | --- | --- | | **.NET Runtime Injection & Diagnostics** | `COR_ENABLE_PROFILING`, `COR_PROFILER`, `COR_PROFILER_PATH`, `CORECLR_ENABLE_PROFILING`, `CORECLR_PROFILER`, `CORECLR_PROFILER_PATH`, `DOTNET_STARTUP_HOOKS`, `DOTNET_ROOT`, `DOTNET_ROOT(x86)`, `DOTNET_HOST_PATH`, `DOTNET_BUNDLE_EXTRACT_BASE_DIR`, `DOTNET_ADDITIONAL_DEPS`, `DOTNET_SHARED_STORE`, `DOTNET_DiagnosticPorts`, `COMPlus_DiagnosticPorts`, `DOTNET_EnableDiagnostics`, `COMPlus_EnableDiagnostics`, `DOTNET_EnableDiagnostics_IPC`, `COMPlus_EnableDiagnostics_IPC`, `DOTNET_EnableDiagnostics_Profiler`, `COMPlus_EnableDiagnostics_Profiler`, `DOTNET_EnableEventPipe`, `COMPlus_EnableEventPipe`, `DOTNET_GCName`, `COMPlus_GCName`, `DOTNET_GCPath`, `COMPlus_GCPath`, `DOTNET_LegacyHostPolicy`, `COMPlus_LegacyHostPolicy`, `DOTNET_LegacyTransform`, `COMPlus_LegacyTransform`, `DOTNET_PerfMapEnabled`, `COMPlus_PerfMapEnabled`, `DOTNET_ZapDisable`, `COMPlus_ZapDisable`, `DOTNET_DbgEnableMiniDump`, `COMPlus_DbgEnableMiniDump`, `DOTNET_DbgMiniDumpName`, `COMPlus_DbgMiniDumpName`, `DOTNET_DbgMiniDumpType`, `COMPlus_DbgMiniDumpType` | Shuts down execution hijacking and process attachment pathways targeting legacy, modern, and cross-compiled `.NET`/`CoreCLR` runtimes. This blocks unauthorized remote diagnostic socket endpoint exposure (`DiagnosticPorts`), runtime profiler/assembly DLL injection setups, custom Garbage Collector (`GCPath`) hijacking vectors, and the redirection of sensitive process memory dumps (`DbgMiniDumpName`) to insecure disk areas. | | **Java Injection** | `JAVA_TOOL_OPTIONS`, `_JAVA_OPTIONS`, `JDK_JAVA_OPTIONS`, `JAVA_OPTS`, `JAVA_OPTIONS`, `CATALINA_OPTS`, `CATALINA_JAVA_OPTS`, `MAVEN_OPTS`, `M2_OPTS`, `GRADLE_OPTS`, `ANT_OPTS`, `JBOSS_JAVA_OPTS`, `WILDFLY_OPTS`, `CLASSPATH`, `JAVA_HOME`, `JRE_HOME`, `JDK_HOME` | Blocks execution exploits (such as malicious `-javaagent` arguments) loaded through native JVM diagnostics (`java.exe` launcher flags) or shell-wrapper scripts commonly deployed in enterprise application frameworks like Tomcat, JBoss, Maven, and Gradle. | | **Node.js & NPM Injection** | `NODE_OPTIONS`, `NODE_PATH`, `NODE_EXTRA_CA_CERTS`, `NPM_CONFIG_PREFIX`, `NPM_CONFIG_USERCONFIG`, `NPM_CONFIG_GLOBALCONFIG` | Defends Node.js runtime instances against preload option injections, local dependency resolution adjustments, rogue Certificate Authority additions (preventing Man-In-The-Middle traffic decryption), and npm registry config tampering. | | **TLS Trust Store & OpenSSL Configuration** | `OPENSSL_CONF`, `OPENSSL_MODULES`, `SSL_CERT_FILE`, `SSL_CERT_DIR`, `REQUESTS_CA_BUNDLE`, `CURL_CA_BUNDLE`, `HTTP_PROXY`, `HTTPS_PROXY`, `ALL_PROXY`, `NO_PROXY` | Prevents arbitrary code execution via OpenSSL dynamic engine/provider module loading (`OPENSSL_CONF`, `OPENSSL_MODULES`), blocks silent Man-In-The-Middle (MITM) traffic decryption by preventing malicious overriding or swapping of trusted CA certificate bundles, and stops outbound HTTP/HTTPS network traffic redirection through attacker-controlled proxies. | | **Python Injection** | `PYTHONSTARTUP`, `PYTHONPATH`, `PYTHONHOME`, `PYTHONUSERBASE`, `PYTHONEXECUTABLE` | Prevents arbitrary script parsing or site-package source location hijacking through specialized system initialization hooks, site library layout directories, or custom interpreter path redirections. | | **Ruby & Perl Injection** | `RUBYOPT`, `RUBYLIB`, `PERL5OPT`, `PERL5LIB`, `PERLLIB` | Disallows option mapping switches and internal code inclusion path manipulations within local Ruby and Perl execution setups. | | **PHP Injection** | `PHPRC`, `PHP_INI_SCAN_DIR` | Blocks attackers from supplying custom configuration directives or dynamically scanning arbitrary directories for malicious extension modules via modified initialization file search paths. | #### Overriding Tier 2 Runtime Variables If your application requires custom runtime options (such as custom heap memory limits in `JAVA_OPTS` or `CATALINA_OPTS` for Apache Tomcat), you can explicitly permit Tier 2 overrides for the service: - **Desktop Configurator UI:** Navigate to the **Advanced** tab -> check **Allow Overridden Runtime Environment Variables (e.g., JAVA_HOME, JAVA_OPTS)**. The **See list of runtime variables.** link below it opens this section. - **CLI:** Pass the `--allowOverriddenRuntimeVars` flag when installing the service (to change the setting on an existing service, run `install` again): ```cmd servy-cli install --name="TomcatService" --path="cmd.exe" --params="/c C:\Tomcat\bin\catalina.bat run" --envVars="JAVA_HOME=C:\JDK21;CATALINA_OPTS=-Xmx2048m" --allowOverriddenRuntimeVars ``` - **PowerShell:** Pass the `-AllowOverriddenRuntimeVars` switch to `Install-ServyService`. - **Import/Export:** Set `AllowOverriddenRuntimeVars` to `true` in the XML or JSON configuration (see [Export/Import Services](https://github.com/aelassas/servy/wiki/Export-Import-Services)). When enabled, Servy logs an audit record (Info level) for each overridden variable every time the service's process or one of its hooks is started, confirming that the runtime variable override was explicitly authorized: ```text Security Audit: Override for protected runtime variable 'CATALINA_OPTS' permitted by service policy configuration. ``` > [!NOTE] > Tier 1 Core System Variables (such as `PATH`, `SYSTEMROOT`, or `COMSPEC`) remain strictly protected and cannot be overridden even when `AllowOverriddenRuntimeVars` is enabled. If you need to extend `PATH` for a service, modify the System environment variables or reference custom paths directly in process parameters. ### Example of Expansion Logic If your system has `TEMP=C:\Windows\Temp` and you define: - `MY_ROOT=C:\ServyApp` - `MY_LOGS=%MY_ROOT%\logs` - `APP_TEMP=%TEMP%` The final environment seen by your process will be: - `MY_ROOT`: `C:\ServyApp` - `MY_LOGS`: `C:\ServyApp\logs` - `APP_TEMP`: `C:\Windows\Temp` > [!NOTE] > **Variable Ordering and Circular References:** > Variables are resolved using a multi-pass fixed-point algorithm, so the **order in which you define them does not matter** - `MY_LOGS=%MY_ROOT%\logs` resolves correctly even if `MY_ROOT` is defined later in the list. The expansion engine runs up to 5 passes (`AppConfig.MaxEnvVarExpansionPasses`); chains deeper than that will leave unresolved `%VAR%` placeholders with **no warning logged** - the loop exits silently once the pass cap is reached while values are still changing. > > **Avoid circular references:** > - **Self-reference** (`A=%A%`): caught as soon as the expansion engine encounters a value that contains its own `%NAME%` token. Logged as `Direct cycle detected for variable 'A'; leaving literal placeholder.` and the placeholder is left literal (unless the OS already exports a value for `A`, in which case the inherited value is substituted to mimic Windows `PATH`-append semantics). > - **Multi-variable cycles** (`A=%B%`, `B=%A%`, or longer chains like `A=%B%`, `B=%C%`, `C=%A%`): not detected by a dedicated check. Two-variable or indirect cycles typically degenerate into a direct self-reference (`%A%` inside `A`) during intermediate resolution and surface as `Direct cycle detected for variable 'A'` on a subsequent pass. If a cycle does not degenerate within 5 passes, resolution halts silently when the pass limit is reached, leaving the remaining `%VAR%` placeholders intact in the expanded environment. ## GUI The advanced tab in Servy allows setting environment variables for the service process: servy-config-advanced ## CLI Option: `--envVars` The `--envVars` command-line option lets you specify environment variables for the service process. - **Syntax:** `--envVars="VAR1=value1; VAR2=value2"` - Separate multiple variables with **semicolons (;)** - Special characters can be escaped: - `\=` to escape `=` - `\"` to escape `"` - `\;` to escape `;` - `\\` to escape `\` - `%%` to escape `%` (collapses to a single `%`, matching `cmd.exe` behaviors) (starting from v8.5+) - Supports environment variable expansion. Example: `--envVars="VAR1=%ProgramData%\MyApp; VAR2=%VAR1%\bin; CHANCE=100%%"` - Useful for setting runtime context without changing system-wide environment variables. ## CLI Example ```powershell servy-cli install ` --name="MyNodeService" ` --description="My NodeJS Server" ` --path="%ProgramFiles%\nodejs\node.exe" ` --startupDir="C:\Apps\App" ` --params="C:\Apps\App\index.js" ` --startupType="Automatic" ` --envVars="NODE_ENV=production; APP_CONFIG=C:\Apps\App\config.json" ``` ## PowerShell Option: `-EnvVars` The `-EnvVars` parameter lets you define environment variables when installing a service via PowerShell. - **Type:** `string` (semicolon-separated list, optional) - Apply the same escaping rules as the CLI. - Multiple variables are separated with **semicolons (;)** - Variables are applied **only to the service process**, not system-wide. ## PowerShell Example ```powershell Import-Module "C:\Program Files\Servy\Servy.psm1" -Force $installParams = @{ Name = "MyNodeService" Description = "My NodeJS Server" Path = "C:\Program Files\nodejs\node.exe" StartupDir = "C:\Apps\App" Params = "C:\Apps\App\index.js" StartupType = "Automatic" EnvVars = "NODE_ENV=production; APP_CONFIG=C:\Apps\App\config.json" } Install-ServyService @installParams ``` ## Tips - **Case Insensitivity:** Environment variable names are case-insensitive. Defining `node_env` will correctly override an existing `NODE_ENV`. - **Expansion Order:** You can reference both existing system variables (like `%ProgramData%`) and other custom variables defined in the same list. - **Safe Percent Escaping:** To pass a literal percent character into your environment safely and prevent it from being processed as an expansion block, use a double percent sign (`%%`). For example, defining `ALERT_MSG=Battery at 100%%` will expand correctly to `Battery at 100%` inside the service process. - **Verification:** To troubleshoot, if you aren't sure if your variables are applying correctly, run this to dump the environment to a file (PowerShell Admin): ```powershell servy-cli install --name="EnvTest" --startupType="Manual" --path="C:\Windows\System32\cmd.exe" --params="/c set > C:\servy_env.txt && timeout /t 3600 /nobreak > nul" --envVars="MY_ROOT=C:\ServyApp; MY_LOGS=%MY_ROOT%\logs" servy-cli restart --name="EnvTest" Start-Sleep -Seconds 3 Get-Content C:\servy_env.txt | Select-String "MY_LOGS" # Clean up when you are done servy-cli uninstall --name="EnvTest" ``` --- # Document: Service Dependencies > Source: https://github.com/aelassas/servy/wiki/Service-Dependencies ## Table of Contents 1. [Introduction](https://github.com/aelassas/servy/wiki/Service-Dependencies#introduction) 1. [GUI](https://github.com/aelassas/servy/wiki/Service-Dependencies#gui) 1. [CLI Option: `--deps`](https://github.com/aelassas/servy/wiki/Service-Dependencies#cli-option---deps) 1. [CLI Example](https://github.com/aelassas/servy/wiki/Service-Dependencies#cli-example) 1. [PowerShell Option: `-Deps`](https://github.com/aelassas/servy/wiki/Service-Dependencies#powershell-option--deps) 1. [PowerShell Example](https://github.com/aelassas/servy/wiki/Service-Dependencies#powershell-example) 1. [Dependency Tree Visualization](https://github.com/aelassas/servy/wiki/Service-Dependencies#dependency-tree-visualization) ## Introduction Servy supports optional service dependencies, allowing a service to start only after one or more other Windows services are running. Enter each service this service depends on by its service name (not the display name) on a new line or separate them with semicolons (`;`). This ensures that your service starts in the correct order and avoids errors if required services are not yet running. ## GUI The advanced tab provides additional configuration options such as service dependencies. servy-config-advanced ## CLI Option: `--deps` The `--deps` command-line option lets you specify one or more Windows service dependencies when installing a service via the CLI. * **Syntax:** `--deps="Service1; Service2; Service3"` * Windows starts the listed services first (automatic-start dependencies are started on demand); if any dependency fails to start or is disabled, the service will not start. * Multiple dependencies can be separated with **semicolons**. * This is especially useful for applications that rely on databases, message brokers, or other background services. ## CLI Example ```powershell servy-cli install ` --name="MyNodeService" ` --description="My NodeJS Server" ` --path="C:\Program Files\nodejs\node.exe" ` --startupDir="C:\Apps\App" ` --params="C:\Apps\App\index.js" ` --startupType="Automatic" ` --deps="MongoDB; MySQL80" ``` ## PowerShell Option: `-Deps` The `-Deps` parameter lets you specify one or more Windows service dependencies when installing a service via PowerShell. * **Type:** `string` (semicolon-separated list, optional) * Windows starts the listed services first (Automatic-start dependencies are started on demand); if any dependency fails to start or is disabled, the service will not start. * Multiple dependencies can be separated with **semicolons**. * Useful for services that rely on databases, message brokers, or other background services. ## PowerShell Example ```powershell Import-Module "C:\Program Files\Servy\Servy.psm1" -Force $installParams = @{ Name = "MyNodeService" Description = "My NodeJS Server" Path = "C:\Program Files\nodejs\node.exe" StartupDir = "C:\Apps\App" Params = "C:\Apps\App\index.js" StartupType = "Automatic" Deps = "MongoDB; MySQL80" } Install-ServyService @installParams ``` ## Dependency Tree Visualization The Dependencies tab in Servy Manager provides a visual representation of a service dependency tree retrieved from the Service Control Manager (SCM). Each dependency is displayed with its current status: a green gear for a running service, a red gear for a service that is not running, an orange circular-arrows icon for a dependency that already appears higher in the same branch (a cycle, where the branch stops), and an orange warning icon for a dependency that could not be resolved or accessed, for example a missing service or one the current account cannot query. An unavailable node shows the error in place of the service's display name. The tree can be refreshed at any time using the Refresh button or by pressing **F5**. This view is especially useful for understanding startup and shutdown order, diagnosing why a service fails to start, and quickly identifying stopped or missing dependencies that may impact service availability. servy-manager-dependencies > [!TIP] > You can combine service dependencies with pre-launch scripts and health checks to ensure that your service starts reliably in complex environments. --- # Document: Export / Import Services > Source: https://github.com/aelassas/servy/wiki/Export-Import-Services ## Table of Contents 1. [Introduction](https://github.com/aelassas/servy/wiki/Export-Import-Services#introduction) 1. [Export](https://github.com/aelassas/servy/wiki/Export-Import-Services#export) 1. [GUI](https://github.com/aelassas/servy/wiki/Export-Import-Services#gui) 1. [CLI](https://github.com/aelassas/servy/wiki/Export-Import-Services#cli) 1. [PowerShell](https://github.com/aelassas/servy/wiki/Export-Import-Services#powershell) 1. [Import](https://github.com/aelassas/servy/wiki/Export-Import-Services#import) 1. [Security Note](https://github.com/aelassas/servy/wiki/Export-Import-Services#security-note) 1. [Format](https://github.com/aelassas/servy/wiki/Export-Import-Services#format) 1. [XML Sample](https://github.com/aelassas/servy/wiki/Export-Import-Services#xml-sample) 1. [JSON Sample](https://github.com/aelassas/servy/wiki/Export-Import-Services#json-sample) 1. [GUI](https://github.com/aelassas/servy/wiki/Export-Import-Services#gui-1) 1. [CLI](https://github.com/aelassas/servy/wiki/Export-Import-Services#cli-1) 1. [PowerShell](https://github.com/aelassas/servy/wiki/Export-Import-Services#powershell-1) ## Introduction Servy supports exporting and importing service configurations through the GUI, the CLI, and the PowerShell module. All services created via Servy, whether through the GUI, CLI, or PowerShell, are stored in a dedicated SQLite database. The GUI can export both registered and non-registered services. The CLI and PowerShell module can export only services already registered in the Servy database. The database is located at: ```text %ProgramData%\Servy\db\Servy.db ``` Passwords are securely encrypted using AES with a key protected via Windows DPAPI. You can find more details on the [Security](https://github.com/aelassas/servy/wiki/Security) page. > [!IMPORTANT] > Passwords are not included in exports, but other sensitive fields like Parameters and EnvironmentVariables may still be present. Always handle exported files securely. Do not share them publicly, commit them to source control, or leave them in unprotected locations. Consider encrypting these files or restricting access to ensure they remain confidential. ## Export Password and UserAccount fields are not exported; re-enter them after import for security reasons. ### GUI * Open Servy * Fill your service configuration * Click on **Export** menu on the top left * Choose your export format (XML or JSON) * Specify the export file path and confirm ### CLI * Run the following command to export in XML format: ```cmd servy-cli export --name="MyRegisteredService" --config="xml" --path="C:\MyRegisteredService.xml" ``` * Run the following command to export in JSON format: ```cmd servy-cli export --name="MyRegisteredService" --config="json" --path="C:\MyRegisteredService.json" ``` If the specified service is not found in Servy's database, the CLI will terminate with an exit code of 1. ### PowerShell * Import Servy PowerShell module: ```powershell Import-Module "C:\Program Files\Servy\Servy.psm1" -Force ``` * Run the following script to export in XML format: ```powershell $exportParamsXml = @{ Name = "MyRegisteredService" ConfigFileType = "Xml" Path = "C:\MyRegisteredService.xml" } Export-ServyServiceConfig @exportParamsXml ``` * Run the following script to export in JSON format: ```powershell $exportParamsJson = @{ Name = "MyRegisteredService" ConfigFileType = "Json" Path = "C:\MyRegisteredService.json" } Export-ServyServiceConfig @exportParamsJson ``` If the specified service is not found in Servy's database, the PowerShell cmdlet will **throw an error**. You can handle this using `try/catch` to check for failure, similar to how the CLI exits with exit code 1. ## Import > [!NOTE] > If a password and user are needed, they must be re-entered after import. ### Security Note > [!CAUTION] > **Infiltration Guard: Local Import Enforcement** > > Importing service configurations from Universal Naming Convention (UNC) paths or through redirected paths (such as symbolic links, junctions, or mapped network drives) poses severe security risks, including attacker-controlled configuration injection, path redirection exploits, and privilege escalation. > > To preserve system integrity, the import pipeline explicitly blocks non-local paths using a multi-layered validation chain that inspects explicit UNC prefixes, queries drive interfaces, walks reparse point ancestors, evaluates file-level symlinks, blocks reserved device names, enforces protected directory boundaries, and verifies the canonical handle via `GetFinalPathNameByHandle`. > > For full technical details on these attack vectors and the defensive validation pipeline, see [Infiltration Guard: Local Import Enforcement](https://github.com/aelassas/servy/wiki/Security#infiltration-guard-local-import-enforcement) on the Security page. ### Format You can import service configurations in XML or JSON formats. Only the **Name** and **ExecutablePath** fields are required; all others are optional. #### Fields | Field | Type | Required | Description | |-------|------|----------|-------------| | Name | string | **Yes** | The unique name of the service. | | DisplayName | string? | No | The human-readable name shown in the Windows Services console. If empty, the service name is used. | | Description | string? | No | Optional description of the service. | | ExecutablePath | string | **Yes** | Path to the executable of the service. | | StartupDirectory | string? | No | Optional startup directory for the service executable. | | Parameters | string? | No | Optional parameters to pass to the service executable. | | StartupType | int? | No | Startup type of the service (integer value from [StartupType](https://github.com/aelassas/servy/wiki/Export-Import-Services#startuptype) table). | | Priority | int? | No | Process priority of the service (integer value from [Priority](https://github.com/aelassas/servy/wiki/Export-Import-Services#priority) table). | | CpuAffinity | string? | No | Logical CPUs the process may run on, as a core list/range or hex mask (e.g. `0-3,8` or `0xFF00`). | | StdoutPath | string? | No | Optional path for the standard output log. | | StderrPath | string? | No | Optional path for the standard error log. | | StartTimeout | int? | No | The timeout in seconds to wait for the process to start successfully before considering the startup as failed (range: `1`-`86400`). | | StopTimeout | int? | No | The timeout in seconds to wait for the process to exit (range: `1`-`86400`). | | EnableConsoleUI | bool? | No | When true, the wrapped process runs with a visible console window; stdout/stderr redirection is disabled. Default is false. | | EnableSizeRotation | bool? | No | Whether size-based log rotation is enabled. | | RotationSize | int? | No | Maximum size of the log file in Megabytes (MB) before rotation (range: `1`-`10240`). | | EnableDateRotation | bool? | No | Whether date-based log rotation is enabled. | | DateRotationType | int? | No | Date rotation type. (integer value from [DateRotationType](https://github.com/aelassas/servy/wiki/Export-Import-Services#daterotationtype) table). | | UseLocalTimeForRotation | bool? | No | Whether to use local server time for log rotation instead of UTC. Default is false (UTC). | | MaxRotations | int? | No | Max log files to keep (range: `0`-`10000`; `0` = unlimited). | | EnableDebugLogs | bool? | No | Whether to enable debug logs in the local log file. Not recommended on production environments, as these logs may contain sensitive data. | | EnableHealthMonitoring | bool? | No | Whether health monitoring is enabled. | | HeartbeatInterval | int? | No | Heartbeat interval in seconds for health monitoring (range: `5`-`86400`). | | MaxFailedChecks | int? | No | Maximum number of consecutive failed health checks before triggering recovery (range: `1`-`100000`). | | RecoveryAction | int? | No | Recovery action (integer value from [RecoveryAction](https://github.com/aelassas/servy/wiki/Export-Import-Services#recoveryaction) table). | | RecoveryOnCleanExit | bool? | No | Whether to trigger the recovery action even when the wrapped process exits with a clean (zero) exit code. Default is `false`. (Available since 8.4) | | MaxRestartAttempts | int? | No | Maximum number of restart attempts if the service fails (range: `0`-`100000`; `0` = unlimited, which bypasses the failure program - see [Health Monitoring & Recovery](https://github.com/aelassas/servy/wiki/Health-Monitoring-&-Recovery)). | | HeartbeatUrl | string? | No | Absolute URL for out-of-band diagnostic heartbeat pings. | | HeartbeatUrlTimeoutSeconds | int? | No | Timeout in seconds for the heartbeat URL request (range: `2`-`30`). | | EnableHeartbeatUrlFlags | bool? | No | Append /start and /fail lifecycle suffixes to heartbeat URL pings. | | FailureProgramPath | string? | No | Optional path to the process to run on failure. | | FailureProgramStartupDirectory | string? | No | Optional working directory for the failure program. | | FailureProgramParameters | string? | No | Optional command-line parameters for the failure program. | | EnvironmentVariables | string? | No | Optional environment variables, in `key=value` format separated by semicolons. | | AllowOverriddenRuntimeVars | bool? | No | Whether the environment variables may override protected runtime (Tier 2) variables such as `JAVA_HOME` or `JAVA_OPTS` (see [Protected Variables](https://github.com/aelassas/servy/wiki/Environment-Variables#protected-variables)). Defaults to `false`. | | ServiceDependencies | string? | No | Optional names of the services this service depends on, separated by semicolons. | | PreLaunchExecutablePath | string? | No | Optional path to an executable that runs before the service starts. | | PreLaunchStartupDirectory | string? | No | Optional startup directory for the pre-launch executable. | | PreLaunchParameters | string? | No | Optional parameters for the pre-launch executable. | | PreLaunchEnvironmentVariables | string? | No | Optional environment variables for the pre-launch executable, in `key=value` format. | | PreLaunchStdoutPath | string? | No | Optional path for the pre-launch executable's standard output log. | | PreLaunchStderrPath | string? | No | Optional path for the pre-launch executable's standard error log. | | PreLaunchTimeoutSeconds | int? | No | Maximum time in seconds to wait for the pre-launch executable to complete (range: `0`-`86400`; `0` = fire-and-forget). | | PreLaunchRetryAttempts | int? | No | Maximum number of retry attempts for the pre-launch executable (range: `0`-`100000`). | | PreLaunchIgnoreFailure | bool? | No | Whether to ignore failure of the pre-launch executable. | | PostLaunchExecutablePath | string? | No | Optional path to an executable that runs after the process starts successfully. | | PostLaunchStartupDirectory | string? | No | Optional startup directory for the post-launch executable. | | PostLaunchParameters | string? | No | Optional parameters for the post-launch executable. | | PreStopExecutablePath | string? | No | Optional path to an executable that runs before the service stops. | | PreStopStartupDirectory | string? | No | Optional startup directory for the pre-stop executable. | | PreStopParameters | string? | No | Optional parameters for the pre-stop executable. | | PreStopTimeoutSeconds | int? | No | Maximum time in seconds to wait for the pre-stop executable to complete (range: `0`-`86400`; `0` = fire-and-forget). | | PreStopLogAsError | bool? | No | Whether to log pre-stop failure as error. | | PostStopExecutablePath | string? | No | Optional path to an executable that runs after the service stops. | | PostStopStartupDirectory | string? | No | Optional startup directory for the post-stop executable. | | PostStopParameters | string? | No | Optional parameters for the post-stop executable. | > [!IMPORTANT] > `UserAccount`, `Password`, and `RunAsLocalSystem` are never exported. On import, any custom identity in the file is **discarded** (the service is reset to a password-less **LocalSystem** baseline) and an informational notice is logged; re-enter the account and password manually after import. `Pid`, `PreviousStopTimeout`, `ActiveStdoutPath`, `ActiveStderrPath`, `RestartAttempts` and `RestartAttemptsUpdatedAtTicks` are silently ignored and cannot be set through an import file. #### StartupType | Value | Name | Description | |-------|-----------|-------------| | 2 | Automatic | The service starts automatically by the Service Control Manager during system startup. | | 3 | Manual | The service must be started manually by the user or an application. | | 4 | Disabled | The service is disabled and cannot be started. | | 5 | AutomaticDelayedStart | The service starts automatically, but with a delay after other auto-start services. | #### Priority | Value | Name | Description | |-------|-------------|-------------| | 0 | Idle | The process runs only when the system is idle and other processes are not using the CPU. This is the lowest priority level. | | 1 | BelowNormal | The process has below normal priority, less than normal but higher than idle. | | 2 | Normal | The process has normal priority, which is the default priority for processes. | | 3 | AboveNormal | The process has above normal priority, higher than normal but lower than high. | | 4 | High | The process has high priority, it receives more CPU time compared to normal priority. | | 5 | RealTime | The process has real-time priority, the highest priority. Use with caution as it can monopolize CPU resources and starve other processes. | #### DateRotationType | Value | Name | Description | |-------|---------|-------------| | 0 | Daily | Rotates the log file once per calendar day (UTC by default; local if `UseLocalTimeForRotation` is true). | | 1 | Weekly | Rotates the log file once per calendar week (UTC by default; local if `UseLocalTimeForRotation` is true; FirstFourDayWeek, Monday as first day; also rotates on 1 January). | | 2 | Monthly | Rotates the log file once per calendar month (UTC by default; local if `UseLocalTimeForRotation` is true). | | 3 | None | Disables date-based rotation. Use this when only size-based rotation is desired. | #### RecoveryAction | Value | Name | Description | |-------|------------------|-------------| | 0 | None | No action will be taken. | | 1 | RestartService | Restart the service. | | 2 | RestartProcess | Restart the process. | | 3 | RestartComputer | Restart the computer. | ### XML Sample ```xml MyTestService My Test Service Sample service for testing import C:\Program Files\TestService\TestService.exe C:\Program Files\TestService -arg1 -arg2 2 1 0-3,8 C:\Logs\TestService_out.log C:\Logs\TestService_err.log 10 5 true 10 false 0 0 false false false true 30 3 1 5 https://hc-ping.com/your-uuid 5 true false C:\Program Files\nodejs\node.exe C:\Apps\Notify C:\Apps\Notify\index.js APP_ENV=production;APP_CONFIG=C:\Apps\App\config.json false ServiceA;ServiceB C:\Program Files\TestService\PreLaunch.exe C:\Program Files\TestService -preArg1 -preArg2 CONFIG=C:\Config;LOGS=C:\Logs C:\Logs\PreLaunch_out.log C:\Logs\PreLaunch_err.log 60 2 true C:\Program Files\TestService\PostLaunch.exe C:\Program Files\TestService -postArg1 -postArg2 C:\Program Files\TestService\PreStop.exe C:\Program Files\TestService -stopArg1 -stopArg2 30 true C:\Program Files\TestService\PostStop.exe C:\Program Files\TestService -stopArg1 -stopArg2 ``` ### JSON Sample ```json { "Name": "MyTestService", "DisplayName": "My Test Service", "Description": "Sample service for testing import", "ExecutablePath": "C:\\Program Files\\TestService\\TestService.exe", "StartupDirectory": "C:\\Program Files\\TestService", "Parameters": "-arg1 -arg2", "StartupType": 2, "Priority": 1, "CpuAffinity": "0-3,8", "StdoutPath": "C:\\Logs\\TestService_out.log", "StderrPath": "C:\\Logs\\TestService_err.log", "StartTimeout": 10, "StopTimeout": 5, "EnableSizeRotation": true, "RotationSize": 10, "EnableDateRotation": false, "DateRotationType": 0, "MaxRotations": 0, "UseLocalTimeForRotation": false, "EnableConsoleUI": false, "EnableDebugLogs": false, "EnableHealthMonitoring": true, "HeartbeatInterval": 30, "MaxFailedChecks": 3, "RecoveryAction": 1, "MaxRestartAttempts": 5, "HeartbeatUrl": "https://hc-ping.com/your-uuid", "HeartbeatUrlTimeoutSeconds": 5, "EnableHeartbeatUrlFlags": true, "RecoveryOnCleanExit": false, "FailureProgramPath": "C:\\Program Files\\nodejs\\node.exe", "FailureProgramStartupDirectory": "C:\\Apps\\Notify", "FailureProgramParameters": "C:\\Apps\\Notify\\index.js", "EnvironmentVariables": "APP_ENV=production;APP_CONFIG=C:\\Apps\\App\\config.json", "AllowOverriddenRuntimeVars": false, "ServiceDependencies": "ServiceA;ServiceB", "PreLaunchExecutablePath": "C:\\Program Files\\TestService\\PreLaunch.exe", "PreLaunchStartupDirectory": "C:\\Program Files\\TestService", "PreLaunchParameters": "-preArg1 -preArg2", "PreLaunchEnvironmentVariables": "CONFIG=C:\\Config;LOGS=C:\\Logs", "PreLaunchStdoutPath": "C:\\Logs\\PreLaunch_out.log", "PreLaunchStderrPath": "C:\\Logs\\PreLaunch_err.log", "PreLaunchTimeoutSeconds": 60, "PreLaunchRetryAttempts": 2, "PreLaunchIgnoreFailure": true, "PostLaunchExecutablePath": "C:\\Program Files\\TestService\\PostLaunch.exe", "PostLaunchStartupDirectory": "C:\\Program Files\\TestService", "PostLaunchParameters": "-postArg1 -postArg2", "PreStopExecutablePath": "C:\\Program Files\\TestService\\PreStop.exe", "PreStopStartupDirectory": "C:\\Program Files\\TestService", "PreStopParameters": "-stopArg1 -stopArg2", "PreStopTimeoutSeconds": 30, "PreStopLogAsError": true, "PostStopExecutablePath": "C:\\Program Files\\TestService\\PostStop.exe", "PostStopStartupDirectory": "C:\\Program Files\\TestService", "PostStopParameters": "-stopArg1 -stopArg2" } ``` ### GUI * Open Servy * Click on **Import** menu on the top left * Choose your import format (XML or JSON) * Choose the file to import If valid, the configuration is displayed in the UI. If the service is installed, the configuration is persisted in the database. If the file is rejected, an error dialog names the reason and nothing is written to the database. ### CLI * Run the following command to import in XML format: ```cmd servy-cli import --config="xml" --path="C:\MyRegisteredService.xml" ``` * Run the following command to import in JSON format: ```cmd servy-cli import --config="json" --path="C:\MyRegisteredService.json" ``` * Run the following command to import an XML and install: ```cmd servy-cli import --config="xml" --path="C:\MyRegisteredService.xml" --install ``` * Run the following command to import a JSON and install: ```cmd servy-cli import --config="json" --path="C:\MyRegisteredService.json" --install ``` If valid, the configuration is saved to the database and the service is installed if `--install` option is supplied. If the file is missing, malformed, blocked by the local-path guard, or contains an invalid field, no service is created and the CLI terminates with an exit code of 1. ### PowerShell * Import Servy PowerShell module: ```powershell Import-Module "C:\Program Files\Servy\Servy.psm1" -Force ``` * Import service configuration from XML: ```powershell Import-ServyServiceConfig -ConfigFileType Xml -Path "C:\MyRegisteredService.xml" ``` * Import service configuration from JSON: ```powershell Import-ServyServiceConfig -ConfigFileType Json -Path "C:\MyRegisteredService.json" ``` * Import service configuration from XML and install the service: ```powershell Import-ServyServiceConfig -ConfigFileType Xml -Path "C:\MyRegisteredService.xml" -Install ``` * Import service configuration from JSON and install the service: ```powershell Import-ServyServiceConfig -ConfigFileType Json -Path "C:\MyRegisteredService.json" -Install ``` If the configuration is valid, it is saved to the Servy database and the service is installed if the `-Install` switch is provided. Under the same conditions the cmdlet throws; wrap the call in `try/catch` as with `Export-ServyServiceConfig`. --- # Document: Pre-Launch & Post-Launch Actions > Source: https://github.com/aelassas/servy/wiki/Pre-Launch-&-Post-Launch-Actions ## Table of Contents 1. [Introduction](https://github.com/aelassas/servy/wiki/Pre-Launch-&-Post-Launch-Actions#introduction) 1. [Startup Hook Lifecycle](https://github.com/aelassas/servy/wiki/Pre-Launch-&-Post-Launch-Actions#startup-hook-lifecycle) 1. [Pre-Launch](https://github.com/aelassas/servy/wiki/Pre-Launch-&-Post-Launch-Actions#pre-launch) 1. [Pre-Launch Settings](https://github.com/aelassas/servy/wiki/Pre-Launch-&-Post-Launch-Actions#pre-launch-settings) 1. [GUI Example](https://github.com/aelassas/servy/wiki/Pre-Launch-&-Post-Launch-Actions#gui-example) 1. [CLI Example](https://github.com/aelassas/servy/wiki/Pre-Launch-&-Post-Launch-Actions#cli-example) 1. [PowerShell Example](https://github.com/aelassas/servy/wiki/Pre-Launch-&-Post-Launch-Actions#powershell-example) 1. [Post-Launch](https://github.com/aelassas/servy/wiki/Pre-Launch-&-Post-Launch-Actions#post-launch) 1. [Post-Launch Settings](https://github.com/aelassas/servy/wiki/Pre-Launch-&-Post-Launch-Actions#post-launch-settings) 1. [GUI Example](https://github.com/aelassas/servy/wiki/Pre-Launch-&-Post-Launch-Actions#gui-example-1) 1. [CLI Example](https://github.com/aelassas/servy/wiki/Pre-Launch-&-Post-Launch-Actions#cli-example-1) 1. [PowerShell Example](https://github.com/aelassas/servy/wiki/Pre-Launch-&-Post-Launch-Actions#powershell-example-1) ## Introduction Servy supports running an optional script or executable before the main service starts. This can be used for tasks like: * Preparing or generating configuration files * Fetching secrets or credentials dynamically * Running any setup or initialization required before the main process Additionally, Servy supports running an optional script or executable after the process starts successfully. This can be used for tasks such as: * Initializing dependent services or processes * Running database migrations or setup scripts * Sending notifications or logging startup events * Performing environment-specific configuration > [!NOTE] > If the pre-launch (or post-launch) script is a PowerShell script (`.ps1`) or any non-executable file, it **must** be invoked through an executable such as `powershell.exe` or `pwsh.exe`. > > For example: > > ```powershell > --preLaunchPath="C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" > --preLaunchParams="-File C:\Scripts\GenerateConfig.ps1 -VaultUrl https://vault.example.com" > ``` > > Directly specifying `--preLaunchPath="C:\Scripts\GenerateConfig.ps1"` **will not work**. ## Startup Hook Lifecycle | Hook Type | Mode | Trigger | Failure Impact | Orphan Cleanup | | :--- | :--- | :--- | :--- | :--- | | **Pre-Launch** | **Synchronous** | Timeout > 0 | Service won't start unless **Ignore Failure** is enabled | Yes | | **Pre-Launch** | **Fire-and-Forget** | Timeout = 0 | Exit code not awaited; a launch failure stops the service unless **Ignore Failure** is enabled | Yes | | **Post-Launch** | **Fire-and-Forget** | Default | Logged, service stays up | Yes | *For shutdown-related hooks, see [Pre-Stop & Post-Stop Actions](https://github.com/aelassas/servy/wiki/Pre-Stop-&-Post-Stop-Actions).* *Servy tracks processes launched during startup to ensure that if the main service crashes, all setup scripts are also terminated.* > [!NOTE] > While a synchronous hook is running, Servy periodically notifies the Windows Service Control Manager that the service is still active, so the SCM's own start timeout does not kill the service while a long-running hook is still within its configured timeout. See `Timing:ScmAdditionalTimeMs` in [Advanced Configuration](https://github.com/aelassas/servy/wiki/Advanced-Configuration#servy-service). ## Pre-Launch ### Pre-Launch Settings * **Pre-Launch Executable Path** - full path to the pre-launch script or executable * **Pre-Launch Startup Directory** - working directory for the pre-launch process (optional; defaults to the main service's working directory) * **Pre-Launch Parameters** - command-line arguments for the pre-launch executable * **Pre-Launch Environment Variables** - optional environment variables for the pre-launch process (same format as main process) * **Pre-Launch Stdout/Stderr File Paths** - log files for capturing output and errors * **Pre-Launch Timeout (seconds)** - maximum allowed time per attempt, set to **0** to run in fire-and-forget mode (default: 30 seconds) * **Pre-Launch Retry Attempts** - number of retries on failure (default: 0) * **Ignore Failure** - if enabled, service startup proceeds even if pre-launch script fails By default, the pre-launch hook runs synchronously with a timeout. If the pre-launch script exits with a non-zero exit code or times out, the service will fail to start unless the **Ignore Failure** option is enabled. Setting the timeout to 0 runs the pre-launch hook in fire-and-forget mode. When set to 0, the hook is started and the service is launched immediately without waiting for completion. Use this only for tasks that do not affect the service's ability to start or run correctly. `stdout`/`stderr` redirection and retries are not available in fire-and-forget mode. The hook's exit code is not awaited in this mode, but if the hook cannot be launched at all, the service still fails to start unless **Ignore Failure** is enabled. Fire-and-forget pre-launch hooks are executed as part of the start sequence and are tracked for orphan cleanup when the service stops. ### GUI Example servy-config-pre-launch ### CLI Example ```powershell servy-cli install ` --name="MyService" ` --description="Runs app with dynamic config" ` --path="C:\Apps\App\App.exe" ` --startupDir="C:\Apps\App" ` --params="--mode=production" ` --preLaunchPath="C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" ` --preLaunchStartupDir="C:\Scripts" ` --preLaunchParams="-File C:\Scripts\GenerateConfig.ps1 -VaultUrl https://vault.example.com" ` --preLaunchEnv="ENV=production;API_KEY=abcdef123" ` --preLaunchStdout="C:\Logs\prelaunch_stdout.log" ` --preLaunchStderr="C:\Logs\prelaunch_stderr.log" ` --preLaunchTimeout="60" ` --preLaunchRetryAttempts="2" ` --preLaunchIgnoreFailure ``` ### PowerShell Example ```powershell Import-Module "C:\Program Files\Servy\Servy.psm1" -Force $installParams = @{ Name = "MyService" Description = "Runs app with dynamic config" Path = "C:\Apps\App\App.exe" StartupDir = "C:\Apps\App" Params = "--mode=production" PreLaunchPath = "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" PreLaunchStartupDir = "C:\Scripts" PreLaunchParams = "-File C:\Scripts\GenerateConfig.ps1 -VaultUrl https://vault.example.com" PreLaunchEnv = "ENV=production;API_KEY=abcdef123" PreLaunchStdout = "C:\Logs\prelaunch_stdout.log" PreLaunchStderr = "C:\Logs\prelaunch_stderr.log" PreLaunchTimeout = 60 PreLaunchRetryAttempts = 2 PreLaunchIgnoreFailure = $true } Install-ServyService @installParams ``` ## Post-Launch ### Post-Launch Settings * **Post-Launch Executable Path** - full path to the post-launch script or executable * **Post-Launch Startup Directory** - working directory for the post-launch process (optional; defaults to the main service's working directory) * **Post-Launch Parameters** - command-line arguments for the post-launch executable **Environment Variables:** This hook inherits the **main service's** `EnvironmentVariables`. There is no separate `Post-Launch / Pre-Stop / Post-Stop / Failure-Program EnvironmentVariables` setting - only `Pre-Launch` supports a per-hook override. The post-launch script is executed after the service process has fully started in fire-and-forget mode. Post-launch hooks run after the service has started and are tracked for orphan cleanup when the service stops. ### GUI Example servy-config-post-launch ### CLI Example ```powershell servy-cli install ` --name="MyService" ` --description="Runs app with dynamic config" ` --path="C:\Apps\App\App.exe" ` --startupDir="C:\Apps\App" ` --params="--mode=production" ` --postLaunchPath="C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" ` --postLaunchStartupDir="C:\Scripts" ` --postLaunchParams="-File C:\Scripts\Notify.ps1 -VaultUrl https://vault.example.com" ``` ### PowerShell Example ```powershell Import-Module "C:\Program Files\Servy\Servy.psm1" -Force $installParams = @{ Name = "MyService" Description = "Runs app with dynamic config" Path = "C:\Apps\App\App.exe" StartupDir = "C:\Apps\App" Params = "--mode=production" PostLaunchPath = "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" PostLaunchStartupDir = "C:\Scripts" PostLaunchParams = "-File C:\Scripts\Notify.ps1 -VaultUrl https://vault.example.com" } Install-ServyService @installParams ``` --- # Document: Pre-Stop & Post-Stop Actions > Source: https://github.com/aelassas/servy/wiki/Pre-Stop-&-Post-Stop-Actions ## Table of Contents 1. [Introduction](https://github.com/aelassas/servy/wiki/Pre-Stop-&-Post-Stop-Actions#introduction) 1. [Shutdown Hook Lifecycle](https://github.com/aelassas/servy/wiki/Pre-Stop-&-Post-Stop-Actions#shutdown-hook-lifecycle) 1. [Pre-Stop](https://github.com/aelassas/servy/wiki/Pre-Stop-&-Post-Stop-Actions#pre-stop) 1. [Pre-Stop Settings](https://github.com/aelassas/servy/wiki/Pre-Stop-&-Post-Stop-Actions#pre-stop-settings) 1. [GUI Example](https://github.com/aelassas/servy/wiki/Pre-Stop-&-Post-Stop-Actions#gui-example) 1. [CLI Example](https://github.com/aelassas/servy/wiki/Pre-Stop-&-Post-Stop-Actions#cli-example) 1. [PowerShell Example](https://github.com/aelassas/servy/wiki/Pre-Stop-&-Post-Stop-Actions#powershell-example) 1. [Post-Stop](https://github.com/aelassas/servy/wiki/Pre-Stop-&-Post-Stop-Actions#post-stop) 1. [Post-Stop Settings](https://github.com/aelassas/servy/wiki/Pre-Stop-&-Post-Stop-Actions#post-stop-settings) 1. [GUI Example](https://github.com/aelassas/servy/wiki/Pre-Stop-&-Post-Stop-Actions#gui-example-1) 1. [CLI Example](https://github.com/aelassas/servy/wiki/Pre-Stop-&-Post-Stop-Actions#cli-example-1) 1. [PowerShell Example](https://github.com/aelassas/servy/wiki/Pre-Stop-&-Post-Stop-Actions#powershell-example-1) ## Introduction Servy supports running an optional script or executable before the main service stops. This can be used for tasks such as: * Gracefully shutting down external dependencies * Flushing logs or metrics * Notifying external systems before shutdown Servy also supports running an optional script or executable after the service process has stopped. This can be used for tasks such as: * Cleanup operations * Notifications or alerts * Post-shutdown automation > [!NOTE] > If the pre-stop (or post-stop) script is a PowerShell script (`.ps1`) or any non-executable file, it **must** be invoked through an executable such as `powershell.exe` or `pwsh.exe`. > > For example: > > ```powershell > --preStopPath="C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" > --preStopParams="-File C:\Scripts\PreStop.ps1 -VaultUrl https://vault.example.com" > ``` > > Directly specifying `--preStopPath="C:\Scripts\PreStop.ps1"` **will not work**. ## Shutdown Hook Lifecycle | Hook Type | Mode | Trigger | Failure Impact | Orphan Cleanup | | :--- | :--- | :--- | :--- | :--- | | **Pre-Stop** | **Synchronous** | Timeout > 0 | Logged, service stops | No | | **Pre-Stop** | **Fire-and-Forget** | Timeout = 0 | Logged, service stops | No | | **Post-Stop** | **Fire-and-Forget** | Default | Logged | No | *For startup-related hooks, see [Pre-Launch & Post-Launch Actions](https://github.com/aelassas/servy/wiki/Pre-Launch-&-Post-Launch-Actions).* *Servy tracks processes launched during startup to ensure that if the main service crashes, all setup scripts are also terminated. For Stop hooks, cleanup is disabled because these processes are intended to finish their work as the service environment itself is being torn down.* > [!NOTE] > While a synchronous hook is running, Servy periodically notifies the Windows Service Control Manager that the service is still active, so the SCM's own stop timeout does not kill the service while a long-running hook is still within its configured timeout. See `Timing:ScmAdditionalTimeMs` in [Advanced Configuration](https://github.com/aelassas/servy/wiki/Advanced-Configuration#servy-service). ## Pre-Stop ### Pre-Stop Settings * **Pre-Stop Executable Path**: Full path to the pre-stop script or executable * **Pre-Stop Startup Directory**: Working directory for the pre-stop process (optional; defaults to the main service's working directory) * **Pre-Stop Parameters**: Command line arguments for the pre-stop executable * **Pre-Stop Timeout (seconds)**: Maximum allowed execution time. Default is 5 seconds. Set to 0 to run in fire-and-forget mode * **Log Pre-Stop Failure as Error**: When enabled, pre-stop failures are logged as errors **Environment Variables:** This hook inherits the **main service's** `EnvironmentVariables`. There is no separate `Post-Launch / Pre-Stop / Post-Stop / Failure-Program EnvironmentVariables` setting - only `Pre-Launch` supports a per-hook override. The pre-stop script is executed synchronously by default. Servy waits for the script to complete before continuing the service shutdown process. If the script fails or times out and **Log Pre-Stop Failure as Error** is enabled, the failure is logged as an error and the service continues stopping. Setting the timeout to 0 runs the pre-stop hook in fire-and-forget mode. In this mode, the hook is started and the service shutdown continues immediately without waiting for completion. This should only be used for non-critical tasks. Fire-and-forget pre-stop hooks are executed as part of the stop sequence and are not tracked for orphan cleanup. ### GUI Example servy-config-pre-stop ### CLI Example ```powershell servy-cli install ` --name="MyService" ` --description="Runs app with dynamic config" ` --path="C:\Apps\App\App.exe" ` --startupDir="C:\Apps\App" ` --params="--mode=production" ` --preStopPath="C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" ` --preStopStartupDir="C:\Scripts" ` --preStopParams="-File C:\Scripts\PreStop.ps1 -VaultUrl https://vault.example.com -SecretName AppSecrets" ` --preStopTimeout="60" ` --preStopLogAsError ``` ### PowerShell Example ```powershell Import-Module "C:\Program Files\Servy\Servy.psm1" -Force $installParams = @{ Name = "MyService" Description = "Runs app with dynamic config" Path = "C:\Apps\App\App.exe" StartupDir = "C:\Apps\App" Params = "--mode=production" PreStopPath = "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" PreStopStartupDir = "C:\Scripts" PreStopParams = "-File C:\Scripts\PreStop.ps1 -VaultUrl https://vault.example.com -SecretName AppSecrets" PreStopTimeout = 60 PreStopLogAsError = $true } Install-ServyService @installParams ``` ## Post-Stop ### Post-Stop Settings * **Post-Stop Executable Path**: Full path to the post-stop script or executable * **Post-Stop Startup Directory**: Working directory for the post-stop process (optional; defaults to the main service's working directory) * **Post-Stop Parameters**: Command line arguments for the post-stop executable **Environment Variables:** This hook inherits the **main service's** `EnvironmentVariables`. There is no separate `Post-Launch / Pre-Stop / Post-Stop / Failure-Program EnvironmentVariables` setting - only `Pre-Launch` supports a per-hook override. The post-stop script is executed in fire-and-forget mode after the service process has fully stopped. Post-stop hooks run after the service has stopped and are not tracked for orphan cleanup. ### GUI Example servy-config-post-stop ### CLI Example ```powershell servy-cli install ` --name="MyService" ` --description="Runs app with dynamic config" ` --path="C:\Apps\App\App.exe" ` --startupDir="C:\Apps\App" ` --params="--mode=production" ` --postStopPath="C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" ` --postStopStartupDir="C:\Scripts" ` --postStopParams="-File C:\Scripts\Notify.ps1 -VaultUrl https://vault.example.com -SecretName AppSecrets" ``` ### PowerShell Example ```powershell Import-Module "C:\Program Files\Servy\Servy.psm1" -Force $installParams = @{ Name = "MyService" Description = "Runs app with dynamic config" Path = "C:\Apps\App\App.exe" StartupDir = "C:\Apps\App" Params = "--mode=production" PostStopPath = "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" PostStopStartupDir = "C:\Scripts" PostStopParams = "-File C:\Scripts\Notify.ps1 -VaultUrl https://vault.example.com -SecretName AppSecrets" } Install-ServyService @installParams ``` --- # Document: Shutdown & Teardown > Source: https://github.com/aelassas/servy/wiki/Shutdown-&-Teardown ## Table of Contents 1. [OS Shutdown Handling (v6.2+)](https://github.com/aelassas/servy/wiki/Shutdown-&-Teardown#os-shutdown-handling-v62) 1. [The Shutdown Sequence](https://github.com/aelassas/servy/wiki/Shutdown-&-Teardown#the-shutdown-sequence) 1. [Key Features](https://github.com/aelassas/servy/wiki/Shutdown-&-Teardown#key-features) 1. [Mandatory Reinstallation](https://github.com/aelassas/servy/wiki/Shutdown-&-Teardown#mandatory-reinstallation) 1. [Extending the Shutdown Window](https://github.com/aelassas/servy/wiki/Shutdown-&-Teardown#extending-the-shutdown-window) 1. [Notes](https://github.com/aelassas/servy/wiki/Shutdown-&-Teardown#notes) ## OS Shutdown Handling (v6.2+) Servy v6.2+ introduces high-reliability service teardown during operating system shutdown and reboot, matching the graceful-shutdown behavior expected of a Windows service wrapper. ## The Shutdown Sequence When a system shutdown or reboot is detected, Servy executes a specialized teardown workflow designed to ensure data integrity and a graceful exit. The sequence is as follows: 1. **Pre-Shutdown Event:** Servy immediately captures the `SERVICE_CONTROL_PRESHUTDOWN` signal from the Windows Service Control Manager (SCM). 2. **Pre-Stop Hook:** If a Pre-Stop hook is configured, it is executed. By default, this runs synchronously to allow for cleanup. However, if the **Pre-Stop Timeout** is set to **0**, the hook runs in **fire-and-forget** mode and Servy proceeds immediately to the next step. 3. **Process Termination:** Servy stops the managed child process. It first attempts a graceful close (sending `WM_CLOSE` or `CTRL_C_EVENT`) before resorting to a forced termination if the process does not exit within the configured timeout. 4. **Post-Stop Hook:** If a Post-Stop hook is configured, it is executed in **fire-and-forget** mode. This hook runs after the child process has exited but does not block the service from finishing its own shutdown. 5. **Logging & Finalization:** Servy logs the successful completion of the pre-shutdown sequence to the Windows Event Log and officially transitions to the `STOPPED` state. ## Key Features * **Pre-Shutdown Registration:** Registers for `SERVICE_CONTROL_PRESHUTDOWN`. This allows Servy to begin cleanup immediately when an OS shutdown or reboot is initiated, occurring before the standard service stop command is issued. * **SCM Progress Reporting:** Periodically reports progress using wait hints and checkpoints to the Windows Service Control Manager (SCM), preventing premature termination during long cleanup tasks. * **Synchronized Teardown:** Protects against race conditions when `STOP` and `PRESHUTDOWN` control codes are received concurrently. ## Mandatory Reinstallation > [!IMPORTANT] > **Compatibility:** You must reinstall your service using Servy v6.2+. Services installed with earlier versions lack the `SERVICE_ACCEPT_PRESHUTDOWN` flag in the SCM database and will ignore these high-priority notifications. ## Extending the Shutdown Window By default, a Servy service (v6.2+, which registers for pre-shutdown notifications) receives the global `PreshutdownTimeout` window (180 seconds on standard Windows configurations) before the SCM proceeds. Servy dynamically sends wait hints and checkpoints to report shutdown progress, preventing the OS from prematurely killing the wrapper during active cleanup. ### Method 1: Per-Service Timeout Override (Recommended) You do **not** need to edit the registry or reboot the system to give a Servy-managed service a longer shutdown window. Servy automatically configures a per-service pre-shutdown timeout directly on the Windows Service Control Manager (SCM) via `ChangeServiceConfig2` using `SERVICE_CONFIG_PRESHUTDOWN_INFO`. The per-service pre-shutdown timeout is calculated dynamically whenever a service is installed or updated: $$\text{Preshutdown Timeout} = \text{Baseline} + \text{PreStopTimeout} + \text{SCM Buffer}$$ Where: * **Baseline:** The highest of three values: your configured `StopTimeout`, any previously recorded historical stop duration (itself capped at 86400 seconds), and a floor of **60 seconds** (`ScmStopTimeoutFloorSeconds`). A `StopTimeout` below the floor does not shorten the window. * **PreStopTimeout:** The maximum duration allocated for the Pre-Stop executable hook, or 0 when no Pre-Stop executable is configured. * **SCM Buffer:** A mandatory 15-second safety margin (`ScmTimeoutBufferSeconds`) added automatically to prevent OS timing race conditions. For example, a service with `-StopTimeout 90` and `-PreStopTimeout 30` that has never recorded a slower stop is registered with a pre-shutdown timeout of `90 + 30 + 15 = 135` seconds. Leaving both at their defaults gives `60 + 0 + 15 = 75` seconds without a Pre-Stop hook, or `60 + 5 + 15 = 80` seconds with one. To grant a specific service a longer shutdown window: 1. Increase the service's `-StopTimeout` (and `-PreStopTimeout` if a Pre-Stop hook is used) via the CLI, PowerShell cmdlet, or Servy Manager UI. 2. Update the service configuration and re-install. The SCM immediately honors the custom pre-shutdown timeout for that specific service - **no registry edits, no system reboots, and no impact on other services on the machine.** > [!NOTE] > For parameter specifications and usage examples, refer to: > > * [Servy CLI Reference](https://github.com/aelassas/servy/wiki/Servy-CLI) (`--stopTimeout`, `--preStopTimeout`) > * [Servy PowerShell Module Reference](https://github.com/aelassas/servy/wiki/Servy-PowerShell-Module) (`-StopTimeout`, `-PreStopTimeout`) > * [Pre-Stop & Post-Stop Actions](https://github.com/aelassas/servy/wiki/Pre-Stop-&-Post-Stop-Actions) ### Method 2: Global System Registry Fallback (Machine-Wide) If you need to increase the hard ceiling for non-Servy services receiving pre-shutdown notifications or extend the subsequent `WaitToKillServiceTimeout` phase (which governs standard services receiving `SERVICE_CONTROL_STOP` and defaults to only **5 seconds** on current Windows versions), you can modify the global registry keys. Because the Service Control Manager reads these global control registry keys during system startup, a full reboot is required after applying changes. The following PowerShell script extends the global shutdown timeouts. Run it as **Administrator**, set the desired timeout in milliseconds, and then reboot the system. ```powershell # Registry path $registryPath = "HKLM:\SYSTEM\CurrentControlSet\Control" # Timeout in milliseconds (example: 80 seconds) $timeoutValue = 80000 # 1. Set PreshutdownTimeout (DWORD, milliseconds) if (Get-ItemProperty -Path $registryPath -Name "PreshutdownTimeout" -ErrorAction SilentlyContinue) { Set-ItemProperty -Path $registryPath -Name "PreshutdownTimeout" -Value $timeoutValue } else { New-ItemProperty -Path $registryPath -Name "PreshutdownTimeout" -Value $timeoutValue -PropertyType DWord -Force } # 2. Set WaitToKillServiceTimeout (REG_SZ, milliseconds) # Note: This is stored as a string (REG_SZ) in the Windows Registry Set-ItemProperty -Path $registryPath -Name "WaitToKillServiceTimeout" -Value "$timeoutValue" Write-Host "Shutdown timeouts updated to $timeoutValue ms." Write-Host "A system reboot is required for these changes to take effect." ``` ## Notes * **Per-Service Preshutdown Timeout:** Configured via Servy's `StopTimeout` / `PreStopTimeout` settings. Registered directly with the SCM using `SERVICE_CONFIG_PRESHUTDOWN_INFO`. Takes effect immediately without a reboot. * **PreshutdownTimeout (Registry):** Controls the global fallback timeout (in milliseconds) Windows grants to pre-shutdown handling services (`SERVICE_CONTROL_PRESHUTDOWN`) that have not set an explicit per-service pre-shutdown timeout. * **WaitToKillServiceTimeout (Registry):** Controls the global fallback timeout (in milliseconds) Windows grants to standard services (`SERVICE_CONTROL_STOP`) before forcibly terminating non-responsive processes. * **Configuration Tip:** Set your service's `StopTimeout` to exceed the maximum expected duration of your longest-running managed process and its associated shutdown hooks so Windows doesn't force-terminate it prematurely. --- # Document: Servy Automation & CI/CD > Source: https://github.com/aelassas/servy/wiki/Servy-Automation-&-CI-CD ## Table of Contents 1. [Introduction](https://github.com/aelassas/servy/wiki/Servy-Automation-&-CI-CD#introduction) 1. [Installation Options](https://github.com/aelassas/servy/wiki/Servy-Automation-&-CI-CD#installation-options) 1. [Manual Download & Silent Install](https://github.com/aelassas/servy/wiki/Servy-Automation-&-CI-CD#manual-download--silent-install) 1. [Package Manager Installation](https://github.com/aelassas/servy/wiki/Servy-Automation-&-CI-CD#package-manager-installation) 1. [CLI Usage](https://github.com/aelassas/servy/wiki/Servy-Automation-&-CI-CD#cli-usage) 1. [Jenkins Integration](https://github.com/aelassas/servy/wiki/Servy-Automation-&-CI-CD#jenkins-integration) 1. [TeamCity Integration](https://github.com/aelassas/servy/wiki/Servy-Automation-&-CI-CD#teamcity-integration) 1. [GitHub Actions Integration](https://github.com/aelassas/servy/wiki/Servy-Automation-&-CI-CD#github-actions-integration) 1. [Azure DevOps Integration](https://github.com/aelassas/servy/wiki/Servy-Automation-&-CI-CD#azure-devops-integration) 1. [Automation Best Practices](https://github.com/aelassas/servy/wiki/Servy-Automation-&-CI-CD#automation-best-practices) 1. [References](https://github.com/aelassas/servy/wiki/Servy-Automation-&-CI-CD#references) ## Introduction Servy is designed for programmatic management, making it ideal for automated environments and CI/CD pipelines. ## Installation Options ### Manual Download & Silent Install **.NET 10.0+ version (x64)** ```text https://github.com/aelassas/servy/releases/download/v/servy--x64-installer.exe ``` **.NET 10.0+ version (ARM64)** ```text https://github.com/aelassas/servy/releases/download/v/servy--arm64-installer.exe ``` **.NET Framework 4.8 version (x64)** ```text https://github.com/aelassas/servy/releases/download/v/servy--net48-x64-installer.exe ``` **Silent installation commands:** ```cmd .\servy--x64-installer.exe /VERYSILENT /NORESTART /SUPPRESSMSGBOXES /SP- /CLOSEAPPLICATIONS /NOCANCEL .\servy--arm64-installer.exe /VERYSILENT /NORESTART /SUPPRESSMSGBOXES /SP- /CLOSEAPPLICATIONS /NOCANCEL .\servy--net48-x64-installer.exe /VERYSILENT /NORESTART /SUPPRESSMSGBOXES /SP- /CLOSEAPPLICATIONS /NOCANCEL ``` **Silent installation commands (CLI only):** ```cmd .\servy--x64-installer.exe /VERYSILENT /NORESTART /SUPPRESSMSGBOXES /SP- /CLOSEAPPLICATIONS /NOCANCEL /SetupType=custom /Components=install_cli .\servy--arm64-installer.exe /VERYSILENT /NORESTART /SUPPRESSMSGBOXES /SP- /CLOSEAPPLICATIONS /NOCANCEL /SetupType=custom /Components=install_cli .\servy--net48-x64-installer.exe /VERYSILENT /NORESTART /SUPPRESSMSGBOXES /SP- /CLOSEAPPLICATIONS /NOCANCEL /SetupType=custom /Components=install_cli ``` For further details, check out the [Installation Guide](https://github.com/aelassas/servy/wiki/Installation-Guide). ### Package Manager Installation - **WinGet**: ```powershell winget install --id aelassas.Servy -e --accept-package-agreements --accept-source-agreements --silent ``` - **Chocolatey**: ```powershell choco install -y servy ``` - **Scoop**: ```powershell scoop bucket add extras scoop install servy ``` - **Patch My PC**: Servy is available in the official [Patch My PC catalog](https://patchmypc.com/supported-products/) for enterprise automated deployment and updates via Microsoft Intune and ConfigMgr (SCCM). > [!NOTE] > For unattended automated environments and CI/CD pipelines, WinGet commands must explicitly include `--accept-package-agreements --accept-source-agreements --silent` to prevent interactive prompt stalls, alongside `--id aelassas.Servy -e` to pin the package by exact identity rather than performing an ambiguous search. Once installed, the CLI executable is available at: ```text %ProgramFiles%\Servy\servy-cli.exe ``` And the PowerShell module is available at: ```text %ProgramFiles%\Servy\Servy.psm1 ``` After a default installation `servy-cli` is on the system **PATH** - see [Installation Guide](https://github.com/aelassas/servy/wiki/Installation-Guide#add-servy-to-path) for the option that controls this and for the portable package. ## CLI Usage Servy CLI can manage services programmatically. Typical commands: ```powershell # Install or update a service servy-cli install --name="MyApp" --path="C:\MyApp\MyApp.exe" --startupType="Automatic" # Start a service servy-cli start --name="MyApp" # Get a service status servy-cli status --name="MyApp" # Stop a service servy-cli stop --name="MyApp" # Uninstall a service servy-cli uninstall --name="MyApp" ``` **Notes:** - All commands return exit codes suitable for CI/CD pipeline checks. - See [Automation Best Practices](https://github.com/aelassas/servy/wiki/Servy-Automation-&-CI-CD#automation-best-practices) for idempotency, restart rules, and security guidelines. - Full CLI documentation is available in the [Servy CLI](https://github.com/aelassas/servy/wiki/Servy-CLI) reference. - Full PowerShell module documentation is available in the [Servy PowerShell Module](https://github.com/aelassas/servy/wiki/Servy-PowerShell-Module) reference. ## Jenkins Integration 1. Install Servy CLI on your Jenkins Windows agent. 2. Add a build step (Execute Windows batch command or PowerShell): ```powershell # Install or update service servy-cli install --name="MyApp" --path="C:\MyApp\MyApp.exe" --startupType="Automatic" # Start the service servy-cli start --name="MyApp" ``` 3. Use exit codes to fail the build if Servy commands fail. ## TeamCity Integration 1. Install Servy CLI on the TeamCity agent. 2. Add a Command Line build step: ```powershell servy-cli install --name="MyApp" --path="C:\TeamCity\Builds\MyApp.exe" --startupType="Automatic" servy-cli start --name="MyApp" ``` 3. Monitor exit codes to verify success. ## GitHub Actions Integration Example step for a Windows runner: ```yaml name: Install MyApp with Servy on: workflow_dispatch: jobs: test-servy: runs-on: windows-latest steps: - name: Install Servy via WinGet run: | winget install --id aelassas.Servy -e --accept-package-agreements --accept-source-agreements --silent shell: powershell - name: Verify Servy CLI installed run: | & "C:\Program Files\Servy\servy-cli.exe" --version --quiet shell: powershell - name: Install MyApp as a Windows Service run: | & "C:\Program Files\Servy\servy-cli.exe" install ` --name="MyApp" ` --path="C:\MyApp\MyApp.exe" ` --startupType="Automatic" ` --startupDir="C:\MyApp" shell: powershell - name: Start MyApp service run: | & "C:\Program Files\Servy\servy-cli.exe" start --name="MyApp" shell: powershell - name: Verify service status run: | if ((Get-Service -Name MyApp).Status -ne 'Running') { exit 1 } shell: powershell ``` ## Azure DevOps Integration 1. Add a Windows agent to your pipeline. 2. Add a PowerShell task: ```powershell servy-cli install --name="MyApp" --path="$(Build.ArtifactStagingDirectory)\MyApp.exe" --startupType="Automatic" servy-cli start --name="MyApp" ``` 3. Use task result codes to fail pipeline on errors. ## Automation Best Practices - **Idempotency:** Always use the `install` command in your scripts. It safely handles both fresh installs and updates to existing services. - **Restart Required:** A service restart is necessary for configuration updates to take effect. - **Security Best Practice:** Avoid using sensitive flags (e.g., `--password`, `--params`, `--envVars`, `--preLaunchEnv`) in production or scripts. Passing these values as command-line arguments makes them visible to any user or process with access to the Windows Process List or shell history files. Instead, set the corresponding environment variables (e.g., `SERVY_PASSWORD`, `SERVY_PROCESS_PARAMETERS`, `SERVY_ENVIRONMENT_VARIABLES`) before running the install command. See [Security](https://github.com/aelassas/servy/wiki/Security#6-sensitive-command-line-arguments--service-account-credentials) page for more information. - **Health Checks:** `servy-cli status` exits `0` whenever it can read the status, including `Stopped` and `NotInstalled`, so its exit code alone does not prove the service is running. Check the status token it prints last: ```powershell $status = servy-cli status --name="MyApp" --quiet | Select-Object -Last 1 if ($status -notmatch '\bRunning$') { Write-Error "MyApp is not running: $status"; exit 1 } ``` The token is invariant (`Running`, `Stopped`, `NotInstalled`, `Unknown`); only the surrounding message is localized. - **Exit Codes:** Servy CLI returns standard exit codes (`0` for success, non-zero for failure). Ensure your CI/CD platform is configured to fail the build on non-zero returns. A non-zero exit from `status` means the query itself failed, not that the service is down. - **Shutdown Handling:** For CI/CD environments that use ephemeral runners or auto-scaling groups, ensure your services are installed with **Servy v6.2+** to take advantage of `SERVICE_CONTROL_PRESHUTDOWN` for graceful teardowns. - **Quote Parameters:** In PowerShell, double-quoted strings expand `$variable` and `$(...)` before the CLI receives them. Use single quotes (`'...'`) when you need the CLI to receive the literal `$`/`` ` ``/`"` characters - for example: `--params='Set-Item Env:Foo "$bar"'`. Use double quotes when you actually want PowerShell to substitute, e.g. `--path="$env:ProgramFiles\MyApp\app.exe"`. ## References - [Servy Releases](https://github.com/aelassas/servy/releases) - [Servy CLI](https://github.com/aelassas/servy/wiki/Servy-CLI) - [Servy PowerShell Module](https://github.com/aelassas/servy/wiki/Servy-PowerShell-Module) --- # Document: Embedding in Custom Installers > Source: https://github.com/aelassas/servy/wiki/Embedding-in-Custom-Installers ## Table of Contents 1. [Overview](https://github.com/aelassas/servy/wiki/Embedding-in-Custom-Installers#overview) 1. [Why Servy Requires Automated Initialization](https://github.com/aelassas/servy/wiki/Embedding-in-Custom-Installers#why-servy-requires-automated-initialization) 1. [WiX Toolset (MSI) Integration](https://github.com/aelassas/servy/wiki/Embedding-in-Custom-Installers#wix-toolset-msi-integration) 1. [Inno Setup Integration](https://github.com/aelassas/servy/wiki/Embedding-in-Custom-Installers#inno-setup-integration) 1. [Advanced Installer & InstallShield](https://github.com/aelassas/servy/wiki/Embedding-in-Custom-Installers#advanced-installer--installshield) 1. [Exit Codes, Re-Runs & Cleanup](https://github.com/aelassas/servy/wiki/Embedding-in-Custom-Installers#exit-codes-re-runs--cleanup) 1. [Verification & Troubleshooting](https://github.com/aelassas/servy/wiki/Embedding-in-Custom-Installers#verification--troubleshooting) ## Overview When packaging software into enterprise installers (such as WiX, Inno Setup, Advanced Installer, or InstallShield), background services are typically installed by writing registry keys or using built-in service tables. Legacy wrappers like NSSM are not secure for production environments because NSSM stores the service configuration, including application parameters and environment variables, in plaintext in the Windows Registry, where anyone with read access to the registry can inspect it. In contrast, Servy encrypts sensitive fields (the account password, the process and hook parameters, and the environment variables) with AES-256 and HMAC-SHA256 authenticated encryption under a DPAPI-protected, HKDF-derived key, and each service account can reach only its own configuration and logs (see [Security](https://github.com/aelassas/servy/wiki/Security)). Servy functions as an enterprise service host rather than a standalone runner script. To maintain production stability, security, and real-time monitoring, services must be installed via the command-line tool (`servy-cli.exe`) during the installation phase and removed during the uninstallation phase. The `servy-cli.exe` utility provides complete service configuration, including process execution settings, environment variables, logging and log rotation, health monitoring and automated recovery, service dependencies, the service account, and pre/post launch and stop hooks. See [Servy CLI](https://github.com/aelassas/servy/wiki/Servy-CLI#install-command) for every `install` option. To include `servy-cli.exe` in your installer package: - Extract `servy-cli.exe` directly from the modern (.NET 10.0+) build portable package (`servy-x.x-x64-portable.7z` or `servy-x.x-arm64-portable.7z`), choosing the one that matches the architecture of the target machines. Servy is built for x64 and ARM64 only; there is no 32-bit build. - **`servy-cli.exe` is completely self-contained** and does not require any external runtime dependencies or pre-installed frameworks (.NET runtime is embedded), making it ideal for clean, standalone installer distributions. It is a single file: `appsettings.cli.json` is optional and nothing else needs to be shipped next to it. - **`servy-cli.exe` carries the rest of Servy inside it.** The first `install`, `start`, `restart` or `import` command extracts the service wrapper (`Servy.Service.CLI.exe`), `Servy.Restarter.exe`, the host service binary (`Servy.Host.exe`) and Sysinternals `handle64.exe` (`handle64a.exe` on ARM64) into `%ProgramData%\Servy`, then installs and starts the `Servy` host service. Do not ship or copy these files yourself, and do not install them to your application folder. - **.NET Framework 4.8 build:** if you embed the legacy build (`servy-x.x-net48-x64-portable.7z`) instead, its `servy-cli.exe` is not a single file: ship it together with the `*.dll` files from the same package, and make sure .NET Framework 4.8 is installed on the target machine. The binaries it extracts are named `Servy.Service.CLI.Net48.exe`, `Servy.Restarter.Net48.exe` and `Servy.Host.Net48.exe`. - **Elevation is required.** `servy-cli install` refuses to run without administrator rights, and creating, starting, stopping or deleting a Windows service needs them anyway. In an MSI, this means a deferred custom action with `Impersonate="no"`, which runs as `LocalSystem`. - **The service name `Servy` is reserved** for the Servy host service and is rejected by `install`. Pick any other name for your service. ## Why Servy Requires Automated Initialization Standard legacy wrappers (like `srvany` or NSSM) rely solely on static registry keys. Servy requires explicit initialization through `servy-cli install`, immediate startup via `servy-cli start`, clean shutdown via `servy-cli stop`, and proper cleanup via `servy-cli uninstall` because it automatically configures: - **Central Host Windows Service (`Servy`):** Installs the `Servy` host service (`Servy.Host.exe`) when it is missing, starts it, and makes every Servy service depend on it. Your service gets its configuration from this host over a local named pipe. - **Encrypted Vault & SQLite Database:** Creates `%ProgramData%\Servy\db\Servy.db`, the SQLite database that holds the configuration of each service (sensitive fields encrypted) and its runtime state. - **DPAPI & AES-256 Key Material:** Creates the machine-wide master key `%ProgramData%\Servy\security\aes_key.dat`, protected with DPAPI in machine scope and bound to the machine. The AES-256 encryption and HMAC-SHA256 authentication sub-keys are derived from it with HKDF. The key cannot be copied to another machine. - **Directory & Pipe ACL Hardening:** Applies strict Windows Access Control Lists (ACLs) to `%ProgramData%\Servy`, the extracted binaries, the log folder of each service (`logs\services\\`) and the host's named pipe, so a service account gets only the access its own service needs. See [Executable Permission Hardening](https://github.com/aelassas/servy/wiki/Security#executable-permission-hardening). Attempting to register or remove the Servy wrapper (`Servy.Service.CLI.exe`) directly via raw registry writes or the MSI `ServiceInstall` table bypasses these steps, causing service launch or uninstallation failures: a service registered that way has no record in `Servy.db` to load its configuration from, and a Servy service removed that way leaves its record and access grants behind. ## WiX Toolset (MSI) Integration To bundle Servy into a WiX installer without opening command prompt windows for the user, use deferred, elevated **Quiet Execution Custom Actions** (`CAQuietExec` or `WixQuietExec`). Place `servy-cli.exe` alongside your application binaries, then configure your `.wxs` source file as follows. The sample uses WiX v3 syntax; `CAQuietExec` and the `WixCA` binary come from `WixUtilExtension`, so pass `-ext WixUtilExtension` to both `candle` and `light`. ```xml NOT Installed AND NOT PATCH NOT Installed AND NOT PATCH REMOVE="ALL" REMOVE="ALL" AND NOT UPGRADINGPRODUCTCODE ``` > [!NOTE] > Setting `Execute="deferred"` with `Impersonate="no"` ensures the installer executes `servy-cli` as `LocalSystem`, with the administrative privileges needed to create the `%ProgramData%\Servy` vault and to install, start, stop, or unregister Windows services. An immediate or impersonated custom action runs as the installing user, who on a UAC-enabled machine typically has no elevated token, so `servy-cli install` fails its elevation check. **Exit codes.** `servy-cli` exits with `0` on success and a non-zero code on failure (see [Exit Codes, Re-Runs & Cleanup](https://github.com/aelassas/servy/wiki/Embedding-in-Custom-Installers#exit-codes-re-runs--cleanup)). `Return="check"` on `InstallServyService` makes the MSI fail and roll back when the service cannot be installed. The stop and uninstall passes use `Return="ignore"` because they exit with `1` when the service does not exist, which must not block an uninstall. `StartServyService` also uses `Return="ignore"`, so a service that does not reach the `Running` state within its start timeout leaves the installation in place; change it to `Return="check"` if a failed start should fail the setup. The sample defines no rollback action: if a later action fails after `InstallServyService` succeeded, the service stays registered unless you add a matching `Execute="rollback"` custom action that runs `servy-cli uninstall`. **Major upgrades.** The upgrade handling above relies on the default `` scheduling (`afterInstallValidate`), which removes the previous version before the new files are installed. The `NOT UPGRADINGPRODUCTCODE` condition must already be present in the version being upgraded from, because the removal runs that version's custom actions. Running `servy-cli install` for a service that already exists updates its configuration instead of failing, and the configuration takes effect the next time the service starts. > [!WARNING] > **Keep secrets out of the MSI log.** Windows Installer writes property values and `CustomActionData` to verbose logs (`/l*v`). If a command line carries a secret (`--password`, or `--params` / `--envVars` holding credentials), hide it: declare the property hidden (`