← ALL WRITING · SEPTEMBER 2026 · 5 MIN READ

Two install pipelines, one ESP timeout

Windows Autopilot pre-provisioning failed on almost every device at exactly 2 hours and 10 minutes, requiring a full reset each time. The fix was a single dropdown in the Enrollment Status Page profile. Getting to that dropdown took reading logs.

Environment

A multi-site healthcare organization running Windows 11 endpoints, Autopilot pre-provisioning with hybrid Microsoft Entra Join, and a standard ESP profile with a 120-minute timeout. Ten required apps at enrollment: eight Win32 line-of-business and security agents totaling roughly 3.9 GB, plus Microsoft 365 Apps and Company Portal.

The symptom

Devices hung at the ESP app phase showing Apps (8 of 9 installed) — sometimes 9 of 10, depending on how Company Portal was being enumerated. The counter never advanced. At 2h10m the timeout fired and the device needed a full reset. Re-running OOBE occasionally succeeded, but inconsistently, and burned another two hours finding out.

The 2h10m was the first useful clue. The ESP profile was set to show an error after 120 minutes. Add the roughly 10-minute Windows OOBE grace window and you get 130. This wasn't a hang. It was a wait that never ended.

To make it worse, the Autopilot Diagnostics report itself wouldn't render — 0x80004005. So the obvious troubleshooting path was closed before it opened.

The diagnostic path

With the diagnostics report dead, the authoritative record is the Intune Management Extension log. It tells you exactly which apps IME was tracking, which it downloaded, which it executed, and which reached a terminal state — none of which the ESP progress counter reliably conveys.


# IME's own record of what it tracked and what it finished.
# Authoritative when the MDM diagnostic HTML report won't render.
Get-ChildItem 'C:\ProgramData\Microsoft\IntuneManagementExtension\Logs\'

Get-Content 'C:\ProgramData\Microsoft\IntuneManagementExtension\Logs\IntuneManagementExtension.log' -Tail 200
  

The logs showed something that reframed the problem: every app IME was responsible for had completed. Nothing was erroring, nothing was retrying, nothing was stuck mid-download. IME had finished its work and gone quiet — well inside the ESP window.

Which raises the obvious question. If IME finished, what was ESP still waiting on?

Two pipelines, not one

Intune doesn't install every app type through the same channel, and this is the part that's easy to miss.

Win32 apps go through the Intune Management Extension. IME installs serially — one app downloaded and executed at a time — holding Windows Installer service locks for the duration of each. Here, that was the eight LOB and security agents.

Microsoft 365 Apps deployed via the native "Microsoft 365 Apps for Windows 10 and later" app type does not go through IME. It goes through the Office Configuration Service Provider, which launches Click-to-Run (OfficeC2RClient.exe) to pull 3–4 GB from the Office CDN. OfficeCSP has no awareness of what IME is doing, and vice versa.

Both were running during the ESP window. Click-to-Run couldn't reliably acquire the installer locks IME was holding, so it sat in a wait state — and critically, never reported a status back that ESP recognized as terminal.

The Intune portal device view matched this exactly, every time:

Every IME-tracked app was done. The one app on the other pipeline was the one holding ESP hostage.

Microsoft documents this, for what it's worth. Their Intune guidance on adding Microsoft 365 Apps to Windows devices recommends deploying M365 Apps as a Win32 app specifically because the native app type isn't managed by IME, and installing it during ESP alongside a tracked Win32 app can create an installation concurrency issue that causes ESP to fail. The failure mode here is the one in the docs.

Root cause

An installation concurrency deadlock between two independent delivery pipelines, turned from an intermittent race into a guaranteed failure by one configuration setting.

The ESP profile had Block device use until required apps are installed set to All. "All" means ESP waits for every Required-assigned app to reach a terminal state before releasing the device — including the OfficeCSP-delivered one that had no reliable path to reaching a terminal state inside the window.

So ESP waited. It had eight terminal statuses and one that would never arrive, and a 120-minute clock. Every enrollment, every device.

The fix

In the ESP profile, Block device use until required apps are installed changed from All to Selected, with the list limited to the eight Win32 apps: the RMM agent, remote support client, Citrix Workspace, EDR agent, Chrome, the clinical SSO agent, the vulnerability management agent, and a PDF tool.

Deliberately left off the blocking list:

"Selected" tells ESP: wait for these specific apps, install everything else but don't block completion on them.

Results

Pre-provisioning completes in about 28 minutes, down from a 130-minute timeout failure — a 78% reduction, and more to the point, a failure rate that went from 85% to zero. All eight tracked apps install during ESP and report Success. Microsoft 365 Apps installs in the background post-ESP and shows Installed in the portal. Reseal works.

Which confirms the diagnosis: Office was never failing to install. It just couldn't finish inside a window it was sharing with 3.9 GB of serialized Win32 installs. Given room to run uncontested, it completed every time.

No infrastructure changes, no licensing, no support case. One dropdown.

The real fix is upstream

Selected-mode blocking works, but it treats the symptom. The structurally correct move — and Microsoft's own recommendation — is to repackage Microsoft 365 Apps as a Win32 app using the Office Deployment Tool.

That collapses two competing pipelines into one serialized pipeline. This class of failure then can't recur: IME won't deadlock against itself. You also get IME's reporting, which is accurate and timely in a way OfficeCSP's isn't, plus full XML control over channel, excluded apps, and cleanup of pre-existing OEM Office installs.


<Configuration ID="m365-apps">
  <Add OfficeClientEdition="64" Channel="MonthlyEnterprise" AllowCdnFallback="True">
    <Product ID="O365ProPlusRetail">
      <Language ID="en-us" />
      <ExcludeApp ID="Groove" />
      <ExcludeApp ID="Lync" />
      <ExcludeApp ID="OneDrive" />
      <ExcludeApp ID="Bing" />
    </Product>
  </Add>
  <Property Name="SharedComputerLicensing" Value="0" />
  <Property Name="FORCEAPPSHUTDOWN" Value="TRUE" />
  <Updates Enabled="TRUE" Channel="MonthlyEnterprise" />
  <RemoveMSI />
  <Display Level="None" AcceptEULA="TRUE" />
  <Logging Level="Standard" Path="%temp%" />
</Configuration>
  

Monthly Enterprise Channel gives predictable, tested monthly updates — the right posture for clinical workstations. <RemoveMSI /> handles OEM trial Office cleanup on the image. OneDrive is excluded because it deploys separately as its own Win32 app.

Wrap it and upload it:


IntuneWinAppUtil.exe -c C:\OfficeSource -s setup.exe -o C:\OfficeOutput
  

Install command setup.exe /configure configuration.xml, install behavior System, detection rule on C:\Program Files\Microsoft Office\root\Office16\OUTLOOK.EXE, and Click-to-Run return codes mapped properly — 0 and 1707 success, 3010 soft reboot, 17000 through 17002 failed. Assign Required, keep it off the ESP blocking list until it's proven. Unassign the old native deployment rather than deleting it, so there's a rollback path for the first few builds.

Once it's stable you'd have the option of putting Office back on the blocking list, meaning users get Office at first sign-in instead of 30–60 minutes later. That costs 20–30 minutes of OOBE. It's a clinical workflow decision, not a technical one.

Takeaways

Dealing with something similar in a clinical or multi-site environment? Let's talk.