Using Autopilot Profiles offline in Windows 10

Scenario - Enroll existing, non-Autopilot enrolled devices to Azure AD and Intune (or 3rd party MDM). This is useful for devices that are currently used by a customer but not enrolled into Autopilot. The benefits are that the customer doesn't need to collect the Autopilot hardware information. This process will use an existing User Driven Autopilot profile and apply it offline. Once the device is enrolled into AAD/Intune, it will be added to Autopilot in the customer's tenant.

High level steps

  1. Create User Driven Autopilot Profile
  2. Install WindowsAutopilotIntune Powershell module
  3. Get the User Driven Autopilot profile and convert to JSON
  4. Create a USB drive that will be used to install Windows
  5. Create Autounattend.xml file for use with a stock Windows 10 installation
  6. Copy AutopilotConfigurationFile.json file to the root of the Boot partition of the USB drive
  7. Create a SetupComplete.cmd file to change power policy to balanced

Create User Driven Autopilot Profile

Make sure you're using User Driven Profiles (Self Deploying profiles don't work with Offline). In this example, we will query this profile by the display name of the profile. So in this case, we'll be using User Driven as the display name.

When creating the User Driven profile, make sure to change "Convert all targeted devices to Autopilot". This is what will enroll the existing device to the Autopilot service so for any subsequent reinstallations/reimages of Windows, it will now apply the profile from the Autopilot service in the cloud.

Install Azure AD and WindowsAutopilotIntune Powershell module

  • Open Powershell as an admin
  • Run Install-Module AzureAD
  • At the untrusted repository message, type Y or A
  • Run Install-Module WindowsAutopilotIntune
  • At the untrusted repository message, type Y or A

Get the User Driven Autopilot profile and convert to JSON

  • Still in Powershell, type in Connect-AutopilotIntune
  • Type in your credentials

The below command will query for our Autopilot Profile with the display name User Driven. It will then convert the profile to the JSON format and save the file to our desktop as AutoPilotConfigurationFile.json and encode it using ASCII (must be saved as ASCII and it must use this exact name)

Get-AutoPilotProfile |? {$_.displayname -like '*User Driven*'} | ConvertTo-AutoPilotConfigurationJSON | Out-File -FilePath $env:userprofile\desktop\AutoPilotConfigurationFile.json -Encoding ASCII

Create a USB drive that will be used to install Windows

An 8GB or larger USB drive can be used. To install Windows on an UEFI device, the USB media needs to be formatted as FAT32 in order to be bootable, however starting in Windows 1709, the size of the install.wim is slightly larger than the 4GB file limitation of FAT32. To work around this, we need to partition the USB drive with a FAT32 bootable partition and a NTFS partition that holds the install.wim. You could also use split WIMs.

How to create a dual-partitioned USB Drive:

  1. Open Command Prompt and run the following commands
  2. Diskpart
  3. List disk
  4. Sel disk X (where X is the disk number of your USB drive - not drive letter)
  5. Clean
  6. Create Part Primary size=2048
  7. Assign
  8. Active
  9. Format fs=fat32 quick Label="Boot"
  10. Create part primary
  11. Assign
  12. Format fs=ntfs quick Label="Deploy"
  13. Exit

You'll next need to copy your boot files to the Boot partition and your install.wim to the Deploy partition

Your Boot drive should contain all of the files except for the X:\Sources\install.wim. Cut the install.wim from the sources\install.wim and paste it into D:\Install.wim (your drive letters may be slightly different)

This is what your deploy drive should look like

Create Autounattend.xml file for use with a stock Windows 10 installation

Autounattend.xml allows for a zero-touch deployment method of a brand new Windows installation. The file is placed in the root directory of the USB drive that contains the Windows installation media.

The contents of the Autounattend.xml (Download here)

<?xml version="1.0" encoding="utf-8"?>
<unattend xmlns="urn:schemas-microsoft-com:unattend">
    <settings pass="specialize">
        <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="http://www.w3.org/2001/XMLSchema-instance">
            <OEMInformation>
                <Manufacturer>Microsoft</Manufacturer>
            </OEMInformation>
            <!-- You can change the timezone below as needed -->
            <!-- <TimeZone>Mountain Standard Time</TimeZone> -->
        </component>
        <component name="Microsoft-Windows-Deployment" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
            <RunSynchronous>
                <RunSynchronousCommand wcm:action="add">
                    <Order>1</Order>
                    <Path>cmd /c PowerCfg.exe /s 8c5e7fda-e8bf-4a96-9a85-a6e23a8c635c</Path>
                </RunSynchronousCommand>
                <RunSynchronousCommand wcm:action="add">
                    <Order>2</Order>
                    <Path>cmd /c md %WINDIR%\provisioning\autopilot</Path>
                </RunSynchronousCommand>
                <RunSynchronousCommand wcm:action="add">
                    <Order>3</Order>
                    <Path>cmd /c copy d:\AutopilotConfigurationFile.json %WINDIR%\provisioning\autopilot</Path>
                </RunSynchronousCommand>
                <RunSynchronousCommand wcm:action="add">
                    <Order>4</Order>
                    <Path>cmd /c md %WINDIR%\Setup\Scripts</Path>
                </RunSynchronousCommand>
                <RunSynchronousCommand wcm:action="add">
                    <Order>5</Order>
                    <Path>cmd /c copy d:\SetupComplete.cmd %WINDIR%\Setup\Scripts</Path>
                </RunSynchronousCommand>
            </RunSynchronous>
        </component>
    </settings>
    <settings pass="windowsPE">
        <component name="Microsoft-Windows-International-Core-WinPE" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
            <SetupUILanguage>
                <UILanguage>en-US</UILanguage>
            </SetupUILanguage>
            <InputLocale>en-US</InputLocale>
            <SystemLocale>en-US</SystemLocale>
            <UILanguage>en-US</UILanguage>
            <UserLocale>en-US</UserLocale>
        </component>
        <component name="Microsoft-Windows-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
            <DiskConfiguration>
                <!-- Format disk 0 using UEFI partitioning -->
                <Disk wcm:action="add">
                    <CreatePartitions>
                        <!-- Windows RE Tools partition -->
                        <CreatePartition wcm:action="add">
                            <Order>1</Order>
                            <Size>300</Size>
                            <Type>Primary</Type>
                        </CreatePartition>
                        <!-- System partition (ESP) -->
                        <CreatePartition wcm:action="add">
                            <Order>2</Order>
                            <Size>100</Size>
                            <Type>EFI</Type>
                        </CreatePartition>
                        <!-- Microsoft reserved partition (MSR) -->
                        <CreatePartition wcm:action="add">
                            <Order>3</Order>
                            <Size>128</Size>
                            <Type>MSR</Type>
                        </CreatePartition>
                        <!-- Windows partition -->
                        <CreatePartition wcm:action="add">
                            <Order>4</Order>
                            <Extend>true</Extend>
                            <Type>Primary</Type>
                        </CreatePartition>
                    </CreatePartitions>
                    <ModifyPartitions>
                        <!-- Windows RE Tools partition -->
                        <ModifyPartition wcm:action="add">
                            <Order>1</Order>
                            <PartitionID>1</PartitionID>
                            <Label>WINRE</Label>
                            <Format>NTFS</Format>
                            <TypeID>de94bba4-06d1-4d40-a16a-bfd50179d6ac</TypeID>
                        </ModifyPartition>
                        <!-- System partition (ESP) -->
                        <ModifyPartition wcm:action="add">
                            <Order>2</Order>
                            <PartitionID>2</PartitionID>
                            <Label>System</Label>
                            <Format>FAT32</Format>
                        </ModifyPartition>
                        <!-- Microsoft reserved partition (MSR) -->
                        <ModifyPartition wcm:action="add">
                            <Order>3</Order>
                            <PartitionID>3</PartitionID>
                        </ModifyPartition>
                        <!-- Windows partition -->
                        <ModifyPartition wcm:action="add">
                            <Order>4</Order>
                            <PartitionID>4</PartitionID>
                            <Label>Windows</Label>
                            <Format>NTFS</Format>
                        </ModifyPartition>
                    </ModifyPartitions>
                    <!-- If the USB detects as disk 0 on machine change the below <DiskID> to 1 so it formats the disk on the devices -->
                    <DiskID>0</DiskID>
                    <WillWipeDisk>true</WillWipeDisk>
                </Disk>
                <WillShowUI>OnError</WillShowUI>
            </DiskConfiguration>
            <ImageInstall>
                <OSImage>
                    <InstallFrom>
                        <Path>E:\1809install.wim</Path>
                    </InstallFrom>
                    <InstallToAvailablePartition>true</InstallToAvailablePartition>
                </OSImage>
            </ImageInstall>
            <RunSynchronous>
                <RunSynchronousCommand>
                    <Order>1</Order>
                    <!-- This sets the power scheme to high performance in WinPE for faster imaging -->
                    <Path>cmd /c PowerCfg.exe /s 8c5e7fda-e8bf-4a96-9a85-a6e23a8c635c</Path>
                </RunSynchronousCommand>
            </RunSynchronous>
            <UserData>
                <ProductKey>
                    <WillShowUI>Never</WillShowUI>
                    <!-- Windows 10 generic retail keys these should cause the machine to use its digital license key in the firmware -->
                    <!-- Windows 10 Professional -->
                    <!-- <Key>VK7JG-NPHTM-C97JM-9MPGT-3V66T</Key> -->
                    <!-- Windows 10 Pro Education -->
                    <Key>8PTT6-RNW4C-6V7J2-C2D3X-MHBPB</Key>
                </ProductKey>
                <AcceptEula>true</AcceptEula>
            </UserData>
        </component>
    </settings>
    <settings pass="offlineServicing">
        <component name="Microsoft-Windows-PnpCustomizationsNonWinPE" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
            <!-- Sets driver folders to use for PNP driver installs. I use multiple drive letters incase the USB drive letter is different
                 on different models in WinPE. Just create a Drivers folder on the USB drive and copy the driver packs you need into the folder. -->
            <DriverPaths>
                <PathAndCredentials wcm:action="add" wcm:keyValue="1">
                    <Path>D:\Drivers</Path>
                </PathAndCredentials>
                <PathAndCredentials wcm:action="add" wcm:keyValue="2">
                    <Path>C:\Drivers</Path>
                </PathAndCredentials>
                <PathAndCredentials wcm:action="add" wcm:keyValue="3">
                    <Path>E:\Drivers</Path>
                </PathAndCredentials>
                <PathAndCredentials wcm:action="add" wcm:keyValue="4">
                    <Path>F:\Drivers</Path>
                </PathAndCredentials>
            </DriverPaths>
        </component>
        <!-- Configures Windows 10 S mode - delete or comment out this component if not needed -->
        <!-- <component name="Microsoft-Windows-CodeIntegrity"
                processorArchitecture="amd64"
                publicKeyToken="31bf3856ad364e35"
                language="neutral"
                versionScope="nonSxS"
                xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State"
                xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
        <SkuPolicyRequired>1</SkuPolicyRequired>
        </component> -->
    </settings>
    <cpi:offlineImage cpi:source="wim:e:/1809install.wim#Windows 10 Pro Education" xmlns:cpi="urn:schemas-microsoft-com:cpi" />
</unattend>

Copy AutopilotConfigurationFile.json file to the root of the Boot partition of the USB drive

Copy the AutopilotCOnfigurationFile.json file from your desktop and paste in the root of the Boot partition of the USB drive

When Windows installs, the Autounattend.xml will instruct it to copy the AutopilotConfigurationFile.json file to the c:\windows\provisioning\autopilot folder

Create a SetupComplete.cmd file to change power policy to balanced

The Autounattend.xml file will change the power policy to High Performance to improve installation speeds during the WinPE and FullOS phases. We want to change this back to Balanced after the installation is complete.

Create a new text file and type in this command (Download here)

#REM Set Power Policy to Balanced
cmd /c PowerCfg.exe /s 381b4222-f694-41f0-9685-ff5bb260df2e

Save the file as SetupComplete.cmd and place it in the root of the Boot partition

A note about Drivers

If you want to install drivers during this process, make a folder on either the Boot or Deploy partitions (most likely D or E drives) of the USB stick and create a folder called Drivers (D:\Drivers or E:\Drivers). Inside of this Drivers folder, create model specific driver folders. Windows will use plug and play matching to find which drivers are necessary. Anything missed or old will be updated via Windows Update after Windows is installed (unless you are blocking driver updates from Windows Update via MDM or Group policy)

Install Windows

At this point, the drive is prepped and you're ready to install Windows. Insert the USB drive into the device and boot from the drive.

Troubleshooting

In some cases you may get an error message "Windows could not clean disk x" or a similar message saying it can't find Disk 0 or Disk 1. This is due to how different devices interpret the disk layout.

The simple solution is to search the AutoUnattend.xml and find this section:

<!-- If the USB detects as disk 0 on machine change the below <DiskID> to 1 so it formats the disk on the devices -->

<DiskID>0</DiskID>

And change the disk ID from 0 to 1 or 1 to 0 (depending on what you have set here).

Can I do this in SCCM?

Yep - in fact, in SCCM 1810 there will be a task sequence template to accomplish this.

7 Responses

  1. nigel says:

    Have you attempted Self Deploying mode?

  2. nigel says:

    Hi there,

    Is there any reason why Self Deploying profiles don't work in offline? I am developing a modern Win10 Kiosk solution and would love to leverage AutoPilot Self deploy.

  3. rbalsley says:

    Self deploying isn't currently supported for offline.

  4. Ricardo says:

    Hello,
    thanks for this guide.
    Only one thing: your wim file on the screenshot is called "install.wim" but in your XML you are referencing to "1809install.wim".

  5. Jj says:

    How do you get surface drivers instead of using the msi they come with?

  6. rbalsley says:

    You can use msiexec /a PathToMSIFile /qb TARGETDIR=DirectoryToExtractTo to extract the MSI to a folder.

  7. rbalsley says:

    Good catch. I use multiple WIM files for each version on my deploy partition and edit the xml accordingly depending on what I'm testing/deploying.

Leave a Reply

Your email address will not be published. Required fields are marked *