Patch Management
Overview
ET Ducky's Patch Management keeps the operating system and third-party applications current across your entire Windows and Linux fleet from a single policy engine. It covers the OS, the application catalog, and everything in between — winget and Windows Update on Windows; apt, dnf, zypper, snap, and flatpak on Linux; and vendor patch scripts for anything a package manager can't reach. The same policies, rings, and maintenance windows drive OS updates and app updates alike, so you configure intent once and let the agent execute it.
Patches are verified, not just installed
A clean installer exit code does not guarantee a healthy machine: a patch can report success and still leave a service stopped, send the patched application into a crash loop, or shift CPU, memory, or disk baselines. After each install, the agent uses the same kernel event stream it already runs for monitoring to check the host — whether critical services came back up, whether the patched application is crash-looping, whether resource baselines deviated, and whether any behavioral rule fired. Rollout gates consume those signals, so a patch is treated as successful only once the host is verifiably healthy afterward, not simply because the installer exited 0.
Tip: Before relying on automated rollout in production, validate your verification gate on a canary ring — deploy a patch you know breaks a service and confirm the wave pauses, the job is marked regressed, and the root-cause analysis identifying the failed service is attached.
Where to find it
Patch Management lives under Systems → Patch Management. The fleet summary stays pinned at the top, and the rest of the page is organized into tabs so you're not scrolling one long column:
- Schedule — an interactive calendar that projects deploys, maintenance windows, and catalog auto-update scans in time, where you can reschedule, cancel, and schedule new deploys (see The Schedule tab).
- Applications — the app-management surface, with sub-tabs including Software Catalog (operator-curated entries for apps no package manager tracks, each with Draft install script, hub seeding, and optional automatic version updates), Approved Applications, and OS Packages (an inventory-sourced view of operating-system packages — see below).
- Policies — patch policies, rings and rollout waves, and the guided Set up patching flow.
- Agents — a host-and-app view with two modes: By host (pick a machine, see its pending updates and installed apps with versions and how each is managed, plus per-app actions) and By app (find every host that has a given app, filter, and uninstall across all of them at once). The fastest way to answer “what's on this box?” or “get this app off every box.”
- Logs — a live activity log of patch work, with two sub-tabs. Changes is the deploy history / job log (installs, uninstalls, migrations, seeds): each job's status and, once it finishes, the captured exit code, stdout, and stderr, with Retry, Re-draft & retry, and Cancel. Each row expands to its full deployment-log detail, and the view is time-windowed (bounded by your data retention). This is where the fleet-wide available-updates view now lives — the former standalone “Updates” tab was merged in here. Scheduled lists upcoming scheduled deployments.
The Distribution Hub's network / firewall egress allowlist (which endpoints the hub host needs outbound) now lives in the docs, on the Distribution Servers page.
The approved / unapproved application lists (including the Available Managers column and Migrate to winget) are a separate card under Systems — see Approved Applications. Drafted vendor patch scripts are reviewed and approved under Integrations → Script Repositories in the built-in Patch Management repo.
The Agents tab (per-host view)
The fleet-wide Updates view answers “which packages need updating across everything?” The Agents tab answers two host-and-app questions, via a mode toggle at the top:
- By host — “what's the state of this one machine?” Pick a host and inspect it.
- By app (bulk) — “which hosts have this app, and act on all of them at once.” The fast path for removing an app fleet-wide.
By host
Pick a host from the dropdown and you get two tables for it:
- Pending updates — the updates that host has scanned (package, installed version, available version, source, and classification).
- Installed apps — everything in the host's latest inventory snapshot, with each app's version, publisher, and a Managed by badge:
winget, a Linux package manager, or No PM (nothing tracks it).
Each installed app has per-row actions:
- Migrate to PM (on No-PM apps) — adopts the app into package-manager management on that specific host so future updates flow through the normal pipeline. ET Ducky detects the matching package automatically by name (the same winget / apt manifest lookup the AI autofill uses) — you don't enter a package id. You can choose to uninstall the existing non-managed copy first (a clean reinstall through the package manager) or adopt the current install in place. If no package-manager match is found, use Set up patching to register a vendor script instead.
- Uninstall — removes the app from that host. ET Ducky generates the uninstall script from a hardened, deterministic template (not an AI guess): it uses the package manager when one applies (e.g.
winget uninstall --silent/apt-get remove -y), an MSI's silentmsiexec /x … /qn, the vendor's own quiet-uninstall command, orRemove-AppxPackagefor Microsoft Store apps. After running, it re-checks the host and only reports success once the app is actually gone — so a job never shows “done” while the app is still installed. Apps managed by a store or launcher (Steam, Epic, GOG, Battle.net) have uninstallers that are inherently interactive and cannot run silently; the script detects these and fails with a clear message rather than opening the client and falsely succeeding — remove those through the store client. Uninstall is approval-gated exactly like a vendor patch script: the drafted script lands as pending review in the built-in Patch Management script repo (Integrations → Script Repositories), and it only runs on the host once an admin reviews and approves it. Nothing is removed without that human approval.
Because uninstall rides the existing vendor-script path, it inherits the same safety properties as patching: the agent pulls the approved script over its existing channel, runs it unattended, and reports the result — there is no new inbound port and no removal until approval.
Run in the interactive session (GUI-coupled installers)
The agent normally runs installers and uninstallers silently in the background service session (Windows Session 0). A few setups are GUI-coupled — they hand off between windowed phases and hang when no desktop is present (the classic case is an Inno Setup uninstaller's two-phase handoff). For those, tick Run in interactive session before you uninstall (or migrate/install) and the agent launches the installer in the logged-on user's desktop session instead, where the handoff completes. It's off by default — silent Session-0 execution is correct for winget, MSI, and Linux package installs. If the option is on but no one is logged on to the host, the job fails clearly (“no interactive session available”) rather than hanging — re-run it with the box unchecked to attempt a silent install. ET Ducky Desktop itself is special-cased: its uninstall always uses a built-in headless switch, so it removes cleanly from Session 0 with nobody logged on.
By app (bulk)
Switch to By app to remove an application from every host that has it, in one action. Type the app name (exactly as it appears in inventory) and choose Find hosts; ET Ducky scans each host's latest inventory snapshot and lists every machine that reports the app, with its installed version, Managed by badge, last-seen IP, last logged-on user, tags, and online state.
Narrow the list with the filters — OS, version-contains, host/tag search, IP, and last user — then tick the hosts you want (or use the header checkbox to select everything currently shown). The Uninstall on selected (N) button submits them all at once.
A bulk uninstall is drafted and approved the same way as a single one, with one detail: ET Ducky groups your selection by operating system and drafts one approval-gated uninstall script per OS (Windows and Linux remove software differently), then queues a withheld job for each host. Approve the script(s) once under Patch Management → Scripts and every queued host runs it — no removal happens on any machine until that approval. Hosts that already have an open uninstall for the app are skipped, so re-running is safe.
The Staged Rollout Model
Patch Management ships as one deployment but turns on in ordered phases. Each phase has its own flag, and each flag is independently reversible — turning a flag off is the rollback for that phase. The phases build on each other from read-only visibility up to AI-assisted regression analysis. Understanding the phases helps you reason about exactly how much automation is active in your environment at any moment.
| Phase | What it turns on |
|---|---|
| Scan | Read-only visibility. Agents scan for available updates (winget / Windows Update / apt / dnf / zypper / snap / flatpak) and report them; the inventory diff records an application-change ledger (installed / removed / version-changed). You see what's available under Systems → Patch Management but nothing is installed. On by default. |
| Execute | Manual approve-and-install. You (or an auto mode, once enabled) approve a specific update; the agent installs it inside the maintenance window and reports a transcript-grade result. This is the authoritative kill switch — while it is off, no agent installs anything, even one configured to. |
| Auto | Policy automation. The server's evaluation loop resolves each agent's policy and auto-approves updates by classification, age (deferral), and exclusions/holds — no per-patch clicking. Vendor patch scripts become available as jobs here. |
| Rings | Staged rollout plus post-patch verification. A version moves through ordered rings (canary → broad), promoted only after a soak period and a clean verification verdict. Regressions auto-pause the wave. |
| AI | Regressed patches are persisted as incidents and fed into the troubleshooting and historical-analysis pipeline, so the AI knows "this KB broke the print spooler on this fleet last month." |
| HubCache | LAN-local installer caching. On multi-endpoint sites, an installer is staged once to a Distribution Hub and every agent fetches it locally (SHA-256 verified, pinned hub certificate) instead of each downloading from the internet. |
Scan + Execute is the credible minimum. Many MSPs run there and approve manually. Rings is where the kernel-verified rollout story lands — turn it on after you've soaked the verification gate against a known-bad patch in a lab.
Patch Policies
A patch policy is the intent you express once and apply to many agents. An organization can have several policies; each agent resolves to exactly one. A policy is created disabled and carries the following settings.
OS update mode
manual— OS updates are scanned and surfaced but never installed without an explicit approval.security_auto— updates classified as security/critical are auto-approved (subject to deferral); feature updates still require a human.all_auto— every available OS update is auto-approved subject to the policy's deferral and exclusions.
App update mode
manual— application updates are surfaced but require approval.policy_auto— application updates are auto-approved per the policy (again subject to deferral and exclusions).
Deferral — AutoApproveAfterDays
The deferral window is your safety buffer against bad vendor releases. An update is held for the configured number of days after it is first seen before an auto mode approves it — for example, "auto-approve security updates 3 days after publish." If a vendor pulls a broken patch within those days, you never installed it. Manual approval always bypasses the deferral clock.
Reboot policy
never— the agent never reboots on its own; an install that requires a reboot parks atawaiting_rebootand surfaces a badge for a human to action.window_only— a required reboot happens only inside the maintenance window. The agent re-checks the window is still open at the moment it would reboot (a long install can outlast the window); if it closed mid-install, the job staysawaiting_rebootuntil the next cycle rather than rebooting late.immediate_if_required— the host reboots as soon as an install reports a reboot is required, regardless of window.
When the agent does reboot, it does so once per batch (not once per patch). Rather than a fixed countdown, any logged-on user gets an interactive reboot prompt in their own session with defer / delay options — they can postpone the restart rather than being force-rebooted out from under their work. (Reboot is performed by the agent, so a host on an agent build that predates reboot support will install but not auto-restart until it's updated.)
A job that reports it needs a reboot parks at awaiting_reboot. It auto-advances to succeeded on its own once the host actually reboots — the agent detects the restart on its next heartbeat and the cloud clears the parked job automatically. An operator no longer has to manually mark these done after a machine comes back up.
Maintenance windows
Maintenance windows define when work is allowed to dispatch and install. Each window is a set of days, a start time, and a duration in minutes — for example, days:[2], start:"02:00", durationMin:240 for a four-hour window beginning Tuesday at 02:00. The start time is interpreted in each agent's own local timezone (reported by the agent's OS), so “Tuesday 02:00” means 2 AM wherever each machine actually is — the right behavior for a fleet spread across regions. Agents whose timezone hasn't been reported yet fall back to UTC. Windows are midnight-wrap aware. Approved jobs sit as scheduled until the agent's local window opens.
Exclusions and holds
Exclusions pin or hold specific packages out of patching — a list of package keys, each with a reason and an optional "until" date. A held package is skipped by the policy evaluator even in an auto mode, so you can freeze a known-problematic application or a version your line-of-business software depends on, while everything else keeps flowing.
Holds are currently enforced server-side — the evaluator skips held packages. Pushing the hold down to the host (so a local admin sees apt-mark hold / dnf versionlock locally) is a planned follow-up.
How an Agent Resolves to a Policy
Policy assignment is deliberately simple and predictable: a tag assignment wins over the organization default.
- A policy can be marked org default. Every agent that is not otherwise assigned falls under it.
- A policy can be assigned to an agent tag. Any agent carrying that tag resolves to that policy instead of the default.
So to put a group of machines on a different patch cadence, you tag them and assign a policy to that tag — no per-agent configuration. An agent always resolves to exactly one policy: its tag-assigned policy if it has one, otherwise the org default.
Rings, Rollout Waves, and Promotion
Rings turn a single approved version into a controlled, staged rollout instead of a fleet-wide blast.
Rings are agent tags
A ring is a tag. Ring 0 is typically a canary tag (a handful of low-risk machines), and later rings are progressively broader. Because rings are just tags, all of your existing tag tooling — bulk assign, filters, saved selections — is the ring-management UI. Each ring within a policy has an order, a soak period, an auto-promote flag, and a verification gate.
Rollout waves
When a new version of a package needs to roll out, it travels through the policy's rings as a rollout wave. The wave tracks which ring it's currently in and keeps per-ring success/fail/regress counts so you can watch progress on a single row.
Starting a rollout
Start rollout kicks off a wave on demand: pick the policy, the source (winget, a Linux package manager, or a vendor script), the package key, and an optional target version (blank = latest). The package-key field has a type-ahead — start typing an app name and it suggests matching apps from your Approved Applications, resolving the friendly name to the real source key (for example 7-Zip → 7zip.7zip) and offering a dropdown of the versions your fleet's scans report as available. It creates the ring-0 (canary) jobs immediately, then promotes through the rings per the rules below.
Promotion
A wave is promoted from ring N to ring N+1 only when all of the following hold:
- the ring's soak hours have elapsed (minimum time the version must bake in the current ring), and
- the verification verdicts in the current ring satisfy the ring's gate (see below), and
- either the ring is set to auto-promote, or a human clicks Promote.
This is the concrete meaning of "more automation than other RMMs": auto-approval by classification and age rather than per-patch clicking, and auto-progression through rings gated on kernel-verified health rather than timers alone.
Auto-pause on regression
Any regressed verdict in the current ring pauses the entire wave (state paused_regression) and fires a notification with the evidence attached — which service died, which baseline deviated, and the bracketed kernel events. The wave stops spreading until a human reviews it. This is the safety net that makes broad rings safe to automate.
Post-Patch Verification Gates
Every ring carries a verification gate that decides how thoroughly the agent checks the host after an install before marking the patch successful. The gate is what turns "the installer exited 0" into "the machine is verifiably healthy," and it determines whether the wave is allowed to promote to the next ring.
Gate levels
none— exit code only. Signals are still recorded, but the verdict is based solely on whether the installer succeeded.basic(default) — for a verification window after the install (and any reboot), the agent confirms it heartbeats healthy, that there is no critical-service-down in heartbeat status, that the patched package's processes are not crash-looping (matched against the package's binaries via kernel process-exit events), and that no behavioral detection fired.full— everything inbasicplus no new performance inflection (a spike or sustained deviation) attributable to the patch window. On any deviation, the root-cause-analysis path runs and attaches an AI explanation to the job — for example, "CPU sustained +40% after the Chrome update; the spike brackets to GPU-process restarts." That text rides along in the auto-pause notification.
Signals each gate consumes
Depending on the level, verification draws on: heartbeat critical-service status, crash-loop detection (kernel process-exit events for the patched binaries), behavioral detections, performance inflections (spike / drop / sustained), and baseline deviation. These are the same kernel-level signals ET Ducky already collects for diagnostics — patch verification simply reads them in the post-install window.
Verdicts
verified— the host is healthy in the verification window; the job succeeds and the wave is eligible to promote.regressed— a signal indicates the patch broke something. The job is not counted as succeeded, the wave is paused, and the incident feeds the AI history pipeline.inconclusive— the agent went offline before the verification window elapsed. This counts as neither verified nor regressed for promotion and is flagged for review.
Rollback
On a regression, where the package manager supports a downgrade the agent can auto-rollback (for example, a winget --version pin back to the prior version). Where a clean downgrade isn't possible, the job is moved to an explicit manual-rollback-required state rather than pretending it rolled back — honesty over theater. You are never left guessing whether the previous version was actually restored.
Vendor Patch Scripts
Package managers cover most software, but not everything — some applications ship their own updaters, or need an installer flag, or live entirely outside any catalog. For those, ET Ducky uses vendor patch scripts: an approved script that performs the update, tied to a package key.
- Approval-gated. A vendor patch script runs through the same command-validation and approval flow as any other script — risk scoring, hard-block checks, and an explicit approval status — before it can ever execute as a patch job.
- Shareable. Vendor scripts are the sharing surface for patching. An MSP vets an updater once and promotes it to the whole workspace, exactly like a shared KB article or runbook, so every tenant benefits from the vetting done once.
- Same execution path. A vendor-script patch job reuses the hub-backed script-fetch path end-to-end, so it benefits from LAN caching and integrity checks like any other script.
Vendor scripts also cover rollback where a package manager can't downgrade, and they are the intended mechanism for bootstrapping winget itself onto Windows Server SKUs that lack the App Installer.
Software Catalog
Some applications aren't tracked by any package manager — no winget, apt, dnf, or other line item exists for them. The Software Catalog is an operator-curated list of those apps, so ET Ducky can still know each one's current latest version and how to install it. The catalog lives under Systems → Patch Management on the Applications tab, on its Software Catalog sub-tab, where admins can add, edit, and delete entries.
What a catalog entry records
| Field | Purpose |
|---|---|
| Name (required) | The application name, matched case-insensitively against the name agents report in inventory. |
| Latest version (required) | The current shipping version. Version enrichment (below) compares each agent's installed version against this. |
| Publisher | Optional vendor label. |
| Download URL | Where the installer is fetched from. Drives the deterministic install-script template (see below). |
| SHA-256 | Expected hash of the installer, for integrity verification. |
| Silent-install args | The flags that make the installer run unattended — for example /S or /quiet. |
| Platform | any, windows, or linux. |
| Notes | Free-text for your own reference. |
Name and latest version are the minimum. The download URL, SHA-256, and silent-install args are what make a fully deterministic install script possible — without them, drafting falls back to AI (see Drafting an install script).
Adding entries: search and AI resolution
You don't have to fill entries in by hand. The Software Catalog's search box queries the public winget catalog and your org's Linux fleet inventory at once; picking a result prefills the entry from the matched manifest or inventory record. When neither source knows the app, a web fallback runs an AI web search that locates the app's official vendor download page and current version. Each resolved entry records where its data came from: winget_manifest, web_search, ai_web_search, or ai_memory.
AI-resolved entries land as needs-review and are not deployable until an admin verifies them. The gate is fail-closed, so an unverified AI result can never be pushed to agents.
Bulk actions
- Scan for PM — matches name-only entries against winget and the Linux package managers. No AI is used; only definitive package-manager matches are adopted.
- Resolve remaining with AI — runs the AI web resolution over the entries Scan for PM couldn't match. This consumes AI quota like other AI features, and its results land as needs-review per the above.
OS Packages
The OS Packages sub-tab under Applications is an inventory-sourced view of the operating-system-level packages your fleet reports — the layer beneath the applications in the Software Catalog. It's read from each agent's collected inventory, so it reflects what the hosts actually report rather than an operator-curated list.
- Linux — the packages tracked by the host's package manager (
apt,dnf, orzypper). - Windows — installed and available operating-system updates (KBs) collected from agent inventory, including the KBs the host reports as installed and those Windows Update lists as available.
Because the list is drawn from inventory, it stays in sync as agents rescan — there's nothing to add or maintain here by hand.
Deploy an app to agents
Keeping installed apps current is one half of the catalog; the other is pushing a cataloged app to agents that don't have it yet. Each Software Catalog row has a Deploy button that opens a target picker and deployment options. (The earlier per-row “Migrate to winget” action has been removed in favor of the bulk Migrate to PM button.)
Building the target set
You assemble the set of machines additively. Pick a filter — Hostname, Last logon user, Tag, or Any field — type a value, then Add all matches or tick individual rows and Add selected. Switch filters and keep adding: you can find one person's machine by their sign-in name and add it, then switch to a tag and add everything carrying it. The accumulated Target set is what receives the install.
Install method
The Install method dropdown only lists the methods the entry actually has configured:
- Auto — picks per each device's OS: winget on Windows, the package manager on Linux, or the vendor binary.
- Winget (Windows) — installs via the entry's winget id.
- Linux PM — installs the entry's
apt/dnf/zypperpackage on Linux hosts. - Vendor binary — the seeded hub installer (or direct download URL) with the entry's silent-install args.
- Install script (approved) — runs the entry's approved drafted install script.
- Hub folder bundle — an install script plus its payload from a hub folder (see Hub folder bundles).
Targets whose OS a chosen method can't serve (for example winget against a Linux host) are skipped and reported, not failed.
When to deploy & maintenance windows
By default a deploy respects each device's maintenance window. Choose As soon as possible (queues now, installs at the next window) or At a specific time. Tick Bypass maintenance windows to install immediately, ignoring the window. Each device is dispatched when its time or window arrives.
Reboots
Choose how a deploy handles an install that reports a required reboot: Reboot inside the maintenance window (default), Reboot immediately if required, or Never reboot (defer until a manual restart). This applies only when the install actually needs one.
Deploying requires an admin role. Queued installs are tracked on the Logs tab of Patch Management.
Filling the form with AI (“Suggest with AI”)
The Set up patching dialog has a Suggest with AI button that pre-fills the latest version, download URL, and silent-install arguments so you're editing rather than starting blank. The suggestion is grounded, best source first, and the response tells you which source was used:
- winget manifest (Windows). If the app is recognized by winget in your inventory, the version, installer URL, and a real SHA-256 are read straight from the public winget manifest. This is the most accurate path — and the only one that can return a genuine SHA-256.
- Package manager (Linux). If the app is tracked by
apt/dnf/snap/flatpakin your inventory, the dialog tells you the package manager owns its updates, so a vendor script usually isn't needed — patch it through the PM instead. - AI web search. For apps no package manager tracks, ET Ducky uses Claude's built-in web search — the model reads the vendor's site and returns the current version and the official download URL from real results, not from memory. The response labels this source as “an AI web search (verify the URL).” This step uses your workspace's AI key and costs AI tokens like other AI features, so no separate search API key is required (see below).
- Model knowledge (fallback). If nothing above applies, the model fills its best guess. The dialog flags these as unverified — the version may be stale and a SHA-256 is never produced.
Every suggestion is a starting point you must verify before approving — especially the download URL. For vendors whose installer sits behind a portal with rotating links (Citrix, AMD, and the like), the dialog deliberately returns no URL rather than a landing page; for those, a vendor script that resolves the latest at run time is the better fit.
Admin setup for web-search grounding. The AI web search runs on your workspace's AI key — your own key if configured (BYOK), otherwise the platform allowance — so it needs no separate search API key. A Brave Search key (PatchManagement:WebSearch:ApiKey) is now optional: if set, it's tried first as a cheaper web pass; if not, the AI web search covers it. winget-manifest and Linux grounding need no key — only outbound access to GitHub. BYOK on OpenAI / Azure: the AI web search runs only when the active provider is Anthropic or the platform allowance; on an OpenAI/Azure key it falls back to model memory or the optional Brave key.
Version enrichment
A background job (gated by the PatchManagement:CatalogEnrich flag) keeps the catalog connected to what's actually installed. It compares each agent's latest-inventory version of a cataloged app against the catalog's Latest version. When an agent's installed version is older — and the app isn't already being reported by a package manager — the app appears in the existing Packages Needing Updates list with a Source of vendor_script.
In other words, the catalog teaches ET Ducky the "current" version for software no package manager tracks, and enrichment turns that into the same needs-update signal you already get for winget and the Linux package managers. Because matching is by name, a catalog entry only enriches installs whose reported name matches the entry's Name.
Drafting an install script
Each Software Catalog entry has a Draft install script button (renamed from “Draft update script” — it drafts an install script for the entry's chosen version). It builds a patch_vendor script that downloads, verifies, and silently installs the app, so a cataloged application can be installed or updated through the same vendor-script path as anything else.
- How it's drafted. When the entry has a download URL and silent-install args, the drafter uses a deterministic template — the same inputs always produce the same script. When those inputs are missing, it falls back to an AI-drafted script. The result is labelled either "Generated from template" or "AI-drafted — review carefully" so you know which path produced it.
- Landing-page URL detection. If the catalog download URL points at a landing or HTML page rather than a direct installer, the drafter detects that at draft time and uses an AI web search to resolve the real direct download URL (and its hash), so the drafted script downloads the actual installer instead of a web page.
- Post-install version check (Windows). The generated Windows script includes a best-effort post-install version check — after the install, it confirms the app reports the expected version, so a script that exits cleanly without actually landing the new version doesn't quietly pass.
- Saved as pending-review. The drafted script is created with an approval status of
pending_review, and the execution gate is enforced: a pending or rejected patch script will not run. Itsvendor_scriptpatch jobs are withheld from agents until it's approved, then dispatch automatically — the same gate that governs recorder-generated automations. - An admin reviews and approves it. Drafted scripts land in the built-in Patch Management repo under Integrations → Script Repositories, alongside Default, Agent Generated, and Imported. Open it, click View to read the content, then Approve (or Reject with a reason). The repo shows a pending-review count so nothing waits unnoticed. The View script button next to a drafted catalog entry jumps straight to this repo.
The review gate is the point. Drafting never produces something that executes on its own — an AI-drafted or templated script is a proposal. Read it, especially when it's AI-drafted, and approve it deliberately before it can ever run as a patch job.
Review an install script with AI
Before you approve a drafted install script — or a bundle's install script — you can have AI check it. In the script drawer, Review with AI sends the script to your workspace's AI and returns an assessment of whether it will succeed when the agent runs it unattended as SYSTEM (Windows) or root (Linux).
The review gives you a verdict (likely to succeed / risky / likely to fail), a plain-language summary, a list of specific issues with suggested fixes — missing silent flags, downloads without integrity checks, no error handling or non-zero exit on failure, reboot handling, and SYSTEM / Session-0 pitfalls such as the winget CLI being unsupported under the SYSTEM account — and an optional corrected script you can adopt.
If the AI returns a corrected script, Replace draft with this version adopts it over the current pending draft (the AI-corrected script becomes the draft, saved pending_review so it still goes through approval). You don't have to hand-edit the original.
You can also approve without leaving this surface: an Approve button sits in the draft drawer (next to Review with AI) and in the bundle's install-script form. Approving there approves the script in place and clears the entry's “needs review” flag in one step — the script becomes deployable immediately, with no need to open Integrations → Scripts.
Approval still gates execution — a pending or rejected script never runs. What's changed is that you can adopt the AI's corrected script and approve it right here, rather than the review being purely advisory. It uses your workspace's AI — your own key if configured, otherwise the platform allowance — so it's subject to the same quota as other AI features.
Distribute installers through the Distribution Hub
For an app with no package manager, each agent would otherwise download the installer from the vendor itself. If the workspace has a Distribution Hub configured, you can instead publish the installer to the hub once and have every other agent install it from the hub over the local network. The vendor is contacted a single time, agents fetch the bytes locally, and in a locked-down environment only the hub agent needs outbound access to the vendor.
Seeding the installer to the hub
Each Software Catalog row that has a download URL or a winget Id shows a Seed to hub button (it reads Seeding… while the job runs, then Re-seed to hub once the file is cached). You can also use Save and distribute via hub in the Set up patching dialog. Either dispatches a one-time job to the hub-host agent, which fetches the installer, records its SHA-256, and caches it on the hub. The entry shows a seed status of seeding, then seeded once the hub holds the file (or failed if the fetch did not complete). If no Distribution Hub is configured, seeding is skipped and agents fall back to downloading directly.
The hub-host agent fetches the installer one of two ways:
- From a download URL. If the entry has a download URL, the hub downloads it directly.
- From a winget Id (no URL needed). If the entry has only a winget Id and no download URL, the hub runs
winget downloadto fetch the official installer once and caches it. From then on the app deploys as a hub-resident vendor binary, so it works under data residency (see data residency) without you ever locating a download URL by hand.
A winget-seeded EXE installer with no silent-install args on the catalog entry may show its UI when it runs. Set silent-install args on the entry for EXE installers. An MSI is detected by content and run silently via msiexec automatically, so it needs no args.
Step by step — seed to the hub (including from winget)
- From the dashboard, open Systems → Patch Management, select the Applications tab, and open its Software Catalog sub-tab.
- On the app's row, click Seed to hub (shown when the app has a download URL or a winget Id). The button reads Seeding… while it runs, then Re-seed to hub once cached.
- What happens: a one-time job goes to the hub-host agent. If the app has a download URL, the hub fetches it from that URL; if it has only a winget Id, the hub runs
winget downloadto fetch the official installer. The file is cached on the hub and its SHA-256 recorded. - Watch the seed status go
seeding→seeded(orfailed). Once seeded, deploy the app and every target installs it from the hub over the LAN.
For a winget-seeded EXE with no silent-install args, set silent-install args on the catalog entry or it may show UI; MSI installers are detected and run silently automatically. Requires a Distribution Hub (otherwise seeding is skipped / returns no-hub).
Installing from the hub
Installs create a binary patch job per agent. Each agent requests a short-lived, certificate-pinned grant, fetches the cached installer from the hub, verifies it against the recorded SHA-256, and runs it with the catalog entry's silent-install arguments (msiexec /i for an MSI, the installer directly otherwise on Windows; an executable run unprivileged on Linux). If the hub cannot be reached, the agent falls back to the direct download URL and verifies the same SHA-256, so an install never depends on the hub being up.
The hub guarantees consistency, not authenticity. Every agent gets byte-identical, hash-verified bits from the hub, but the trust anchor is the first fetch from the vendor URL. Confirm the download URL points at the official vendor installer (and, where the vendor publishes one, check the SHA-256 against their checksum) before distributing it to the fleet.
Network requirements for the hub
Because the hub host is the one machine that reaches the internet for these downloads, it needs outbound access to the control plane, the LAN hub port, the winget / Microsoft set, common Linux mirrors, and the vendor hosts your cataloged apps download from. The full allowlist — with each entry marked as fleet-wide or Patch Management–only — lives on the Distribution Servers page under Network / firewall egress, so you can lock down every other agent to the hub. Verify the Microsoft and Linux sets against current vendor documentation; they change over time.
Add an app straight from the hub
When you add a catalog entry, Choose from distribution hub… lists the installers already cached on a hub (Windows .exe/.msi/.msix and Linux .deb/.rpm/.AppImage and the like, plus anything seeded as a patch binary). Picking one prefills the name, version, and SHA-256, and links that hub file to the entry, so installs run LAN-locally with no separate seed step.
Hub folder bundles
Some apps don't install from a single file — they need a script plus a payload (an installer the script drives with a config file, a folder of files, an unpack-then-build step). A hub folder bundle packages that: the payload lives in a folder on your Distribution Hub, and an install script you author runs against it on each target.
1. Drop the payload on the hub
Map your Distribution Hub as a network drive (Integrations → Distribution Servers issues a mount credential for this), then copy the installer and any support files into a versioned folder under /bundles/ — for example /bundles/acme-tool/3.2/. The hub indexes whatever you drop there automatically; there's no separate upload step in the dashboard.
2. Point the catalog entry at the folder and write the script
On the catalog entry's Hub folder bundle section, set the payload folder (it must be under /bundles/), click Refresh payload to confirm the dropped files have been indexed, then write the install script (PowerShell or bash). It runs in the payload folder, so reference files by relative name (e.g. Start-Process .\setup.exe -ArgumentList '/S' -Wait). Use Save script for review, and optionally Review with AI first.
3. Approve, then deploy
The bundle's install script is saved pending_review and must be approved under Integrations → Script Repositories before it can run — the same gate as any vendor script. Once approved, deploy it with the Hub folder bundle install method (see Deploy an app to agents). Each target fetches the payload from the hub over the LAN (SHA-256 verified per file), runs the approved script against the staged folder, and honors your schedule, maintenance-window, and reboot choices.
A bundle reports it needs a reboot if its script exits 3010 (Windows) or creates a file named ETDUCKY_REBOOT_REQUIRED in the folder (either OS). The reboot then follows the deploy's reboot policy — it isn't forced.
Migrate an app to package-manager management
If an app was installed manually but is also available in a package manager (winget on Windows, apt / dnf / zypper on Linux), you can move it under that manager so it patches automatically and you stop maintaining a download URL for it. The Migrate to PM button at the top of the Software Catalog migrates the apps matching your current name/publisher filter — filter to the app (or set of apps) you want, then migrate. (The old per-row “Migrate to winget” action was removed in favor of this filtered, bulk button.)
By default migration adopts the app in place: the package manager installs over the existing app so it takes ownership, with no removal step. Tick replace non-PM copy for a clean swap — the package-manager install runs first, and the existing non-PM copy is removed only after that install succeeds, so the app is never left uninstalled. After migrating, the app reports as managed by winget (or the Linux manager) and is patched through the normal pipeline, so it no longer needs a vendor script.
Linux note: the migration install is not covered by the default upgrade-only sudoers rule, so a Linux host needs an updated /etc/sudoers.d/etducky-rmm entry permitting the install before migration can run; until then the agent reports that sudo was refused.
Automatic updates (version watching)
A catalog entry can keep itself current. Turn on Watch for new versions & auto-update on the entry and ET Ducky watches for a newer version, bumps the entry, re-seeds the new installer to the Distribution Hub, and lets your patch policy roll it out to the agents already running the app. Off by default; nothing changes until you enable it per app.
Step by step — tell ET Ducky to watch an app
- From the dashboard, open Systems → Patch Management, select the Applications tab, and open its Software Catalog sub-tab.
- Find the app in the catalog list and click Edit.
- Turn on Watch for new versions.
- Optional but recommended — set a version source so detection is exact. Set a Version source URL (a releases page, JSON, or RSS feed), choose a mode (
regexorjson), and give a pattern: forregex, a .NET regex with a capture group, e.g.v([0-9.]+); forjson, a dot-path, e.g.tag_nameor0.version. For versioned installer links, set a download URL template containing{version}. - If you set no version source URL, detection falls back to the AI web search (Claude reads the vendor site).
- Click Save.
Step by step — turn the scanner on (org-wide cadence)
- From the dashboard, open Systems → Patch Management and select the Policies tab.
- In the Catalog auto-update card, check Scan catalog apps for newer versions automatically.
- Set Check every (hours) (
1–720). - Click Save. Last run shows there after the next cycle.
A found newer version is bumped, re-seeded to the hub, and rolled out through this org's patch policy (approval, rings, maintenance window). A manual policy still gates it; only apps with Watch for new versions turned on are scanned.
Turn it on for your org
The check is configured per organization on the Patch Management Policies tab, in the Catalog auto-update section:
- Enable — turns the periodic check on for the org. Off by default.
- Check every (hours) — how often the org's catalog is scanned, from
1to720hours.
When enabled, a leader-elected background check (it pulses about every 30 minutes and acts on each org per that org's interval) scans every catalog entry with Watch for new versions turned on, resolves the latest version, bumps the entry, and re-seeds it to the hub. The section also shows Last run and any error from the most recent scan.
Where the new version comes from
The watcher resolves the latest version in this order:
- The Distribution Hub. If a newer installer for this app is seeded to a hub (tagged with its version), the watcher adopts it — no new download.
- A version source URL. Point Version source URL at a releases page, JSON, or RSS feed and give a version pattern — a regex with a capture group (e.g.
v([0-9.]+)) or, in JSON mode, a dot-path (e.g.tag_nameor0.version). When the resolved version is newer than the entry's, it updates. Use a download URL template with a{version}placeholder for versioned installer URLs. - AI web search (fallback). For an entry with no version URL, the watcher falls back to the same AI web search the autofill uses — Claude reads the vendor's site and returns the current version. Useful for apps that don't expose a machine-readable version feed.
- Content-change fallback. With no version source, the watcher watches the download URL itself; a changed ETag/Last-Modified/size is treated as a new release and stamped with a date-based version. This has no real version number, so a version source is more reliable — prefer it when the app exposes one.
How it deploys
Auto-update only refreshes the catalog version and the hub copy. The rollout itself still runs through your normal pipeline: version enrichment flags agents whose installed copy is now older, and the patch policy approves and deploys per its app-update mode (approval, rings, and maintenance window all apply). A manual policy still gates the rollout — auto-update never bypasses it. Each detection also fires a Catalog App Update Detected automation trigger, so you can attach a notification or other rule under Automations.
Auto-update is driven by the per-org Catalog auto-update settings above. The PatchManagement:CatalogWatch server flag is now an optional master kill-switch — with it off, no org's check runs regardless of the dashboard setting. Any per-entry check error is shown on the entry's edit form.
Platform Specifics
Windows
Windows has two engines working together under one policy:
- Applications — winget. The agent scans with
winget upgradeand installs with a silent, non-interactivewinget upgrade --id <Id> --version <v>under the service context. Wherewingetis absent (some Server 2016/2019 hosts without App Installer), the scan records a capability flag and those hosts rely on vendor scripts. - Operating system — Windows Update (WUA). The agent talks to the in-box Windows Update Agent COM API directly (no PSWindowsUpdate dependency) to search, classify (security / critical / feature), and install updates by KB. When an install reports a reboot is required, the job parks at
awaiting_rebootand obeys the reboot policy and maintenance window. WSUS-managed hosts are detected and their OS updates are marked externally-managed rather than fought.
Linux
On Linux, OS and applications share one engine — the platform's native package manager:
- Scan and install via
apt,dnf, orzypperfor system packages, plussnapandflatpakfor applications. Security classification comes from each manager's update metadata (the Debian-securitypocket,dnf updateinfo, etc.). - The narrow sudoers requirement. The Linux agent runs unprivileged. To install packages it relies on a tightly-scoped
sudoersdrop-in that grants passwordless permission for exactly the upgrade-only package-manager invocations — full-path and argument-anchored, never blanket sudo. This drop-in ships inside the agent package, so enabling Linux patch execution requires rebuilding and reinstalling the .deb/.rpm. Until the package is rebuilt, Linux package installs fail cleanly with a "sudo refused" message rather than silently doing nothing.
If unattended-upgrades is enabled on a Linux host, the agent detects and reports it so your policy doesn't double-drive the same updates.
Security Model
Patch Management inherits ET Ducky's tenancy and integrity invariants. There is no new attack surface introduced by the feature.
- Org-private data. Patch jobs and available-update history are organization-private, enforced by row-level security (RLS) at the database. A tenant can never read another tenant's patch history.
- No server free-text into commands. The agent constructs every package-manager invocation from structured job fields — package key and version — not from free-text supplied by the server. A compromised dashboard session cannot inject a command, because there is no free-text command path for winget / WUA / package-manager installs.
- Unverifiable installer = failed job. Hub-cached and vendor-script installers are SHA-256 verified, and Windows executables may additionally pin an expected publisher. An installer that cannot be verified is a failed job — there is no override flag, matching ET Ducky's verify-or-withhold stance on agent self-updates.
- Agent-pulled dispatch. Jobs are pulled by the agent over its existing channel; there is no new inbound port or listener on the endpoint.
Set Up Patching from the Dashboard
Patching is configured under Systems → Patch Management on the Policies tab — the operator surface for everything below: policies, rings, rollout waves, and turning scanning and execution on at the agents.
1. Create a policy with “Set up patching”
Click Set up patching on the Policies tab to open the guided form. It walks through the policy in order:
- Scope — choose Org default (applies to every agent not assigned through a tag) or Tag (applies only to agents carrying the chosen tag). A tag assignment wins over the org default.
- OS update mode and App update mode —
manual,security_auto/all_autofor the OS, andmanual/policy_autofor apps. - Maintenance window (optional) — pick the days, a start time (interpreted in each agent's local timezone; UTC fallback if the agent's zone is unknown), and a duration in minutes. Approved jobs wait as
scheduleduntil the agent's local window opens. - Reboot policy —
never,window_only, orimmediate_if_required. - Deferral — the auto-approve after (days) field holds an update for that many days before an auto mode approves it.
Org-default + auto-mode guard: if you set an org-default policy to an automatic update mode, the dashboard asks you to confirm, because that mode auto-approves patches for every untagged agent — your whole fleet by default. Scope it to a tag instead if you want a smaller blast radius.
2. Manage policies
The Policies list shows each policy's scope, OS/app modes, reboot policy, and deferral, with Edit, Rings, and Delete actions. Deleting a policy also removes its tag assignments and rings.
3. Edit rings
Click Rings on a policy to open the rings editor. Each ring row has an order, the agent tag it targets, a soak (hours) value, an auto-promote checkbox, and a verification gate (none / basic / full). Add or remove rings and save. Ring orders must be unique. Rings target agent tags, so create the tags first.
4. Roll out a version with waves
Under Rollout waves, click Start rollout to ring out a specific package version: pick the policy, the source (winget, Windows Update, apt, dnf, zypper, snap, flatpak, or vendor script), the package key, and an optional target version. The wave appears in the list showing its current ring and state; while it's active you can Promote it to the next ring or Abandon it.
5. Set scanning / execution on agents
This control pushes the per-agent flags. Pick agents from the list — filter by name or ID, use Select all (filtered), or Select by tag to check every agent carrying a tag. Then set what to push using two three-state dropdowns, one for scanning (PatchScanEnabled) and one for execution (PatchExecuteEnabled):
- Leave unchanged — pushes nothing for that flag; the agent's current value is untouched.
- Turn on — enables the flag on the selected agents. For scanning, the host starts reporting available updates; for execution, the host is allowed to install approved updates.
- Turn off — disables the flag on the selected agents. You can now turn scanning or execution back off from here, not just on — useful for pulling a group of hosts out of patching without editing a policy.
Click Push to selected agents to write the chosen values; the control reports how many agents succeeded and lists any failures. This is a one-time push, not a saved setting — the dropdowns show what you're about to push, not the agents' current state, and they reset to Leave unchanged after the push. Setting both to Leave unchanged pushes nothing.
Recommended ramp: create a conservative policy (manual or security-auto with a few days of deferral), push scanning to a handful of agents and review what comes back, then enable execution. Introduce rings and rollout waves only once you trust the verification gate. Unapproved third-party installs you find along the way can be reviewed and allowlisted under Approved Applications.
The Schedule tab
Patch Management has a Schedule tab — a calendar that projects what will happen and when, so you can see your patch activity laid out in time instead of inferring it from the other tabs. The calendar is interactive: as well as visualizing your patch activity, you can reschedule and cancel deploys, schedule a new deploy, and adjust a maintenance window for a single day, right from the calendar.
What it overlays
The calendar overlays three kinds of event, color-coded with a legend:
- Deploys — each approved or scheduled patch job at the time it will run: its scheduled time, or the next maintenance window if it's waiting on one.
- Maintenance windows — the recurring windows from your patch policies.
- Catalog auto-update scans — the cadence of the per-org catalog check (see Automatic updates).
Views
Toggle between a Month grid and a Week / agenda view, and move through time with prev / next and Today. Times are shown in your (the viewer's) local timezone.
Using the calendar
- From the dashboard, open Systems → Patch Management and select the Schedule tab. Toggle Month / Week; use ‹ › / Today to navigate. Times are in your local timezone.
- Reschedule a deploy: click its chip, pick a new date/time (and optionally Bypass maintenance window), and click Reschedule — or drag the chip to another day. Only pending / approved / scheduled deploys can be rescheduled; an already-dispatched one shows a note and only a Cancel button.
- Cancel a deploy: click its chip → Cancel deploy.
- Schedule a new deploy: click an empty day → pick an app; the Deploy dialog opens preset to that date.
- Adjust a maintenance window for one day: click a window block, then choose Edit recurring policy (changes every occurrence), Skip this day (no window that date), Change time for this day (a one-off start time and duration), or Restore recurring window (remove the one-day override).
Rescheduling and cancel act on real jobs immediately; single-day window changes affect only that date and don't alter the recurring policy.
Maintenance windows are projected in UTC-derived terms, while the dispatcher evaluates each window in the agent's own local timezone (see maintenance windows). So a window's shown time can differ from a specific agent's actual run by that agent's UTC offset — the calendar is a planning aid, not a per-agent guarantee.
Data residency (require a distribution hub)
The Team → Workspace setting Maintain Data Residency By Requiring a Distribution Hub (formerly “Require a distribution hub (strict mode)”) keeps file transfers on your own network. When it's on, file transfers, hub-backed scripts, and app installers must come from a reachable Distribution Hub on the network — ET Ducky never falls back to the cloud or a direct internet download.
Which deploy sources comply
| Source | Under data residency |
|---|---|
| Hub folder bundle | Honored — the payload is hub-resident (see Hub folder bundles). |
| Seeded vendor binary | Honored — the installer is cached on the hub (see seeding to the hub). |
| Hub-backed install script | Honored — imported from a hub script repo and served from the hub. |
| winget / package-manager install | Blocked — pulls from public/vendor sources, which the hub doesn't serve. |
| Windows Update | Blocked — pulls from Microsoft's update service, not the hub. |
A blocked deploy returns an error telling you to seed the installer to the hub or use a hub folder bundle — it doesn't silently fall back. Enforcement is fail-closed end to end: the cloud blocks a non-hub-resident deploy at request time, and the agent itself refuses the direct-download or cloud-script fallback when data residency is on and the hub didn't serve the bytes. (Because the agent enforces its half, updating agents to the current build is what closes the gap on an existing fleet.)
Make an app comply
- Seed its installer to the hub — from a download URL or straight from a winget Id with Seed to hub (see seeding to the hub). Once cached it deploys as a hub-resident vendor binary.
- Package it as a hub folder bundle — payload plus install script on the hub (see Hub folder bundles).
- Import its install script into a hub repo — so the script is served from the hub rather than the cloud.
Step by step — enable strict mode
- From the dashboard, open Team → Workspace (admin).
- Turn on Maintain Data Residency By Requiring a Distribution Hub.
- Confirm a Distribution Hub is configured for the workspace under Integrations → Distribution Servers — strict mode requires a reachable hub.
Step by step — make an app comply
So an app can deploy under strict mode, do any one of the following:
- Seed its installer to the hub. Open Systems → Patch Management → Software Catalog, find the app, and click Seed to hub (see the hub-distribution card), then deploy it as a vendor binary.
- Package it as a hub folder bundle (see Hub folder bundles).
- Import its install script into a hub script repo.
Under strict mode, winget / package-manager / Windows-Update deploys are blocked (they pull from public sources), and the Deploy dialog returns an error telling you to seed to the hub or use a bundle.
Troubleshooting
| Symptom | Cause & fix |
|---|---|
| No available updates show for an agent | The scan flag hasn't reached the agent — PatchScanEnabled is not yet pushed/active on that host. Confirm the agent is online and has received its config; available updates appear after the next scan cycle. |
| Linux job fails with "sudo refused; rebuild the agent package" | The upgrade-only sudoers drop-in ships in the agent package. Rebuild and reinstall the .deb/.rpm (an agent release that carries the drop-in), then retry. This is expected on a host whose package predates patch execution. |
| Agent installs nothing even though it's configured to | The server-side Execute flag is the authoritative kill switch — while it's off, the jobs endpoint returns empty and no agent installs anything. Confirm the phase flag is enabled. |
Job stuck at awaiting_reboot badge | The install succeeded but needs a reboot, and the reboot policy is never or window_only (window not yet open). Once the host actually reboots, the job auto-advances to succeeded on the next agent heartbeat — you don't clear it by hand. To move it along, trigger or wait for the reboot (adjust the reboot policy, or wait for the maintenance window). |
Job stuck at scheduled | The job is approved but waiting for the next maintenance window to open. Check the policy's window days, start time, and duration — remember the start is the agent's local time, so confirm against that host's timezone (and that the agent has reported a timezone; otherwise it falls back to UTC). |
| Install needs a reboot but the host never restarts | Either the reboot policy is never (parks by design), the window_only window closed during the install (parks until the next cycle), or the host is on an agent build that predates agent-side reboot support — update the agent. When a reboot does fire, a logged-on user sees an interactive prompt with defer / delay options and can postpone it, so a restart may be waiting on the user. Once the host reboots, the parked job auto-advances to succeeded on the next heartbeat. |
| OS updates marked externally-managed and not installed | The host is WSUS-managed (or, on Linux, has unattended-upgrades enabled). ET Ducky reports these rather than fighting the existing management; manage them where they're configured, or remove the external management. (Separately, a job that finds an OS update already installed or superseded — common for fast-moving updates — is now recorded as a success / no-op rather than a failure.) |
| A flood of failed Windows Update jobs for “Security Intelligence Update” (Defender) | These rolling Defender signature definitions (KB2267602) re-publish many times a day and are self-managed by Defender. ET Ducky now excludes them from the patch pipeline (both agent and cloud), so they no longer appear as failed jobs. Historical failed rows from before the update can be ignored. |
| Deploy blocked with a “data residency (strict mode)” error | The workspace requires a distribution hub (see Data residency). Seed the app's installer to the hub with Seed to hub (works from a download URL or a winget Id) or use a hub folder bundle. winget / package-manager / Windows-Update sources can't be served from the hub. |
Verdict comes back inconclusive | The agent went offline before the verification window elapsed. It counts as neither verified nor regressed for promotion and is flagged for review — bring the host back online and let it re-verify. |
Related
See Agent Tags for the tagging that drives policy assignment and rings, Approved Applications for reviewing and allowlisting unapproved third-party installs, Behavioral Detections and Health Monitoring for the signals verification consumes, Distribution Servers for LAN-local installer caching, Automations for the application-change ledger triggers, and Security for the wider tenancy and integrity model.