You flip the Memory Integrity switch in Windows Security. The toggle slides to On. You reboot. The toggle is back to Off, and a small grey line says something about an incompatible driver. Sometimes it names a driver. Very often it names nothing at all, or it shows an empty list under a heading that promises one.
This is the single most valuable hardening switch in Windows 11, and it is also the one that fails most quietly. This post explains what Memory Integrity actually is, what it actually prevents, the exact requirements a driver has to meet, and how to find the offending .sys by name and full path. It then covers the Microsoft vulnerable driver blocklist, which is a completely different mechanism that almost everybody conflates with Memory Integrity, and how to prove the blocklist is on.
Memory Integrity (also called HVCI) runs kernel-mode code integrity checks inside a hypervisor-isolated second kernel, and enforces that kernel memory pages are never writable and executable at the same time. Any loaded driver that violates that rule stops the whole feature from starting, and the Settings UI is frequently unable to name it. The reliable evidence lives in three places: the Win32_DeviceGuard WMI class, the volatile registry value HKLM\SYSTEM\CurrentControlSet\Control\CI\State\HVCIEnabled, and the Microsoft-Windows-CodeIntegrity/Operational event channel. The Microsoft vulnerable driver blocklist is a separate control that blocks known-bad signed drivers by policy; it has shipped on by default since the Windows 11 2022 Update and is verified in Windows Security or by event 3099, not by anything HVCI reports.
The problem: the toggle reverts and names nothing useful
Here is the shape of the failure, in the order a helpdesk usually sees it.
- A user or a policy turns on Memory Integrity.
- Windows asks for a restart, because the feature can only start at boot.
- After the restart the toggle is Off again.
- Windows Security shows a message about an incompatible driver, and often an empty list.
There are three separate reasons that message is so unhelpful, and it is worth separating them before you go hunting.
First, the driver scan in the Windows Security user interface is a best-effort static check. It looks at driver files it can find and reason about. A driver that only misbehaves at runtime, when a particular code path executes, will pass that static check and still break the feature.
Second, some drivers load so early in boot that nothing has a chance to log the block. Microsoft states this outright: if an incompatibility exists for a boot-critical driver, Memory Integrity is silently turned off if it had been auto-enabled. Silently. No dialog, no event you can rely on.
Third, there is a deliberate safety net that looks identical to a failure. Windows can auto-disable Memory Integrity if the machine crashes during boot shortly after it was turned on. That behaviour is driven by two registry values, and it is doing exactly what it was designed to do when it reverts your change.
Terminology, once, so the rest of this makes sense. Memory Integrity, HVCI (hypervisor-protected code integrity), and hypervisor enforced code integrity are three names for the same feature. It originally shipped as part of Device Guard. Microsoft says Device Guard is no longer used as a name except to locate the VBS and Memory Integrity settings in Group Policy and the registry, which is why every registry path below still says DeviceGuard. VBS means virtualization-based security, the platform Memory Integrity runs on.
And then there is the confusion that sends people down the wrong road entirely. The Windows Security page that hosts the Memory Integrity toggle also hosts a toggle called Microsoft Vulnerable Driver Blocklist. They sit next to each other under Core isolation. They are not the same thing, they fail in different ways, and a fix for one does nothing for the other. We will pull them apart properly.
Why it happens: what HVCI is and what it enforces
The chain, from power-on to enforcement
Normally, kernel-mode code integrity is a function inside the Windows kernel. It checks every driver and kernel binary before it starts, and refuses to load anything unsigned or untrusted. The problem is obvious once you say it out loud. If an attacker compromises the kernel, they have compromised the thing doing the checking.
VBS changes that arrangement. Here is the order of events.
- The Windows boot loader loads
hvloader.dll, which selects and starts the hypervisor image for the platform. - The hypervisor creates an isolated virtual environment that becomes the root of trust for the operating system. Microsoft's framing is explicit: this environment assumes the kernel can be compromised.
- A second kernel, the secure kernel, starts inside that isolated environment.
- When Memory Integrity is on, code integrity decisions move into that secure environment. Kernel memory pages are only made executable after passing code integrity checks inside the secure runtime environment.
- From then on, executable pages are never writable.
That last sentence is the whole feature. Say it as a rule: kernel memory can be writable, or it can be executable, but never both at the same time. That is why the acronym W+X (write plus execute) keeps coming up.
Microsoft lists two headline protections for Memory Integrity. It protects modification of the Control Flow Guard (CFG) bitmap for kernel mode drivers. And it protects the kernel mode code integrity process itself, the process that ensures other trusted kernel processes have a valid certificate. Practically, that means a buffer overflow that lets malware scribble on memory still cannot turn that memory into running code.
The requirements a driver has to meet
Compatibility with Memory Integrity has been a requirement for all drivers since the Windows 10 Anniversary Update, version 1607. That is a decade of notice. Plenty of shipping drivers still fail. Microsoft's documented rules for building a compatible driver are short and blunt.
- Opt in to NX by default. NX means no-execute, a page attribute that forbids running code from that memory.
- Use NX APIs and flags for memory allocation, specifically
NonPagedPoolNx. - Do not use sections that are both writable and executable.
- Do not attempt to directly modify executable system memory.
- Do not use dynamic code in the kernel.
- Do not load data files as executable.
- Section alignment must be a multiple of
0x1000, which is PAGE_SIZE. For exampleDRIVER_ALIGNMENT=0x1000.
When a driver fails, it fails in one of a documented set of ways. Microsoft publishes the failure categories that Driver Verifier and the HLK test report. Knowing them helps you write a useful bug report to the vendor instead of "your driver breaks HVCI".
| Failure category | What the driver did wrong |
|---|---|
| Execute Pool Type | Called a memory allocating function that requests executable memory. All pool types must carry a non-executable NX flag. |
| Execute Page Protection | Specified an executable page protection. It needs a no-execute page protection mask. |
| Execute Page Mapping | Specified an executable memory descriptor list (MDL) mapping. The mask must contain MdlMappingNoExecute. |
| Execute-Write Section | The driver image contains a section that is both executable and writable. |
| Section Alignment Failures | The image contains a section that is not page aligned. |
| Unsupported Relocs | A relocation straddles a page boundary. Only affects Windows 10 versions 1507 through 1607. |
| IAT in Executable Section | The import address table sits in a read-and-execute section, so Windows cannot write the resolved addresses into it. |
Gotcha: a static scan cannot catch all of these. Microsoft says so directly. Static code analysis tools simply are not capable of detecting all Memory Integrity violations possible at runtime. Their own guidance is that a driver must be tested on a system with VBS and Memory Integrity actually enabled, exercising every code path. This is exactly why the incompatible-driver list in the Settings UI can be empty while the feature still refuses to start.
The hardware and firmware prerequisites, including the TPM question
VBS has a documented component list. Every item has to be present and correctly configured.
| Requirement | What it means in practice |
|---|---|
| 64-bit CPU with virtualization extensions | Intel VT-x or AMD-V. The Windows hypervisor only runs on 64-bit processors with these. |
| Second Level Address Translation (SLAT) | Intel VT-x2 with Extended Page Tables (EPT), or AMD-V with Rapid Virtualization Indexing (RVI). |
| IOMMU or SMMU | Intel VT-D, AMD-Vi, or Arm64 SMMUs. Every DMA-capable I/O device must sit behind one. |
| Trusted Platform Module (TPM) 2.0 | Listed as a VBS component in the OEM requirements table. See the note below, because this is where almost every blog post gets it wrong. |
| Firmware support for SMM protection | Firmware must implement the Windows SMM Security Mitigations Table (WSMT) protections and set the corresponding flags. |
| UEFI Memory Attributes Table (MAT) | UEFI v2.6 MAT. Runtime code and data ranges must be cleanly separated, page-aligned, non-overlapping, and every entry must carry EFI_MEMORY_RO, EFI_MEMORY_XP, or both. |
| Secure MOR revision 2 | Secure Memory Overwrite Request v2, with the MOR lock protected by a UEFI secure variable. |
| Memory-integrity-compatible drivers | Every driver on the system. This is the one that bites in production. |
| Secure Boot | Must be enabled on devices using VBS. |
The TPM claim, stated precisely. Microsoft lists TPM 2.0 in the VBS component table on the OEM VBS page. That is real and you should quote it. But be careful about the conclusion people draw from it. Nothing in the documented Memory Integrity enablement surface tests for a TPM. The RequiredSecurityProperties enumeration in Win32_DeviceGuard has values for hypervisor support, Secure Boot, DMA protection, secure memory overwrite, NX, SMM mitigations and MBEC. There is no TPM value. The documented VBS_COMPAT_ISSUES bit array used by the setup-time auto-enablement check has bits for SLAT, Secure Boot, IOMMU, MBEC, UEFI, the MAT, WSMT, MOR lock, hardware virtualization, RAM, storage and architecture. There is no TPM bit. And the hardware table for automatic Memory Integrity enablement lists processor, RAM, storage, drivers and BIOS virtualization, and does not mention TPM. So: TPM 2.0 is a documented VBS platform component, but a missing TPM is not one of the documented reasons Memory Integrity refuses to start. If you are troubleshooting a stuck toggle, TPM is not where to look. Do not write detection logic that gates HVCI on TPM state.
Separately from those platform requirements, Windows has an auto-enablement bar. Memory Integrity is turned on by default on clean installs of Windows 11 on hardware that meets a specific minimum, and on all Secured-core PCs.
| Component | Minimum for automatic enablement |
|---|---|
| Processor | Intel 8th generation or later from Windows 11 22H2 (11th generation Core and newer for 21H2), AMD Zen 2 and newer, Qualcomm Snapdragon 8180 and newer. |
| RAM | Minimum 8GB, x64 only. |
| Storage | SSD with a minimum size of 64GB. |
| Drivers | Memory-integrity-compatible drivers must be installed. |
| BIOS | Virtualization must be enabled. |
Two footnotes on that table matter enormously in an enterprise fleet. Auto-enablement pertains only to clean installs, not upgrades of existing devices. And Intel 11th generation Core desktop processors are not included in the current default enablement logic, even though Microsoft calls them a recommended platform. So a fleet that was upgraded in place rather than reimaged will mostly have Memory Integrity off, and that is by design, not a bug.
The blocklist is a different mechanism entirely
Now the part people conflate. The Microsoft vulnerable driver blocklist does not care about W+X pages or section alignment. It is a deny list of specific third-party drivers, by signature, that Microsoft has determined are dangerous.
Microsoft's stated criteria for adding a driver are:
- Known security vulnerabilities an attacker could exploit to elevate privileges in the Windows kernel.
- Malicious behaviours, or certificates used to sign malware.
- Behaviours that are not malicious but circumvent the Windows security model in a way an attacker could exploit to elevate privileges in the kernel.
The two features overlap in exactly one place, and it is worth being precise. Since the Windows 11 2022 update the blocklist is enabled by default for all devices, and can be turned on or off in the Windows Security app. Except on Windows Server 2016, the blocklist is also enforced when Memory Integrity, Smart App Control or S mode is active. So turning on Memory Integrity brings the blocklist with it, but the blocklist stands on its own and does not need Memory Integrity.
Delivery is not what most people assume either. The blocklist is updated quarterly, and blocklist updates are also delivered through the monthly Windows updates as part of the standard servicing process. It ships as part of Windows and Defender servicing, not as a thing you have to go and fetch. There is a downloadable version, and Microsoft is unusually candid about why it exists: the downloadable list usually contains a more complete set of known vulnerable drivers than the version in the operating system, because Microsoft holds back some blocks to avoid breaking existing functionality while partners get users onto patched versions.
Blocking drivers can blue-screen a machine. This is Microsoft's own warning, not an editorial one. Blocking drivers can cause devices or software to malfunction, and in rare cases lead to blue screen. The same warning applies to Memory Integrity itself: incompatibility can cause devices or software to malfunction and in rare cases may result in a boot failure. If you deploy the downloadable blocklist, validate it in audit mode first and review the audit block events before enforcing. And never turn Memory Integrity on fleet-wide without a pilot ring.
How to verify: WMI, registry, Event Viewer, setupact.log
This section is the part you will come back to. Work through it in order, because each surface answers a different question, and reading them out of order is how people conclude the wrong thing.
1. Win32_DeviceGuard: the documented source of truth
Windows exposes a WMI class for VBS state. It is the only supported programmatic surface for this, and it is what you should build reporting on. The command below reads it. Run it from an elevated PowerShell session, because Microsoft documents it as an elevated query.
Read that output as follows. SecurityServicesConfigured is what policy asked for. SecurityServicesRunning is what actually came up. A value present in the first list and absent from the second is the whole diagnosis in one line: you asked for it, the platform refused.
Here are the documented enumerations you need to interpret it, so you are not guessing at integers.
| Property | Value | Documented meaning |
|---|---|---|
| VirtualizationBasedSecurityStatus | 0 | VBS is not enabled. |
| 1 | VBS is enabled but not running. | |
| 2 | VBS is enabled and running. | |
| SecurityServicesConfigured / SecurityServicesRunning | 0 | No services. |
| 1 | Credential Guard. | |
| 2 | Memory integrity. | |
| 3 | System Guard Secure Launch. | |
| 4 | SMM Firmware Measurement. | |
| 5 / 6 | Kernel-mode Hardware-enforced Stack Protection, enforced or audit. | |
| 7 | Hypervisor-Enforced Paging Translation. | |
| AvailableSecurityProperties / RequiredSecurityProperties | 0 | No relevant properties, or nothing required. |
| 1 | Hypervisor support. | |
| 2 | Secure Boot. | |
| 3 | DMA protection. | |
| 4 | Secure Memory Overwrite. | |
| 5 | NX protections. | |
| 6 | SMM mitigations. | |
| 7 / 8 | MBEC or GMET; APIC virtualization. Value 8 is Available-only. | |
| CodeIntegrityPolicyEnforcementStatus and the usermode equivalent | 0 | Off. |
| 1 | Audit. | |
| 2 | Enforced. |
Tip: the two-line fleet check. If you only get one query into a compliance script, make it this. SecurityServicesConfigured containing 2 while SecurityServicesRunning does not is the single most useful signal in the whole feature area. It separates "nobody turned it on" from "we turned it on and something is blocking it", and those two need completely different remediation. The MBEC and GMET property, value 7, is only reported from Windows 10 version 1803 and Windows 11 version 21H2 onwards, so do not treat its absence on older builds as a fault.
For a quick eyeball check with no PowerShell, msinfo32.exe from an elevated session shows the VBS features at the bottom of the System Summary section. Look for the line "Virtualization-based security Services Running" and check that it reports "Hypervisor enforced Code Integrity".
2. The registry: policy intent versus live state
There are two completely different kinds of registry data here, and mixing them up is the most common analysis error in this feature area. One set records what you asked for. One records what actually happened. Read both.
Everything in the first group hangs off this parent key:
| Value (relative to the parent above) | Type and data | What it does |
|---|---|---|
EnableVirtualizationBasedSecurity | REG_DWORD 1 | Turns VBS on. Nothing else here matters without it. |
RequirePlatformSecurityFeatures | REG_DWORD 1 or 3 | 1 requires Secure Boot only. 3 requires Secure Boot with DMA protection. |
Locked | REG_DWORD 0 or 1 | 0 is VBS without UEFI lock. 1 is with UEFI lock. |
Mandatory | REG_DWORD 1 | Prevents the OS loader from continuing to boot if the hypervisor, secure kernel or a dependent module fails to load. |
Scenarios\HypervisorEnforcedCodeIntegrity > Enabled | REG_DWORD 1 | Turns Memory Integrity on. This is the value that matters most. |
Scenarios\HypervisorEnforcedCodeIntegrity > Locked | REG_DWORD 0 or 1 | 0 is Memory Integrity without UEFI lock. 1 is with UEFI lock. |
Scenarios\HypervisorEnforcedCodeIntegrity > WasEnabledBy | REG_DWORD | Part of the crash safeguard. Deleting it greys out the Memory Integrity UI with "This setting is managed by your administrator". Setting it to 2 restores normal UI behaviour. |
Scenarios\HypervisorEnforcedCodeIntegrity > EnabledBootId | REG_DWORD | The boot counter at the time it was enabled. Pairs with WasEnabledBy. |
Those WasEnabledBy and EnabledBootId values deserve their own paragraph, because they explain a failure that looks like sabotage. Together they arm a safeguard against an unbootable device. When set, the device will automatically turn off Memory Integrity if the system crashes during boot, which may well have been caused by Memory Integrity blocking an incompatible boot-critical driver. That auto-disable only applies while the current BootId is less than EnabledBootId plus 3. The current boot counter lives here:
Microsoft's guidance for high security systems is that WasEnabledBy and EnabledBootId should NOT be set. That is a real trade-off. Leave them and a crashing driver silently wins. Remove them and a bad driver leaves you booting into recovery.
The second group is state, not intent. These are the values that tell you what is actually true right now.
| Value (relative to the parent above) | Data | Meaning |
|---|---|---|
State\HVCIEnabled | REG_DWORD | Documented as the volatile registry key that reflects the state of Memory Integrity. This is live state, not policy. |
Config\VulnerableDriverBlocklistEnable | REG_DWORD | Observed on live devices as the value the Windows Security blocklist toggle writes. See the warning below. |
TestFlags | REG_DWORD 0x300 | Documented switch that turns on the ISG and Managed Installer diagnostic events 3090, 3091 and 3092. Needs a restart. |
Gotcha: one of those values is undocumented. HKLM\SYSTEM\CurrentControlSet\Control\CI\Config\VulnerableDriverBlocklistEnable is what you will observe on a live Windows 11 device, and it is what the Windows Security toggle appears to write. But Microsoft documents the toggle, not the value name. Treat it as a diagnostic hint you read, never as a supported detection contract, and never as something you write. An undocumented value can change in any update, and a compliance rule built on it can silently start reporting the wrong answer after a monthly patch. The supported way to confirm the blocklist is on is the Windows Security app, or event 3099 for a policy you deployed yourself.
There is a third registry location, and forgetting it wastes hours. Group Policy and ADMX-backed Intune settings do not write to CurrentControlSet. They write here:
If you hand-edit the CurrentControlSet copy on a managed device, the next policy refresh overwrites you. Check for values under SOFTWARE\Policies before you conclude that anything you set by hand has stuck.
Here is what the scenario key looks like in Registry Editor on a working machine.
3. Event Viewer: the channel that names the file
Microsoft's troubleshooting guidance for driver issues is explicit about where to look. Check the code integrity logs to see if any drivers were blocked from loading as a result of Memory Integrity. That channel is:
Every event ID below is documented by Microsoft for that channel. The ones marked with a dagger are the ones that will name a file you can chase.
| Event ID | Documented meaning | Use it for |
|---|---|---|
| 3001 | An unsigned driver was attempted to load on the system. | Signing, not HVCI |
| 3004 † | Could not verify the file as the page hash could not be found. Also seen for a kernel driver with an invalid signature, or code opted into /INTEGRITYCHECK but signed wrongly. | Driver name |
| 3010 | The catalog containing the signature for the file under validation is invalid. | Catalog noise |
| 3023 † | The driver file under validation did not meet the requirements to pass the App Control policy. | Driver name |
| 3033 † | The file under validation did not meet the requirements to pass the policy. Often a revoked signature, or a Lifetime Signing EKU that has expired. | Driver or DLL name |
| 3034 † | Audit-mode equivalent of 3033. | Pre-enforcement triage |
| 3074 † | Page hash failure while hypervisor-protected code integrity was enabled. | Directly HVCI |
| 3076 † | Main App Control block event for audit-mode policies. Would have been blocked if enforced. | Audit triage |
| 3077 † | Main App Control block event for enforced policies. The file was blocked. | The enforced block |
| 3082 † | If the policy was enforced, it would have blocked this non-WHQL driver. | WHQL gaps |
| 3084 / 3085 | Code Integrity is, or is not, enforcing WHQL driver signing requirements this boot session. | Boot-session context |
| 3087 † | Memory integrity compatibility event. Microsoft's own driver-debugging guidance says compatibility events generally have EventID 3087. | The HVCI compat event |
| 3089 | Signature information for a file that was blocked or audit-blocked. One event per signature. Correlate with 3004, 3033, 3034, 3076 and 3077 using the Correlation ActivityID in the System portion of the event. | Who signed it |
| 3095 / 3096 / 3097 | Policy could not be refreshed and needs a reboot; was already up to date; could not be refreshed. | Policy plumbing |
| 3099 | Indicates that a policy has been loaded. Details include the policy options, PolicyNameBuffer and PolicyIdBuffer. | Blocklist verification |
| 3111 † | The file under validation did not meet the hypervisor-protected code integrity (HVCI) policy. | The clearest HVCI block |
Context: 3033 and 3077 are the famous pair, but 3087 and 3111 are the specific ones. Most write-ups on this topic point at the 3077 and 3033 family, and that is fair, because they are the main App Control block events and they do name files. But if you want the events that are specifically about hypervisor-enforced code integrity rather than App Control policy generally, Microsoft documents 3111 as "the file under validation did not meet the hypervisor-protected code integrity (HVCI) policy", 3074 as a page hash failure while HVCI was enabled, and 3087 as the Memory Integrity compatibility event. Filter for all of them. A second channel, Applications and Services Logs\Microsoft\Windows\AppLocker\MSI and Script, carries the equivalent events for MSI installers, scripts and COM objects. It is irrelevant to drivers, so ignore it here.
Here is what a filtered view looks like when a driver is genuinely being refused.
That is an illustrative panel using a fictional driver name, not a capture from a real device. The real capture is in the Proof section further down.
Now the query. This pulls the blame events and reads their messages, which is where the driver path lives.
Gotcha: this channel is small and circular. On a stock Windows 11 device the CodeIntegrity/Operational log is configured Circular with a maximum size around one megabyte. On a chatty machine that is hours of history, not weeks. If you enable Memory Integrity on Monday and investigate on Friday, the evidence may already have rolled off. Increase the channel size before a pilot, or re-trigger the change immediately before you look. And remember the harder case: a boot-critical driver can silently disable Memory Integrity before anything gets logged at all, so an empty channel is not proof of innocence.
4. The log file: setupact.log and the VBS_COMPAT_ISSUES bitmask
There is one more surface, and it is the one almost nobody checks. When Windows decides at install time whether to auto-enable Memory Integrity, it writes the decision and its reasoning to the setup log. Full path:
Search that file for the string HVCI. Microsoft documents three result lines you can find.
| String to search for | What it means |
|---|---|
SYSPRP HVCI: Enabling HVCI | Healthy. Memory Integrity was auto-enabled at setup. |
SYSPRP HVCI: OS does not meet HVCI auto-enablement requirements. Exiting now. | Not enabled. If this is the only HVCI line, the device was opted out by the registry method. |
SYSPRP HVCI: Compatibility did not pass. VBS_COMPAT_ISSUES 0xXXXXXXXX | A compatibility issue. The hex value is a bitmask you decode against the table below. |
That bitmask is genuinely useful, because it tells you which prerequisite failed rather than making you guess. Each issue is a single bit.
| Hex value | Compatibility issue |
|---|---|
0x00000001 | Unsupported architecture, for example x86. |
0x00000002 | SLAT required. |
0x00000004 | Secure Boot capability required. |
0x00000008 | IOMMU required. |
0x00000010 | MBEC or GMET required. |
0x00000020 | UEFI required. |
0x00000040 | UEFI WX Memory Attributes Table required. |
0x00000080 | ACPI WSMT table required. |
0x00000100 | UEFI MOR Lock required. |
0x00000400 | Hardware virtualization required. |
0x00000800 | Secure Launch required, ARM64. |
0x00002000 | Device fails the 64GB minimum volume size. |
0x00004000 | System drive SSD required. |
0x00008000 | Intel CET required, Windows 11 21H2 only. |
0x00010000 | ARM SoC is not compatible with VBS. |
0x00020000 | 8GB RAM required. |
Microsoft's own worked example: VBS_COMPAT_ISSUES 0x000000C0 decomposes into 0x00000080 plus 0x00000040, which is "ACPI WSMT table required" plus "UEFI WX Memory Attributes Table required". Both of those are firmware problems, so the fix is a BIOS update from the OEM, not anything you can do in Windows.
5. System files and binaries in the flow
It helps to know which files are actually doing the work, both for understanding and for support calls. The table below lists what is present on a running Windows 11 device, verified on the machine used for this post. Microsoft documents the feature rather than publishing a role-by-role reference for each binary, so the role column is described from behaviour and should be read as explanation, not as a Microsoft-sourced contract.
| File | Location | Role in the flow |
|---|---|---|
hvloader.dll | C:\Windows\System32\ | Loaded during boot; selects and starts the correct hypervisor image. |
hvix64.exe | C:\Windows\System32\ | The hypervisor image used on Intel platforms. |
hvax64.exe | C:\Windows\System32\ | The hypervisor image used on AMD platforms. |
securekernel.exe | C:\Windows\System32\ | The secure kernel that runs inside the VBS environment. |
skci.dll | C:\Windows\System32\ | Secure kernel code integrity. This is the component that enforces HVCI inside the isolated environment. |
ci.dll | C:\Windows\System32\ | Kernel-mode code integrity on the NT side. |
vbsapi.dll | C:\Windows\System32\ | The readiness API the setup-time check calls. The setupact.log lines name its exports, including VbsGetIssues and HvciIsRecommended. |
driversipolicy.p7b | C:\Windows\System32\CodeIntegrity\ | The in-box vulnerable driver blocklist policy binary. |
SiPolicy.p7b | C:\Windows\System32\CodeIntegrity\ | Where you place the downloadable blocklist if you deploy it yourself. |
the offending .sys | usually C:\Windows\System32\drivers\ | The driver named in the event. This is the file you chase. |
6. Services and scheduled tasks: honestly, there are none
This is worth stating plainly, because people go looking. There is no Windows service that runs Memory Integrity, and no scheduled task under \Microsoft\Windows\... that drives it. The hypervisor and the secure kernel are boot-loaded components, started by the boot loader before the service control manager exists. You cannot restart them, and there is nothing to set to Automatic.
Two services are adjacent but not causal. SecurityHealthService, display name Windows Security Service, renders the Core isolation page you clicked; if that page misbehaves, that service is the one to look at, and it has nothing to do with whether HVCI starts. HvHost, display name HV Host Service, exists on machines with Hyper-V components. Do not treat either as a health signal for Memory Integrity. The authoritative state is Win32_DeviceGuard, full stop.
The fix: find the driver, then enable through policy
Step 1: enumerate what is actually loaded
Once an event names a driver you are nearly done. When it does not, you need a candidate list. Both commands below list loaded drivers with their file paths, so you can cross-reference against vendor updates.
Microsoft names the categories where it has observed incompatibilities, and the list is a good place to start guessing: anti-cheat solutions with gaming, third-party input methods, and third-party banking password protection. In an enterprise fleet, add VPN clients, legacy storage filter drivers, virtual audio devices and older backup agents.
Step 2: confirm the driver, do not guess
If you have a lab machine and a suspect driver, Driver Verifier will tell you definitively. There is a Code Integrity option flag, 0x02000000, that enables extra checks validating compliance with Memory Integrity.
Driver Verifier changes machine state and can render a machine unbootable. The command below is included for completeness because it is Microsoft's documented compatibility test, but it is not a read-only diagnostic. It configures the kernel to apply extra runtime checks, and a failing driver under Verifier will bugcheck the machine on purpose. Run it on a lab device you can rebuild or roll back with a snapshot, never on a user's machine and never on a server you care about. Have a recovery plan before you type it. The same warning applies to the documented recovery procedure later in this section, which involves booting into the Windows Recovery Environment.
The documented syntax is verifier.exe /flags 0x02000000 /driver <driver.sys>. In the Verifier GUI, choose "Create custom settings (for code developers)", then Next, then "Code integrity checks". On success there is no output at all. A failure looks like a Verifier assertion naming the exact violation, for example "The caller specified an executable page protection 0x40", which maps to the Execute Page Protection row in the failure table earlier.
There is also a supported tool for inspecting the platform rather than the driver. The Windows SDK ships SkTool.exe in its bin folder, typically under a path like C:\Program Files (x86)\Windows Kits\10\bin\10.0.26100.0\x64. Run with no switches it displays the current state of the hypervisor and VBS, including the reason VBS has or has not started. /status shows hypervisor and secure kernel information, /mitigations shows NT and secure kernel mitigations, and /lkey shows VSM master key provisioning status, which is the switch you want when Windows Hello stops accepting a PIN after a security posture change.
Step 3: fix the driver
There are only three real outcomes, and it is worth being honest about them with whoever is asking.
- Update it. Microsoft's first troubleshooting step: if a device driver fails to load or crashes at runtime, you might be able to update the driver using Device Manager. Check the vendor's site for a build newer than the one on the device. Compatibility has been required since 1607, so a current build usually complies.
- Remove it. If the hardware or software is retired, uninstall it. This is the most common resolution in practice for old agents nobody owns any more.
- Escalate it. If the vendor's newest build still fails, send them the Driver Verifier output and the failure category name. "Your driver fails HVCI with an Execute-Write Section violation" gets a real answer. "Memory Integrity won't turn on" does not.
If a device has already been made unstable, Microsoft documents the recovery path: disable any policies used to enable VBS and Memory Integrity, boot the affected computer into the Windows Recovery Environment, and set HKLM\SYSTEM\CurrentControlSet\Control\DeviceGuard\Scenarios\HypervisorEnforcedCodeIntegrity value Enabled to 0, then restart. If Memory Integrity was turned on with UEFI lock, you must disable Secure Boot in firmware to complete those steps, which means physical access to the machine.
Step 4: enable it properly, through Group Policy
Once the drivers are clean, turn the feature on through policy rather than by hand. The Group Policy path is:
The full click-through, as an ordered list:
- Open Group Policy Editor with
gpedit.msc, or open the GPO you want in the Group Policy Management Console. - Navigate to Computer Configuration > Administrative Templates > System > Device Guard.
- Double-click Turn On Virtualization Based Security.
- Select Enabled.
- Under Virtualization Based Protection of Code Integrity, select Enabled without UEFI lock. Only choose Enabled with UEFI lock if you specifically want to prevent Memory Integrity being turned off remotely or by policy update.
- Under Select Platform Security Level, choose Secure Boot in most situations. Choosing Secure Boot and DMA Protection means machines without an IOMMU get no VBS at all.
- Select OK to close the editor.
- On a domain-joined computer, restart or run
gpupdate /forcefrom an elevated Command Prompt. - Restart the device. The feature can only start at boot.
The setting is backed by DeviceGuard.admx and writes to HKLM\SOFTWARE\Policies\Microsoft\Windows\DeviceGuard. That is worth knowing, because it means you can confirm the policy arrived by reading the registry, before you even reboot.
Gotcha: the UEFI lock is a one-way door in practice. Once Memory Integrity is enabled with UEFI lock, Microsoft's documentation is clear that you must have access to the UEFI BIOS menu to turn off Secure Boot if you want to turn Memory Integrity off. On a remote workforce that is a desk visit or a reimage per device. Use "Enabled without UEFI lock" for the initial rollout, prove the fleet is stable, and only then consider the lock for high-value devices.
Step 5: the same setting from Intune
For cloud-managed devices, use the settings catalog. Microsoft's documented route is the Virtualization Based Technology > Hypervisor Enforced Code Integrity setting.
- Sign in to the Microsoft Intune admin center at
intune.microsoft.com. - Go to Devices > Configuration.
- Select Create > New Policy.
- Platform: Windows 10 and later. Profile type: Settings catalog. Select Create.
- Give the profile a name, for example W11-Baseline-MemoryIntegrity. Select Next.
- Select Add settings.
- In the settings picker, browse to or search for the category Virtualization Based Technology.
- Tick Hypervisor Enforced Code Integrity. Close the picker.
- Set the value. Enabled without lock is the value to start with. Enabled with UEFI lock is the hardened option. Disabled turns it off remotely, but only if it was configured previously without UEFI lock.
- Optionally add Require UEFI Memory Attributes Table if you want to refuse VBS on firmware that does not report a compliant MAT.
- Select Next, add scope tags if you use them, then assign to a pilot group first. Never assign this to All Devices on day one.
- Select Next, review, and Create.
If you prefer a custom profile or you are on a different MDM, the CSP node is documented. The OMA-URI is:
| CSP value | Meaning | Notes |
|---|---|---|
| 0 | Disabled. Turns HVCI off remotely if it was configured previously without UEFI lock. | The documented default value. |
| 1 | Enabled with UEFI lock. | Cannot be reversed remotely. |
| 2 | Enabled without UEFI lock. | Start here. |
Format is int. Scope is Device only, not User. Applicable from Windows 11 version 21H2, build 10.0.22000, on Pro, Enterprise, Education and IoT Enterprise. The related node ./Device/Vendor/MSFT/Policy/Config/VirtualizationBasedTechnology/RequireUEFIMemoryAttributesTable takes 0 or 1.
Context: this one is not CSP-only or GPO-only. It is both, and they map to the same place. That is unusual and it is good news. The CSP node's documented Group Policy mapping is the policy named VirtualizationBasedSecurity, friendly name Turn On Virtualization Based Security, element name Virtualization Based Protection of Code Integrity, under Computer Configuration, path System > Device Guard, ADMX file DeviceGuard.admx, registry key SOFTWARE\Policies\Microsoft\Windows\DeviceGuard. So GPO and Intune are writing the same value to the same key. Configure it from one place only, or you will spend an afternoon on a conflict that reports as a mystery.
There is a third route worth knowing. App Control for Business policy can turn Memory Integrity on: through the App Control Wizard's Hypervisor-protected Code Integrity option on the Policy Rules page, through the Set-HVCIOptions PowerShell cmdlet, or by editing the <HVCIOptions> element in the policy XML. One trap there: if your App Control policy is set to turn Memory Integrity on, it will be turned on even if the policy is in audit mode.
Step 6: the blocklist, verified and deployed
The blocklist needs its own handling because it is a separate control with a separate verification path.
To check the in-box blocklist, the supported route is the Windows Security app:
To deploy and verify the more complete downloadable version, Microsoft's documented procedure is:
- Download the App Control policy refresh tool from
aka.ms/refreshpolicy. - Download and extract the vulnerable driver blocklist binaries from
aka.ms/VulnerableDriverBlockList. - Select either the audit-only version or the enforced version, and rename the file to
SiPolicy.p7b. - Copy
SiPolicy.p7bto%windir%\system32\CodeIntegrity. - Run the policy refresh tool to activate and refresh all App Control policies on the computer.
Then verify it landed, which is the step people skip:
- Open Event Viewer.
- Browse to Applications and Services Logs > Microsoft > Windows > CodeIntegrity > Operational.
- Select Filter Current Log.
- Replace
<All Event IDs>with3099and select OK. - Find a 3099 event where
PolicyNameBufferandPolicyIdBuffermatch the Name and ID from the PolicyInfo settings in the blocklist policy XML. A machine may have more than one 3099 event if other App Control policies are present.
Activating a policy does not stop a driver that is already running. Microsoft states this plainly: if any vulnerable drivers are already running that the policy would block, you must reboot for those drivers to be blocked, because running processes are not stopped when a new App Control policy is activated without a reboot. A remediation script that applies the policy and reports success has not actually protected anything until the device restarts. Build the reboot into the change, and do not let a dashboard tell you a fleet is protected when it is only configured.
Step 7: the Defender angle
There is one more control in this family, and it is genuinely different again. Microsoft recommends enabling the attack surface reduction rule Block abuse of exploited vulnerable signed drivers alongside the blocklist. Its GUID is 56a863a9-875e-4185-98a7-b882c64b5ce5. In Intune it lives under Endpoint security:
- Go to Endpoint security > Attack surface reduction.
- Select Create Policy. Platform Windows, profile Attack Surface Reduction Rules.
- Name the profile, then find Block abuse of exploited vulnerable signed drivers (Device).
- Set it to Block, or to Audit first if you want telemetry before enforcement.
- Assign to a pilot group, review, and create.
Understand exactly what that rule does, because the boundary matters. The ASR rule prevents apps from saving vulnerable signed drivers to the computer. It does not prevent loading drivers already on the computer. Enabling the Microsoft vulnerable driver blocklist, or applying the App Control policy, is what prevents an existing driver from loading. The rule is classified as a Standard protection rule, it is supported on Windows 11 and later, it is deployable via Intune, MDM CSP and Group Policy but not Configuration Manager, and it supports user notification pop-ups but does not generate EDR alerts. Its advanced hunting action types are AsrVulnerableSignedDriverAudited and AsrVulnerableSignedDriverBlocked.
So the full picture is three layers, and it is worth being able to recite it: the ASR rule stops a vulnerable driver being written to disk, the blocklist stops one that is already on disk from loading, and Memory Integrity stops any driver, malicious or merely badly written, from making kernel memory both writable and executable.
Proof it worked: a real run on Windows 11 build 26200
The companion script for this post is Get-HvciReadinessReport.ps1. It is read-only. It reads the WMI class, the four registry locations, the on-disk binaries and policy files, the CodeIntegrity event channel, and the setup log, then translates every documented enumeration into plain English and names any .sys it finds. It changes nothing.
The output below is a genuine run on a Windows 11 Enterprise device, build 26200, under Windows PowerShell 5.1. Identifiers are replaced; nothing else is edited.
The interesting half is the evidence section, because this device is healthy and the script has to say so without pretending it looked harder than it did.
Read that last block carefully, because it contains the two lessons of this whole post. There were twenty 3033 events on a device where Memory Integrity is perfectly healthy. A naive script that counted code integrity errors would have raised an incident. And the setup log confirms that auto-enablement was skipped because this device was upgraded rather than clean installed, which matches Microsoft's documented behaviour exactly, and is why enterprise fleets need policy rather than trusting the default.
Tip: distinguish "read failed" from "genuinely absent" in every check you write. The script aborts with exit code 1 if it is not elevated, and again if the Win32_DeviceGuard query fails, rather than printing empty fields. A blank report reads as "VBS is off" when it actually means "we could not look", and that is how a fleet gets reported compliant while being wide open. Every registry read in the script reports ABSENT and READ FAILED as different outcomes, for the same reason.
The script lives here: Windows-11-Scripts\hvci-memory-integrity-driver-blocklist\Get-HvciReadinessReport.ps1. It needs no modules, runs on both Windows PowerShell 5.1 and PowerShell 7, and takes -EventDays, -MaxEvents, -IncludeAllDrivers and -SkipSetupActLog.
References
- Enable memory integrity - the registry values, the Group Policy steps, the
Win32_DeviceGuardproperty enumerations, and the Windows RE recovery procedure. - Memory integrity enablement - auto-enablement hardware bar,
CI\State\HVCIEnabled, theWasEnabledByandEnabledBootIdsafeguard, event 3087, the setupact.log strings and the fullVBS_COMPAT_ISSUESbit table, and SkTool. - Virtualization-based Security (VBS) - the platform component table including TPM 2.0, SLAT, IOMMU, WSMT, the UEFI Memory Attributes Table and Secure MOR v2.
- Driver Compatibility with Hypervisor-Protected Code Integrity (HVCI) - how to build a compatible driver, the Driver Verifier
0x02000000flag, the failure category table and the affected APIs. - Microsoft recommended driver block rules - what the vulnerable driver blocklist is, how it ships, the download and apply steps, and the event 3099 verification procedure.
- Understanding App Control event IDs - the CodeIntegrity/Operational event catalog, including 3033, 3074, 3076, 3077, 3082, 3089, 3099 and 3111.
- VirtualizationBasedTechnology Policy CSP - the OMA-URI, the allowed values, and the Group Policy mapping including the ADMX file and registry key.
- Attack surface reduction rules reference - the "Block abuse of exploited vulnerable signed drivers" rule, its GUID, and the boundary between writing a driver to disk and loading one.
- driverquery - the documented syntax and parameters for the in-box driver inventory command.
- Memory Integrity and Virtualization-Based Security (VBS) - the driver-developer framing of what VBS isolates and why.
- KB5020779: the vulnerable driver blocklist - confirmation that the blocklist is enabled by default from Windows 11 version 22H2, and the Windows Security toggle steps.
No community or MVP deep-dive on this specific topic verified as both reachable and genuinely on-subject at the time of writing, so no third-party table is included here. Every claim above traces to a Microsoft-official page in the list, to the documented enumerations quoted inline, or - where explicitly labelled - to observation on a live device.
Download it from Imran76Awan/Windows-11-Scripts — no sign-in required. It is read-only: it reports and never changes a device or anything in Intune. Validate it in your own environment before relying on the output.