Back to blog
FILE 0x4F·FREEZEGUARD: A WINDOWS UWF AGENT SHIPPED AS A SERVICE

FreezeGuard: a Windows UWF agent shipped as a service

April 5, 2026 · windows, agent, side-project

I shipped a small side-project that wraps Windows' Unified Write Filter (UWF) — the feature that lets you "freeze" a system drive so nothing written to it survives reboot — behind a web console, a serverless API, and a tenant model. The agent runs as a Windows service, polls a configuration endpoint, and toggles UWF on or off per the tenant's policy.

Why UWF needs a wrapper

UWF ships with Windows but the friction is real. It's a Windows Enterprise / Education / IoT feature, enabled through DISM, managed through uwfmgr.exe from an elevated prompt, with overlay management, exclusion lists, and a reboot required to apply most changes. It's powerful — but for the "I want public terminals to auto-revert on every reboot" use case, the day-to-day operational surface is too sharp for non-experts.

The wrapper smooths it: enroll a device, pick a policy from a web console, the agent does the rest.

The shape

The agent itself is small: a Windows service that polls a config endpoint every 60 seconds, applies whatever policy the tenant admin has set, and reports state back.

Test deployment

Put the agent on a throwaway Windows VM. Installed as FreezeGuardAgent. Polled every 60 seconds. Enabled UWF, marked the C: volume protected, queued the pending reboot.

> uwfmgr get-config
Unified Write Filter Configuration
----------------------------------
  Current Session Settings:
    Filter state: ON
  Next Session Settings:
    Filter state: ON
  Volume Settings
    Volume 1
      Volume ID:        \\?\Volume{...}
      Type:             Physical
      Bind by Drive Letter: No
      Volume name:      C:
      Volume state:     Protected

Took a VM snapshot at this point — labeled it freezeguard-tested — so future test runs start from a known-good state.

Architecture decisions

A few choices worth flagging:

One DynamoDB table for everything. Tenants, devices, policies, and audit log all share keys like TENANT#<id> / DEVICE#<id> / POLICY#<id> / LOG#<timestamp>. Single table means one set of CloudWatch metrics, one set of permissions, one cost line. The classic Rick Houlihan pattern.

API key per tenant. Tenants get an fg_live_<random> key that the agent sends on every request. Simple, rotatable, no OAuth dance required for an agent that does nothing but poll a single endpoint.

Two separate CloudFront distributions. One for the console (authenticated, no caching), one for downloads (anonymous, heavy caching). They have different cache and origin behavior, so splitting them lets each be configured optimally.

Marketing under the same parent domain. The marketing page lives under a /freezeguard/ path on a sibling marketing site, sharing that site's S3 bucket and CDN. Adding a new product to the marketing site is just a new subdirectory and a CloudFront invalidation.

What I'd do differently

The agent installer story is the weakest piece. It's currently a raw service binary plus install instructions. A real MSI installer (or even a signed PowerShell installer script) would dramatically lower the "deploy to 50 machines" friction.

I'd also add a CloudWatch metric for "devices last reported in the last 24 hours" and an alarm on that. The agent reports state every 60 seconds; if a device falls out of that report cadence, that's usually the first sign UWF froze something it shouldn't have, or the service crashed. Currently I'd notice the next time I opened the console, which is fine for one tester and bad for a real deployment.