This is the last post in a forty-part series on Windows patching troubleshooting, and it exists because of something six of the earlier posts each discovered independently, without any of them setting out to.
Every single one of them was writing a small diagnostic snippet. Every single one of them found that the snippet lied.
Not crashed. Not errored. Lied — returned a clean, confident, plausible verdict that was flatly contradicted by the device it had just read. Six times, in six different subsystems, with six different registry keys. That is not six coincidences. That is a pattern, and it has a shape: on Windows, checking whether something exists is not the same as checking what it says, and the gap between those two questions is where triage scripts go to die.
Post 40 in this series covers the human side of that — which log to read for which symptom, and the five reflex fixes that destroy your evidence before you get to it. It names the pattern "the empty-key trap". This post owns the automation of it: why a patching triage script is far harder to write correctly than it looks, what each trap does to a naive implementation, and a single read-only collector that handles all of them.
Everything measured below came off one corporate Windows 11 Enterprise device — 25H2, build 26200.9168, servicing stack 10.0.26100.9156 — read only, on 23 August 2026. The script was written, saved, and then run from disk four times with different switches before a single number went into this post.
A patching triage script fails in a specific, repeatable way: it answers "does this key exist" when the question was "what does this device do", and the two disagree constantly. Measured on one device in one session: the CBS RebootPending marker is a subkey, so a value-based check reports "no reboot pending" permanently — and Microsoft's own published pending-reboot script gets this right by calling GetSubKeyNames(). ...\WindowsUpdate\AU exists with ValueCount 0, so a Test-Path reports legacy Automatic Updates management on a device that has none. ...\CurrentVersion\Policies\Servicing exists holding only CountryCode. ...\SystemCertificates\AuthRoot exists with zero values and three auto-created subkeys. IsWUfBConfigured read 0 at the same instant as IsDeferralIsActive=1 and a seven-day quality deferral. The MDM WMI bridge returned 2 / 0 / 7 / 2 to an elevated administrator while the registry held 6 / 7 / 30 / 7 — every value its documented default, and no error raised. The classic Group Policy hive held 2 values while the MDM hive held 23; the classic Delivery Optimization key did not exist at all while 17 DO policies were in force. The legacy Auto Update\Results\{Detect,Download,Install} keys are gone on this build, so the classic LastSuccessTime scan check silently returns nothing. And [Environment]::OSVersion.Version reports revision .0 while Win32_OperatingSystem.Version reports no revision at all, so neither can tell you the patch level. The answer is a collector that reports key state rather than key presence, never uses IsWUfBConfigured as a test, reads both policy hives side by side, takes the UBR from the registry paired with CurrentBuild, and changes absolutely nothing. It is on GitHub, it produces a self-contained shareable HTML report, and it audits its own source to prove the read-only claim.
The problem: your triage script returns a confident answer that is wrong
Here is the scenario, and if you manage a fleet you have lived it. A batch of devices is not patching. You need a first pass across all of them, so you write forty lines of PowerShell: build, pending reboot, services, policy, last scan. You run it against the estate, get a tidy table back, and start working from it.
The table is wrong in at least three columns, and nothing in the output tells you which three.
This is worse than a script that crashes. A crash sends you to the device. A confident false negative sends you to the wrong theory, and you spend the afternoon there. On the lab device, a naive collector and a correct one were run against the same registry within the same minute and disagreed on the pending-reboot verdict, the management state, and the last-scan time.
The uncomfortable part is that the naive version is the version everybody writes, because it is the version that reads correctly in English. "Is a reboot pending? Test the RebootPending value." "Is this device managed by Windows Update for Business? Read IsWUfBConfigured." "Is legacy Automatic Updates policy in force? Test-Path the AU key." Each of those sentences is a perfectly sensible thing to say, and each of them maps to a line of PowerShell that returns the wrong answer on a real 25H2 device.
Read that block again and notice what is missing: an error. Not one of those four lines failed. Two returned nothing, one returned True, one returned 0. In PowerShell, "returned nothing" and "returned false" and "returned zero" all collapse into the same falsy value the moment you put them in an if, and that is where the wrong verdict gets born.
Why it happens: six places where existence is not evidence
The root cause is architectural, and once you see it you cannot unsee it. A Windows policy hive is not a database of settings. It is a namespace, and lots of different components create keys in it for lots of different reasons that have nothing to do with a policy being configured.
Group Policy creates keys when it applies a setting and, crucially, sometimes leaves them behind when it stops. The MDM policy stack creates a parallel set of keys somewhere else entirely. Certificate auto-update creates its own subkeys the first time it runs regardless of policy. The servicing stack uses subkeys as flags rather than values because a subkey can be created and deleted atomically in a transaction. And a value can exist while holding an empty string, which is a third state that neither Test-Path nor a truthiness test can see.
So "the key is there" tells you almost nothing. Here are the six instances confirmed on the lab device, each of which breaks a different naive check.
| Trap | What the naive check does | What is actually true (measured) |
|---|---|---|
| 1. CBS reboot markers are subkeys | Get-ItemProperty tests for a value named RebootPending. Returns nothing, forever. | RebootPending, RebootInProgress and PackagesPending are subkeys of the Component Based Servicing key. Microsoft's own published CheckForPendingReboot.ps1 opens the CBS key and enumerates GetSubKeyNames(). Measured: 14 subkeys present, then 15 a minute later. |
| 2. The AU key exists empty | Test-Path ...\WindowsUpdate\AU returns True, read as "legacy Automatic Updates policy in force". | Test-Path True, ValueCount 0, SubKeyCount 0, no properties. Not one of UseWUServer, NoAutoUpdate, AUOptions or ScheduledInstallDay is present. Verified three separate times on this device. |
| 3. A policy key holding something unrelated | Test-Path ...\CurrentVersion\Policies\Servicing returns True, read as "an optional-component repair source is configured". | The key exists with ValueCount 1, and the one value is CountryCode = GB. There is no LocalSourcePath. The key's existence is unrelated to the policy you were testing for. |
| 4. Auto-created subkeys | Test-Path ...\Policies\Microsoft\SystemCertificates\AuthRoot returns True, read as "root certificate auto-update has been policy-configured". | ValueCount 0, SubKeyCount 3 — Certificates, CRLs and CTLs, created regardless of policy. DisableRootAutoUpdate is absent, which is the value that would actually have meant something. |
| 5. A resolved flag that contradicts its own neighbours | Branch on IsWUfBConfigured to decide whether the device is managed. | On one read of one key: IsWUfBConfigured=0, IsDeferralIsActive=1, QualityUpdatesDeferralInDays=7, DeferQualityUpdates=1. The flag disagrees with the three values sitting beside it. |
| 6. An API that returns defaults instead of failing | Get-CimInstance MDM_Policy_Result01_Update02 from an elevated prompt, treated as the effective policy. | Returned AllowAutoUpdate=2, DeferQualityUpdatesPeriodInDays=0, ConfigureDeadlineForQualityUpdates=7, ConfigureDeadlineGracePeriod=2 — every one its documented default — while the registry held 6, 7, 30, 7. No exception, no warning. |
Trap 6 deserves its own paragraph because it is the nastiest of the six. Microsoft is explicit about the requirement, in the WMI Bridge Provider scripting article: "For all device settings, the WMI Bridge client must be executed under local system user." The documented way to satisfy that is psexec.exe -i -s cmd.exe. What is not documented is what happens when you ignore it. Measured behaviour: the query succeeds and returns the documented default for every property. You get plausible fiction with a clean exit code, which is the worst possible failure mode for a diagnostic.
SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate hive is where Group Policy writes. The MDM stack writes to SOFTWARE\Microsoft\PolicyManager\current\device\Update instead, and the names differ — the Policy CSP node AllowAutoUpdate maps to the Group Policy value name AUOptions, so grepping the classic hive for the CSP name could never find it. Microsoft's Policy CSP reference gives a "Group policy mapping" registry key name for each setting, and that path is where the GPO twin lands, not where MDM writes the value. Read it as a translation table, not as a location.That distinction is not academic. On the lab device the two hives are wildly asymmetric, and an audit that reads only the classic one concludes the device is barely managed at all.
The MDM hive. Every value below was read on 23 August 2026. Note that the raw value count is 65 while the real policy count is 23 — PolicyManager decorates each policy with _ProviderSet, _WinningProvider and _LastWrite siblings, so counting raw names roughly triples the apparent configuration.
| Value | Meaning | What to look for |
|---|---|---|
AllowAutoUpdate | Automatic update behaviour. The Policy CSP documents values 0 to 5 and maps this to the Group Policy value name AUOptions. | Measured 6 — outside the published enumeration. Record it, do not assert a meaning for it. Its presence at all is what proves MDM is driving this setting. |
DeferQualityUpdatesPeriodInDays | Quality-update deferral. Documented range 0-30. | Measured 7. Compare against the classic hive, which does not contain this value at all on this device. |
ConfigureDeadlineForQualityUpdates | Days before a pending quality update is forced. Documented range 0-30, default 7. | Measured 30. Add it to the deferral, not instead of it. |
ConfigureDeadlineGracePeriod | Grace period after the deadline before the forced restart. Documented range 0-7, default 2. | Measured 7. Deferral plus deadline plus grace is the number to quote: 7 + 30 + 7 = a 44-day worst case against a portal that reports 7. |
TargetReleaseVersion | The release the device is pinned to, via MDM. | Measured present but empty string. This is the third state: neither absent nor set. A Test-Path says the policy is there; a truthiness test says it is not. Both are wrong. |
PauseQualityUpdatesStartTime | Start timestamp of an active quality-update pause. | Measured present-but-empty with a _LastWrite sibling — the fingerprint of a pause that was set and then cleared, rather than one that never existed. |
ConfigureDeadlineNoAutoReboot | Suppresses the automatic restart at the deadline. | Measured 1. Combined with a 16-hour active-hours window, this is why "the deadline passed and nothing rebooted" is not a bug. |
QualityUpdateEnrolled / FeatureUpdateEnrolled / DriverUpdateEnrolled | Autopatch-style enrolment nodes, written by a second management authority. | Measured 0 / 1 / 1. Two distinct _WinningProvider GUIDs were present on this one device — check which authority owns which setting before you go looking in one portal. |
And the agent's own resolved state key, which is the closest thing Windows has to "what did the update client actually conclude". Eighteen values, one of which cannot be trusted.
This is the update agent's resolved verdict after it has merged every policy source. It is the most useful key in the entire diagnostic — and it contains the single most misleading value.
| Value | Meaning | What to look for |
|---|---|---|
IsWUfBConfigured | The agent's own claim about whether Windows Update for Business is configured. | Measured 0 on a device with an active 7-day deferral. Never branch on this value. Report it for the record and derive the verdict from the policy values instead. |
IsDeferralIsActive | Whether a deferral is currently in force. (The doubled "Is" is Microsoft's spelling, not a typo here.) | Measured 1 at the same instant as IsWUfBConfigured=0. This is the value that is telling the truth. |
QualityUpdatesDeferralInDays | The resolved quality deferral the agent is applying. | Measured 7, matching the MDM hive. Agreement between the resolved state and the policy hive is good evidence; disagreement is a finding. |
BranchReadinessLevel | The servicing branch the agent resolved to. | Measured as the string CB, while the Policy CSP documents this as an integer enumeration (2, 4, 8, 16, 32, 64, 128). Do not compare the two forms directly. |
TargetReleaseVersion / TargetProductVersion | The resolved release pin. | Measured 24H2 and Windows 11 on a device whose installed DisplayVersion is 25H2. The pin has been overtaken — it is no longer describing this device, so it is not what is holding it back. |
PolicySources | A bitfield describing which sources contributed to the resolved policy. | Measured 4. Undocumented publicly; useful as a change detector across a fleet rather than as an absolute value. |
One more class of trap, because it is the one that quietly corrupts compliance reporting rather than triage: the version APIs.
[Environment]::OSVersion.Version returned 10.0.26200.0 on this device and Win32_OperatingSystem.Version returned 10.0.26200 — a zero revision and no revision at all. The real patch level, 26200.9168, exists only in HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion as CurrentBuild plus UBR. And you must read both: KB5121003 produces UBR 9168 on 25H2 build 26200 and on 24H2 build 26100, so a compliance rule that tests UBR -ge 9168 without also pinning CurrentBuild passes a 24H2 device against a 25H2 baseline. While you are in that key, ProductName reads "Windows 10 Enterprise" on this Windows 11 device, ReleaseId is frozen at 2009, and BuildLabEx still carries a 26100 lab string — forensic proof the device was installed as 24H2 and moved up in place.How to verify: reading each trap correctly, with the real output
Before writing the collector, each trap needs a read that is provably correct. That means, for every check, asking the same three questions: does the key exist, how many values and subkeys does it hold, and is the specific value I care about present, empty or absent. Three states, never one boolean.
Here is the pending-reboot check done properly, alongside the naive one, on the same key in the same second.
That TiRunning observation is worth sitting with for a second. The set of CBS subkeys is not a constant. It changed between two consecutive runs of the same read-only script, because the Windows Modules Installer service transitioned from Stopped to Running in between. Any heuristic of the form "this key has more subkeys than I expected, something must be pending" is measuring service state, not servicing state.
Next, the two policy hives, side by side. This is the check that changes how you read every Intune-managed device.
Then the bridge. This one is worth running deliberately, once, so you have seen it with your own eyes and never trust it again from the wrong context.
The event log is the other half of the evidence, and it needs the same discipline: counts are a measurement at a moment, not a device property. Between successive reads in this series the Event 26 count on this channel moved from 210 to 412 to 555 to 1,815. Quote what you measured and when.
| Event ID | Message (verbatim, as observed) | What it tells you |
|---|---|---|
26 | "Windows Update successfully found N updates." | 344 of the 400 examined. Beware: "found 0 updates" is emitted identically by a fully-patched device and by a device excluded from everything by a stale pin. On its own it is not diagnostic. |
41 | "An update was downloaded." | 55 of the 400 examined. Proves the transfer path works, which separates a download problem from a scan problem and from an install problem. |
25 | "Windows Update failed to check for updates with error 0x80240438." | 1 in the window, dated 31 July 2026. Note carefully: 0x80240438 is not enumerated in Microsoft's published Windows Update error list. It has been observed repeatedly on this device. Record it; do not assert a meaning for it. |
31 | "Windows Update failed to download an update." | Exactly 2 across the entire channel, on 23 and 24 July 2026 — against 55 successful Event 41 downloads in the last 400 records alone. Rare enough that its presence is signal rather than noise, and it separates a transfer failure from a scan failure cleanly. |
| Event ID | Message (verbatim, as observed) | What it tells you |
|---|---|---|
2 | "Package <KB> was successfully changed to the Staged state." | 240 of the 400 examined. Staged is not Installed. A wall of Event 2 with no Event 3 means packages are landing but not committing. |
4 | "A reboot is necessary before package KB5120708 can be changed to the Installed state." | 3 in the window, on 19 August 2026. This is the event that corroborates a pending-reboot verdict from the registry. When the registry says clear and Event 4 says otherwise, one of them is stale — check the timestamps. |
1013 | "Initiating system store corruption detection and repair. Detection Only: 1, Automatically Triggered: 0." | The start of a component-store scan. Detection Only: 1 is what distinguishes a ScanHealth from a RestoreHealth — the single most useful field in the pair. |
1014 | "System store corruption detection and repair has completed. Status: 0x0, Total instances of corruption found: 0, total instances of corruption repaired: 0." | The completion half. Measured 21 August 2026, four minutes after its 1013. Zero found, zero repaired — which is the evidence that lets you stop chasing a corruption theory. |
Finally, the binaries, because half of the false corruption reports in this space come from someone looking for a file in the wrong directory and concluding it is missing.
| Binary | Role | Where it lives, and the measured version |
|---|---|---|
wuaueng.dll | The Windows Update Agent engine. It is the ServiceDll for wuauserv, which runs as svchost.exe -k netsvcs -p under LocalSystem. | C:\Windows\System32. Version 1509.2607.1012.0 — versioned entirely separately from the OS build 10.0.26200.9168. That mismatch is normal, not drift. |
wuapi.dll | The Windows Update client COM API — what UpdateSession and UpdateServiceManager resolve to. | C:\Windows\System32, version 1509.2607.1012.0, matching the engine. |
TrustedInstaller.exe | The servicing host. Its FileDescription reads "Windows Modules Installer", which is the service display name, not a different component. | C:\Windows\servicing, version 10.0.26100.7019. That folder holds only TrustedInstaller.exe, CbsApi.dll, CbsMsg.dll and wrpintapi.dll. |
poqexec.exe | Primitive Operations Queue Executor — runs the boot-time file operations the servicing stack queued. | C:\Windows\System32, version 10.0.26100.9156, which is the servicing-stack version. Writes C:\Windows\Logs\CBS\poqexec.log. |
MoUsoCoreWorker.exe | Update Session Orchestrator worker — drives the scan, download, install and restart sequence. | C:\Windows\UUS\amd64, not System32. UUS is the Unified Update Stack and is serviced independently of the OS build. |
cbscore.dll | The CBS core the servicing stack loads. Its version is the servicing-stack version. | Not System32 — the versioned WinSxS servicing-stack component directory, alongside TiWorker.exe and wcp.dll. Confirmed from a real "Loaded Servicing Stack" line in CBS.log. |
usocore.dll | Frequently cited in community guidance as the orchestrator core. | Does not exist in System32 or SysWOW64 on 26200.9168. Confirmed absent three times. The real System32 USO files are usosvc.dll, usoapi.dll, usodocked.dll and usocoreps.dll. |
The fix: one read-only collector, and every trap handled in code
The "fix" in this post changes nothing on the device. That is deliberate and it is the whole argument of the series: the correct first action on a patching failure is to collect, not to remediate. So the deliverable is a collector.
Get-WindowsPatchingEvidence.ps1, in the repository at github.com/Imran76Awan/Windows-Patching-Scripts. It is 100% read-only: no Set-, Remove-, Stop-, Start-, Restart- or Rename- cmdlet touching device state, no service control, no folder renames, no wuauclt, no usoclient, no DISM repair switches. The only thing it ever writes is the HTML report you explicitly ask for. Pass -VerifyReadOnly and it will audit its own source and tell you so.Follow this as a numbered path. Each step is a read, and each step is designed so that the answer cannot be a silent false negative.
- Establish what the device really is. Read
CurrentBuildandUBRfrom the registry and report them as one paired value. Print[Environment]::OSVersion.VersionandWin32_OperatingSystem.Versionbeside them so the gap is visible rather than assumed. FlagProductNameand aBuildLabExthat disagrees withCurrentBuild. If you get this wrong nothing downstream is meaningful, because you are comparing the device against the wrong baseline. - Settle the pending-reboot question across every source. CBS markers via
GetSubKeyNames(); the Windows Update client'sAuto Update\RebootRequiredkey, which genuinely is a key soTest-Pathis correct there;PendingFileRenameOperationsas a specific value, counted;WinSxS\pending.xmlas a file; and a computer-rename check comparingActiveComputerNameagainstComputerName. Report each source separately with the method used. If a reboot is pending, stop — everything else queues behind it. - Check the services against an expected steady state, not against "Running".
trustedinstallerandmsiserverStopped/Manual while idle is correct. A collector that flags them generates a false alarm on every healthy device in the fleet, which is how people learn to ignore the tool. - Read both policy hives and print them together. Classic hive with
ValueCountand the named legacy AU values; MDM hive with the metadata siblings stripped out so the policy count is real. Compare the two counts and say so out loud when they diverge. - Read the agent's resolved state, and derive the management verdict from evidence. Print all eighteen
PolicyStatevalues includingIsWUfBConfigured— then build the verdict from the deferral state and the policy values actually present, and say explicitly in the output that the flag was not used as a test. - Only query the MDM bridge deliberately, and only trust it as SYSTEM. The collector keeps this behind
-IncludeMdmBridge, checksWindowsIdentity.IsSystem, compares every returned value against the registry, and labels the whole section untrusted when the context is wrong. - Compare the inventory against an honest denominator.
Get-HotFixreturned 4 rows. The CBSPackagessubkey count on the same device is 7,490.Win32_QuickFixEngineeringreturns only Component Based Servicing updates, so the gap is expected — but it is whyGet-HotFixis the wrong basis for a compliance report. - Prove the legacy last-scan check is dead before you rely on its absence. Test all three
Auto Update\Resultskeys and report their non-existence as a finding, not as "never scanned". Use the event channel for scan evidence instead. - Read the restart-suppression surface, including the parts policy cannot see. Active hours live in
...\WindowsUpdate\UX\Settings, are user-chosen, and are invisible to a policy-key audit. Measured here:ActiveHoursStart=8,ActiveHoursEnd=0— a 16-hour daily window in which automatic restarts are suppressed. - Emit findings with severities, and distinguish "clean" from "unknown". Anything the collector could not read goes into a separate gap list and forces exit code 2, because a section that failed to read must never render as a section that came back clean.
The mechanism that makes all of this possible is small: three helper functions that refuse to collapse three states into one boolean.
Two switches matter operationally. -Redact masks the machine name, every GUID in every emitted string, and the hardware serial, so the report can be attached to a public forum post or a vendor case — values are masked, never removed, because "field is populated but hidden" and "field is absent" are different pieces of evidence. -OutputHtml <path> writes a self-contained styled report: no external CSS, no web fonts, no scripts, no images, so it renders identically offline, from a USB stick, or behind a proxy that blocks outbound requests from a local HTML file.
Proof it worked: the run, the self-audit, and two bugs that parsed clean
The script was saved to disk and run four times: plain, with -VerifyReadOnly, with -IncludeMdmBridge, and with -Redact -OutputHtml. Here is the tail of the real run.
Ten findings on a device that every dashboard reports as healthy. None of them is a fault. All of them are things you would want to know before you started changing anything — and four of them are cases where a naive script would have produced a different, wrong answer.
The same run with -Redact added produced a 20,774-byte report against the plain run's 20,702. Both files were then checked mechanically: DOCTYPE present; every tag balanced, at 134 tr and 298 td elements each with matching closers; zero <script>, <img> and <link> elements; zero @import; zero url(); no unresolved template variables anywhere in the output; and exactly one outbound hyperlink in the whole document, the repository link in the footer. In the redacted copy the machine name, the hardware serial and all six enrollment GUIDs were confirmed absent by string search, and the same strings were confirmed present in the unredacted copy — so the switch is doing work rather than being decorative.
[System.Management.Automation.Language.Parser]::ParseFile() reporting zero errors does not mean your script works. Both of the bugs below parsed completely clean and failed at run time, and both were only found by saving the file and running it from disk. If you take one operational habit from this post, take that one: parse-clean is not tested.The first bug is a genuine PowerShell 5.1 quirk that I had not met before. Wrapping a System.Collections.Generic.List[object] in the array subexpression operator throws:
The second bug is funnier and more instructive. The read-only self-audit originally worked by reading its own source file line by line and searching for mutating command names. It reported three violations on its first real run:
Device-mutating commands found : 3 — net stop, wuauclt and usoclient, all three on line 15. Line 15 is inside the script's own help block, in the sentence that promises the script contains no net stop, no wuauclt and no usoclient. The audit had flagged its own documentation, raised a Blocking finding, and set exit code 1 on a script that was in fact perfectly clean.That is the empty-key trap in a different costume: a check that answers "does this text appear somewhere in the file" when the question was "does this file execute this command". The fix is the same in kind as every other fix in this post — stop pattern-matching the surface, parse the structure. The audit now tokenises itself with the PowerShell parser, discards every Comment token, and searches only real code. That is the 8,517 code tokens in the output above, and it is why the result is now 0.
Forty posts. One recurring lesson, discovered independently six times: on Windows, the question "is this configured" almost never has a boolean answer, and a script that pretends it does will lie to you politely and at scale. Ask for the state. Print the counts. Name the method. And run the thing before you ship it.
References
- CheckForPendingReboot.ps1 — Microsoft's own published pending-reboot script. It opens
Software\Microsoft\Windows\CurrentVersion\Component Based Servicing\and callsGetSubKeyNames(), then tests the returned array forRebootPending. Archived, and still the clearest statement anywhere that the CBS markers are subkeys. - Using PowerShell scripting with the WMI Bridge Provider — the source of the SYSTEM requirement: "For all device settings, the WMI Bridge client must be executed under local system user", with the documented
psexec.exe -i -s cmd.exeroute. It also explains theInPartition("local-system")class qualifier that marks a device-scoped class. - MDM_Policy_Result01_Update02 class — the class the collector queries behind
-IncludeMdmBridge, and itsInPartition("local-system")declaration. - Policy CSP - Update — the documented allowed values and defaults that let you recognise the silent-defaults fallback:
AllowAutoUpdatedefault 2 (enumerating 0-5 only),DeferQualityUpdatesPeriodInDaysrange 0-30 default 0,ConfigureDeadlineForQualityUpdatesrange 0-30 default 7,ConfigureDeadlineGracePeriodrange 0-7 default 2. Also the per-setting "Group policy mapping" registry key names, including theAllowAutoUpdatetoAUOptionstranslation. - Windows Update log files — the log inventory, the component tag list, and the note that
C:\Windows\WindowsUpdate.logis a stub pointing atGet-WindowsUpdateLograther than the real trace. - Windows-Patching-Scripts —
Get-WindowsPatchingEvidence.ps1, the read-only collector described in this post, with-OutputHtml,-Redact,-IncludeMdmBridgeand-VerifyReadOnly.