Chapter 5 of 7
Deploying the Windows Agent with Microsoft Intune
Overview
This chapter deploys the PatchMon agent to Windows devices as an Intune Win32 app. A single package, built from three scripts kept in the PatchMon repository, enrols every device with one auto-enrolment token, installs the agent and registers the PatchMonAgent service. You do not need to create hosts by hand or copy per-host install commands.
The scripts live in tools/intune/ on GitHub:
| File | Used as | What it does |
|---|---|---|
install.ps1 |
Win32 app install command | Enrols the device through the Auto-Enrollment API, downloads the server's Windows installer with the new host's credentials, runs it and checks the service is running |
detect.ps1 |
Custom detection script | Reports the app as installed when the PatchMonAgent service is running |
uninstall.ps1 |
Win32 app uninstall command | Downloads and runs the server's Windows removal script |
How it Works
- Intune runs
install.ps1as SYSTEM. Intune starts Win32 app commands in 32-bit PowerShell, so the script relaunches itself in 64-bit PowerShell first. - The script reads the device's
MachineGuidand callsPOST /api/v1/auto-enrollment/enrollwith the computer name and that machine ID. PatchMon creates a pending host and returns itsapi_idandapi_key. - The script fetches
GET /api/v1/hosts/install?os=windowswith those credentials and runs the returned installer, the same one the Add Host wizard uses. That installer downloads the agent binary, writesC:\ProgramData\PatchMon\config.ymlandcredentials.yml, and creates thePatchMonAgentservice. - The script exits
0only when the service is running.
Retries
The script tells Intune how to treat a failure through its exit code:
| Exit code | Meaning | What Intune does |
|---|---|---|
0 |
The agent is installed and the service is running | Marks the app installed |
1618 |
A failure that may clear by itself: a network error, the token's daily limit, a failed download, the installer failing (often Defender), or the service not starting | Retries up to three times, five minutes apart |
1 |
PatchMon refused the enrolment (HTTP 400, 401, 403 or 409). Retrying will not help until someone fixes the cause | Marks the install failed and offers it again on its next re-evaluation, roughly every 24 hours |
1618 is in Intune's default return code list as Retry, so you do not need to add it. After its retries run out, Intune treats the install as failed and tries again on the 24-hour cycle.
The script is safe to run again at any point:
- The service is running: the script exits
0straight away. If the service exists but is stopped, the script tries to start it, and reinstalls if it will not start. - The agent already has credentials (an earlier attempt got as far as writing
credentials.yml): the script reuses them and does not enrol again. - An earlier attempt enrolled but failed before writing credentials: the script sends the host ID it saved in
C:\ProgramData\PatchMon\intune-host-id. Because that host has never reported, PatchMon re-issues its credentials instead of creating a duplicate.
Before You Start
Intune
- Devices are Microsoft Entra joined, hybrid joined or Entra registered, and enrolled in Intune. The Intune Management Extension installs itself when the first Win32 app is assigned.
- Devices run 64-bit Windows 10 or 11. 32-bit Windows is not supported by the agent.
- You have the Microsoft Win32 Content Prep Tool (
IntuneWinAppUtil.exe).
PatchMon
- Devices can reach the PatchMon server over HTTPS.
- On a self-hosted install, Settings → Server URL is set to the address devices will use. The installer writes it into the agent's config.
- If PatchMon uses a certificate from a private CA, deploy that CA to devices first with an Intune Trusted certificate profile. The enrolment call checks the certificate even if Ignore SSL self-signed is turned on in PatchMon.
Microsoft Defender
The agent binary is not code-signed yet, and real-time protection can quarantine it or lock it while scanning, which fails the install. Before assigning the app, add a Defender exclusion for C:\Program Files\PatchMon through Endpoint security → Antivirus and assign it to the same devices.
Step 1: Create an Auto-Enrolment Token
- In PatchMon, go to Settings → API integrations, open the Auto-Enrollment (Direct) tab and select New Token.
- Fill in:
- Token Name: for example
Intune - Windows. - Max Hosts Per Day: at least the number of devices you expect to enrol in a day. When the limit is reached, further devices retry and then wait for Intune's next cycle.
- Default Host Group (Optional): a group such as
Windows - Intune, so new hosts are easy to find. - Allowed IP Addresses (Optional): leave empty unless every device reaches PatchMon from known public IPs. Remote and home-working devices are refused otherwise.
- Expiration Date (Optional): set one if you want the token to stop working after the rollout.
- Token Name: for example
- Copy the Token Key and Token Secret. The secret is shown only once.
Step 2: Prepare the Scripts
-
Download
install.ps1,detect.ps1anduninstall.ps1fromtools/intune/. -
In
install.ps1, set the three values at the top:$Server = "https://patchmon.example.com" $Key = "patchmon_ae_xxxxxxxx" $Secret = "xxxxxxxx" -
In
uninstall.ps1, set$Serverto the same URL. -
Put
install.ps1anduninstall.ps1in an otherwise empty folder, for exampleC:\IntunePackages\PatchMon\source. Keepdetect.ps1and the prep tool out of it: everything in the folder is packed into the app.
Step 3: Build the Package
From the folder that holds IntuneWinAppUtil.exe:
.\IntuneWinAppUtil.exe -c C:\IntunePackages\PatchMon\source -s install.ps1 -o C:\IntunePackages\PatchMon\output -q
This writes install.intunewin to the output folder.
Step 4: Create the Win32 App
In the Intune admin center, go to Apps → All Apps → Create, choose Windows app (Win32) and upload install.intunewin. Use these settings:
| Page | Setting | Value |
|---|---|---|
| App information | Name / Publisher | PatchMon Agent / your organisation |
| Program | Installer type | Command line |
| Program | Install command | powershell.exe -NoProfile -ExecutionPolicy Bypass -File install.ps1 |
| Program | Uninstall command | powershell.exe -NoProfile -ExecutionPolicy Bypass -File uninstall.ps1 |
| Program | Installation time required | 30 minutes |
| Program | Install behaviour | System |
| Program | Device restart behaviour | No specific action |
| Program | Return codes | Leave the defaults |
| Requirements | Operating system architecture | x64 and ARM64 |
| Detection rules | Rules format | Use a custom detection script |
| Detection rules | Script file | detect.ps1 |
| Detection rules | Run script as 32-bit process on 64-bit clients | No |
| Detection rules | Enforce script signature check | No |
| Assignments | Required | A device group |
Both scripts switch to 64-bit PowerShell themselves, so the commands can use plain powershell.exe.
Detection checks that the service is running, not only that it exists. Two things follow from that:
- If someone stops the agent, Intune starts it again (or reinstalls it) at its next evaluation. Exclude a device from the assignment while you work on it.
- An Uninstall assignment skips devices whose agent service is stopped, because Intune sees the app as already gone. Remove the agent from those devices with the removal script described in the Operator Guide.
Assign the app to a small pilot group first, then widen it.
Step 5: Check the Rollout
- Intune: the app's Device install status shows each device. Installs normally finish a few minutes after the device next checks in.
- PatchMon: new hosts appear under Hosts, named after the computer and placed in the token's default host group. They turn active when the installer's connectivity test reaches the server.
- On a device:
install.ps1logs every run toC:\ProgramData\Microsoft\IntuneManagementExtension\Logs\PatchMonInstall.log, which Intune's Collect diagnostics device action also gathers. The agent's own log isC:\ProgramData\PatchMon\patchmon-agent.log.
To test the install script on one machine without Intune, run it as SYSTEM with PsExec from an elevated prompt, then check the exit code:
psexec -i -s powershell.exe -NoProfile -ExecutionPolicy Bypass -File C:\IntunePackages\PatchMon\source\install.ps1
Uninstalling
Assign the app to a group with the Uninstall intent. uninstall.ps1 stops and removes the service and deletes the agent's program files, configuration, credentials and logs. It downloads the removal script from your PatchMon server, so the server must be reachable when it runs.
The host record stays in PatchMon. Delete it from the host's page once the device has gone. If the same device will get the agent again later, delete the host before reassigning the app: otherwise PatchMon recognises the machine and refuses to enrol it a second time.
Troubleshooting
Every message below is in PatchMonInstall.log on the device.
| Message | Cause | Fix |
|---|---|---|
HTTP 429 with Rate limit exceeded |
The token's Max Hosts Per Day was reached | Raise the limit. Devices retry on their own |
HTTP 401 with Invalid or inactive token, Invalid token secret or Token expired |
Wrong key or secret in install.ps1, or the token was revoked or has expired |
Fix the values, rebuild the package and upload the new .intunewin to the same app |
HTTP 403 with IP address not authorized for this token |
The device's public IP is outside Allowed IP Addresses | Widen or clear the allow list |
HTTP 403 with Host limit reached for this host's package |
Your plan's host allowance is used up | Remove hosts you no longer need, or raise the allowance |
HTTP 409 with Host already enrolled |
PatchMon already has a host with this machine ID and computer name: the device was uninstalled and reassigned without deleting its host, or it had an earlier manual install | Delete that host in PatchMon. The device enrols on Intune's next cycle |
HTTP 409 with code host_not_reenrollable |
The device enrolled with a previous token and never finished, then the token was replaced | Delete the pending host in PatchMon. The device enrols as a new host on Intune's next cycle |
HTTP 409 with code host_reporting |
The saved host ID belongs to a host that has already reported, for example after its credentials were regenerated in PatchMon | Reinstall with the install command on the host's page, or delete the host in PatchMon |
HTTP 0, or Installer download failed with a connection error |
The device could not reach the server: DNS, firewall, proxy or an untrusted certificate | Check the device can open $Server in a browser, and deploy your CA if it is private |
PatchMon installer exited with 1, agent binary missing from C:\Program Files\PatchMon |
Defender quarantined it | Add the exclusion described in Before You Start, then let Intune retry |
| Intune shows the app installed but no host appears in PatchMon | A running agent from an earlier install points at another server, or uses credentials that were deleted in PatchMon | Check patchmon_server in C:\ProgramData\PatchMon\config.yml. Uninstall the old agent, then let Intune install again |
No PatchMonInstall.log and the scripts never run |
A group policy enforces an AllSigned execution policy, which overrides the Bypass in the install command |
Sign the scripts with a trusted certificate, or exclude these devices from that policy |
Security Notes
- The token secret is inside the package. Anyone who can download the app from Intune, and SYSTEM on a device while the install runs, can read it. Use a dedicated token for Intune, keep Max Hosts Per Day close to your real rollout pace, and revoke or replace the token when the rollout ends. Revoking it does not affect hosts that are already enrolled.
- A leaked token lets someone add hosts to PatchMon, which can use up your host allowance and block new enrolments. With a pending host's ID and its machine's
MachineGuidas well, it can re-issue that host's credentials. It gives no access to hosts that are already reporting, or to their credentials. - The installer locks
C:\ProgramData\PatchMonto SYSTEM and Administrators before it writescredentials.yml.