14-day trial, no credit cardStart now

MSI installer

PermitUSB ships as a single PermitUSB.msi: per-machine install, signed, no forced reboot, clean uninstall. This page covers invoking msiexec directly, which is right when the install is driven by an external system rather than an interactive admin.

DeploymentGPO, SCCM, MDT

Prerequisites

The installer blocks at launch with a clear message if either is missing. For fleet deploys, put both in place before pushing the MSI.

  • Windows 10, Windows 11, or Windows Server 2016 or later, x64. Older Windows lacks the WMI surface the agent uses for USB enumeration
  • .NET 10 Desktop Runtime (x64). The service and tray ship framework-dependent, so the runtime must already be present. Pick the Windows Desktop Runtime installer, not the ASP.NET or SDK variants. For Intune, SCCM or GPO rollouts the Microsoft Update Catalog distributes it as a deployable package: chain it ahead of PermitUSB in your sequence

Silent install

From cmd.exe, the format every msiexec doc shows:

msiexec /i PermitUSB.msi /qn TENANT_TOKEN="<token>"

From PowerShell, use the stop-parsing token:

msiexec --% /i PermitUSB.msi /qn TENANT_TOKEN="<token>"

Properties

PropertyWhat it does
TENANT_TOKENRequired for fresh installs. The enrollment token from the dashboard.
SERVEROptional agent-channel URL, default https://agent.permitusb.com. It lives on its own DNS-only subdomain so installed-agent traffic bypasses edge buffering and bot-detection challenges, while the dashboard stays proxied.
ENDPOINT_GROUPOptional group name for the new endpoint. Matched case-insensitively and trimmed. Unrecognized names fall back to the default group with a warning logged cloud-side.
PURGE_DATAOptional, only meaningful on uninstall. Set to 1 to also remove %ProgramData%\PermitUSB\. Default uninstall leaves it so a reinstall keeps the same endpoint identity.

The Enrollment page generates a token and shows the full msiexec command with the token pre-filled, so there is no need to type it by hand.

Logging

msiexec is silent on failure by default. Pass /l*v to write a verbose log somewhere you can find it:

msiexec /i PermitUSB.msi /qn TENANT_TOKEN="<token>" /l*v %TEMP%\PermitUSB-install.log
Exit codeMeaning
1603Generic install failure, usually a missing prereq or no admin rights.
1618Another install is running. Wait and retry.
1625Blocked by group policy.
3010Success, reboot requested. The service enforces without it, but the kernel filter only attaches during boot, so the endpoint stays on user-mode enforcement until it restarts.

For 1603, search the log for "Return value 3" or "LaunchCondition". The line just above is typically the actual cause.

Upgrading the agent

New version, same machines: run the new MSI with no properties.

msiexec /i PermitUSB.msi /qn

Windows Installer matches the UpgradeCode across builds and runs a MajorUpgrade: stop service, uninstall old binaries, install new binaries, restart service. The agent picks up the new build on its next policy poll and the dashboard Agent version column catches up through the version drift header.

What you do not need to pass on upgrade

  • TENANT_TOKEN: already enrolled. credentials.bin exists, so the agent skips first-run enrollment entirely
  • ENDPOINT_GROUP: agent.json is canonical post-enrollment and the bootstrap registry is not consulted again. Even if you pass it, it is ignored
  • SERVER: same story. ApiUrl in agent.json wins

Version-bump rule: the MSI Version must increase in one of its first three components or MajorUpgrade silently no-ops, because Windows Installer ignores the fourth component when comparing. The assembly version feeds the dashboard Agent version column, so bump both together.

Moving an endpoint between groups after install

Two equally good ways, and you do not need to reinstall for either.

  • From the dashboard’s Endpoints page. The agent picks the change up on its next policy poll, within PolicyPollIntervalSeconds (default 5 minutes), and rewrites its local agent.json to match. Use "Check in now" to make that happen in seconds instead
  • On the endpoint, edit %ProgramData%\PermitUSB\agent.json, set EndpointGroup to the new group’s name and restart the PermitUSB.Agent service. Useful for a site-side admin re-homing a machine without dashboard access

Edge cases

  • Migrating an enrolled endpoint to a new API host: agent.json’s ApiUrl is set during first-run enrollment and survives MSI upgrades, so an existing endpoint keeps talking to the old host. Either hand-edit agent.json and restart the service, or reset and reinstall, which picks up the new default automatically
  • Downgrade is blocked: MajorUpgrade refuses to install an older version over a newer one. Uninstall first if you need to roll back
  • Force a re-enroll: stop the service, delete credentials.bin and agent.json, then reinstall with a fresh token

What gets installed

Path or objectContents
%ProgramFiles%\PermitUSB\Agent\The Worker Service
%ProgramFiles%\PermitUSB\Tray\The per-user tray app
%ProgramData%\PermitUSB\Config, SQLite event store, encrypted credentials
Service PermitUSB.AgentStarts automatically
Run key PermitUSB.TrayLaunches the tray per user
HKLM\Software\PermitUSB\BootstrapInstall-time properties, cleared on uninstall

Code signing

Production builds are EV code-signed. The service, tray app, bundled libraries and the MSI package each carry a SHA-256 Authenticode signature from JJMK Studios, LLC, so Windows shows a verified publisher and SmartScreen does not warn on install. Local pre-release builds may be self-signed, and SmartScreen warns on those.

Uninstall

msiexec /x PermitUSB.msi /qn # Also remove %ProgramData%\PermitUSB\ msiexec /x PermitUSB.msi /qn PURGE_DATA=1

Uninstall removes the service, tray app, files and registry keys. It leaves the endpoint record in the cloud: delete that from the Endpoints page.

Something missing or wrong here? Tell us. Documentation gaps get filled fast.