Windows Autopilot In-Depth Processes from Device Side – Part 3

Let’s get into another deep dive blog post about Windows Autopilot processes. I call it behind the scene processes and data flows.

Related Posts

Introduction

I discussed the functional block and concepts of Windows Autopilot from the perspective of IT Admin setup in my previous post.

In this post, I will be talking about the workings of Windows Autopilot In-Depth from the device side processes.

Patch My PC

Know About Windows Configuration Passes

Before we start, I would like to give some insights on Windows Configuration Passes. People with an OSD background will be already familiar with this Windows Configuration.

Windows Setup - Configuration Passes - Windows Autopilot In-Depth Processes
Windows Setup – Configuration Passes – Windows Autopilot In-Depth Processes 1

Installing Windows on a device – Windows Setup happens in a series of configuration passes (phases?) in a specific order. There are 7 of these as listed below. However, it is important to note that a particular installation might not go through all of them.

  1. Windows PE  
  2. OfflineServicing
  3. Generalize
  4. Specialize  
  5. auditSystem
  6. auditUser
  7. oobeSystem

An answer file (unattend.xml) can be used to customize/automate the Windows Setup in one or any of these configuration passes.

Note: At the beginning of each phase, it checks the Answer file to see if any values are provided to drive that phase. If found, it uses those values and continues. Else will resort to user input to continue. This is how, traditionally, in OSD, the Windows Setup is customized.

What configuration passes a Windows Setup goes through?

Below is the schematic representation showing the configuration passes through which the Windows Setup process handles the OS installation (generalized).

Windows Setup Config Pass
Windows Setup – Configuration Passes (generalized) 2

Configuration pass -> WindowsPE

This is the pass we boot from install media and start the Windows Setup, which copies the OS Image to the local drive and prepares the system to boot from the local industry. There is a restart when done.

  • Windows Autopilot In-Depth Processes from Device Side - Part 3 1
  • Windows Autopilot In-Depth Processes from Device Side - Part 3 2
  • Windows Autopilot In-Depth Processes from Device Side - Part 3 3
  • Windows Autopilot In-Depth Processes from Device Side - Part 3 4
  • Windows Autopilot In-Depth Processes from Device Side - Part 3 5
  • Windows Autopilot In-Depth Processes from Device Side - Part 3 6

Configuration pass -> OfflineServicing

Post restart, Setup continues from the local drive and not boot media. During this time, it initializes the drivers and prepares the system to support Windows for 1st boot.

There is a restart again post which starts the actual first boot of the OS – this is when the OS (NT kernel) initializes on the system for the 1st time marking the end of the OfflineServicing pass.

At this stage, the Kernel is initialized, and it launches the smss.exe, the first user-mode SYSTEM process, which initializes the csrss.exe process, which initializes the Win32 subsystem to support the Windows environment.

Windows Setup Pass OfflineServicing and Generalize -  Windows Autopilot In-Depth Processes
Windows Setup Pass OfflineServicing and GeneralizeWindows Autopilot In-Depth Processes 3

Configuration pass -> Generalize

Post end of OfflineServicing pass and entering the oobeSystem pass, there is a small transition in between – Generalize pass.

Specialize configuration pass always runs after a computer has been generalized, regardless of whether the computer is configured to boot to audit mode or Windows Welcome.

-----------------SYSPREP (Generalize Config Pass)-------------------------------
[windeploy.exe] Waiting for essential OOBE services to start…
[windeploy.exe] Essential OOBE services started successfully.
[windeploy.exe] Windeploy: Executing PreSysprep commands
[windeploy.exe] ExecuteCommandFromValue: Executing command line: C:\$WINDOWS.~BT\Sources\SetupPlatform.exe /presysprep
[windeploy.exe] Found generalization state [0x4], setup.exe completion flag [False] --> launching setup.exe.
[windeploy.exe] Windeploy: Running default setup.
[windeploy.exe] Windeploy: Executing PostSysprep commands
[windeploy.exe] ExecuteCommandFromValue: Executing command line: C:\$WINDOWS.~BT\Sources\SetupPlatform.exe /postsysprep
[windeploy.exe] OrchestrateDetermineComputerNameChange: Checking computer name change conditions:
[windeploy.exe]   Did Setup change computer name? TRUE
[windeploy.exe]   Could OOBE change computer name? TRUE
[windeploy.exe] ShouldShutdownAfterSetup: Checking reboot conditions:
[windeploy.exe]   Are only OOBE services running? FALSE
[windeploy.exe]   Is there a computer name change? TRUE
[windeploy.exe]   Was Winlogon reboot requested? TRUE
[windeploy.exe]   Is Upgrade in progress? FALSE
[windeploy.exe]   Is this Audit mode boot? FALSE
[windeploy.exe] Reboot required after setup.exe and PostSysprep commands, before launching OOBE.
[windeploy.exe] An immediate reboot or shutdown was requested/required…

Configuration pass -> oobeSystem

This is when Setup enters the user mode GUI setup, or what Microsoft likes to call Out-Of-Box-Experience.

[windeploy.exe] Launching [C:\WINDOWS\system32\oobe\oobeldr.exe /system /quiet]…
[oobeldr.exe] Found no unattend file for oobeSystem pass; skipping pass.
[oobeldr.exe] Launching [C:\WINDOWS\system32\oobe\msoobe.exe]…
[msoobe.exe] Starting OOBE
[msoobe.exe] Running OOBE wizard…
  • Windows Autopilot In-Depth Processes from Device Side - Part 3 7
  • Windows Autopilot In-Depth Processes from Device Side - Part 3 8
  • Windows Autopilot In-Depth Processes from Device Side - Part 3 9
  • Windows Autopilot In-Depth Processes from Device Side - Part 3 10

But why are we discussing the configuration passes?

Autopilot device provisioning happens during the oobeSystem phase of Windows Setup.

However, it is important to note that before Setup enters the OOB system config pass, it searches for an Answer file (unattend.xml) which is used to customize the entire configuration pass.

A sample unattend file example:

<?xml version="1.0" encoding="utf-8"?>
<unattend xmlns="urn:schemas-microsoft-com:unattend">
<settings pass="oobeSystem">
<component name="Microsoft-Windows-Shell-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance">
            <OOBE>
                <HideEULAPage>true</HideEULAPage>
                <HideLocalAccountScreen>true</HideLocalAccountScreen>
                <HideOEMRegistrationScreen>true</HideOEMRegistrationScreen>
                <HideOnlineAccountScreens>true</HideOnlineAccountScreens>
                <HideWirelessSetupInOOBE>true</HideWirelessSetupInOOBE>
                <NetworkLocation>Home</NetworkLocation>
                <ProtectYourPC>3</ProtectYourPC>
                <SkipMachineOOBE>true</SkipMachineOOBE>
                <SkipUserOOBE>true</SkipUserOOBE>
                <UnattendEnableRetailDemo>false</UnattendEnableRetailDemo>
            </OOBE>
</component>
</settings>
</unattend>

Suppose Setup finds an unattend.xml to drive the oobeSystem pass, which happens mostly in the case of custom prepared images. In that case, the device will not trigger Autopilot provisioning even if it is assigned – the reason why a business-designed OS image is not suggested with Autopilot provisioning.

For a non-customized OS image and an OEM image, it won’t find one and, as such, will continue with the default values – showing all the OOBE screens as required.

Windows Out-Of-Box-Experience…

The Out-Of-BoxExperience (OOBE) is the first boot setup process, as Microsoft likes to call it that way.

What’s so special about Windows 10 OOBE?

For Windows 10, the OOBE is web-driven and carried out in a special host process called CloudExperienceHost. This process runs under a temporal user account “defaultuser0” (yes, the same way we see in the case of KIOSK deployment)

What is this defaultuser0 account?

Post-installation as Setup starts the OOBE (First Boot Setup), Windows is already fully functional at the point but devoid of a working user account profile.

For security reasons, starting with Windows 10, the built-in Administrator account is disabled by default.

OOBE requires a user account to work as it cannot run in Session 0

Session 0 is the SYSTEM session which is the reserved session for system processes that usually do not require access to GUI for user interaction. But OOBE requires user interaction to work…

So what the system does is,

  • Creates a temporary user profile causing Winlogon to initiate a new login session – Session 1 which is a user-mode session.
  • In that session, it creates the CloudExperienceHost process of running the OOBE and tags it to WinSta0, a desktop object, making it capable of user interaction.

This temporary user account is the defaultuser0 And it has full access to Windows.

[msoobe.exe] TASK: Begin running task PrepareUserOOBE...
[msoobe.exe] Creating a new default account
[msoobe.exe] Not setting autologon since this is an upgrade or the machine is domain-joined.
[msoobe.exe] Default account: defaultuser0 is created successfully
[msoobe.exe] TASK: End successfully running task PrepareUserOOBE
[msoobe.exe] Post-setup for the default account is run successfully
OOBE running under defaultuser0 account -  Windows Autopilot In-Depth Processes
OOBE running under defaultuser0 accountWindows Autopilot In-Depth Processes 4

This account is deleted at the point when Setup has provisioned the existing user profile (usually post completion of the ESP 2nd stage – Device setup) and can continue by using it.

What is the difference between Windows 7 and Windows 8/8.1?

In Windows 7 and 8/8.1 (also called Windows downlevel), the OOBE setup used local pages and ran under SYSTEM, making them incompatible with Windows Autopilot.

Windows Autopilot OOBE flow (simplified overview only)

  • Setup starts the CloudExperienceHost process. (windeploy.exe -> oobeldr.exe -> msoobe.exe which starts the CloudExperienceHost process, refer above)
  • CloudExperienceHost renders the Cortana Welcome Screen.
  • CloudExperienceHost renders the Language (Region) selection screen.
  • CloudExperienceHost renders the Keyboard layout selection and additional Keyboard layout selection screens.
  • If Windows Setup detects no Ethernet connection, CloudExperienceHost renders the Network screen. Else this is skipped.
Each of this OOBE screen as rendered are essentially webapps (in the form of
html, oobe<part>.html) utilizing JavaScript (client code implementation of 
Worker API, as oobe<part>-page.js) capable of calling WinRT API via the
CloudHostExperience process and can be found here under the path
"C:\Windows\SystemApps\Microsoft.Windows.CloudExperienceHost_cw5n1h2txyewy\webapps\inclusiveOobe"

Each of these webapps is also supported by the Cortana voice-over functionality
via JavaScript (oobe<part>-vm.js) which gives voice guidance to the user 
through the OOBE, enabling users to complete parts of setup using speech 
(voice command) as well. However, with Windows 10 1903 and later, this 
voice-over feature is disabled by default for Pro, Enterprise and Education SKU.

Where does the real action start from?

As the device gets connected to the network is where the real things start. There are a lot of background activities performed like:

  • Windows Critical Updates (Windows Zero-Day patches, as we call them)
  • Windows Activation license check, and yes, the most important
  • Autopilot check.

NOTE: Till Win 10 v1709, Autopilot activation check was initiated post connecting to the network. (If using a wired connection, this page is skipped by default, but Autopilot check was used to start to post the OOBE Network screen timeframe before the EULA screen was to be rendered). As the device connected to the network, the device initiated the autopilot check and downloaded the profile from the Autopilot service to drive the rest of OOBE.

NOTE: From Win 10 v1803, Autopilot activation check is initiated as soon as it enters OOBE setup, essentially from the Region screen and if using a wired connection, reaches out to Autopilot service to get the profile downloaded while the device might still be in OOBE keyboard selection screen. If there is no wired connection, it will wait until the machine connects to a network in OOBE.

Thus for Windows 10 1803 and above, if you are using a wireless connection, this explains the reason why you would expect to see the below entries in the Autopilot events

Event ID 100 AutoPilot policy [AUTOPILOT_OOBE_SETTINGS_AAD_AUTH_USING_DEVICE_TICKET] not found. 

Event ID 165 AutoPilotManager determined Internet is not available; policy download will queue when available. 

Event ID 167 AutoPilotManager reported Internet is still not available. 

Want to see the Worker API (client code) responsible for the Autopilot check?

The client code (JavaScript – Worker API) is autoPilot.js found at C:\Windows\SystemApps\Microsoft.Windows.CloudExperienceHost_cw5n1h2txyewy\js

autoPilot.js - client code -  Windows Autopilot In-Depth Processes
autoPilot.js – client codeWindows Autopilot In-Depth Processes 5

The worker API essentially calls WinRT functions via CloudExperienceHost implemented in the autopilot.dll

autopilot.dll functions
Windows Autopilot – component autopilot.dll – functions 6

Want to see the actual sequence of Activities as performed during the OOBE?

You can use Windows Performance Recorder (WPR) to capture an ETW trace (initiated from CMD in OOBE). Open the trace as captured with Windows Performance Analyzer (WPA), part of the Windows 10 ADK.

Expand the System Activity > Add the Generic Events to the Graph Analysis view. The Event Series Microsoft.Windows.Shell.CloudExperienceHost.Common will contain Windows Autopilot activities

WPA - Microsoft.Windows.Shell.CloudExperienceHost.Common - Windows Autopilot In-Depth Processes
WPA – Microsoft.Windows.Shell.CloudExperienceHost.Common – Windows Autopilot In-Depth Processes 7

Now add the Regions of Interest to the Graph Analysis view, and you can see the sequence of activity as performed. As can be seen, the Autopilot process starts before the OOBE Welcome page is rendered.

OOBE Webactivity WPA - Region of Interest - Windows Autopilot In-Depth Processes
WPA – Region of Interest – Windows Autopilot In-Depth Processes 8
Till Win 10 1803, the autopilot profile as downloaded was cached locally 
which remained persistent and as such required a re-generalize 
(sysprep /generalize /oobe) or reset to remove the settings, even if you 
had not completed the entire OOBE. 

For Win 10 1809 and above, the profile as downloaded can be removed by just
rebooting the system while still in OOBE to get a new profile. However, once 
it completes the OOBE, the profile is persistent and then it would still 
require a re-generalize or reset.

What happens as the device gets connected to the network?

You would require a network capture to see the connections the device is making while it goes through the OOBE to give a clearer picture.

You can use the netsh trace and analyze with Netmon (windows parser). You can use Wireshark or any tool you like. I used Netsh and Fiddler running from USB to see and compare the network traffic.

Off the topic, want to know how to make Fiddler run from USB?

Extract the FiddlerSetup.exe as downloaded to USB via 7zip and you get a folder
named $PLUGINSDLR inside which you would get another FiddlerSetup.exe. 
Extract it again using 7zip to the root of the USB. Now you get the runtime
executable which is Fiddler.exe which can run from the USB stick itself. 

Windows Autopilot In-Depth Processes from Device Side - Part 3 11
How to run Fiddler from USB while still in OOBE? 

While in the initial pages of OOBE and if not connected to network, insert the
USB drive as prepared above. Press Shift+F10 to open the CMD console. 
You can use DISKPART > LIST VOL function to check the USB volume drive letter.
Then you can simply run Fiddler with command line <Vol_Drive_Letter>:\Fiddler.exe

Start the network capture and continue to OOBE. Fiddler will go to background.
Want to stop capture or bring it to front - use the CMD console to open 
Task Manager (taskmgr) to bring Fiddler on front. Simple isn't it! 

Windows Autopilot dependencies?

Before we start analyzing the network trace, it is important to understand that Windows Autopilot relies on many other Microsoft online services to function. See the network requirements for Autopilot.

How is the Autopilot check performed?

As we connect the device (Windows 10 build 18362.356) to a wireless network and proceed

Netsh ETL trace - Netmon Windows Parser - Windows Autopilot In-Depth Processes
Netsh ETL trace – Netmon Windows Parser – Windows Autopilot In-Depth Processes 9

The device starts connecting to the Windows Update channel fe2cr.update.microsoft.com to process the OOBE-ZDP updates (Windows Zero-Day-Patch updates).

Note: No security or feature updates are performed, but only the critical driver updates and patches are processed per the Windows Update catalog as maintained in the cloud, commonly referred to as Windows Zero-Day Patch. This is a mandate, and users can’t opt-out of this. With 1903, Autopilot component updates are also processed in this OOBE ZDP update phase.

Essentially it uses the same Windows Update channel endpoint to reach out to login.live.com, a device authentication endpoint to check if it is Autopilot enabled or not.

This activation check is essentially done against the device registration details (HWHash) in Autopilot Service (DDS). If positive, it gets the ZTDID with which

  • it connects to cs.dds.microsoft.com endpoint to download the Concierge profile (AutopilotConciergeFile.json)
  • it relates to ztd.dds.microsoft.com endpoint to download the Autopilot profile (AutopilotDDSZTDFile.json).
The AutopilotConciergeFile.json as introduced from Windows 1809, is behind 
the customization of the OOBE Language (Region) and Keyboard selection screens.
But this is only available for the self-deploy mode.

Windows Autopilot In-Depth Processes from Device Side - Part 3 12
For other autopilot deployment modes, the AutopilotDDSZTDFile.json is the one
which drives the OOBE.

NOTE: Due to issues with TPM attestation in Windows 1809, self-deploy mode support has been moved to Windows 1903 and is in a preview state.

The event logs for the same are

Event ID 166 AutoPilotManager reported Internet is now available.

Event ID 164 AutoPilotManager determined Internet is available to attempt policy download.

Event ID 704 Autopilot downloader retrieved an empty profile for ConciergePolicyManager (applicable for 1903)

Event ID 703 Autopilot downloader retrieved an empty profile for DdsZtdPolicyManager (applicable for 1903)

Event ID 161 AutoPilotManager retrieve settings succeeded.

Event ID 153 AutoPilotManager reported the state changed from ProfileState_Unknown to ProfileState_Available.

Event ID 170 AutoPilotManager reported that Autopilot profile download is now complete

Event ID 163 AutoPilotManager determined download is not required and the device is already provisioned.  Clean or reset the device to change this.

Event IDs 101, 103 and 109 are the events of AutopilotManager retrieving the settings from the profile to drive the OOBE. 

As I mentioned above, with 1809 and above, if autopilot is processed and you are at the custom Azure sign-in page and haven't signed-in yet, a restart will result the autopilot profile present to be cleared and there will be attempt to download profile again in the subsequent device start. The event (this is from 1903 though) for the same would be 

Event ID 705 Autopilot downloader cleared the local profile for DdsZtdPolicyManager

We will also see the device connecting to licensing.mp.microsoft.com, which is a Windows Activation endpoint, and a lot of traffic to oscp.digicert.com endpoint, which you can understand, for the SSL cert checks.

When the device is doing the above, you get the below screen.

OOBE-ZDP update check and Autopilot Activation - Windows Autopilot In-Depth Processes
OOBE-ZDP update check and Autopilot Activation – Windows Autopilot In-Depth Processes 10

How to confirm if the device is doing the Autopilot flow?

The device will restart as soon as the OOBE ZDP updates are completed to implement the device name change if you have used a custom Device naming convention in your Autopilot profile. (This restart is an indication that the device has picked up the Autopilot profile)

Else OOBE will skip the rest of the normal OOBE flow (EULA) and load the CloudDomainJoin web app https://login.microsoftonline.com/WebApp/CloudDomainJoin/10 HTTP/1.1

If a device has picked up the Autopilot profile and custom branding is configured in Azure, CloudExperienceHost process will render the custom Azure sign-in page. (This custom branded Azure sign-in page confirms the device has successfully picked up the Autopilot profile)

Simultaneously, you can see in network trace that it reaches out to
https://login.microsoftonline.com/common/.well-known/openid-configuration
HTTP/1.1 
to prefetch the auth endpoints by retrieving the OpenID configuration. 

AutopilotManager already has the tenant details based on which it calls the
CloudDomainJoin webapp. In normal scenario, the OpenID config is retrieved 
as part of home-realm discovery, post user enters the UPN and clicks on next.
Custom branded Azure Sign-in page - confirms Autopilot flow -  Windows Autopilot In-Depth Processes
Custom engraved Azure Sign-in page – ensures Autopilot flowWindows Autopilot In-Depth Processes 11

If the Autopilot check is returned false, the device starts the consumer OOBE flow, and the end-user is presented with the EULA screen followed by the default Sign-in with Microsoft Azure sign-in page instead.

Default Cloud Sign-in Page
Sign in with Microsoft – Not Autopilot 12

You need to check the autopilot profile assignment status and device membership in such a case.

Post checking and verification, if you are running Windows 10 1809, you can restart at this point which will cause the AutopilotManager to re-download the profile and start again.

Does the custom branded Sign-in page confirm autopilot provisioning?

For a user-driven normal autopilot deployment, the device will still show you the custom branded sign-in page if you have deleted the pre-created Azure AD object. Still, provisioning will resort to the normal OOBE AAD joining the flow. I have this mentioned in my previous Autopilot post here.

The explanation – I registered a VM with a serial number 2012-7193-2759-5095-3412-1583-38 and, post DDS registration, deleted the associated Azure AD object.

The device properties under the Windows Autopilot device are shown below.

Windows Autopilot In-Depth Processes from Device Side - Part 3 13
Windows Autopilot – Have you deleted the associated Azure AD object? 13

As the device connects to the network, it reaches out to the Autopilot service to check the provisioning status. The query response will be true as the device is registered with DDS, and a profile is also assigned.

Thus it gets the profile downloaded to drive the OOBE and pre-negotiate to render the custom sign-in page.

Windows Autopilot In-Depth Processes from Device Side - Part 3 14
Windows Autopilot – Still getting the custom sign-in page though the associated Azure AD object is deleted? 14

As the user performs sign-in, it reaches out to Azure DRS with the join request.

At this time, Azure DRS will fail to find a match. But since this is a user-driven flow, Azure DRS will create a new device object to continue the join.

The device provisioning will continue with ESP taking over, and there will be a restart post-ESP 2nd stage – Device setup.

As the device returns from the restart, it will come up with the Privacy and other consumer OOBE flow screens before continuing with the ESP last stage – Account setup.

For Self-Deploy and WhiteGlove, deleting the associated Azure AD object will fail device provisioning. This is a security mechanism implemented in Azure DRS for non-user-based device provisioning.

If the device completes the provisioning, you will get the Event ID 303 in the Autopilot events.

Windows Autopilot - Event ID 303 - Success
Windows Autopilot – Event ID 303 – Success 15

Want to validate the profile as being used by the device while still in OOBE?

You are just in luck as you can use this script.

#Get Windows Version
$WinVersion = (Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows
NT\CurrentVersion" -Name ReleaseId).ReleaseId
Write-Host ""
Write-Host "WindowsVersion"= $WinVersion
if ($WinVersion -eq '1803' -OR $WinVersion -eq '1809')
{ 
Write-Host ""
Write-Host "AutoPilot Registry Entries"
Get-ItemProperty 'HKLM:\SOFTWARE\Microsoft\Provisioning\Diagnostics\AutoPilot'
#Show AutoPilot events
Write-Host "AutoPilot Event Logs"
Write-Host ""
Get-WinEvent -MaxEvents 10 -LogName 'Microsoft-Windows-Provisioning-Diagnostics-Provider/AutoPilot'
}
elseif ($WinVersion -eq '1903')
{
Write-Host ""
Write-Host "AutoPilot Registry Entries"
Get-ItemProperty 'HKLM:\SOFTWARE\Microsoft\Provisioning\Diagnostics\AutoPilot'
#Show AutoPilot events
Write-Host "AutoPilot Event Logs"
Write-Host ""
Get-WinEvent -MaxEvents 10 -LogName 'Microsoft-Windows-ModernDeployment-Diagnostics-Provider/AutoPilot'
} 

Save it as a .ps1 script to a USB drive and insert it into the device when you are still in the OOBE cloud sign-in screen. Open the CMD console (Shift + F10) and start PowerShell (powershell.exe).

You can’t change the directory to point to the USB drive here in OOBE, so that way to run the script is PS C:Windows\system32> E:\.\Autopilotcheck.ps1 where E:\ is the USB drive letter. (Make sure to enable running script is allowed if you get an error using Set-ExecutionPolicy)

Script Output - Autopilot profile check from OOBE - Windows Autopilot In-Depth Processes
Autopilot profile check from OOBE – Windows Autopilot In-Depth Processes 15

What is CloudAssignedOobeConfig?

As you can see, the value 28, as shown in the snap, is a bitmap value which translates to SkipExpressSettings (4) + SkipOemRegistration (8) + SkipEula (16) = 28 as configured in my autopilot profile.

Bit values as can be possible
SkipCortanaOptIn = 1
OobeUserNotLocalAdmin = 2
SkipExpressSettings = 4
SkipOemRegistration = 8
SkipEula = 16  

With the Azure sign-in page displayed, the role and scope of Windows Autopilot are over.

As the user enters credentials to authenticate, the Azure AD join mechanism takes over the provisioning, which is covered here in this Microsoft Technet blog post (original credit Jairo Cadena). ESP tracks the device provisioning.

ESP page - ESP tracking the device provisioning -  Windows Autopilot In-Depth Processes
ESP tracking the device provisioning – Windows Autopilot In-Depth Processes 16

As the device provisioning completes, ESP gives way to what Microsoft calls the First Sign-in Animation (FSIA) screen.

  • Windows Autopilot In-Depth Processes from Device Side - Part 3 15
  • Windows Autopilot In-Depth Processes from Device Side - Part 3 16

This is when the Winlogon process is initiated for the original user account.

If the tenant is managed, the user is not presented with the Winlogon UI as it uses the buffered credentials from the CloudDomainJoin process.

If it is a federated tenant (or in the case of Hybrid Azure AD join), the user is presented with the Winlogon UI for login.

If Hello for Business is enabled (or required), user is presented with the
helloEnrollmentPage webapp.

Event ID 358 under User Device Registration

Windows Hello for Business provisioning will be launched. 
 Device is AAD joined ( AADJ or DJ++ ): Yes 
 User has logged on with AAD credentials: Yes 
 Windows Hello for Business policy is enabled: Yes 
 Windows Hello for Business post-logon provisioning is enabled: Yes 
 Local computer meets Windows hello for business hardware requirements: Yes 
 User is not connected to the machine via Remote Desktop: Yes 
 User certificate for on premise auth policy is enabled: No 

As the user completes the Hello setup, Winlogon calls the Userinit process to prepare the User environment for the 1st time, starting the Explorer process and giving the end-user the Desktop.

End Result - Windows Autopilot In-Depth Processes
End Result – Windows Autopilot In-Depth Processes 17

Log and events check

Autopilot Profile Path:

For version till 1809, AutoPilotManager saves configuration file to path:
C:\Windows\Provisioning\AutoPilot\AutoPilotConfigurationFile.json 

For version 1903 and above, Autopilot downloader saves the new profile to
C:\Windows\ServiceState\Autopilot\<config file name>

With 1903, there are two config files now - 
AutopilotConciergeFile.json and AutopilotDDSZTDFile.json 

Though for existing device scenario, profile location remains the same.

Registry Path:

HKLM\SOFTWARE\Microsoft\Provisioning\Diagnostics\AutoPilot

Windows 10 1809 - Autopilot regsitry -  Windows Autopilot In-Depth Processes
Windows 10 1809 – Autopilot registry – Windows Autopilot In-Depth Processes 18
Windows 10 1903 - Autopilot regsitry - Windows Autopilot In-Depth Processes
Windows 10 1903 – Autopilot registry – Windows Autopilot In-Depth Processes 19

Noticed the newly added Autopilot-related keys. Well, 1903 has a few more surprises for you.

Event Viewer:

For Windows 10 version till 1809: Application and Services Logs –> Microsoft –> Windows –> Provisioning-Diagnostics-Provider –> AutoPilot

Windows Autopilot In-Depth Processes  - Autopilot Event Logs
Windows Autopilot In-Depth Processes – Autopilot Event Logs 20

For Windows 10 version 1903 and above: Application and Services Logs –> Microsoft –> Windows –> ModernDeployment-Diagnostics-Provider –> AutoPilot

Windows Autopilot In-Depth Processes  - Autopilot Event Logs 2
Windows Autopilot In-Depth Processes – Autopilot Event Logs 2,21
Autopilot Events Functions
==========================

AutopilotGetPolicyStringByName function is to retrieve string values 
like CloudAssignedTenantDomain from the loaded profile.

AutoPilotGetPolicyDwordByNamefunction is to retrieve integer values 
like CloudAssignedDomainJoinMethod from the loaded profile.
 
AutoPilotRetrieveSettings function is to retrieve the OOBE bitmap 
value CloudAssignedOobeConfig from the profile. 

AutoPilotGetOobeSettingsOverride function shows if AutopilotManager succeeded 
in overriding the OOBE with the profile retrieved values 

Want to generate a complete log set for review or to be sent to MS support?

Open elevated CMD and from C:\Windows\System32 the run. MdmDiagnosticsTool.exe -area Autopilot -cab c:\autopilotlogs.zip

MDMDiagnosticTool Autopilot log collection -  Windows Autopilot In-Depth Processes
MDMDiagnosticTool Autopilot log collection – Windows Autopilot In-Depth Processes

This is nearly equivalent to the below GUI log collection method, which gives you a CAB file at C:\Users\Public\Documents\MDMDiagnosticsBut the above CMD method will provide you with a log set specific to the Autopilot area.

Export Autopilot Logs  -  Windows Autopilot In-Depth Processes
Export Autopilot Logs – Windows Autopilot In-Depth Processes 22

Both the CMD and GUI method uses the registry path HKLM\Software\Microsoft\MdmDiagnostics to know what to collect

MDMDiagnostics Registry -  Windows Autopilot In-Depth Processes
MDMDiagnostics Registry – Windows Autopilot In-Depth Processes 23

The resulting CAB/ZIP file contains all the data you would need for analysis.

Diagnostic generated logs -  Windows Autopilot In-Depth Processes
MDMDiagnostic generated logs – Windows Autopilot In-Depth Processes 24

Want to know what information you would get from each of these. Read this excellent blog post from Vimal Das.

Trying out Autopilot for existing device flow with Windows 10 v1903

Though this post does not cover Autopilot for an existing device, still adding this up as you might find it useful.

Suppose you are trying Win 10 1903 using the default task sequence template from Config Manager for Autopilot for the existing devices. In that case, there is a good chance that you have encountered the issue as posted in this blog by Michael Niehaus.

Due to a change in behavior of Autopilot from 1903, the process will fail as 
the last step of the task sequencePrepare Windows for Captureis
essentiallysysprep /generalize /oobe which deletes the Autopilot profile
as copied to C:\Windows\Provisioning\Autopilotvia theApply Windows Autopilot configurationstep.

The suggested workaround is to delete the generalize step from task sequence 
and add asysprep /oobeinstead for a successful deployement.

This made me think if 1809 was working fine with the Generalize pass, what has changed with 1903, which led me to this file path.

C:\Windows\System32\Sysprep\ActionFiles\Generalize.xml

The Generalize.xml from an 1809 image does not contains the below lines which the same from a 1903 image contains, justifying the workaround as suggested…

fileActions
deleteDirectory path="$(runtime.windows)\Provisioning\Autopilot"
deleteDirectory path="$(runtime.windows)\ServiceState\Autopilot"
registryActions
deleteKey
path="HKEY_LOCAL_MACHINE\Software\Microsoft\Provisioning\AutopilotPolicy"
deleteKey path="HKEY_LOCAL_MACHINE\Software\Microsoft\Provisioning\Diagnostics\Autopilot"

To Be Continued…

In my next post, I will be highlighting the WhiteGlove process as introduced in Autopilot. Till then, read something every day, learn something every day!

Resources

6 thoughts on “Windows Autopilot In-Depth Processes from Device Side – Part 3”

  1. Thank you, this is very detailed and helpful. The comment:

    “If setup finds an unattend.xml to drive the oobeSystem pass which happens mostly in case of custom prepared images, the device will not trigger Autopilot provisioning even if it is assigned”

    Is only partly true. You can still have an unattend.xml if you remove the section “Settings pass=oobeSystem”. In my case, I am using the unattend.xml to upload the hardware hash to Intune. I was able to keep unattened.xml, but remove that section and it worked.

    Reply
    • Hi Lance,

      Yes that’s true. You can have an unattend.xml but it cannot have the Settings pass=oobeSystem.
      That was the purpose of mentioninig this, because if you are providing an answer file, you can for the other config passes but not for oobeSystem config pass.

      Reply
  2. Hi there, thanks for this incredibly useful blog. I have an issue I’m trying to deal with — devices that go through Autopilot which are then logged onto by the final end user don’t ever show up as a user’s device in Azure AD (Normally I would see it under Intune -> Users – All Users -> John Doe -> Devices). We base our Conditional Access Control on the devices that a user has assigned to them. Is there a reason the autopiloted device doesn’t show up under the Devices screen?

    Reply
  3. Thanks, this is really informative to a relative Azure Noob like me! A question about this comment though:

    “For Win 10 1809 and above, the profile as downloaded can be removed by just
    rebooting the system while still in OOBE to get a new profile. However, once
    it completes the OOBE, the profile is persistent and then it would still
    require a re-generalize or reset.”

    So, if we apply a standard MS W10 2004 image to a device, and have it plugged into the network sat at the OOBE Region screen while we harvest the HWID – it has already checked that there is no autopilot profile.
    We then power the machine off, and upload the HWID to Intune. When the machine is powered back on, it should check again and /not/ return “Autopilotmanager determined download is not required….” – is this correct? Also, is there any official MS documentation for this – as I have a customer who thinks this is their problem!

    Thanks!

    Mike.

    Reply
  4. Hello! We are going through setups right now and seeing the defaultuser0 account on the device ones it’s fully setup and it isn’t being removed when the device is fully provisioned and actual user is logged in.

    Do you have any thoughts on this? It’s messing with password compliance policies based on our testing.

    Reply

Leave a Comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.