Appearance
Windows MSI installer
MyDLPAgent.msi is the supported enterprise deployment artefact for the x64 Windows agent. It is authored with WiX 4 in deploy/windows/installer/Package.wxs; deploy/windows/installer/build_msi.ps1 builds it from the agent executable and the native custom-action DLL.
Install
Run from an elevated deployment context:
powershell
msiexec.exe /i MyDLPAgent.msi /qn /norestart `
SERVERURL=https://dlp.example.com `
ENROLLTOKEN=<one-time-token> `
/l*v C:\Windows\Temp\mydlp-install.logBoth properties are required only for a fresh install, and ENROLLTOKEN is not required when Group Policy supplies the token (below). SERVERURL and ENROLLTOKEN are secure MSI properties; the token is additionally hidden. The deferred custom action has HideTarget=yes, reads the token from CustomActionData, and gives it to dlp-agent.exe only through the child process environment. It is not written into agent.toml, an executable command line, an MSI log or a machine-wide environment value.
The package is per-machine and requires elevation. It installs exactly one feature:
C:\Program Files\MyDLP\dlp-agent.exe;- the
MyDLPAgentLocalSystem service, delayed automatic start; - three escalating service recovery actions at 5, 30 and 120 seconds;
- an all-users Start Menu shortcut;
- one Windows Installer inventory row in Apps/Programs and Features;
C:\Program Files\MyDLP\dlp-session.exeand anHKLM\…\CurrentVersion\Runvalue named MyDLP Session that starts it at every sign-in (DLP-1126).
How it shows in Windows (DLP-1264). Both executables carry a version resource and the cyberkap icon, built in by agent/dlp-agent/build.rs, so they appear under their own names and not as bare file names:
- Task Manager lists them as cyberkap Endpoint Agent (
dlp-agent.exe) and cyberkap Session Agent (dlp-session.exe), publisher cyberkap, with the agent's version (named MyDLP untilDLP-1859), with the cyberkap mark as its icon, made from the owner's logo (DLP-1857). The toast does not carry the mark yet (DLP-1898). - Programs and Features shows the icon beside the entry, because the entry's
DisplayIconis the agent executable.
Every release checks this on the Windows agent it publishes: deploy.sh runs tools/pe_version.py. That the entry's DisplayVersion follows an automatic update is not asserted yet (DLP-1264, item 3).
The session agent at sign-in. The clipboard monitor, the justification prompt and the notifications run in dlp-agent session, one per signed-in person. dlp-session.exe is its windowless launcher, because dlp-agent.exe is a console program and would put a console window on every desktop. The Run value is named and machine-wide, so Task Manager lists it under Startup apps. Windows Installer removes both with the package. The graphical setup program and dlp-agent install register the same value when the launcher sits beside the agent. The standalone dlp-agent-windows-x86_64.exe download has no launcher beside it, so a scripted install from it does not, and its report says so. The setup program's value and launcher have been found in place on a physical Windows 11 host (DLP-1176); the MSI's have not been installed on one yet: see Verification. A Run value fires only at sign-in. So the setup program and dlp-agent install, run in a person's session, also start the launcher at once through explorer.exe, which runs it with that person's ordinary token rather than the installer's elevated one. It is not started when one is already running there (DLP-1247). An MSI runs as SYSTEM, so the service enumerates the people already signed in and starts the launcher with each person's own WTS token, environment and desktop. It never starts one in session 0 and never inherits a service handle. A failure is Windows Application event 3011 and the Run value remains the next-sign-in recovery path. This path is unit- and cross-compile-checked but has not yet completed on a native Windows runner. Once started, the session agent reconnects when the service restarts, doubling its wait from a second to a minute, and exits only when the pipe is held by something other than the agent (DLP-1248).
More than one signed-in session may connect at once. Windows supplies the named-pipe client's kernel session identifier; clipboard events and notices stay on that exact route. The service does not substitute the active console session for an event it cannot attribute (DLP-1127). An unattributed file-system event is warned only when exactly one person is signed in and their session is active, in that session; otherwise it is recorded as not_delivered and no person is warned (DLP-1125).
Configuration, identity, queue and keys live below C:\ProgramData\MyDLP. They are created by the enrolled agent under the restricted state-directory ACL, not copied from the MSI.
On the command-line route the service is not started until enrollment has succeeded. A bad or spent token, invalid server URL or unreachable server makes the MSI return non-zero; Windows Installer then removes the binary, service and shortcut, while the rollback custom action removes any partial configuration and agent state.
Install with the token from Group Policy
When the EnrollmentToken setting of MyDLP.admx is in force (HKLM\SOFTWARE\Policies\MyDLP\Agent), a fresh install needs no properties (DLP-1191):
powershell
msiexec.exe /i MyDLPAgent.msi /qn /norestart /l*v C:\Windows\Temp\mydlp-install.logThe server comes from SERVERURL if given, otherwise from the policy's ServerUrl. The launch condition reads the policy token into the hidden MYDLP_POLICY_TOKEN property only to check that it exists. The bootstrap action receives SERVERURL and an empty ENROLLTOKEN, and runs the agent with --enrol-at-start, which writes configuration without enrolling. The agent refuses that when policy carries no token, and nothing is installed. The service then enrols at its first start with the policy's token (group_policy::startup, DLP-558).
Unlike the command-line route, a bad, spent or expired token does not roll the install back. The service reports running and retries with a back-off of up to 15 minutes, writing event 3004 to the Application log each time. The install is complete and the machine is not in the console until the token works. Rolling the Windows agent out with Group Policy §1 and §6 say what to watch.
Giving ENROLLTOKEN without SERVERURL is refused, with a token in policy or without: a token with nowhere to go is a mistyped command line.
Upgrade and downgrade
Installing a higher version is a WiX major upgrade:
powershell
msiexec.exe /i MyDLPAgent-new.msi /qn /norestart /l*v C:\Windows\Temp\mydlp-upgrade.logNo second token is supplied. The old product receives UPGRADINGPRODUCTCODE, so its removal action does not wipe C:\ProgramData\MyDLP; the new product sees WIX_UPGRADE_DETECTED and does not enrol again. The service is stopped before its executable is replaced and started after the new files and service configuration are committed.
A lower version is refused with a named downgrade error, with one exception: the agent's own watchdog, rolling back an update that failed, passes MYDLP_ROLLBACK=1. The older package then removes the newer one in the same transaction, as an upgrade removes an older one, and the identity is kept (DLP-1121). The package writes out the rows MajorUpgrade would generate so that this one exception can exist; Updates, claim by claim §3 has why AllowDowngrades was not used. This has not run on Windows (DLP-1122). A same-version repair does not enrol or replace identity.
Uninstall
powershell
msiexec.exe /x MyDLPAgent.msi /qn /norestart /l*v C:\Windows\Temp\mydlp-uninstall.logThe service is stopped first. Before RemoveFiles, the agent gets up to its bounded flush deadline to deliver queued events, sends an uninstall notice when the server is reachable, and wipes identity, EDM keys, cached policy, queue, local history and logs. The MSI custom action then removes the generated configuration.
The session agents stop with it (DLP-1289). The same dlp-agent uninstall step removes the sign-in Run value first, so a sign-in during removal cannot start another. It then ends every session agent this installation started, in every session: a dlp-session.exe launcher or a dlp-agent.exe session process, including a copy an update moved aside, whose program is in the install folder. A process of the same name elsewhere is left alone, and so are the service and the uninstaller itself. A major upgrade does not run this step, so session agents stay and reconnect to the new service (DLP-1248). Not verified on a Windows host yet. Quarantined customer files are deliberately retained; an uninstall is not authority to destroy them.
Supported operating systems
The launch condition admits the builds the agent supports, one minimum per edition (DLP-1136, DLP-1137):
- a client needs build 19041 (Windows 10 version 2004) or later;
- a server needs build 17763 (Windows Server 2019) or later.
agent/core/tests/installer_admits_what_the_agent_supports.rsholds the two numbers to the agent's own (windows_build). The build is read from the registry valueCurrentBuildNumber, not from the installer'sWindowsBuildproperty, whose documented values stop at Windows 8.1. A build that cannot be read is refused.Installedproducts can still be repaired or removed if support policy changes later.
Not verified on a host: the refusal on a real client older than 19041 or a real Server 2016. The CI test used to simulate one by passing WindowsBuild on the command line, which the registry search does not honour (DLP-449).
A fresh install or major upgrade is also refused while Windows Installer reports a pending reboot. Removal of an already installed product stays available. This avoids entering a service/file replacement transaction whose result depends on an earlier pending rename; restart Windows and retry.
Signing and release construction
The release workflow builds the agent and custom-action DLL on a general Windows runner, verifies their immutable handoff on the protected signing runner, and then:
- Authenticode-signs and verifies both executable payloads;
- builds the MSI from those exact signed bytes;
- Authenticode-signs and verifies the MSI;
- publishes the signed agent, signed MSI, release manifest and timestamped manifest signature.
This order matters: signing an agent after packaging it would make the standalone file differ from the bytes inside the MSI. Production signing is still unavailable until the public-trust certificate, cloud-HSM workload identity and protected runner described in exist. An unsigned CI MSI is test evidence, not a production release.
Verification
tests/windows_msi_installer.ps1 has two layers:
- keyless assertions pin the hidden/secure token boundary, deferred LocalSystem action, rollback, OS gate, service lifecycle and identity-preserving upgrade condition. These run, under
pwsh, on Linux as well; windows-e2eis written to build two MSI versions onwindows-latestand exercise the steps below. It has not yet passed (Windows CI status), so none of them has been observed: named OS refusal, invalid-token rollback, unreachable-server rollback, silent install, running-service upgrade, identity preservation, downgrade refusal, SCM recovery configuration, ARP inventory, versioned first Event Log entry and silent uninstall. Every log is searched for the exact token supplied to that transaction.
The package compiles and links on Linux too: tools/wix_link_check.py runs WiX's preprocessor, compiler and linker on a copy without the Subdirectory attributes that WiX's Linux path check refuses, and stops at the binder, which needs Windows' msi.dll. It is wired into CI on Linux beside the other gates. It did not run there while no hosted job ran (2026-09-15 to 2026-10-01, DLP-1215), so it was run by hand. That check is what found the shortcut naming CommonProgramsFolder, a folder Windows Installer does not have. WiX refused to link it, so the MSI build would have failed on every platform since it was written. No Windows job ran to say so, because no hosted job ran from before the Windows jobs existed until 2026-10-01 (DLP-1214, DLP-1215). The MSI steps above, and the session launcher's install and removal, have not run on Windows since then.
What this does not prove is a domain/GPO rollout, a machine genuinely running Server 2016, a real disk-full volume, coexistence with endpoint protection, or a reboot. Those remain rollout qualification cases rather than claims derived from one hosted CI image.