Skip to content

Latest commit

 

History

History
207 lines (142 loc) · 12.1 KB

README.md

File metadata and controls

207 lines (142 loc) · 12.1 KB

Devolutions Gateway Windows Installer

Windows Installer project for Devolutions Gateway.

Overview

A wixsharp project to build a complete .msi for Devolutions Gateway. wixsharp has a comprehensive wiki and samples database.

A broad undertanding of the relevant technologies is recommended when working on the installer, but a brief overview is provided here:

wixsharp

  • Project built on the managed setup development model.
  • Provides a script file written in plain C# syntax which is transpiled into WiX3 source code (wxs).
  • Managed custom actions are integrated directly into the project instead of as sub-modules.
  • Installer custom interface is built using WinForms. This uses the WiX/MSI EmbeddedUI feature with the interop interface abstracted by wixsharp. The default dialogs are recreated in WinForms (and extended by this project).

WiX3

  • wixsharp generates standard WiX source code. This can be viewed at or after build time by setting PreserveTempFiles to true on the top-level wixsharp ManagedProject, which is helpful in understanding the transpilation process.
  • wixsharp automatically invokes the standard WiX toolchain to generate the final mst/msi files.

Windows Installer

Build

MSBuild

msbuild must be in your PATH; it's easiest to use the Developer Command Prompt for VS 2022.

The following environment variables should be defined:

DGATEWAY_EXECUTABLE The absolute path to the main executable (DevolutionsGateway.exe) to be packaged

DGATEWAY_PSMODULE_PATH The absolute path to the top-level directory containing the PowerShell module to be package

DGATEWAY_VERSION The version to use for the installer. Note that in Windows Installer, the product version is restricted as follows:

[0-255].[0-255].[0-65535]

Visual Studio

Tested on Visual Studio 2022. It may be necessary to install the ".NET Framework 4.6 Targetting Pack" using "Tools > Get tools and features".

Either configure the environment variables detailed above, or override the relevant properties in Program.cs.

When building with VS, I get System.IO.IOException: The process cannot access the file '...DevolutionsGateway.msi' because it is being used by another process.

  • Ensure you don't have the previously built MSI open. Close it if you do.
  • This appears to be a bug in the latest wixsharp versions. Try the build again and it should work.
  • If it still doesn't work, it's possible a crash in a prior run is causing msiexec to keep a handle open to the msi file. Either use Task Manager to kill all msiexec processes, or reboot your machine.

Nuget and references

It's possible to include managed references in the installer project and use them in the mananged UI and custom actions.

The references are added as normal but it's necessary to declare them to the installer script, e.g.

/// Add Devolutions.Picky to be available at runtinme
project.DefaultRefAssemblies.Add(typeof(PickyError).Assembly.Location);

Native references are trickier. First they must be embedded in the MSI as binaries:

string pickyPath = Path.GetDirectoryName(typeof(PickyError).Assembly.Location;
string nativePath = Path.Combine(pickyPath, "runtimes", "win-x64", "native", "DevolutionsPicky.dll");
project.AddBinary(new Binary(nativePath)); // optionally specify an ID here

But the binary won't be copied to the installer's temp directory at runtime. It's necessary to extract it manually, this can be done in the UIInitialized event for example:

byte[] pickyBytes = e.Session.GetEmbeddedData("DevolutionsPicky.dll");
System.IO.File.WriteAllBytes(Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "DevolutionsPicky.dll"),pickyBytes);

Localization

Installer strings live in Resources/Strings_<culture>.json, with en-US as the source of truth. The Strings.g.tt T4 template generates the DevolutionsGateway_<culture>.wxl localization files and Strings.g.cs from them. Do not edit the generated files by hand. After changing a JSON file, run package\Update-InstallerLocalization.ps1 (it requires Visual Studio) and commit the regenerated files. Keys missing from a translation fall back to English.

Each language is built as a separate MSI, turned into a transform, and embedded in the final MSI. To add a language, follow the checklist in .agents/skills/installer-localization/SKILL.md.

Command line properties

Public properties can be passed to msiexec to drive unattended installs and upgrades.

msiexec /i DevolutionsGateway.msi /qn REBOOT=ReallySuppress P.SERVICEACCOUNT="CONTOSO\gateway$"

Service account

Gateway 2026.3.1 is the first release that supports the service-account properties below. Older MSIs ignore them; for 2026.3.0 and earlier, use the legacy manual procedure in the Windows service-account guide. The guide also covers account preparation, migration from a manual setup, failed-upgrade recovery, and diagnostics.

By default the service runs as NT AUTHORITY\NetworkService. Use these properties or Install-DGatewayPackage -ServiceAccount to select another account; there is no account-selection dialog.

Property Description
P.SERVICEACCOUNT The account the service logs on as, in DOMAIN\Name or .\Name form. On upgrade, defaults to the account of the existing service.
P.SERVICEPASSWORD Required for password-based accounts on first install and major upgrade. Hidden from normal MSI logs, but not from the process command line or Windows Installer's Debug=7 logging policy.

Supported accounts:

  • NT AUTHORITY\NetworkService (default), passwordless.
  • NT SERVICE\DevolutionsGateway, the virtual account of the service, passwordless.
  • Standalone and group managed service accounts (DOMAIN\Name$), passwordless, installed on this host and able to retrieve their managed password.
  • Regular local or domain user accounts, which require P.SERVICEPASSWORD.

LocalSystem and NT AUTHORITY\LocalService are rejected.

The installer grants the account the Log on as a service right and read/write access to %ProgramData%\Devolutions\Gateway. It grants access to a system-store certificate's private key only when TlsCertificateStoreLocation is explicitly LocalMachine, including for retained configuration. An explicit deny policy still takes precedence. Configure access to externally stored keys, custom user databases, logs, recordings, and remote resources separately. Changing the service account does not revoke earlier grants on shared certificate keys or remove previously assigned logon rights.

An omitted or null certificate-store location means CurrentUser at runtime; the installer must not substitute LocalMachine or inspect its own SYSTEM profile. When the existing service and selected account resolve to the same SID and no reconfiguration is requested, setup leaves retained CurrentUser or CurrentService configuration and private-key ACLs unchanged and unmanaged. Setup logs that it skips certificate discovery, permission grants, and runtime access verification for these stores. This does not establish certificate or runtime availability. An identity change, missing service, or requested reconfiguration with retained non-machine-store configuration is rejected before the installation is modified; migrate to explicit LocalMachine or external certificate/key files first. Setup also aborts if configuration approved for retention changes or is removed after validation. New wizard selections of CurrentUser are rejected because the interactive administrator's profile is not the service's profile.

Upgrades preserve the existing account unless another is specified. The existing MSI upgrade sequence recreates the service: password-based accounts therefore require the password again, supplied directly or through Install-DGatewayPackage -ServiceCredential. Missing or invalid credentials fail validation before the existing installation is removed. If Windows policy prevents the network-logon credential check, setup fails rather than removing a working installation with unchecked credentials. The installer never extracts or stores the old service password for reuse. Supplying credentials to the new MSI does not guarantee that an older MSI can restore its service credentials during rollback; retain the credentials and a recovery procedure before upgrading.

Repair preserves the account and password of an existing service. Account or password changes during repair are rejected rather than changing permissions without changing the service. If the service is missing, provide the account explicitly and its password when required.

Devolutions Agent updates Gateway only under NETWORK SERVICE, the Gateway virtual account, or a verified managed service account. Password-based accounts require manual upgrades. Use Agent 2026.3.1 or later; older Agents grant update-channel write access only to NETWORK SERVICE. After an external account change, the Agent refreshes those permissions on its periodic status check, normally every five minutes. The existing Agent downgrade mechanism remains an uninstall followed by installation; direct MSI downgrades remain blocked. Older target installers may not recognize custom-account properties. The Agent's update_status.json records update failures in Products.Gateway.LastUpdateError; this field is not exposed by the current Gateway update HTTP response and is reset when the Agent restarts.

The former installer configuration-access report has been removed. Verify actual service startup, TLS access, and configured data paths after deployment; installer success alone is not a runtime health check. See the automated Windows installer lab for repeatable scenarios.

Compatibility

The custom UI targets .NET Framework 4.5.1; which is available out-of-the-box on Windows. The provides compatiblity with Windows 8.1 and Windows Server 2012 R2, but it's an additional download on Windows 8 / Windows Server 2012.

Important

The managed installer UI and actions are currently run as x86, meaning x64-only references cannot be used. Additionally, when querying the registry, it's important to ensure you don't check the WoW64 view. There is a path to work around this for custom actions only, if it becomes important to do so.

The MSI project only targets the x64 architecture and the install won't execute on an x86 operating system. Behaviour on arm64 is currently undefined.

Debugging

Installation script

Script generation can be debugged in the normal way using breakpoints and the Debug > Start New Instance in Visual Studio.

It doesn't seem straightforward to debug the event driven custom actions (OnLoad, BeforeInstall, AfterInstall). For complex code, regular managed custom actions should be used instead.

Debugging UI

  1. You must run VS as an elevated (administrator) user.
  2. Launch the compiled MSI
  3. "Attach to process" in Visual Studio
  4. Filter the process list by "msiexec" and look for the proper Window title ("Devolutions Gateway Setup")
  5. Attach the debugger and debug as normal

While developing custom UI, it can be faster to use "Demo mode" to "play" dialogs without running the full msi:

UIShell.Play(typeof(CertificateDialog));

Custom Actions

You won't be able to attach the debugger manually. Instead, (again ensure that VS is run elevated) insert a System.Diagnostics.Debugger.Break() call at the site you wish to debug, and then run the MSI.

Once the Break() call is hit, the just-in-time debugger will be invoked and you can select your VS instance and proceed as normal.

Ensure that you remove any break statements after debugging is complete. A helpful macro to use might be:

private static void Breakpoint()
{
#if DEBUG
    System.Diagnostics.Debugger.Break();
#endif
}