Troubleshooting Improvements in Windows Autopilot
I wrote a couple of blogs (the basics and the more advanced scenarios) about troubleshooting Windows Autopilot late last year, which focused on the capabilities that existed at that point in time. But there have been some enhancements since then:
- Registry entries, so you can see the Autopilot-related activity after the fact. This was introduced in Windows 10 1709.
- Event log entries, to show the Autopilot-related activity in a more friendly form. This was introduced in Windows 10 1803.
Of course you can continue doing ETW traces if you like, but the registry and event log entries are nice because they don’t require reproducing the scenario with a trace running. Let’s look at each of those in more detail.
There are some key pieces of information stored in the registry on Windows 10 1709 and above. These can be found at HKLM\SOFTWARE\Microsoft\Provisioning\Diagnostics\AutoPilot. Here are the properties you will see:
- AadTenantId – The GUID of the Azure AD tenant the user signed into. This should match the tenant that the device was registered with, since you’ll get an error if they don’t match.
- CloudAssignedTenantDomain – The Azure AD tenant the device has been registered with, e.g. “contosomn.onmicrosoft.com.” If the device isn’t registered with Autopilot, this value will be blank.
- CloudAssignedTenantId – The GUID of the Azure AD tenant the device has been registered with (the GUID corresponds to the tenant domain from the CloudAssignedTenantDomain registry value). If the device isn’t registered with Autopilot, this value will be blank.
- IsAutoPilotDisabled – If set to 1, this indicates that the device doesn’t believe it is registered with Autopilot (but this could happen if there were network connectivity issues, timeouts downloading the Autopilot profile settings, etc.). This is a good place to start troubleshooting, since the value must be 0 (not disabled) for the standard Autopilot behaviors to happen.
- TenantMatched – This will be set to 1 if the tenant ID of the user matches the tenant ID that the device was registered with. (If this would be false, the user would be shown an error and forced to start over.)
- CloudAssignedOobeConfig – this is a bitmap that shows which Autopilot settings were configured. From the previous level 300/400 blog, bit values include:
- SkipCortanaOptIn = 1,
OobeUserNotLocalAdmin = 2,
SkipExpressSettings = 4,
SkipOemRegistration = 8,
SkipEula = 0x10
- SkipCortanaOptIn = 1,
So first, let’s look at a device that wasn’t deployed using Autopilot, running Windows 10 1709 or above. Here’s what you should expect to see:
Notice the numbered subkeys? Those correspond to different pages in OOBE. Each of those keys will contain a value named “ConfigName” that says what Autopilot setting it is tied to (e.g. page 0 is the “personal or work” question, configured by a ZTP_CONFIG_AAD_JOIN_ONLY flag that really means “you don’t need to ask”) and a second “Enabled” value that indicates whether the page was displayed (value 1) or skipped (value 0). (You might notice that the subkeys are different in Windows 10 1709 and 1803, as there are new things in 1803 that need to be skipped.)
Now, let’s look at a device that did use Autopilot (in this case on a Windows 10 1803 device, so there are some more subkeys and a few other properties that we’ll skip over for now):
So I can see that my device was enrolled, what tenant it was enrolled with, that the user signed in with the right tenant, and that the bitmap config is 28, which translates to
SkipExpressSettings (4) + SkipOemRegistration (8) + SkipEula (16) = 28
And if we click into each of the subkeys, we can see all of the different OOBE pages that were skipped.
Windows 10 1803 takes diagnostics to the next level with event log entries. To find the events, open Event Viewer and navigate to “Application and Services Logs –> Microsoft –> Windows –> Provisioning-Diagnostics-Provider –> AutoPilot”. If the device isn’t registered, you will only see two events (basically indicating that the device is not registered). If the device is registered and deployed with Autopilot, you’ll see a lot more:
Let’s look at some of the event IDs, in the order that you might typically see them:
- Event 100, warning. “AutoPilot policy [name] not found.” This is typically a temporary problem, while the device is waiting for an Autopilot profile to be downloaded.
- Event 160, info. “AutoPilotRetrieveSettings beginning acquisition.” This shows that Autopilot is getting ready to download the needed Autopilot profile settings.
- Event 164, info. “AutoPilotManager determined Internet is available to attempt policy download.” Pretty obvious.
- Event 161, info. “AutoPilotManager retrieve settings succeeded.” A good sign, we were able to download the settings (and you can see how long it took).
- Event 153, info. “AutoPilotManager reported the state changed from [original state] to [new state].” Typically this should say “ProfileState_Unknown” to “ProfileState_Available” to show that a profile was available for the device and downloaded, so the device is ready to be deployed using Autopilot.
- Event 171, error. “AutoPilotManager failed to set TPM identity confirmed. HRESULT=[error code].” For now, you can ignore this error as it’s related to a future scenario.
- Event 172, error. “AutoPilotManager failed to set AutoPilot profile as available. HRESULT=[error code].” Ignore this one too, it’s related to the previous one.
- Event 163, info. “AutoPilotManager determined download is not required and the device is already provisioned. Clean or reset the device to change this.” This is just telling you that there is now a profile on the device, it’s not going to go away on its own and there won’t be any attempts to download it again. So you can ignore this one.
- Event 111, info. “AutoPilotRetrieveSettings succeeded.” This means that the bitmap settings stored in the Autopilot profile have been retrieved successfully, so Autopilot now knows how to tell OOBE to behave.
- Event 109, info. “AutoPilotGetOobeSettingsOverride succeeded: OOBE setting [setting name]; state = [state].” This shows Autopilot retrieving and processing various OOBE settings.
- Event 101, info. “AutoPilotGetPolicyDwordByName succeeded: policy name = [setting name]; policy value [value].” This is very similar to the previous one, just for a slightly different type of setting, an integer.
- Event 103, info. “AutoPilotGetPolicyStringByName succeeded: policy name = [name]; value = [value].” Also similar to events 101 and 109, but for string values (e.g. the tenant name).
So definitely check those out, they are very useful to follow the process, to see any errors that might have occurred (e.g. timeouts), and to confirm that the device is configured the way you expect it to be.
More to come
If you remember the errors shown in the previous blogs, it’s quite possible that you’ll see a screen that says “Something went wrong” with a typical error code, e.g. 80180018. While we haven’t yet fixed those, we do understand that something more descriptive would be more helpful. So we’re working on those, especially for common enrollment and join issues. Stay tuned for future feature updates.