12. Install agents on Windows
This guide describes Lawliet 1.5.13.s (the current release). Screens, commands and procedures may change in later versions; the usage guide is updated with each release. Check the version your server runs under Settings > Platform or with ./lawliet version, and see the Releases page for what changed.
This chapter covers every way to put the agent on Windows hosts:
| Method | Section | Use it when |
|---|---|---|
| Copy-paste command | 12.2 | You can open PowerShell on the host, and it can reach the server |
| Offline package (ZIP) | 12.3 | The host cannot download anything |
| Group Policy: MSI by Software installation | 12.5 | A domain; you want every computer of an OU to install at boot |
| Group Policy: MSI by computer startup script | 12.6 | A domain; you prefer a startup script to Software installation |
| Remote deployment over WinRM | 12.8 and chapter 13 | The server logs in to the hosts with an account |
For what the agent does, read chapter 10 first.
12.1 Before you start#
| Requirement | Detail |
|---|---|
| Windows | 64-bit Windows (x64). The x64 agent also runs on Windows on ARM |
| PowerShell | Windows PowerShell 5.1 (powershell.exe, built into Windows). With -CaCert the installer refuses PowerShell 7 |
| Account | A local Administrator, in an elevated PowerShell ("Run as administrator") |
| Network | Outbound from the host to the server: 443/tcp (HTTPS mode) or 8000/tcp (lab mode) |
| Clock | Within 1 minute of the server (w32tm /resync) |
| Disk | At least 200 MB free on C: (remote deployment warns under 1 GB) |
What the installer creates:
| Item | Value |
|---|---|
| Program folder | C:\Program Files\Lawliet Agent (SYSTEM and Administrators full control, Users read) |
| Data folder | C:\ProgramData\Lawliet (token, state, log; SYSTEM and Administrators only) |
Scheduled task LawlietAgent | Runs the agent as SYSTEM at startup |
Scheduled task LawlietWatchdog | Checks every 20 seconds and starts the agent again; restores the program from its known-good copy |
| Log | C:\ProgramData\Lawliet\lawliet-agent.log |
The agent is a scheduled task, not a Windows service. The console's step text says "Windows service"; the installer uses the two scheduled tasks above.
For a server with a self-signed certificate, export it on the server and copy it to each host, for example to C:\path\to\lawliet-server.pem:
sudo ./lawliet tls --export # on the server; writes ./lawliet-server.pem12.2 Procedure: install with the copy-paste command#
Required permission (console): Manage agents. Four-eyes: no.
Risk: installs a SYSTEM task on the host. Rollback: uninstall (12.9).
- Get the command:
- Console: Environment > Hosts > Install agent > Install command > Windows, then the copy button. Keep Self-signed certificate ticked when the server's certificate is self-signed.
- Server:
sudo ./lawliet token, section "Windows (PowerShell, as Administrator)".
- For a self-signed server, copy
lawliet-server.pemtoC:\path\to\lawliet-server.pemon the host, or edit that path in the command. - Open Windows PowerShell as Administrator and paste the command. It is one line, starting
powershell -NoProfile -ExecutionPolicy Bypass -Command "& {...}".
You cannot type this command: it contains the SHA-256 of the installer the server serves. It downloads install.ps1 into a new random folder under your %TEMP%, runs it only if its SHA-256 matches, removes the folder and exits with the installer's status.
What you see: the installer checks the server, downloads lawliet-agent.exe, checks it against the SHA-256 the server sends, starts it once to test it, registers the two scheduled tasks and waits up to 90 seconds for enrolment. The host appears on Environment > Hosts.
If it fails:
| Message | Meaning and fix |
|---|---|
| "Refused: install.ps1 is missing or is not the installer this server published. Nothing was run." | The download failed or was changed. Check the address and that the host reaches the server |
| A certificate verdict | Export the certificate again and check the -CaCert path (see chapter 10.9) |
| HTTP 409 (exit 3) | An older record of this host exists. Remove it in the console; the agent then enrols by itself |
| HTTP 401 (exit 3) | Wrong enrolment secret. Copy the command again |
Notes:
With a self-signed certificate, the command downloads the installer with
curl.exe -sSfk. The installer is checked by its hash, then everything after it (the agent, the enrolment, every heartbeat) is checked against the pinned certificate.curl.exeis in Windows 10 1803 and later and Windows Server 2019 and later. Windows Server 2016 has none. There, either importlawliet-server.peminto the host's Trusted Root store and untick Self-signed certificate to get the command that usesInvoke-WebRequest, or copyagents\install_windows.ps1from the bundle next to the certificate and run, in an elevated Windows PowerShell, from a folder only administrators can write to:powershell -NoProfile -ExecutionPolicy Bypass -File .\install_windows.ps1 -Server 'https://10.0.0.5' -Token '<enrolment-secret>' -CaCert 'C:\path\to\lawliet-server.pem'Where PowerShell is locked to Constrained Language Mode (AppLocker, WDAC),
-CaCertdoes not work. Use a certificate the host already trusts, or the MSI (12.5).If
%TEMP%points at a shared folder such asC:\Temp, run the command from an account whose temp folder is its own.
12.3 Procedure: install from an offline package (ZIP)#
Required permission: Deploy agents remotely. Four-eyes: yes in the console.
Make the package: Environment > Hosts > Install agent > Offline package, Target Windows x64, Package ZIP, installed by hand on each host. Then follow the same steps as for Linux: chapter 11.3.1. On the server instead:
sudo ./lawliet agent-package --os windows --hosts 20 --days 3 --label "Branch office"On a trusted machine, compare the ZIP's SHA-256 with the value shown when it was made:
Get-FileHash -Algorithm SHA256 .\lawliet-agent-windows-amd64-offline-12.zipOn the host, in Windows PowerShell as Administrator:
Expand-Archive .\lawliet-agent-windows-amd64-offline-12.zip -DestinationPath C:\LawlietPackage cd C:\LawlietPackage\lawliet-agent-windows-amd64 powershell -NoProfile -ExecutionPolicy Bypass -File .\install_windows.ps1 -OfflinePackage .
What you see: "Package contents match its checksum list (SHA256SUMS).", then the install. Nothing is downloaded. A host that cannot reach the server yet is installed anyway and enrols later, while the code is valid. The scheduled task LawlietEnrolCleanup removes the code from config.env once the agent has enrolled, then deletes itself. To check (prints nothing when the code is gone):
Select-String -Path 'C:\Program Files\Lawliet Agent\config.env' -Pattern '^LAWLIET_REGISTRATION_SECRET=.'Revoke the code when you are done (Install agent > Offline package > Enrolment codes > Revoke).
12.4 Group Policy: make the rollout package#
The Group Policy methods (12.5 and 12.6) use the Windows MSI for Group Policy: the agent MSI plus a transform (.mst) made for one rollout. The MSI holds no server, code or certificate, so it is the same file everywhere and can carry an Authenticode signature. The transform holds the server address, an enrolment code and, for a self-signed server, the certificate.
Required permission: Deploy agents remotely. Four-eyes: yes.
Open Environment > Hosts > Install agent > Offline package.
Target Windows x64, Package Windows MSI for Group Policy. (The option appears when the server carries the MSI.)
Fill in:
Field What to enter Label For example "OU Workstations rollout" Valid for (days, at most 30) Default 30 for a rollout. A computer that first boots after the expiry installs the agent but is not enrolled Computers in the OU (at most 1000) How many computers may enrol. Every computer that installs uses one, a reinstalled one too Server address the hosts reach Filled in; change if needed Click Request package. A second administrator approves it (the approver reads "Group Policy rollout (Windows MSI + transform)").
Click Check again, then Create package. Note the Package SHA-256 and download the ZIP (the link works once, for 15 minutes).
On the server instead (root, no second signature, audited as made through the CLI):
sudo ./lawliet agent-package --os windows --gpo --hosts 400 --label "OU Workstations"The ZIP contains:
| File | What it is |
|---|---|
lawliet-agent-windows-amd64.msi | The agent MSI of this release |
lawliet-rollout-<id>.mst | The transform with the enrolment code |
README.txt | The SHA-256 of both files, the MSI product code, and the Group Policy steps |
SHA256SUMS | Checksums of the other files |
Before deploying:
- Compare the ZIP's SHA-256 with the value shown (
Get-FileHash -Algorithm SHA256 .\<file>.zip). - Unpack it. If README.txt says the MSI is Authenticode-signed, check it:
Get-AuthenticodeSignature .\lawliet-agent-windows-amd64.msimust sayValid. - If your policy requires your own signature, sign the MSI (not the transform) with
signtoolbefore you add it to Group Policy. Its SHA-256 then changes; note the new one.
Where the enrolment code ends up (read this first)#
- On the share, inside the
.mst. - With Software installation (12.5): Group Policy copies the transform's properties, the code included, into the GPO's folder in SYSVOL. SYSVOL is readable by every domain user unless the GPO is filtered.
- On every computer: Windows Installer keeps a copy of the transform in
%WINDIR%\Installer. The MSI restricts those copies to SYSTEM and Administrators.
So: restrict the share, apply Security Filtering to the GPO before you add the package, and revoke the code when the rollout is done. The console reminds you while a rollout's code is active ("Group Policy rollout still active").
12.5 Procedure: Group Policy with Software installation (MSI)#
On a domain controller or an admin workstation with Group Policy Management (RSAT).
Risk: installs the agent as SYSTEM on every computer of the OU at its next boot. Rollback: remove the package from the GPO (below); for protected agents turn protection off first.
- Share. Copy the MSI and the
.mstto a share every target computer reaches by UNC path, for example\\fileserver\LawlietDeploy$. Share and NTFS permissions: Read for Domain Computers, Full control for the admins who manage it, nothing for Authenticated Users or Everyone. A mapped drive letter or a local path does not work. - GPO. Group Policy Management > the OU holding the computers > Create a GPO in this domain, and Link it here (for example "Lawliet Agent").
- Security Filtering (required). Select the GPO > Scope > Security Filtering:
- remove Authenticated Users;
- add a group of only the target computers (recommended), or Domain Computers (simplest, but then any computer of the domain can read the code).
Then Delegation > Advanced: that group has Read and Apply group policy. Keep the default entries (Domain Admins, Enterprise Admins, ENTERPRISE DOMAIN CONTROLLERS, SYSTEM). Give Read to no one else. Check it: as an ordinary domain user,
dir \\<domain>\SYSVOL\<domain>\Policies\{<GPO id>}\Machinemust be refused. - Edit the GPO. Computer Configuration > Policies > Software Settings > Software installation > right-click > New > Package. Give the UNC path of the MSI. Choose Advanced.
- Transform. In the properties: Modifications tab > Add > the UNC path of
lawliet-rollout-<id>.mst. A transform can only be added now, not later. Deployment tab: Deployment type Assigned. OK. - Recommended: Computer Configuration > Policies > Administrative Templates > System > Logon > Always wait for the network at computer startup and logon: Enabled.
- Restart a computer of the OU.
gpupdate /forcealone does not install software; Windows installs it during the next boot, before the logon screen.
What you see: the computer appears on Environment > Hosts. On the computer, gpresult /r /scope computer lists the GPO, and the Application event log has an event from source Lawliet Agent Setup (table below).
12.6 Procedure: Group Policy with a computer startup script#
The same rollout package, installed by a startup script instead of Software installation. The script only names the files on the share, so the enrolment code is not written into the GPO's SYSVOL folder; it is still in the .mst on the share. Apply the same share permissions and Security Filtering as in 12.5 (steps 1 to 3).
Risk and rollback: as 12.5.
Do steps 1 to 3 of 12.5 (share, GPO, Security Filtering).
Edit the GPO. Computer Configuration > Policies > Windows Settings > Scripts (Startup/Shutdown) > Startup > Properties > Add.
Script Name:
C:\Windows\System32\msiexec.exeScript Parameters (one line, your share and rollout id):/i \\fileserver\LawlietDeploy$\lawliet-agent-windows-amd64.msi TRANSFORMS=\\fileserver\LawlietDeploy$\lawliet-rollout-<id>.mst /qnOK, close the editor, and restart a computer of the OU.
The script runs at every boot as SYSTEM. On a computer where the agent is installed, running the MSI again changes nothing.
To test on one computer by hand first, as Administrator, with both files in the current folder:
msiexec /i lawliet-agent-windows-amd64.msi TRANSFORMS=lawliet-rollout-<id>.mst /qnDo not add /l*v (verbose logging) unless support asks: a verbose Windows Installer log records the enrolment code. If you used it, delete the log afterwards.
12.7 MSI results, upgrades and removal#
Event log#
Application log, source Lawliet Agent Setup:
| Event | Level | Meaning |
|---|---|---|
| 1000 | Information | Installed and enrolled |
| 1001 | Information | Installed; not enrolled yet, keeps trying while the code is valid |
| 1002 | Warning | Installed, but the server refused the enrolment (expired or used-up code, or 409: delete the old record) |
| 1003 | Information | A newer agent was already installed; it was kept |
| 1004 | Information | The cached transform copies are restricted to SYSTEM and Administrators |
| 1100 | Error | Not installed; the reason is in the event |
| 1101 | Error | The MSI was run without the transform on a computer with no enrolled agent |
| 1104 | Warning | The cached transform could not be restricted yet; retried |
| 2000 | Information | Removed |
| 2001 | Error | Not removed: the agent is protected and no valid authorisation was given |
| 2100 | Error | Removal failed |
msiexec exit codes#
| Code | Meaning |
|---|---|
| 0 | Done |
| 1603 | The Lawliet action failed (events 1100, 1101, 2001, 2100); nothing changed |
| 1624 | The transform could not be read (wrong path, or the computer account cannot read the share) |
| 1618 | Another installation was running; Group Policy retries at the next boot |
| 1638 | Another version is installed; use an upgrade |
Upgrade#
- Software installation: add the new release's MSI as a new package in the same GPO (with a new transform if the old code expired), then its properties > Upgrades > Add > the old package, "Uninstall the existing package, then install the upgrade package".
- Startup script: put the new MSI on the share and point the script at it.
The agent keeps its identity and history. An older MSI than the installed one is refused.
Removal#
The MSI removes the agent only when the agent accepts the removal (self-protection):
- Unprotected agents (or after you turned protection off in the console, four-eyes): Software installation > the package > All Tasks > Remove > "Immediately uninstall the software from users and computers". It is removed at the next boot.
- A protected agent is not removed (msiexec 1603, event 2001). Turn protection off for that host, or remove it by hand with an uninstall code for that host. Put the code in a file, not on the command line (process auditing records command lines):
Set-Content -Path C:\Windows\Temp\lawliet-uninstall.txt -Value '<code>' -NoNewline msiexec /x {<product code from README.txt>} LAWLIET_UNINSTALL_CODE_FILE=C:\Windows\Temp\lawliet-uninstall.txt /qn Remove-Item C:\Windows\Temp\lawliet-uninstall.txt
Then remove the host in the console (chapter 10.7).
What you see: msiexec exit code 0 and an Application event from Lawliet Agent Setup (see the tables above); the host goes offline in the console.
12.8 Preparing hosts for remote deployment over WinRM#
Remote deployment (chapter 13) logs in to Windows hosts over WinRM. The host needs a listener, a firewall rule and an administrator account.
Account#
- A domain account in the host's local Administrators group (directly or through a group), for example a dedicated
svc-lawliet-deployin aLawliet-Deployersgroup added to the local Administrators of the target OUs by Group Policy. Do not use a Domain Admins account. - A local account other than the built-in Administrator loses its administrator rights over the network (UAC remote restrictions). WinRM then refuses it like a wrong password. Use a domain account.
- The Lawliet server does not need to join the domain.
WinRM over HTTPS on 5986 (recommended)#
In PowerShell as Administrator on the host:
See the listeners. If WinRM is not running, start it with
Enable-PSRemoting -SkipNetworkProfileCheck -Forcefirst.winrm enumerate winrm/config/listenerWith AD Certificate Services: let the computers get a computer certificate by auto-enrolment, then on each host:
winrm quickconfig -transport:httpsPaste your AD CS root (and any intermediate) certificate as WinRM server CA on the credential in the console.
Without AD CS: a self-signed certificate per host. Set
$ipto the address you will enter in Lawliet:$ip = '<host IP>' $c = New-SelfSignedCertificate -CertStoreLocation Cert:\LocalMachine\My -Subject "CN=$env:COMPUTERNAME" -TextExtension @("2.5.29.17={text}IPAddress=$ip&DNS=$env:COMPUTERNAME") -NotAfter (Get-Date).AddYears(3) New-Item -Path WSMan:\localhost\Listener -Transport HTTPS -Address * -CertificateThumbPrint $c.Thumbprint -Force New-NetFirewallRule -DisplayName "WinRM HTTPS 5986" -Direction Inbound -Protocol TCP -LocalPort 5986 -Action Allow -RemoteAddress <Lawliet server address> Export-Certificate -Cert $c -FilePath "$env:TEMP\winrm.cer" certutil -f -encode "$env:TEMP\winrm.cer" "$env:TEMP\winrm.pem" Get-Content "$env:TEMP\winrm.pem"Paste the printed PEM as WinRM server CA on the credential. For several hosts, paste their PEMs one after another in the same field.
The certificate must name the host as you enter it in Lawliet (its DNS name or its address).
WinRM over plain HTTP on 5985 (insecure)#
winrm quickconfig alone creates only an HTTP listener on 5985. When agents are needed before HTTPS listeners exist, a credential can use WinRM connection: HTTP 5985 (insecure).
Warning. This is not protected by TLS. With Kerberos the messages are encrypted by Kerberos and the host proves its identity. With NTLM the login can be captured and cracked offline, or relayed, and the host's identity is not verified. Use it only on a trusted network, temporarily, then switch back to HTTPS or use Group Policy (12.5).
What Lawliet always does on HTTP: every message is encrypted with the login's session key; Basic authentication and unencrypted sessions are never used; client-certificate credentials cannot use HTTP. Creating or switching a credential to HTTP needs a second administrator. While a credential uses HTTP, the review queue shows "Insecure WinRM in use - switch back to HTTPS".
Risk: as in the warning above. Rollback: switch the credential back to HTTPS (13.7) and remove the HTTP listener when it is no longer needed.
- On the host, as Administrator, run
winrm quickconfig(creates the HTTP listener on 5985) and allow TCP 5985 from the Lawliet server only in the host firewall. - In the console, add or edit the credential with WinRM connection: HTTP 5985 (insecure) (13.2) and have it approved.
- Test it against the host (13.3). What you see: the checklist passes; the credential shows the insecure chip and the review queue shows "Insecure WinRM in use - switch back to HTTPS".
- Deploy, then switch back to HTTPS as soon as listeners exist.
Kerberos (for domains that restrict NTLM)#
A WinRM password credential logs in with Kerberos when the account's domain is listed under Kerberos realms in the console (chapter 13.4). Requirements:
- The server reaches the domain controllers on TCP 88.
- You enter hosts by their DNS name in the domain (
ws01.corp.example.com), and the server resolves that name. An IP address has no Kerberos identity. - The server's clock is within 5 minutes of the domain's.
12.9 Procedure: uninstall the agent#
Risk: the host stops being monitored. Rollback: install it again.
If the agent is protected, get an uninstall code: Environment > Hosts > the host > Self-protection > Issue uninstall code (four-eyes; valid 1 hour, this host only).
A host installed by the MSI: remove it as in 12.7.
Any other host: in Windows PowerShell as Administrator, run the installer the server serves (
agents\install_windows.ps1from the bundle):powershell -NoProfile -ExecutionPolicy Bypass -File .\install_windows.ps1 -Uninstall powershell -NoProfile -ExecutionPolicy Bypass -File .\install_windows.ps1 -Uninstall -Code '<code>' # protected agentRemove the host in the console.
What you see: "Lawliet agent removed from this host. Remove it in the console too ...".
If it fails: "This agent is protected. Removing it needs an authorization code from the console ..." - issue a code for this host and run again.
12.10 Installer parameters (install_windows.ps1)#
Add the parameters to the command from 12.2 (or 12.3) and run it in an elevated PowerShell. What you see: the installer prints each step and ends with the agent running; the host appears in Environment > Hosts.
| Parameter | Purpose |
|---|---|
-Server URL | Server address |
-Token SECRET | Enrolment secret |
-Name NAME | Name shown in the console (default: computer name) |
-CaCert PATH | Trust and pin this server certificate (self-signed server) |
-Sha256 HASH | Check the agent against a hash you got separately |
-LocalBinary PATH | Install this lawliet-agent-windows-amd64.exe; needs -Sha256 |
-OfflinePackage PATH | Install from an offline package (ZIP or unpacked folder) |
-Python | Install the Python fallback agent |
-Uninstall | Remove the agent |
-Code CODE | With -Uninstall: an uninstall code for a protected agent |
-RecoveryKey KEY | With -Uninstall: the installation's recovery key |
-RefreshCa | With -CaCert: give the installed agent a new server certificate |
-Insecure | Allow a plain-HTTP server. Lab only |
Managing the agent on the host:
Get-ScheduledTaskInfo -TaskName LawlietAgent # last and next run, last result
Get-Content "$env:PROGRAMDATA\Lawliet\lawliet-agent.log" -Tail 50 -Wait # live log
Stop-ScheduledTask -TaskName LawlietAgent; Start-ScheduledTask -TaskName LawlietAgent # restartRun these in an elevated PowerShell. With self-protection on, the watchdog starts a stopped agent again within 20 seconds; turn protection off in the console first if you need it stopped (chapter 16). To repair a damaged installation, run the installer again with the same command (12.2 or 12.3): it upgrades in place and keeps the host's identity.
More detail: Windows Group Policy reference, offline packages and remote deployment reference.

