Windows Autopilot
FluxDeploy hands a freshly imaged machine over to Windows Autopilot as part of a normal deployment. You turn Autopilot on or off per recipe; FluxDeploy works out how to hand the device over and tells you what it picked.
If you want the short version: turn on Convert all targeted devices to Autopilot in your Intune deployment profile, then paste your tenant's Autopilot profile into Settings > Cloud Integrations > Autopilot. Autopilot recipes then stop costing about 15 to 30 minutes of first boot per machine, and the devices still end up registered with Autopilot - so a machine that is wiped comes back under your management. Both halves matter, and FluxDeploy will not use the faster path without the first one.
Autopilot is part of the Enterprise feature set: any valid license or an active trial unlocks it. It is configured on Core only, and that configuration is synced to your relay sites so a branch office can register devices even when its link to Core is down - a relay that has no usable credentials forwards the registration to Core instead (the Security section below says exactly what is held where). The settings page is reachable by Admin and Read Only roles - Operators are redirected away.
When a relay site registers a device, it reports the registration status back to Core with its next heartbeat, so the machine's Autopilot status on Core (Machine detail and the machines report) matches what the relay did. A relay that is cut off from Core catches up as soon as the link returns. A Core older than the relay ignores the update, and the status then only shows on the relay.
Windows Server images never use Autopilot
Windows Autopilot is a Windows 10 and Windows 11 client feature. Windows Autopilot is not available for Windows Server images, so FluxDeploy does not offer it for them:
- On a recipe whose image is Windows Server, the Autopilot switch is disabled and the panel says why. Creating a recipe from an Autopilot template and then picking a Server image creates it with Autopilot off, and cloning a Server recipe never copies an Autopilot setting.
- The recipe API answers
400with the same sentence if you try to switch Autopilot on, or pin a mechanism, for a Server image, or to move a recipe that has Autopilot on onto a Server image. Turn Autopilot off first, then change the image. - A recipe saved before this rule (Autopilot on, image later identified as Windows Server) is not broken. Its Autopilot setting is ignored: the machine is deployed as an ordinary deployment, with the normal answer file, no hardware hash, no first-boot registration script, and the deployment token retired when the deployment completes. The recipe page offers Clear the saved setting to remove the stale flag.
- Relay sites are never sent an Autopilot setting for a recipe whose image is Windows Server.
See Deploying Windows Server for the rest of what differs.
The three mechanisms, and how FluxDeploy chooses
Microsoft ships three ways to hand a device to Autopilot. They are Microsoft's internal architecture, not a decision you should have to make, so you do not choose between them: the recipe still just says "Autopilot on", and FluxDeploy works out which one this deployment can use and tells you what it picked and why.
Classic Windows Autopilot. The device is registered with your tenant before it can be deployed: its hardware hash is collected at first boot, uploaded to Core, imported through Microsoft Graph, and the machine waits for Intune to assign it a deployment profile before it syspreps and reboots into OOBE. Targeting is by group tag.
Windows Autopilot for existing devices. The Autopilot profile is written into the image as a file, and OOBE runs it directly. No pre-registration, no hardware hash, no temporary account, no sysprep, no wait for Intune - and nothing of FluxDeploy's runs at first boot. It is Microsoft's own scenario for products that image machines, it works on Windows 10 as well as Windows 11, it is the only one of the three that can do Microsoft Entra hybrid join without registering the device first, and it works on virtual machines.
The deployment itself registers nothing, which would normally be a serious problem: an unregistered device that somebody wipes is just a clean Windows machine. It does not meet Autopilot again at the next OOBE and it does not come back under your management. That is closed by your tenant's Convert all targeted devices to Autopilot setting, which registers these devices after they enrol - and FluxDeploy refuses to use this path until it has confirmed that setting is on, because with it off the result is a fleet that is managed only until somebody reinstalls Windows. See The control question below.
Autopilot device preparation. No registration, no hardware hash and no group tag. The machine reaches a normal OOBE with a network, the user signs in with their work account, and the device preparation policy in your tenant takes over from there. Targeting is by Intune's enrollment time grouping. This is Microsoft's newest generation, and where their engineering investment is going.
Which one covers which scenario
| Classic | For existing devices | Device preparation | |
|---|---|---|---|
| Device must be registered first | Yes | No | No |
| Time added at first boot | ~15 to 30 minutes (gives up at 90) | None | None |
| Microsoft Entra join | Yes | Yes | Yes |
| Microsoft Entra hybrid join | Yes | Yes | No |
| Windows 10 | Yes | Yes | No |
| Windows 11 | Yes | Yes | 24H2+ (see below) |
| Works on a virtual machine | No (TPM attestation) | Yes | Yes |
| Pre-provisioning / self-deploying | Yes | No (needs TPM attestation) | No |
| Autopilot into co-management | Yes | No | No |
| FluxDeploy writes an answer file | Yes | No | Yes |
| Device ends up registered with Autopilot | Yes, during the deployment | Not by the deployment. Intune's Convert all targeted devices to Autopilot registers it within ~48 hours of enrolment | No |
| Autopilot re-runs after a later reset | Yes | Yes, once conversion has processed. Not before | No |
Nothing here is a downgrade of classic. Classic remains the only option for pre-provisioning, self-deploying mode, Autopilot into co-management, and HoloLens or Teams Rooms devices, and it is still the only one that leaves the device permanently registered with the Autopilot service. It is also the fallback for everything FluxDeploy could not establish.
What FluxDeploy derives, and in what order
The Windows Autopilot panel on Recipes > (recipe) > Overview states the mechanism and the reason, in that order. The rules, top to bottom - the first one that applies wins:
| Condition | Mechanism | Why |
|---|---|---|
| The recipe is pinned (see below) | Whatever you pinned | You asked |
| Windows 11 24H2 or later, no domain join, and your tenant has device preparation policies | Device preparation | See "Why device preparation comes first" below |
| A valid profile is saved, this recipe does not join a domain in its answer file, and your tenant converts these devices to Autopilot registrations | For existing devices | It reaches the same registered device with none of the first-boot cost |
| A profile is saved but your tenant does not convert these devices (or FluxDeploy could not check) | Classic | Classic registers the device during the deployment. An unregistered device that is wiped does not come back under your management - see The control question |
| A profile is saved but this recipe joins an Active Directory domain in its answer file | Classic | This mechanism writes no answer file, so that join would silently not happen |
| A profile is saved but it is not usable | Classic | The Autopilot page names the problem |
| No profile is saved, and domain join is configured in Settings > Deployment > Unattend Settings | Classic | Device preparation is Microsoft Entra join only. It cannot do Microsoft Entra hybrid join |
| No profile is saved, and the recipe's image is Windows 10 or Windows Server | Classic | Device preparation is Windows 11 client only |
| No profile is saved, and the recipe's image is Windows 11 older than 24H2 | Classic | See the note below |
| No profile is saved, and FluxDeploy cannot tell which Windows release the image is | Classic | Re-detect the version on Windows Images and the derivation will pick it up |
| No profile is saved, and your tenant has no device preparation policies | Classic | Nothing would take over at OOBE |
| No profile is saved, and FluxDeploy could not check your tenant | Classic | An unknown is never treated as a yes |
One thing removes answers instead of choosing between them. On a Microsoft cloud other than global Azure, Microsoft supports neither Windows Autopilot mechanism at all, so the table above only ever lands on device preparation there. Classic is still named, and then refused outright with the reason on the panel; the offline profile is ruled out before the table runs, so a pin to it falls back the same way a stale pin does. See Sovereign clouds. Nearly every customer, including Microsoft 365 GCC, is on global Azure and never meets this.
Why device preparation comes first. Microsoft's rule is that any one device runs one of the two solutions, and an Autopilot deployment - which is exactly what the offline profile starts at OOBE - takes precedence over a device preparation policy on a device that is not associated with your tenant. So preferring the offline profile in a tenant that has positively moved to device preparation would defeat that rollout in the same way registering a device does. If you want the offline profile in such a tenant, pin the recipe.
If you save no profile, nothing changes. An existing install keeps deriving exactly what it derived before. Saving a profile is the whole of turning this on.
About the 24H2 line. Microsoft's actual floor is Windows 11 22H2 or 23H2 with KB5035942 or later, or any 24H2 build. FluxDeploy records an image's release but not its patch level, so on a 22H2 or 23H2 image it cannot tell whether that update is present. Rather than guess, it treats 24H2 as the floor. If you know your 22H2 or 23H2 image carries KB5035942, pin the recipe.
Classic is always the fallback. Every "we could not establish that" outcome lands on classic, because it is the behaviour every existing deployment already has. The failure this avoids is the expensive one: choosing device preparation for a tenant with no device preparation policy produces a machine that reaches OOBE, has nothing take over, and is silently never enrolled.
What we can and cannot tell you about your tenant. FluxDeploy can establish that device preparation policies exist. It cannot establish that the person who signs in at OOBE will be covered by one - device preparation policies are assigned to user groups, not device groups, and the deployment begins when a user in a targeted group signs in. So the panel says your tenant has policies, never that this particular device will be prepared.
Overriding the choice
Under the mechanism override on the same panel (Advanced: override how this recipe enrols, which opens by itself and renames to Choose how this recipe enrols when the recipe has landed on the offline profile):
- Let FluxDeploy choose (default).
- Always register the device with Intune before OOBE - classic. Choose this for pre-provisioning, self-deploying devices, Autopilot into co-management, or simply because your tenant is not ready to prepare devices at sign-in yet. Choose it too when you need the device to stay registered so a later Autopilot Reset re-runs Autopilot.
- Always hand off at OOBE to a device preparation policy - device preparation. Refused, naming the conflict, if the recipe's image or its unattend settings rule it out. Honoured when FluxDeploy has not established that your tenant has a device preparation policy - your tenant is not ready yet is a listed reason to pin - but the panel then leads with
WARNING:and names why, because this mechanism has no fallback: the machine reaches OOBE, no policy applies, and it is never enrolled, with no symptom until somebody notices an unmanaged fleet. Pin it only if you know the policy exists or is about to. - Always write the Autopilot profile into the image - for existing devices. Refused if no usable profile is saved, or if this recipe joins a domain in its answer file. Use it when your tenant has device preparation policies for some other fleet but you want these machines on the offline profile.
A pin that later stops being legal - someone turns domain join on, or removes the saved profile - falls back to classic at deployment time and says so on the panel, rather than producing a deployment nothing would pick up.
Device association, and why FluxDeploy cannot help with it
Device association is an optional extra for device preparation: it binds a specific physical machine to your tenant by writing a tenant affinity marker into the machine's UEFI firmware. That marker survives re-imaging, re-partitioning and a FluxDeploy deployment, and association takes precedence over Autopilot registration - an associated device follows the device preparation path at OOBE whatever else is true of it.
FluxDeploy does not create, read or remove associations, and cannot detect one:
- Pre-associating a device means exporting a DeviceLink CSV from the machine's own Autopilot diagnostics (
MdmDiagnosticsTool.exe -area Autopilot -cab <path>, or Settings > Accounts > Access work or school > Export your management logs) and uploading it in Intune by hand. Microsoft supports no API for it: "device uploads are only supported through Intune." - It requires a physical Windows 11 device with a healthy TPM 2.0. Virtual machines are not supported.
- The collection only makes sense before a machine is deployed, which is not a moment FluxDeploy is present for.
The practical consequence to plan for: if you pre-associate a fleet, every FluxDeploy re-image of those machines will go through device preparation at OOBE, no matter what the recipe derives or what you pin it to.
Sovereign clouds
Windows Autopilot works on global Azure only. Microsoft: "Windows Autopilot only supports customers using global Azure. Global Azure doesn't include the following three entities: Azure Germany. Azure China 21Vianet. Azure Government." And elsewhere on the same page: "Windows Autopilot isn't currently supported in any sovereign cloud."
That sentence covers both of the mechanisms that use the Autopilot service: the classic flow, and Autopilot for existing devices. The offline profile is not a way around it - the profile written into the image starts the same Autopilot flow at OOBE, against the same service. FluxDeploy refuses it on those clouds for the same reason it refuses classic, and refusing it matters more: that mechanism writes no answer file, so a machine deployed with it where Autopilot does not run comes up with no computer name, no product key and nothing having taken it over.
Autopilot device preparation is the exact mirror image and is the path Microsoft steers those customers to: "For Government Community Cloud High (GCCH) and Department of Defense (DoD) environments, consider using Windows Autopilot device preparation." Microsoft's own comparison table has one row for government clouds - device preparation supported, classic not - and the device preparation FAQ adds "Windows Autopilot device preparation is available for Government Community Cloud (GCC) High, U.S. Department of Defense (DoD), and Intune operated by 21Vianet in China."
So when the Graph endpoint is anything other than graph.microsoft.com:
- FluxDeploy keeps the endpoint. It is still the base address every Graph request is built on.
- It refuses both Windows Autopilot mechanisms on that cloud - classic registration and the offline profile - and says so on the settings page and on every affected recipe panel, rather than letting every import fail out at the machine with a message about Azure credentials that are perfectly fine. A recipe pinned to the offline profile falls back and the panel names the pin, so the machine still gets its normal answer file rather than an Autopilot profile nothing would act on.
- Autopilot device preparation is the supported path, and FluxDeploy will move recipes onto it for you. Its Microsoft Graph sign-in follows the cloud you selected - GCC High and DoD sign in at
login.microsoftonline.us, 21Vianet atlogin.chinacloudapi.cn- so your tenant is read exactly like a commercial one. Create an Autopilot device preparation policy in Intune and an eligible recipe switches to it on its own. (Before v1.4.3 the sign-in was hardcoded to the global Azure authority and scope, so on these clouds FluxDeploy could not get a token at all, could never observe your policy, and told you to pin every recipe by hand. If you pinned recipes for that reason, you can clear those pins.) You can still pin one deliberately: Always hand off at OOBE to a device preparation policy. - Pinning device preparation is all a deployment needs. That mechanism asks nothing of Graph: FluxDeploy writes a minimal answer file, the user signs in at OOBE and Intune takes over. The tenant check exists to pick the mechanism, not to run it.
- A recipe that does not qualify for device preparation - a Windows 10 or Windows Server image, or an answer file that joins an Active Directory domain - has nowhere to go on that cloud. The panel names what is in the way. Fix that, or turn Autopilot off on the recipe so deployments do not stop at registration.
- The same applies to a Graph endpoint FluxDeploy cannot name at all. It will not send your access token to an address that is not one of Microsoft's national cloud service roots, and it will not guess that an unrecognised address means global Azure, so Autopilot is refused until the endpoint is corrected.
A GCC (not GCC High) tenant is on the worldwide Graph endpoint, so none of this applies to it: classic Autopilot is supported and nothing changes.
DFCI and devices FluxDeploy registers
Device Firmware Configuration Interface (DFCI) cannot manage a device that FluxDeploy registered. Microsoft, verbatim:
"You can't use DFCI with devices manually registered for Windows Autopilot, such as imported from a csv file. By design, DFCI management requires external attestation of the device's commercial acquisition through an OEM or a Microsoft CSP partner registration to Windows Autopilot."
This is not a FluxDeploy limitation and there is no setting that changes it. DFCI's whole premise is that the OEM or CSP partner vouches for who bought the hardware. A hardware hash uploaded by any tool - FluxDeploy, a CSV in the portal, Microsoft's own scripts - carries no such attestation, so the device is registered but not attested, and DFCI profiles will not apply to it.
The useful half: a device the OEM or a CSP partner already registered keeps its attestation, and FluxDeploy works with it perfectly well. When FluxDeploy pre-checks a serial and Intune reports it already registered with a profile assigned, it takes the fast path: no temporary admin account, no hardware hash collection, no import, no wait on Intune. It images the machine and hands over to the profile that is already attached. So on a fleet bought pre-registered for Autopilot, FluxDeploy never registers anything, nothing is manually registered, and DFCI keeps working. That is also the fastest deployment shape the product has - it is worth asking your supplier for.
If you need DFCI on hardware that was not bought pre-registered, the registration has to come from the OEM or a CSP partner. Deregistering and re-uploading the hash yourself does not add the attestation.
Registering a device is not free
An Autopilot deployment profile takes precedence over a device preparation policy. So if your tenant has moved to device preparation but FluxDeploy keeps registering devices for classic Autopilot, those machines keep running the old flow and your device preparation policies never apply to them. That is why FluxDeploy checks the tenant rather than defaulting blindly, and why a device preparation recipe refuses to upload a hardware hash at all.
If you are expecting device preparation and the Enrollment Status Page appears during OOBE, device preparation is not running on that device.
Setting up Autopilot for existing devices
One field, on Settings > Cloud Integrations > Autopilot > General, under Autopilot Profile (existing devices).
In Intune, create or pick the user-driven Autopilot deployment profile you want these machines to get. Microsoft Entra join and Microsoft Entra hybrid join are both supported; self-deploying and pre-provisioning profiles are not, because those need TPM attestation.
On that profile's Basics page, set Convert all targeted devices to Autopilot to Yes, and make sure the profile is assigned to a group these machines will join. This is not optional: without it the devices are never registered, and FluxDeploy will refuse to use the offline profile. See The control question.
On an internet-connected PC, export it:
Install-Module -Name WindowsAutopilotIntune -MinimumVersion 5.4.0 -Force Connect-MgGraph -Scopes "DeviceManagementServiceConfig.ReadWrite.All" Get-AutopilotProfile | ConvertTo-AutopilotConfigurationJSONPaste one profile - the text from
{to}- into the box and Save.
FluxDeploy checks it as you save and refuses anything that would not work, naming the problem: a missing required property, a GUID wrapped in braces (Microsoft requires them without), a domain join method outside the two documented values, an array of several profiles rather than one, or a profile exported from a different tenant than the one this server is configured against. That last one is the reason the check exists at all: a profile from the wrong tenant enrols every machine from that recipe into somebody else's tenant, and Windows reports nothing unusual while doing it.
There is deliberately no validation you can skip. Windows reads this file with no diagnostics of any kind - if it does not like the file, OOBE just runs an ordinary Windows setup, and the only symptom is a fleet that never enrolled.
One profile per server. Microsoft's mechanism is one profile per file and one file per image. If you need different Autopilot profiles for different fleets, keep those recipes on classic Autopilot with group tags.
You still need the Azure credentials below. This mechanism itself writes nothing to your tenant and would work without them, but the Autopilot master switch is only unlocked by a successful connection test, and a recipe cannot turn Autopilot on until it is. That is deliberate rather than accidental: exporting the profile already needs a Graph app registration, and the same registration is what lets FluxDeploy tell whether your tenant uses Autopilot device preparation - which is how each recipe gets the right path in the first place.
The control question, and why FluxDeploy checks it
The hardware-hash path registers each device during the deployment. From that moment the device is bound: wipe it, reset it, hand it to somebody else, and it meets Autopilot at the next OOBE and returns under your organisation's control. That property is the point of registration, and it is why this offline path was not worth offering until the check below existed.
Microsoft's own remedy, named on the existing-devices page itself, verbatim:
After Windows is updated on an existing device, make sure to register the device so it has the Windows Autopilot experience when the PC resets. Automatic registration can be enabled for a device by using the Convert all targeted devices to Autopilot setting in the Windows Autopilot profile that is assigned to a group that the device is a member of.
What that setting produces is a real Autopilot device identity, obtained the same way ours is. From Automatic registration of existing devices, verbatim:
An existing device can automatically register if it's: Running a supported version of Windows; Enrolled in a mobile device management (MDM) service such as Intune; A corporate device that isn't already registered with Windows Autopilot. For devices that meet these requirements, the MDM service can ask the device for the hardware hash. After it has that, it can automatically register the device with Windows Autopilot.
and, on the same page, that this is exactly the pairing intended here:
When the [Windows Autopilot for existing devices] scenario is used, devices don't need to be preregistered with Windows Autopilot. Instead, a configuration file (AutopilotConfigurationFile.json) containing all the Windows Autopilot profile settings is used. The device can then be registered with Windows Autopilot using the same Convert all targeted devices to Autopilot setting.
And from the deployment profile's Basics page, where the setting lives:
If all devices in the assigned groups should automatically register to Windows Autopilot, set Convert all targeted devices to Autopilot to Yes. All corporate owned, non-Windows Autopilot devices in assigned groups register with the Windows Autopilot deployment service. Personally owned devices aren't registered to Windows Autopilot. Allow 48 hours for the registration to be processed. When the device is unenrolled and reset, Windows Autopilot enrolls it again. After a device is registered in this way, disabling this setting or removing the profile assignment won't remove the device from the Windows Autopilot deployment service. The device must instead be removed directly.
So the two paths end in the same place, and this one gets there without the 15 to 30 minutes of first boot. It is not a weaker posture in the steady state - it is the same posture, reached a couple of days later.
FluxDeploy checks, because the setting is off by default. Its Graph property is documented as "Default value is FALSE", so assuming it would be assuming the thing that matters most. Every Autopilot recipe check reads your deployment profiles, and:
| What FluxDeploy found | What it does |
|---|---|
| Every Windows PC profile has the setting on | Uses the offline profile |
| Some profiles have it on, some do not | Uses the offline profile, and says so - which profile a device lands under depends on the groups it joins, which FluxDeploy cannot work out |
| No profile has it on | Refuses. Recipes stay on classic Autopilot, which registers the device during the deployment |
| Your tenant has no Autopilot profiles at all | Refuses, same reason |
| FluxDeploy could not read your profiles | Refuses. "We could not check" is never treated as "it is on" |
The check needs no permission you have not already granted: listing deployment profiles is covered by DeviceManagementServiceConfig.ReadWrite.All, which the hardware-hash import has always required.
The residual risk, stated plainly. Registration is processed within about 48 hours of enrolment. In that window the machine is deployed and not yet registered, so a device wiped on its first day does not come back under management - the hash path has no such window, because it registers before the deployment finishes. The same window is when Microsoft's known issue about BitLocker defaulting to 128-bit on unregistered devices applies. Two further limits from Microsoft's text above: only corporate-owned devices are converted, and conversion is a registration only - it "doesn't automatically convert existing Microsoft Entra hybrid device in the assigned groups into a Microsoft Entra device".
If you want this path without conversion - a lab, a kiosk, a short-lived build bench, anywhere an unregistered machine is acceptable - pin the recipe using the mechanism override on its Autopilot panel - it is already open when the recipe is on this path, because that is when the choice matters. FluxDeploy will not make that choice by derivation, but it will not stop you making it: the recipe panel then leads with what it means.
Confirm it once, on your own tenant, before you deploy a fleet this way. FluxDeploy checks that the setting is on; only your tenant can show you that a device deployed this way actually becomes registered, and that a wiped one comes back. That takes up to 48 hours to become true, so it is a one-off manual confirmation rather than something the test suite can do: tests/install/README.md, under Autopilot for existing devices: the 48-hour check nobody automated, is a short checklist covering what to configure, what to check on the day, what to check after the window, and how to wipe the machine and confirm it Autopilots again. The automated smoke legs deliberately stop short of that last step - they prove the profile written into the image is correct and that a real device enrols through it, and nothing more.
What you give up, and what to do about it
FluxDeploy writes no answer file for these deployments. This is not a choice; Microsoft: "When there's both an unattend.xml file and a Windows Autopilot profile JSON file during Windows Setup, Windows Setup ignores the Windows Autopilot profile JSON file, and it only processes the unattend.xml file." Microsoft's own optimised task sequence for this scenario deletes the answer file for exactly the same reason. So for these recipes:
| Normally from the answer file | Where it comes from instead |
|---|---|
| Computer name | The Autopilot profile's device name template (Microsoft Entra join only; hybrid takes a prefix from the domain join profile) |
| Locales, region, keyboard | The Autopilot profile and Intune policy |
| Product key | The firmware OEM key, or an Intune policy. Volume-license keys need an Intune configuration profile |
| Local Administrator account and password | Not created. Nothing of FluxDeploy's is left on the machine either |
| Domain join | An Intune Domain Join device configuration profile plus the Intune Connector for Active Directory, with CloudAssignedDomainJoinMethod set to 1 in the profile |
| Connected Cache cache host | DHCP Option 235, exactly as on every other deployment - FluxDeploy writes no cache host onto any machine it deploys, on any mechanism (Connected Cache) |
If a recipe has domain join turned on in Settings > Deployment > Unattend Settings, FluxDeploy will not use this mechanism for it - that join would silently not happen, and a machine in a workgroup with no explanation is worse than a slower deployment.
The device is not registered by the deployment. That is covered in full under The control question above, including why FluxDeploy refuses this path until your tenant is set up to register these devices, and the roughly 48-hour window before it does.
An already-registered device ignores the file. Microsoft: "If the device is already registered, the assigned profile takes precedence. The Windows Autopilot for existing devices profile only applies if the online profile times out." So writing it is never harmful - it is either the whole mechanism or a fallback.
Prerequisites
An Azure App Registration dedicated to Autopilot. Do not reuse the Connected Cache registration - Connected Cache needs an Azure RBAC role, Autopilot needs a Graph permission.
Both of these Microsoft Graph application permissions on that registration, with admin consent granted:
DeviceManagementServiceConfig.ReadWrite.All- registers devices for classic Autopilot.DeviceManagementConfiguration.Read.All- lets FluxDeploy see whether your tenant has Autopilot device preparation policies.
The second one is not a nice-to-have. Without it FluxDeploy cannot tell whether this tenant uses Autopilot device preparation, so it registers every device for classic Autopilot - and a classic Autopilot profile takes precedence over a device preparation policy. On a tenant that has moved to device preparation, those policies will then never apply to the machines FluxDeploy deploys, and the only visible symptom is the Enrollment Status Page appearing at OOBE when it should not. The check is also circular: without the permission, FluxDeploy cannot establish whether the permission mattered. "Not needed" is only true for a tenant that will never use device preparation, and that is exactly the fact it is unable to check. The Dashboard raises a persistent item while this permission is missing, and clears it once consent is granted.
A client secret for the registration.
For classic Autopilot, an Intune deployment profile that will match the devices you register (directly, or via their group tag). For device preparation, a device preparation policy assigned to the user group whose members will sign in at OOBE.
Settings > Cloud Integrations > Autopilot has an Azure Setup Guide with a ready-made PowerShell script (requires the Az module), or a four-step manual walkthrough if you would rather click through the Entra ID portal. Click Download .ps1 and run the file in PowerShell as a Global Admin:
Unblock-File .\FluxDeploy-Autopilot-Setup.ps1
.\FluxDeploy-Autopilot-Setup.ps1
Unblock-File is needed because the browser marks the download as coming from the internet, and PowerShell's default execution policy refuses to run such a script until that mark is cleared. Running the file is more reliable than pasting the script into a console, which can break its line continuations. Copy Script is still there if you need it.
Configuring Autopilot
Settings > Cloud Integrations > Autopilot (/settings/autopilot). The Start setup button opens a three-step wizard - Azure connection, First-boot account, Review and enable - which is the shortest path. The same values are editable afterwards on the page's two tabs.
Do this first. Until Autopilot is set up and enabled here, FluxDeploy will not create a recipe from an Autopilot template, clone an Autopilot recipe, or switch Autopilot on for a recipe (the API refuses with a 400 naming this page). A recipe like that could never register a device.
Azure tab
| Field | Notes |
|---|---|
| Tenant ID | Directory (tenant) ID of the App Registration |
| Client ID | Application (client) ID |
| Client Secret | Encrypted at rest with ASP.NET Data Protection. Shows (unchanged) once stored |
| App Registration Name | Only used to label the generated setup script. Defaults to FluxDeploy Autopilot |
General tab
| Setting | Notes |
|---|---|
| Enable Windows Autopilot Registration | The master switch. Cannot be on unless the connection test passes - Save runs it |
| Graph API Endpoint | Commercial (graph.microsoft.com), US Government GCC High (graph.microsoft.us), US Department of Defense (dod-graph.microsoft.us) or China 21Vianet (microsoftgraph.chinacloudapi.cn). Only Microsoft's clouds are accepted - your tenant's access token is sent to this address. A Microsoft 365 GCC tenant uses the commercial endpoint, not the GCC High one. See Sovereign clouds before picking anything other than commercial |
| Temp Local Admin Password | Password for the temporary fluxdeploy_autopilot local admin that runs the registration script at first boot. Minimum 8 characters with upper, lower and digit |
| Autopilot Profile (existing devices) | Your tenant's Autopilot profile, exported from Intune. Saving one switches eligible recipes to the offline path; leaving it empty changes nothing. Checked when you save, and refused with the reason if it would not work. See Setting up Autopilot for existing devices |
Save tests the credentials before it stores them. It signs in with what is on the form and reads Windows Autopilot devices through Microsoft Graph; if that fails, nothing is saved and the message says why (for example, admin consent not yet granted). Fix the cause in Entra and click Save again - there is no earlier error to clear first. Test Connection runs the same check on what is typed without saving it.
The temp account password is deliberately fixed rather than random, so a technician can unlock the screen if Windows locks during the long wait for Intune. The account is deleted before sysprep runs, and its auto-logon values are cleared with it.
Enabling it on a recipe
The master switch turns the feature on; each recipe still opts in individually.
On Recipes > (recipe) > Overview, the Windows Autopilot panel has Enable Autopilot Registration and, once on, states the mechanism it derived and why. For classic Autopilot it also shows a Group Tag field with its own Save button. The group tag is not matched against a profile directly: it is written onto the Autopilot device record, and it reaches a deployment profile only if you built an Entra ID dynamic group on the device's OrderID attribute and assigned the profile to that group. Beside the field, FluxDeploy reports how many deployment profiles your tenant has, and warns outright when there are none - but it will not claim your tag matches one, because the group rule that decides it lives in Entra ID and FluxDeploy does not read it.
The other two mechanisms never register a device, so there is nothing for a group tag to match: device preparation replaces it with Intune's enrollment time grouping, and the offline profile already names one specific Autopilot profile. The field is hidden in both, and any stored tag is ignored. It is hidden again when the mechanism FluxDeploy derived cannot be used at all - on a sovereign cloud, for instance - because a tag is not a thing that would fix it. Creating a recipe from the Autopilot Registration starting-point tile still asks for a group tag on the details step; it is harmless on a recipe that ends up using device preparation.
A recipe cannot be switched on until the global settings are complete: Autopilot enabled, tenant ID, client ID, client secret and temp account password all present. Until then the panel says so and links to the settings page.
What happens during a deployment: for existing devices
Almost nothing, and it finishes in WinPE.
After the image is applied and the drivers are injected, the agent writes one file into the offline Windows volume:
C:\Windows\Provisioning\Autopilot\AutopilotConfigurationFile.json
ASCII-encoded, no byte order mark, because Microsoft's requirement is explicit: "Windows OOBE doesn't follow the Windows Autopilot experience if the file is saved with ... Unicode encoding. UTF-8 encoding." No answer file is written, no hardware hash is collected, no device is registered, nothing is staged for first boot, there is no temporary admin account, nothing auto-logs on and there is no sysprep. The machine reboots, OOBE runs the Autopilot deployment, and the user signs in with their work account.
It also removes any Windows\Panther\unattend.xml the applied image brought with it. A captured or customised WIM can carry its own, and Windows Setup ignores the Autopilot profile whenever an answer file is present regardless of who wrote it - so an image with one baked in would deploy and silently never enrol.
If the profile is missing or unusable at that moment, the deployment stops there with AUTOPILOT_PROFILE_INVALID and the answer file has already been skipped, so nothing half-configured reaches the technician. That is deliberate: the alternative is a machine that looks finished, has no computer name, is not enrolled, and says nothing about why.
Because there is no TPM attestation anywhere in this path, it works on virtual machines - unlike classic Autopilot, whose hardware-hash step usually cannot complete on a vTPM without an OEM-rooted endorsement key chain.
What happens during a deployment: device preparation
Almost nothing, and that is the point. FluxDeploy's job here is to get out of the way cleanly.
The answer file it generates keeps the specialize pass - computer name, product key, registered owner and organization, locales, and the Connected Cache host if you use one - and deliberately leaves out everything that would interfere with the handover:
| Left out | Why |
|---|---|
| The local Administrator account and its password | Not needed; the work account is the first sign-in, and the password would otherwise sit in plaintext on a machine about to be handed to a user |
| Auto-logon | An automatic logon consumes the first sign-in, which is the trigger for device preparation. The device would reach the desktop and never enrol |
SkipMachineOOBE / SkipUserOOBE |
The user must reach the sign-in screens |
HideOnlineAccountScreens |
The user signs in with their work account there |
HideWirelessSetupInOOBE |
The whole flow depends on reaching Intune, so the device must be able to join a network |
| Domain join | Device preparation is Microsoft Entra join only |
| First-logon commands | There is no registration script to run |
No hardware hash is collected and no device is registered. No temporary admin account is created, nothing auto-logs on, and there is no sysprep. The answer file is scrubbed from C:\Windows\Panther by the usual cleanup after Windows Setup finishes, and the machine's deployment token is revoked when the deployment completes, exactly as on a non-Autopilot deployment. (A classic Autopilot deployment keeps its token, because its first-boot registration script still needs it.)
Intune may rename the device from its own policy after enrolment. That is expected and it wins.
What happens during a deployment: classic Autopilot
Autopilot runs after the answer file and first-boot phases, just before the deployment completes. While still in WinPE, for every classic Autopilot deployment the agent also:
- sets
PreventDeviceEncryptionso Windows 11 24H2+ does not silently auto-encrypt the disk during OOBE, and - clears Windows S mode if the image has it, because S mode blocks the PowerShell the registration script needs (this is logged to the deployment console).
The agent then asks Core whether the device is already enrolled with an assigned profile:
Already enrolled. No first-boot scripts are written at all. The generated unattend.xml is removed so OOBE runs stock and Autopilot intercepts at the network step; hostname, locale, time zone and region come from the Intune profile.
Not yet enrolled. The hardware hash cannot be collected from WinPE - it needs full Windows with the MDM stack - so the agent stages a registration script, its configuration and Microsoft's Get-WindowsAutopilotInfo.ps1 into C:\Windows\Temp\FluxDeploy\, and patches the answer file with the temp admin account, an auto-logon and a first-logon command. At first boot, in a visible window, the script:
- Disables screen lock and power timeouts, and shows a "Registering with Microsoft Autopilot - do NOT power off" background.
- Pauses Windows Update and Store downloads, and turns off BitLocker if it is on (sysprep refuses to generalize an encrypted volume).
- Attempts OEM activation from the firmware key, best effort.
- Collects the hardware hash from the MDM WMI bridge, retrying for up to a minute, and falls back to Microsoft's
Get-WindowsAutopilotInfo.ps1if that comes back empty. - Uploads the hash to Core (three attempts with backoff), which imports it into your tenant and triggers an Autopilot-to-Intune sync.
- Polls for the profile assignment every 15 seconds, showing a live timer, for up to 90 minutes.
- On success, removes the status screen and runs
sysprep /generalize /oobe /quit. Only once sysprep has exited 0 does it delete the temp account and its auto-logon, delete the cached answer file, restore the paused services and restart the machine itself. The order matters: a device whose generalize failed keeps the temp account and auto-logon so a technician can still sign in.
The whole first-boot log is streamed back to Core, so you can watch it on the machine's detail page rather than at the device. It is also left on disk at C:\Windows\Temp\fluxsysprep.log.
Import plus tenant sync usually takes 1 to 2 minutes. Intune profile assignment is typically 10 to 15 minutes. Graph reports assignment status 15 to 30 minutes behind the Intune admin UI, which is why the wait is generous.
Security
- Azure credentials are held by Core and by every relay site. A branch office has to be able to register a device when its link to Core is down, so the tenant ID, client ID, client secret and temporary account password are sent to each relay in the same settings sync that already carries your domain-join and local Administrator passwords - over the relay link, which is authenticated by the site's API key and pinned to both servers' certificates. Every server encrypts them at rest with its own key store, so the copy on a relay can only be read on that relay. They are sent only while Autopilot is switched on, and a relay clears its copy as soon as Core stops sending it: switching Autopilot off, clearing the credential, or a lapsed licence revokes it at every site on the next sync. Weigh this when you site a relay somewhere less physically secure than Core - the app registration only needs
DeviceManagementServiceConfig.ReadWrite.All(plusDeviceManagementConfiguration.Read.Allfor the tenant check), so scope it to that and nothing more. - A relay that cannot use its credentials falls back to Core rather than failing the device: it forwards the registration and Core talks to Graph. If neither server can reach Graph, the deployment stops with a message naming the server that could not get there, and the machine is left usable and not generalized.
- The deployed machine never sees an Azure credential. It authenticates to FluxDeploy with its own per-machine deployment token, and its configuration file is deleted on every exit path.
- Graph calls are rate limited, and every registration attempt is written to the audit log.
- The stored hardware hash is treated as a per-device credential and is never returned by the API.
Troubleshooting
"Could not collect hardware hash" - both the WMI bridge and the PSGallery fallback came back empty, so the device stops before sysprep with the window still open. This is the normal outcome on virtual machines: a vTPM without an OEM-rooted endorsement key chain usually cannot produce a hash. Validate Autopilot end to end on real OEM hardware. The partial CSV is kept at C:\Windows\Temp\FluxDeploy\hardware-hash.csv for a manual upload.
"Server rejected registration" - Core refused the import. The usual cause is incomplete or stale Azure credentials; re-run Test Connection. The machine is marked Failed and an audit entry is written.
"No Autopilot profile was assigned by Intune within 90 minutes" - the device imported, but nothing in Intune claims it. Check that a deployment profile exists and that its assignment covers the device or its group tag. FluxDeploy now tries to catch the commonest version of this before you deploy: the recipe's Autopilot panel reads your tenant's deployment profiles and warns beside the Group Tag field if there are none at all. It deliberately stops short of claiming your tag matches a profile - a deployment profile carries no group tag, it is assigned to Entra ID groups, and a tag only reaches a profile through a dynamic group rule on the device's OrderID attribute that FluxDeploy has no permission to read. Register one device and confirm its Date assigned column populates before deploying a fleet.
Nothing runs at first boot at all - SkipUserOOBE in an answer file prevents first-logon commands from executing, which is exactly what classic Autopilot registration depends on. FluxDeploy omits it automatically for classic Autopilot recipes and strips it as a safety net, so this only appears with a hand-edited answer file.
A re-imaged machine runs device preparation even though the recipe says classic - the machine has a device association. Pre-association writes a tenant affinity marker into the machine's UEFI firmware, so it survives re-imaging and re-partitioning; FluxDeploy never sees it and cannot clear it. Microsoft: if a device is both registered and associated, association takes precedence, and Windows follows the device preparation path at OOBE regardless of what the recipe intends. If you pre-associate a fleet, expect every re-image of those machines to go through device preparation. There is no supported API for reading or removing an association from the device; remove it in Intune.
A device preparation deployment auto-logged on and then failed with AUTOPILOT_REGISTRATION_FAILED - the machine was deployed by an old boot image. The agent decides what to do at first boot, and an agent built before device preparation support only understands classic Autopilot: it ignores the mechanism the server sent, patches an auto-logon into the answer file and tries to register at first boot. The server refuses that registration, so nothing wrong reaches your tenant and the failure is loud rather than silent, but the device does not get a clean handover. Rebuild your boot images after upgrading FluxDeploy; Boot Images flags one whose agent is behind.
"The Autopilot device preparation check has been failing since ..." on the Dashboard - FluxDeploy has had no answer about your tenant for more than two days, and this is not a permissions problem: the call is not completing at all. While that lasts it cannot tell whether your tenant uses Autopilot device preparation, so it registers every device for classic Autopilot, and on a tenant that has moved to device preparation that registration takes precedence and those policies will not apply. Check that this server can reach graph.microsoft.com (or your sovereign cloud's endpoint) through any proxy or firewall in the way. The item clears itself the next time the check succeeds. A check that has only just started failing stays quiet, because a Graph incident or a proxy hiccup is measured in hours and would otherwise put a row on every customer's Dashboard.
"Microsoft Graph refused the read" on the recipe panel, or the Dashboard item about the device preparation check - the app registration is missing DeviceManagementConfiguration.Read.All, or its admin consent. Until that is granted FluxDeploy cannot tell whether your tenant uses Autopilot device preparation, so it registers every device for classic Autopilot - and on a tenant that has moved to device preparation that registration takes precedence and those policies will not apply. Add the permission, grant consent, and reload the recipe page; the Dashboard item clears on its own.
"This recipe is pinned to Autopilot device preparation, but device preparation cannot be used here" - something changed after you pinned it: domain join was turned on, or the recipe was repointed at an older or non-Windows-11 image. FluxDeploy fell back to classic rather than producing an answer file that nothing would pick up. The message names the conflict; fix it, or clear the pin.
"This deployment was handed Windows Autopilot device preparation ... re-deploy it to change the mechanism" - a machine that is mid-deployment called an endpoint that only classic Autopilot uses. The mechanism a device runs is decided once, when it checks in, and it keeps that decision for the rest of its deployment: a classic first boot then registers, polls Intune for up to 90 minutes and syspreps, and editing the recipe during that window does not reach a machine that has already been told what to do. So an edit made mid-deployment changes the next deployment, not this one, and the devices already running are unaffected either way. If the machine genuinely should be on the new mechanism, re-deploy it.
The machine booted to an ordinary Windows setup with no Autopilot branding, on a recipe using the offline profile - the file was written but Windows did not act on it. Check, in this order: the device is not already registered with a different Autopilot profile (an assigned online profile takes precedence); the Autopilot profile in Intune is user-driven, not self-deploying or pre-provisioning; enrollment restrictions in Intune are not set to block personal Windows devices, which Microsoft documents as incompatible with this scenario; and the machine can reach ztd.dds.microsoft.com, login.live.com and time.windows.com (UDP 123) from OOBE.
AUTOPILOT_PROFILE_INVALID in the deployment log - the profile this server sent could not be used, and the message names the reason. Fix it on Settings > Cloud Integrations > Autopilot and re-deploy. Nothing was written to the machine.
AUTOPILOT_PROFILE_WRITE_FAILED - the profile was fine but could not be written to the target volume. Treat it as a disk or permissions problem on the applied image, not an Autopilot problem.
A relay site's recipes say classic when Core says the offline profile - the relay has not synced since the profile was saved. The profile reaches each site through the ordinary sync manifest; wait for the next heartbeat or restart the sync from Sites.
A re-imaged machine is not re-running Autopilot after a reset - expected, and documented above: the offline profile does not register the device. Turn on Convert all targeted devices to Autopilot in the Intune profile, or use classic Autopilot for that fleet.
"Windows Autopilot cannot be used for this recipe" - FluxDeploy is configured against a Microsoft cloud where Microsoft does not support Windows Autopilot. That covers the classic flow and the offline profile, because the offline profile starts the same Autopilot flow at OOBE; Autopilot is global Azure only, and GCC High, DoD and 21Vianet tenants use Autopilot device preparation instead, which is supported there. If the recipe was pinned to the offline profile, the message says so - the pin fell back to classic and classic is refused too. See Sovereign clouds for what to do about it. A Microsoft 365 GCC tenant is not affected - it belongs on the commercial endpoint. The same message, naming the endpoint rather than a cloud, means the stored Graph endpoint is not one of Microsoft's national cloud service roots at all: fix it on Settings > Cloud Integrations > Autopilot.
Turn on Settings > Diagnostics > Debug Logging > Autopilot to log hardware hash collection, Graph API calls and registration status.
Import errors Intune reports for a specific device
These come back after Intune has accepted the upload and then rejected the individual device, and the message on the machine's deployment log names the remedy. The two that look alike and are not:
806 ZtdDeviceAlreadyAssigned - the device is already registered in your own tenant. Usually harmless: a registered device does not need registering again, and re-imaging keeps its Autopilot profile. The reason FluxDeploy tried anyway is almost always that Intune reported no deployment profile assigned to it. Check the serial under Devices > Enrollment > Windows Autopilot > Devices: is the group tag the one the recipe sets, is a profile assigned to a group the device is in, and is Date assigned populated? If the record should not exist at all, delete it there. FluxDeploy never deletes Autopilot or Intune records for you.
808 ZtdDeviceAssignedToOtherTenant - the device is registered in someone else's Entra tenant. Nothing in your portal clears this and neither can FluxDeploy. Only Microsoft Support can release a registration held by another tenant, and they require proof that you own the hardware: raise a service request with the device's CSV and an original bill of sale or invoice in PDF, naming your company and carrying the serial number or chassis ID. Screenshots are not accepted. Collect Mdmdiagnosticstool.exe -area Autopilot -cab c:\out.cab on the device first. Second-hand hardware and machines moved between subsidiaries are the usual causes; until it is released, deploy the machine with Autopilot turned off on the recipe.
ZtdDeviceDuplicated - Intune saw the same hardware hash twice and processed one copy. FluxDeploy imports one device per request, so this normally means a retry or a second deployment raced the first.
InvalidZtdHardwareHash - the hash is missing its manufacturer or serial number. Check on the device with Get-CimInstance Win32_BaseBoard | Select-Object Manufacturer, SerialNumber. A blank value there is a firmware problem fixed with the OEM's BIOS tooling, not in Intune, and is common on whitebox hardware and virtual machines.
StorageError - Intune's generic failure. Microsoft documents no cause and says to try again later. FluxDeploy does not retry it automatically, because an import that Intune accepted and then rejected normally gives the same verdict every time; redeploy the machine in a few minutes.
An error code Microsoft has not documented still reaches you with its name and number intact, plus what to search for - it is never rendered as a blank.
A second deployment of a self-deploying or pre-provisioned device stops at 0x80180014 - Microsoft blocks the second Autopilot deployment of a device enrolled in self-deploying or pre-provisioning mode: "If a device is redeployed so that it reruns the Windows Autopilot deployment again, it fails with a 0x80180014 error code." The device log shows Enrollment blocked for AP device by SDM One Time Limit Check.
FluxDeploy detects the state that produces it and writes a warning to the machine's deployment log at the start of the Autopilot step, while a technician is still at the machine. It triggers on a prior enrolment - Intune's own enrollmentState for the Autopilot record - not on the profile's mode alone, so a first deployment of a self-deploying device is not flagged. Where it can read the assigned profile it says so outright; where it cannot, it says it could not and hedges, rather than guessing.
It does not clear the block for you. The remedies are all tenant-side, and FluxDeploy issues no delete against your tenant:
- Delete the device's record under Devices > Windows > Windows devices. That is the Intune managed device record - not the Autopilot registration, which must stay.
- Or select it under Devices > Enrollment > Windows Autopilot > Devices and choose Unblock device. Microsoft's caveat: this "only works for certain OEMs and doesn't work on the Fix pending status", and no success message is shown even when it worked.
- Or allow Windows (MDM) personally owned devices in your enrollment restrictions.
Imaging continues either way; the block bites at OOBE, not during deployment.
Where to see results
- Machine detail shows an Autopilot Status row for any machine that has one.
- Reports > Machines shows registered / pending / failed counts once at least one machine has a status.