Patch My PC / Blog

How the Enrollment Status Page Tracks Security Policies During Autopilot

by | May 20, 2025 | Blog

Ever wondered how the Enrollment Status Page (ESP) identifies which security policies are tracked and applied during Windows Autopilot enrollment? This blog uncovers how it tracks them through the ExpectedPolicies file, and how we can add some (security) policies ourselves!

The ESP and the Identifying Security Policies step

It all started during one of our MMSMOA sessions. Michael Niehaus mentioned how Autopilot (enrollment status page) only tracks EntDMID as security policy “Security policies (1 of 1 applied)” during ESP. That one line stuck in my head.

Not because EntDMID is exciting. It’s not. But because the idea of only tracking one placeholder value felt… off. I couldn’t help but wonder: How does ESP actually know which policies are applied, and is it really just EntDMID behind that whole “1 of 1” or the identifying security policies thing?

What followed was a weekend of testing, digging into DLLs, SyncML traces, provisioning internals, and of course, a lot of poking with send-localmdmrequest.

Let’s walk through it.

Step One: The ProgramData Folder and The ExpectedPolicies

Once I got back from MMS, I started poking around. I opened up Procmon, sent a send-localmdmrequest -omauri to try and GET the status of the ExpectedPolicies CSP from the DMClient CSP documentation.

dmclient csp and tjhe enrollmentstatustracking csp are used during the ESP to track the apps and policies

While using the LOCALMDM request to poke at the DMClient CSP, The system was writing a file to:  C:\ProgramData\Microsoft\DMClient\<enrollment-guid>\FirstSync\ExpectedPolicies

That file seemed to list the policies that the ESP was expecting. One line in particular kept showing up:

./Vendor/MSFT/DMClient/Provider/MS DM Server/EntDMID

And it wasn’t just showing up in that file. I also saw it mirrored in the registry under: HKLM\SOFTWARE\Microsoft\Windows\Autopilot\EnrollmentStatusTracking\ESPTrackingInfo\Diagnostics\ExpectedPolicies

At that point, I had a new question:  Why does ESP only seem to care about EntDMID?

Quick side note: What is EntDMID?

EntDMID stands for Enterprise Device Management ID. It’s a unique ID created during MDM enrollment that links the device to the management server. But it’s not really a policy. ESP just treats it like one. If EntDMID shows up in the ExpectedPolicies file, it becomes trackable even though it doesn’t configure anything by itself.

Back to the story. My assumption was: if EntDMID is the only trackable thing, maybe adding other CSP paths manually to that file would make ESP show more than just “Security policies 1 of 1.”  That assumption was about to get tested. Hard.

Step Two: The Custom CSP to track Security Policies

Let me try this the clean way first, I thought.

I created a custom configuration profile in Intune with this OMA-URI:

./Vendor/MSFT/DMClient/Provider/MS DM Server/FirstSyncStatus/ExpectedPolicies

And gave it this value:

./Vendor/MSFT/DMClient/Provider/MS DM Server/EntDMID./Device/Vendor/MSFT/LAPS/Policies/AutomaticAccountManagementEnableAccount

(Side note: yes, I used the correct 0xF000 delimiter between them.)

But… Intune wasn’t impressed. I got 2016281112 (SyncML error code 405).

error 2016281112

Which makes sense once you re-read the DMClient CSP docs, this node isn’t writable via normal policy.

custom uri settings for the dmclient csp are not supported

Still, I wasn’t giving up that easily.

Step Three: Going Local

Time for send-localmdmrequest.

I switched to using a local SyncML injection with this PowerShell-based approach:

Send-LocalMDMRequest -omauri “./Vendor/MSFT/DMClient/Provider/MS DM Server/FirstSyncStatus/ExpectedPolicies” -data “./Vendor/MSFT/DMClient/Provider/MS DM Server/EntDMID./Device/Vendor/MSFT/LAPS/Policies/AutomaticAccountManagementEnableAccount”

This time, the request succeeded, and I could see the ExpectedPolicies file in ProgramData had been updated. However, after a while, ESP still showed that 1 of the 1 policies had been applied. My extra policy didn’t seem to count, and I quickly realized why.

Step Four: Timing is Everything

When I first entered the send-localmdm command, the device was still syncing with Intune, and with it, the expected policies got overwritten. However, entering the command too late would also be blocked. Let me explain why! Once provisioning completes, a certain registry key in the firstsync node flips:

HKLM\SOFTWARE\Microsoft\Enrollments\<guid>\FirstSync\IsServerProvisioningDone

Once this value is set to 1, the system stops accepting changes to the ExpectedPolicies node. Even if you send SyncML again or change the file directly, it no longer matters.

To fix this, I wrote a script, I waited until Intune Management Extension (IME) was getting installed. The moment I noticed the Intune Management extension folder appearing I executed the PowerShell script.

  • Sends the local MDM request to inject the ExpectedPolicies entry
  • Then it sets the value IsServerProvisioningDone manually

Please NOTE: I used this PowerShell script on the device itself because the moment the Intune Management Extension is installed, it directly moves over to the security policies. The PowerShell scripts themselves don’t have enough time to be executed before the ESP moves over to the security policies.

With the local PowerShell script timed correctly, it finally worked! The ESP showed 2 of 2 applied.

One of them was the ENTMID, and the other one was the LAPS automatic account management.

Step Five: Adding More Security Policies to be tracked

With the timing right, I could now test real-world policy tracking.

Then I added an AppLocker policy to the expectedpolicies with:

./Vendor/MSFT/AppLocker/ApplicationLaunchRestrictions/EXEGroup/EXE/Policy

ESP bumped up to 3 of 3 applied.

To confirm it was really tracking deployment, I removed the AppLocker assignment from Intune.  Boom. ESP dropped back to 2 of 3 applied,

 The corresponding ESPtrackinginfo Diagnostics key showed a value of 0 for the AppLocker node.

That confirmed it. ESP doesn’t just blindly show the status, it really checks if those ExpectedPolicies are actually applied. But what now? As I really wanted to deploy this idea from Intune using a PowerShell script… but with a PowerShell script and the CSP not working… why not converting the PowerShell script to an MSI file? The LOB app will be deployed at the same time as the Intune Management Extension.

Convert PowerShell to A LOB App?

I wondered if I could somehow convert the PowerShell to an MSI file and deploy it as an LOB app during Autopilot. Well, the idea was pretty good (at first) because the timing is crucial.

The expected policies of CSP need to be implemented the moment the IME gets installed, and just before the device switches over to identify security policies. I already knew that using a PowerShell script wasn’t going to do what I wanted as it would kick in too late, but an MSI? Well, don’t say I didn’t try.

With the use of Iexpress, I converted the PowerShell script to an EXE file, and that exe file to a MSI file.

And from there on, the PowerShell scripts started another PowerShell script with the -mta and the -encodedcommand parameters.

The idea was good, but it was again a matter of timing. Because I needed to install the localmdm module and the NuGet provider first, it just took too long (a couple of seconds) before it could apply the policy.

So, I decided to test the same thing, but this time WITHOUT installing the NuGet provider (installing it before enrolling the device) …. well, that did the trick… it saved me the magical 10 seconds I needed. With the magical 10 seconds less, it indeed kicked in during the Enrollment Status Page Device Setup!

Under the Hood: How Security Policy Tracking Really Works

By this point, I had also gone peeking inside windows. internal. management. dll and enterprisecsp. dll. The moment the device syncs, the OMADMClient receives the expected policies CSP and executes it.

When the CSP gets executed, it will drop the expected policies file in the program data folder. From there, svchost and windows.internal.management.dll pick up the trail.

Inside the windows.internal.management, we will spot a function called  FirstSync::GetResourceProvisionedCount (part of the main lambda_735d8649ee1050d87d2636f382dd4853 function), the system checks whether a policy listed in the ExpectedPolicies file is actually deployed to the device.

If the policy is NOT successfully deployed to your device, the Diagnostics registry key records a 0, and ESP gets stuck on that last line saying “Working on it”.

After the ESP time-out the Security Policies will display (Error) because the policy is NOT deployed!

When looking at the shell-core event log, we will notice that the bootstrapstatus will mention that the monitoring policies from management server failed: expected 3 items provisioned, but got only 2.

monitoring policies from management server failed

The ESP uses svchost to validate that the policies listed in ExpectedPolicies were actually configured. If one isn’t, ESP keeps waiting.

Conclusion: It’s possible to add custom tracking policies

At first, I thought EntDMID was just a dummy. And it kind of is. But it’s also a signal. A placeholder that lets ESP know at least one policy is expected, and allows it to start counting.

But if you time things right and use the provisioning window carefully, you can make ESP track more security policies. As of today, I can add all the policies I want Autopilot/ESP to track… but still manually. (Even though I proved my point that it is possible)

Will Microsoft ever officially support custom ExpectedPolicies tracking? Who knows, but it would be cool if they did! But now we know how it works, and how it breaks.