[AUM 3.1] Build Sheet: Standing Up Update Manager Across the Estate

Every machine assessed on a schedule, tagged into a ring, running under a maintenance configuration, and one full patch cycle completed with WSUS still supplying every byte. That last clause is the proof that the schedule and the source are two separate levers.


By the end of this sheet every machine in this estate is assessed on a twenty four hour schedule, carries a governed ring tag, sits under a maintenance configuration that resolves its membership at run time, and one full ring has completed a real monthly cycle with WSUS still supplying every byte. Nothing here changes where a single update comes from. That is the point: if a schedule can run a whole cycle without touching the content source, the two powers are separable and the cutover later is one change rather than two.


Before step one

What has to be true: the eight on-premises machines are Arc-connected and showing Connected, which [ARC 2.1] covers at scale and this sheet does not re-teach; the two Azure virtual machines are running; you hold Owner or Contributor on the subscription for the setup itself, because you are creating policy assignments with managed identities and granting those identities a role; and the WSUS Group Policy object is untouched throughout. The steady state afterwards is narrower: Scheduled Patching Contributor for whoever owns the windows, tag write access for whoever owns membership.

One honesty note, made once. This sheet is written from Microsoft’s current documentation and the product’s documented behaviour, not from a console session against a live Cat Snack Jack, which does not exist. Where a value is derived by the product I show the command that reads it rather than printing one. Two places below are marked as unverified and those are the places to slow down.


Naming convention

Fix the names first. Two of these objects cannot be renamed and a deleted maintenance configuration holds its name in reserve for twenty minutes. Everything is lower case except the tag, whose values are case sensitive and therefore mandated exactly as printed.

ObjectPatternExample
Resource group for patching objectsrg-ORG-patchingrg-csj-patching
Maintenance configurationmc-RING-PURPOSEmc-ring1-general
Dynamic scopeds-RING-PURPOSEds-ring1-general
Policy assignmentaum-FUNCTION-PLATFORM-OSaum-assess-arc-win
Remediation taskrem- plus the assignment namerem-aum-assess-arc-win
Ring tagName PatchRing, values fixedRing0 Ring1 Ring2 RingSQL RingAzure

Two names are not yours. The configuration assignment binding a machine to a schedule is generated when the portal creates it, and a policy assignment’s system-assigned identity gets its principal ID at creation. Never type either. Every command below that consumes one reads it first.

The value set is five rather than three for a specific reason. SQL01 and AZSRV01 each own a window, and a dynamic scope has no exclusion filter, so a machine carrying Ring2 is caught by the Ring2 scope whether or not you also attached it to a schedule of its own. Two schedules, two runs, one server patched twice in a week. Separate values are the only clean way to keep membership declarative. The domain controllers are split for a different reason: Microsoft documents exactly one concurrency guarantee, for Azure virtual machines in a common availability set, and there is no equivalent promise for two Arc machines sharing a configuration. So DC01 and DC02 go in different rings and the ring boundary does the work a runbook comment cannot.

Tag valueMachinesRuns monthly onWindowReboot
Ring0FS02day 16, 20:003 hoursReboot if required
Ring1FS01, APP02, AZSRV02, DC02day 20, 20:003 hoursReboot if required
Ring2DC01, APP01, WSUS01day 24, 22:003 hours 55Reboot if required
RingSQLSQL01day 26, 01:003 hoursReboot if required
RingAzureAZSRV01day 18, 03:002 hoursReboot if required

Calendar dates rather than ordinal weekdays, deliberately. Patch Tuesday lands between the eighth and the fourteenth and an ordinal weekday floats independently of it, so in some months a third Saturday arrives before a second Thursday would have and the ring order inverts. Day 16 is the earliest date that follows every possible Patch Tuesday. WSUS01 is in Ring2 because the box being retired still has to be patched until the day it goes.


Files that travel

Four files move, all from your workstation to the subscription. None of them touches a server.

FileWhere it comes fromWhat it is for on arrival
params-assess-azure-win.jsonAuthored by you, using parameter names read from the definition in step 2Operating system type and assessment mode for the Azure virtual machine assessment assignment
params-assess-arc-win.jsonThe same, against the Arc definitionThe same values for the Arc assessment assignment
policy-patchring-allowed.jsonAuthored by you. Custom definition, not a built-inThe rule constraining PatchRing to the five permitted values
params-patchring.jsonAuthored by youThe allowed value array and the effect, so audit and deny are one definition with different parameters

Step 1: Register the Microsoft.Compute resource provider

First, because it is the failure that produces no error. Microsoft’s note is that for Arc-enabled servers the subscription the machine is onboarded into must be registered to the Microsoft.Compute resource provider, and the troubleshooting page names the symptom: the subscriptions are not producing assessment data. Not failing loudly. Just not producing it. Skip this and you get a compliant policy dashboard, healthy extensions, and eight Arc machines with nothing in patchassessmentresources.

  1. Open Subscriptions and select the subscription your Arc machines are onboarded into.
  2. Under Settings, open Resource providers and search for Microsoft.Compute.
  3. If the status is anything other than Registered, register it. It passes through a Registering state for a few minutes.
  4. Repeat for every subscription holding Arc machines. This is per subscription, not per tenant.
# Gate. Run BEFORE assuming assessment will work anywhere.
az provider show --namespace Microsoft.Compute --query registrationState -o tsv
# Expected: Registered
# NotRegistered means assessment data for Arc machines here is silently absent
# no matter what else you configure.

az provider register --namespace Microsoft.Compute
az provider show --namespace Microsoft.Compute --query registrationState -o tsv

Step 2: Turn periodic assessment on with policy

Two assignments, because the two modify policies are platform specific and each takes an operating system type. This estate is entirely Windows, so two rather than four. Both definitions sit in the Azure Update Manager policy category.

SettingValueWhy
Definition, Azure virtual machinesConfigure periodic checking for missing system updates on azure virtual machines, 59efceea-0c96-497e-a4a1-4eb2290dac15Covers AZSRV01 and AZSRV02. The lower case azure is Microsoft’s, not a typo here
Definition, Arc machinesConfigure periodic checking for missing system updates on azure Arc-enabled servers, bfea026e-043f-4ff4-9d1b-bf301ca7ff46Covers the eight on-premises machines. Separate definition, separate assignment
ScopeThe subscriptionA resource group scope means re-assigning every time a machine lands somewhere new
Assessment modeAutomaticByPlatformThis is what periodic assessment is, and it is the parameter default on both definitions
OS TypeWindowsMandatory per assignment. Microsoft states you need separate policies for Windows and Linux
Policy enforcementEnabledDisabled evaluates without modifying, which is a dry run rather than a deployment
Managed identitySystem assignedModify cannot write without one. The definition determines the role granted
Remediation taskCreate itThe assignment alone catches machines only as they are created or updated. Everything you already own needs the task
  1. Open Policy, then Definitions, and set the Category filter to Azure Update Manager.
  2. Select the Arc-enabled servers definition and choose Assign. Set the scope to your subscription.
  3. On the Parameters tab, clear the option showing only parameters that need input, so assessment mode and OS Type are visible rather than inherited blind. Set OS Type to Windows.
  4. On the Remediation tab, create a remediation task and set the identity to system assigned.
  5. Review and create, then repeat for the Azure virtual machines definition.

The gate goes in front of the remediation task, not after it. Assessment is a metered event on an unwaivered Arc machine, so this is the step that starts a bill.

Before running the remediation task, establish which waiver you hold. Software Assurance with attestation, Defender for Servers Plan 2 on the subscription, and Extended Security Updates enablement each remove the charge on Arc machines, and the absence of all three does not. The licensing article has the list and the arithmetic. The point here is that the cheapest moment to find out is now, with eight Arc machines about to be switched on.

SUB=$(az account show --query id -o tsv)
SCOPE="/subscriptions/$SUB"
LOC=uksouth   # region for the assignment identity, not for the machines

# Read the parameter NAMES from the definition rather than guessing them. They
# differ between the two definitions and have changed between versions.
az policy definition show --name bfea026e-043f-4ff4-9d1b-bf301ca7ff46 --query parameters

# Build params-assess-arc-win.json from that output, then assign.
az policy assignment create \
  --name aum-assess-arc-win \
  --display-name "Periodic assessment, Arc, Windows" \
  --policy bfea026e-043f-4ff4-9d1b-bf301ca7ff46 \
  --scope "$SCOPE" --location "$LOC" \
  --mi-system-assigned --identity-scope "$SCOPE" \
  --params @params-assess-arc-win.json

# The identity's principal ID is generated. Read it, never type it.
az policy assignment show --name aum-assess-arc-win --scope "$SCOPE" \
  --query identity.principalId -o tsv

# Only once the waiver question is settled:
az policy remediation create --name rem-aum-assess-arc-win \
  --policy-assignment aum-assess-arc-win

# Failure mode: the remediation completes reporting zero resources remediated.
# That is almost always evaluation not having run. A new assignment applies in
# about five minutes and first evaluation has no published completion time.
az policy state trigger-scan --resource-group rg-csj-patching

Two documented traps belong here rather than in an appendix. Specialized, migrated and restored virtual machines land non-compliant even when created after the assignment, and the fix is a remediation task rather than patience. And at management group scope the in-wizard remediation task is not supported: assign, wait for evaluation, then remediate separately.

Verification is not the compliance dashboard, which only reports that a property was set. It is the assessment data, which will not appear until the first cycle runs.

az extension add --name resource-graph   # once per workstation

az graph query -q "patchassessmentresources
| where type !has 'softwarepatches'
| extend p = parse_json(properties)
| extend machine = tostring(split(id, '/', 8)),
         seen = todatetime(p.lastModifiedDateTime), os = tostring(p.osType)
| project machine, os, seen | order by seen desc" -o table

# Expected: ten rows, one per machine, within 24 hours of the remediation.
# Stopped and Stopped (deallocated) machines are not scanned at all, so a missing
# row is a power state question before it is a pipeline question.

Step 3: The Azure virtual machine prerequisite

Scheduled patching on an Azure virtual machine requires patch orchestration set to Customer Managed Schedules, which sets the patch mode to AutomaticByPlatform and the platform safety check bypass on user schedules to true. Skip it and Microsoft’s stated consequence is that the schedules will fail to patch the virtual machines. For Arc machines it is explicitly not a requirement, and the prerequisite policy’s description ends by saying so, which is why nothing in this step touches the eight on-premises machines.

Two ways to do it, and the choice is scale rather than correctness. Assigning the built-in named Set prerequisite for Scheduling recurring updates on Azure virtual machines, 9905ca54-1471-49c6-8291-7582c04cd4d4, is a deploy-if-not-exists that keeps catching Azure machines you have not built yet. Setting the property on two machines is a two minute job with nothing to maintain. With exactly two, I set it directly and note the decision, and I assign the policy the day somebody starts building Azure virtual machines from a pipeline. I would not do both: a deploy-if-not-exists that never finds work is a compliance object nobody can explain in two years.

The gate matters because this changes who patches the machine. A machine on Azure Managed Safe Deployment is being patched by the platform today, and switching it to Customer Managed Schedules means it is patched by your schedule and nothing else. Switched but never attached to a schedule is a machine nobody is patching.

# Gate: read the whole patchSettings object, not one property, so you see the
# current orchestration and the bypass flag as the API actually names them.
az vm show -g rg-csj-azure -n AZSRV02 \
  --query "osProfile.windowsConfiguration.patchSettings"

# In the portal this is Update settings, Patch orchestration, Customer Managed
# Schedules, and the portal writes both properties after asking for consent.
az vm update -g rg-csj-azure -n AZSRV02 \
  --set osProfile.windowsConfiguration.patchSettings.patchMode=AutomaticByPlatform

# Failure mode: if the automaticByPlatformSettings object does not exist on the VM
# yet, a --set against a property inside it fails rather than creating the parent.
# Use the portal Update settings page or the prerequisite policy for those machines.

Step 4: The ring tag, and a guardrail on its values

Ten machines, one tag each, name PatchRing and value from the fixed set. Three mechanical facts govern this and all three bite quietly. Tag names are case insensitive and tag values are case sensitive, so ring1 is not Ring1 and a machine tagged the wrong way is simply never patched. Resources do not inherit tags from a resource group or a subscription, so tagging the container achieves nothing. And tags are plain text, which is Microsoft’s way of saying never put anything sensitive in one.

Arc machines are ordinary resources of type Microsoft.HybridCompute/machines and take tags through the portal Tags page, the CLI, or at onboarding. Merge rather than replace, because these machines already carry whatever Arc onboarding put on them.

# Resource IDs are derived. Read them, do not construct them by hand.
ID=$(az graph query -q "Resources | where name =~ 'FS02' | project id" \
     --query "data[0].id" -o tsv)
az tag update --resource-id "$ID" --operation Merge --tags PatchRing=Ring0

# Verification gate. Run this before building a single schedule.
az graph query -q "Resources
| where type =~ 'microsoft.hybridcompute/machines'
   or type =~ 'microsoft.compute/virtualmachines'
| project name, ring = tostring(tags['PatchRing'])
| order by ring asc" -o table

# Expected: ten rows, every value spelled exactly as the convention says.
# An empty ring column on a machine you know you tagged usually means the KEY was
# stored in different casing, because Resource Graph returns the key as written.

Now the guardrail, in two parts, because no single built-in does both jobs. Presence is a built-in: Require a tag on resources, 871b6d14-10aa-478d-b590-94f262ecfa99, a deny effect taking the tag name as a parameter, whose description notes it does not apply to resource groups. Assign it at the subscription with the tag name PatchRing and a new machine cannot be created without declaring a ring.

Constraining the value to a list has no built-in. The definition that sounds like it does takes exactly one permitted value per assignment, so enforcing a set of five means a custom definition: a rule over the tag, an in condition against an array parameter, deny effect, indexed mode. I am saying that plainly rather than dressing it up as configuration. The Azure Policy series on this site owns how a custom definition is authored, parameterised and staged, and this is the case it walks. What belongs here is the operational shape: author it with the effect as a parameter, so audit and deny are the same definition, and stage it.

  1. Assign the custom definition at the subscription with the effect parameter set to Audit and the allowed values array set to the five ring values.
  2. Trigger a compliance scan rather than watching the dashboard. A new assignment applies in about five minutes and the first evaluation has no published completion time.
  3. Read the compliance state. Every non-compliant resource here is a machine you were about to break, and finding it under Audit costs nothing.
  4. Only when non-compliance is zero, change the effect parameter to Deny on the same assignment.

One thing I have not verified and will not assert. No Microsoft page states in a single sentence that the built-in tag deny policies apply to Microsoft.HybridCompute/machines. The component evidence is strong, since Arc machines are ordinary tagged resources and the definition is not resource type specific, and I expect it to work. Confirm it in your own tenant during the audit pass, before the effect becomes deny, because a deny policy that behaves unexpectedly on Arc is a bad thing to discover while onboarding an Arc machine.


Step 5: Build the maintenance configurations

Five configurations, one per ring value, all in rg-csj-patching. The blade is reached from Azure Update Manager, Overview, Schedule updates, Create a maintenance configuration.

SettingValueWhy
Maintenance scopeGuest (Azure VM, Arc-enabled VMs/servers)The API value is InGuestPatch. Any other scope creates a valid resource that never installs an update
Resource grouprg-csj-patchingDelete this group and you delete every patch window in the estate. Keep it away from workload groups
RegionYour management regionThe configuration has a location of its own, independent of where the machines are
Start onNext occurrence of the ring’s date and timeStart must be at least 15 minutes after creation. Avoid creating new schedules between 23:45 and midnight, because trigger evaluation is delayed 15 minutes for a new schedule
Maintenance window durationPer the ring tableFloor 1 hour 30, ceiling 3 hours 55. Below 25 minutes remaining the run stops attempting installs entirely
RepeatsMonthly, on a calendar dayOrdinal weekdays float independently of Patch Tuesday and can invert ring order. Repeats must be at least 6 hours apart
Time zoneOne zone for the whole estateWindows adjust for daylight saving in the zone you pick, so mixing zones stops the gaps between rings being fixed
Reboot settingReboot if requiredNever reboot is not a guarantee: registry keys can force a restart anyway, and a never reboot run against a pending reboot ends as Completed with warnings
Update classificationsCritical, Security, Update RollupSet on the Updates tab. During coexistence WSUS approval is the real gate, so this is a second filter over an already filtered set

An honest exception on the medium rather than a faked symmetry: the classification list is set on the portal Updates tab, and I am not printing a CLI form for it because I have not verified how the Azure CLI accepts more than one classification inside the Windows patch parameters argument. Check that against the command’s own help before scripting it. Everything in the block below is a documented form.

RG=rg-csj-patching; LOC=uksouth; TZ="GMT Standard Time"
az group create -n "$RG" -l "$LOC"

# Ring1. Repeat with the ring table's values for the other four.
az maintenance configuration create \
  --resource-group "$RG" --resource-name mc-ring1-general \
  --maintenance-scope InGuestPatch --location "$LOC" \
  --maintenance-window-duration "03:00" \
  --maintenance-window-recur-every "Month day20" \
  --maintenance-window-start-date-time "2026-09-20 20:00" \
  --maintenance-window-time-zone "$TZ" \
  --reboot-setting "IfRequired" \
  --extension-properties InGuestPatchMode="User"

# Verify what was created, especially the recurrence string, which is the field
# most likely to have been accepted in a form you did not intend.
az maintenance configuration show --resource-group "$RG" \
  --resource-name mc-ring1-general \
  --query "{scope:maintenanceScope, window:maintenanceWindow, reboot:installPatches.rebootSetting}"

Worked example: SQL01 and a window of its own

SQL01 is the Windows Server 2019 machine running the estate’s only production database, and the obvious move is to put it in the sensitive ring with the domain controllers. I would not, for two reasons that generalise to every machine that ends up owning its own configuration.

The first is shape rather than length. Ring2 runs at 22:00 for three hours fifty five because APP01 reboots reluctantly and a domain controller should never be rushed. SQL01 wants a short window at 01:00, after the nightly backup and before the morning batch. Joining Ring2 means either dragging Ring2 earlier, which does not suit the controllers, or accepting that the database server can begin installing at 22:15 on a weeknight.

The second is that Ring2 is a shared object. Every future change to Ring2’s window becomes a change to SQL01’s window, made by somebody who was thinking about domain controllers at the time. A machine whose window is a real business constraint should own the resource expressing it, so changing it is a deliberate act against a named object rather than a side effect.

So SQL01 gets mc-ringsql-database on day 26 at 01:00 with a three hour window, and its tag is RingSQL rather than Ring2. That last part is the trap in this pattern. Leave the tag as Ring2 and simply attach a second configuration, and the Ring2 dynamic scope still matches it, both schedules are associated, and both run. It would be patched on day 24 by a window built for domain controllers and again on day 26 by its own, with nothing in the product warning you. Membership is declarative, so the declaration has to be exclusive.

Its reboot setting is Reboot if required, and that is deliberate rather than inherited. The temptation on a database server is Never reboot, so a human decides when the service goes away. That setting does not do what its name promises: Microsoft documents that a reboot can occur anyway because the Windows Update registry keys can force one, and on this machine those keys arrive by Group Policy and Update Manager will not touch them. What Never reboot reliably produces is a run completing with warnings and a machine sitting on a pending reboot until somebody notices. A short, well placed window with Reboot if required puts the restart inside a period you chose, which is the entire point of owning the window.

One thing SQL01 does not get here, on the record now. Its SQL Server engine updates arrive today because WSUS approves them, and when the source moves to Microsoft Update that machine needs the opt-in for updates to other Microsoft products or those patches silently stop being offered. That is cutover work and the cutover build sheet handles it. Nothing in this phase changes it.


Step 6: Attach the dynamic scopes

One scope per configuration, filtering on the ring tag. In the portal this lives on the maintenance configuration itself, and the subscription is a mandatory selection. Microsoft’s note is worth heeding: create subscription level scopes with an empty location, because a subscription is not associated with a region.

  1. Open Azure Update Manager, then Machines, then Maintenance configurations, and select mc-ring1-general.
  2. Select Dynamic scopes, then Add a dynamic scope, and select the subscription.
  3. In Filter by, set OS type to Windows and add the tag PatchRing with the value Ring1. Leave resource group, resource type and location empty, so a machine moving between resource groups does not fall out of its ring.
  4. Read the preview of machines. This is the verification gate, and it sits in front of the irreversible part, which is the first real run. Expected: exactly the four machines from the ring table.
  5. Save. If the scope catches Azure virtual machines whose orchestration is not yet Customer Managed Schedules, the portal asks for consent to change it or to continue with supported machines only. After step 3 that prompt should not appear. If it does, step 3 did not take.

The preview carries a caveat that is the whole design of the feature: the list might differ at run time, because the criteria are evaluated when the schedule runs. The preview proves your filter is correct today. It does not promise tonight’s membership.

A real portal limitation belongs here, and it is the second place to slow down. The portal cannot accept more than one value for a tag filter in a dynamic scope. Microsoft documents this as a known issue and names the workaround: use the Azure CLI or Azure PowerShell, both of which accept multiple values. Every scope in this estate uses a single value, so it does not bite here, and it will the first time somebody wants one window covering two rings.

# The configuration's ARM ID is derived. Read it.
MC_ID=$(az maintenance configuration show \
  --resource-group rg-csj-patching --resource-name mc-ring1-general \
  --query id -o tsv)

az maintenance assignment create-or-update-subscription \
  --maintenance-configuration-id "$MC_ID" \
  --name ds-ring1-general \
  --filter-os-types windows \
  --filter-tags "{PatchRing:[Ring1]}" \
  --filter-tags-operator All \
  -l global

# Quoting of the tag filter differs between shells and the documented example uses
# a brace form rather than strict JSON. Confirm the accepted form for your shell:
#   az maintenance assignment create-or-update-subscription --help

# Read back what is actually associated. Assignment names are generated, so never
# assume the one you passed is the one in place.
az graph query -q "maintenanceresources
| where type =~ 'microsoft.maintenance/configurationassignments'
| project name, id, properties" -o table

Three timing rules apply from here and all three are buffers. Any modification, including adding or removing machines and editing a scope, needs fifteen minutes of clearance before the window opens. Machines must be on fifteen minutes before it. And trigger evaluation is delayed fifteen minutes for a new schedule and three for an existing one. In practice: stop touching schedules an hour before a run, and entirely on the night of one.


Step 7: Run one ring and read the record

The end to end test is not a smoke test on one machine. It is Ring0 completing a real monthly cycle on the real date, in the real window, against whatever WSUS approved that month. FS02 is the pilot because it is one half of a file server pair, so a bad night still leaves the other half serving. Before the window, confirm the scope preview still returns FS02 and only FS02, that the machine is on and staying on, and that nobody edited the configuration inside the fifteen minute buffer. During the window, do nothing. The portal allows a run to be cancelled until ten minutes before it starts and not after.

az graph query -q "patchinstallationresources
| where type !has 'softwarepatches'
| extend p = parse_json(properties)
| extend machine   = tostring(split(id, '/', 8)),
         ran       = todatetime(p.lastModifiedDateTime),
         status    = tostring(p.status),
         installed = toint(p.installedPatchCount),
         failed    = toint(p.failedPatchCount),
         pending   = toint(p.pendingPatchCount),
         exceeded  = tostring(p.maintenanceWindowExceeded),
         reboot    = tostring(p.rebootStatus),
         source    = tostring(p.patchServiceUsed),
         runId     = tostring(p.maintenanceRunId)
| where ran > ago(7d)
| project ran, machine, status, installed, failed, pending, exceeded, reboot, source, runId
| order by ran desc" -o table

The shape you want: status Succeeded, window exceeded false, an installed count matching what WSUS approved and the machine was offered, failed zero, pending zero, reboot status Completed or NotNeeded, and a run identifier that correlates to the maintenance run. A status of CompletedWithWarnings is not a pass and usually means a reboot was needed and not taken. Window exceeded true with a non-zero pending count is the silent skip: the run reported, and updates were left behind because the arithmetic ran out of window.

A pass is one ring, one real cycle, one legible record. Not one machine and a green tick.

The source field is where I have to be careful with you. The documented enumeration for patchServiceUsed has no bare WSUS member. Current documentation prose writes the Windows value with a hyphen while the API enumeration renders it with an underscore, and the same member covers both the Windows Update service and Windows Server Update Services, which is exactly the distinction you would want it to draw. So read your own record after the Ring0 run, write down what it actually says while WSUS is definitively the source, and keep that as your baseline. When the cutover moves a ring, compare against your baseline rather than against a documented value. The registry checks and the update service query in the cutover build sheet are the authority on where content came from. This field is a corroborating signal at best.

Retention decides how long the evidence lives: thirty days for installation results, seven for assessment data. If this cycle is going to be cited as the exit criterion for cutting a ring’s source, export the row now. Anything beyond thirty days is a pipeline you build, and the operations article builds it.


What you have, and what comes next

Ten machines assessed daily, five windows expressed as resources you can point at, membership declared by a governed tag and resolved at run time, and one ring with a real cycle behind it. WSUS is still approving, the Group Policy object is untouched, and every byte that reached FS02 came from where it came from last month. The one exception was never in that arrangement: AZSRV01 has been patching itself directly from Microsoft since it was built, and has now simply acquired a window it never had.

Rings 1 and 2 need their own cycles before anything else happens, because the exit criterion for cutting a ring’s source is that ring completing a full cycle with the record to show for it. Three months of this is not wasted. It is the period in which you find out that a window is too short, that a tag was typed in lower case, or that a machine nobody remembers owning has been off on the night of every run.

Next is hotpatch, the one part of this subject where the reboot conversation improves rather than merely becoming better organised. APP02 and AZSRV01 both get there, by completely different routes, one of them free since May and one of them decided the moment somebody picked an image.


Azure Update Manager
‹ Previous: [AUM 3] Rings, Windows, and Who Owns the Reboot
Next: [AUM 4] Hotpatch: Buying Back the Reboot