Cloud OS Deployment, Part 4 – Imaging over Internet, directly into Windows Autopilot

Cloud OS Deployment, or Cloud Imaging, allows you to deploy machines without any local infrastructure other than Internet access. It can for example be used to:

  • Image devices from directly home
  • Image from a remote office without overloading the VPN connection, or even without having a VPN connection.
  • Rebuild an entire infrastructure after a ransomware attack.

Update #1: October 1, 2025 – Updated the server-side registration to support the latest Microsoft.Graph module. I recommend using version 2.30 or later. The splash screen is also updated to the latest PSD version, plus some well-needed cleanup of supporting scripts.

Update: #2 November 23, 2025 – Updated the server-side registration to use background jobs and regular check-ins from the client. This to avoid long-running API calls (load balancers, API gateways, proxies, firewalls may have an idle or max-request timeouts between 30 seconds and 5 minutes).

Introduction

In this post, you learn how to configure MDT/PSD for a proof-of-concept scenario: having machines automatically enroll into Windows Autopilot during imaging via some clever PowerShell automation.

Note: The concept described in this guide works regardless of deployment solution, but in this guide, I'm using MDT/PSD since it supports deployment over HTTPS directly over the Internet and P2P via BranchCache, which keeps the Azure/AWS download cost down to a minimum.

Special thanks:

  • To Steve Adams and the Produhktiv LLC team for their invaluable support and testing during the early development of this solution in 2020.
  • To Dick Tracy at Microsoft for developing the PSD splash screen used in the solution.

Disclaimer: While this solution does work just fine, it's more of a proof-of-concept than anything, and it could certainly benefit from some additional error handling. I would love to get your feedback on what can be improved, so feel free to comment below or contact me on LinkedIn at https://www.linkedin.com/in/jarwidmark.

Sneak peek at the result… 🙂

The client-side splash screen, while the PSD Server securely takes care of the Autopilot registration

The Scenario and Step-by-Step Guide

For this setup, you'll be using the "classic" user-based Windows Autopilot scenario, where the machine will be pre-registered in Intune and added to a device group that has applications and profiles deployed to it. But you are configuring your MDT/PSD task sequence and server-side scripts to handle all that for you during deployment. So that you, or the end user, only have to do the following:

  1. Boot the machine into the cloud imaging platform.
  2. In the deployment wizard, assign a computer name and select the Intune group to which your Autopilot profile is assigned.
  3. Start the deployment, read a book, or watch an episode of your favorite TV show. While you are doing that, the computer will deploy Windows 11 over the Internet, create the hardware hash file, send it to the PSD Server, which will upload it to Intune, assign the computer to the correct security group in Intune, assign the correct computer name in Intune, and stop at the OOBE experience that is Windows Autopilot.
  4. Once at the Windows Autopilot OOBE screen, type in your username and password, and let Windows Autopilot deploy the Intune profiles, assigned applications, etc.

Step #1 – Setup Your Cloud Imaging Server

Part 2 of this blog post series – Bare Metal Deployment via MDT from the Cloud – provides details for setting up your cloud imaging server. You can also check out this video: Installing PowerShell Deployment (PSD) | Extend MDT w/ support for Cloud Imaging.

Step #2 – Configure Windows Autopilot

You also need to have setup Intune and Windows Autopilot. For example having created a Windows Autopilot deployment profile, an Enrollment Status Page, and assigned them to your groups in Intune. You can also create Intune profiles, and/or Win32 applications in Intune, and assign them to same groups. Here is a guide from Microsoft for setting up Windows Autopilot: Enroll Windows devices in Intune by using Windows Autopilot.

Note: In my environment, the Intune groups I use for Autopilot are configured for static membership. I simply found that adding devices directly to the group during deployment was faster and more reliable than using group tags (which are using dynamic groups, which in turn have to be evaluated, and that can take a little while).

Step #3 – Create an App Registration for Intune Automation

When scripting for Azure AD, and/or Intune, you typically don't want to use a real user account – or even worse, your own global admin account – but rather an app registration, to which you grant the needed permissions for the task. In my lab, I created an app registration for Microsoft Graph access, and granted it the following permissions:

  • DeviceManagementServiceConfig.ReadWrite.All
  • Directory.ReadWrite.All
  • Group.ReadWrite.All
  • GroupMember.ReadWrite.All
  • User.Read

Security Note: While using an app registration with its secret key stored securely on the host running the remote web service is secure enough for a proof-of-concept (imho), you probably want to look into using OIDC (OpenID Connect) tokens from GitHub Actions as a more secure way for your workflows to authenticate to cloud providers or other identity-aware services, without needing to store long-lived credentials (like secrets or service principals).

For a great guide on creating an app registration for Windows Autopilot, check out this blog post from Michael Niehaus: https://oofhours.com/2025/04/18/automatically-registering-autopilot-devices-with-intune

To connect to the app registration from the PowerShell script, I created a client secret for the app registration and configured the script to use it. Since the Invoke-PSDAutopilotRegistration.ps1 script is running locally on the PSD deployment server only, you can store the secret in a location that only that server can reach, safe from prying eyes. The clients that you deploy should never have access to that secret; they will only have access to the remote web service.

This is what the server-side Microsoft Graph connection section looks like in the script (obviously, you need to replace it with your information):

$TenantID = "<your tentant id>"
$AppID = "<your app registration client id>" 
$AppSecret = "server-side code to lookup the secret key"

# Clear any Graph cache
Write-Log "Clearing any Graph cache"
Disconnect-MgGraph -ErrorAction SilentlyContinue

# Disable shared token cache for this run
Write-Log "Disabling shared token cache for this run"
$env:AZURE_IDENTITY_DISABLE_SHARED_TOKEN_CACHE = "true"

try {
    Connect-MgGraph -TenantId $tenantID -ClientSecretCredential $ClientSecretCredential -NoWelcome -ErrorAction Stop
    Write-Log "Connection to Microsoft Graph successful"
}
catch {
    Write-Log "Unable to connect to Microsoft Graph" 
    Write-Log "Error message: $($_.Exception.Message)" 
    Return "Failure: Device with serial number $SerialNumber was not correctly registered with Autopilot"
}
Client secret for the app registration.

Step #4 – Setup a RESTful APi on the PSD Deployment Server

As mentioned previously, since you are going to run scripts during deployment that authenticate against Microsoft Graph, you want to run those scripts protected on your deployment server, accessible only via a web service, instead of running them on the actual client. For that purpose, I recommend that you set up a RESTful APi on your deployment server, which allows you to run PowerShell scripts as a service on the server itself. A free open source example is RestPS which I'm using for this guide, but there are also commercial alternatives like PowerShell Universal from Ironman Software, or iPXE Anywhere from 2Pint Software.

Details for setting up RestPS as a service are beyond the scope of this blog post, but I made a video about the setup here: Installing RestPS for OSD – PowerShell RESTful Endpoints

Step #5 – Install Required PowerShell Modules on the PSD Deployment Server

The server-side script requires the following PowerShell modules to be installed:

Tip: If you install the WindowsAutopilotIntuneCommunity module first, it will automatically install the other required modules.

  • WindowsAutopilotIntuneCommunity
  • Microsoft.Graph.Groups
  • Microsoft.Graph.Authentication
  • Microsoft.Graph.Identity.DirectoryManagement

Step #6 – Add the Autopilot Automation Scripts to the PSD Deployment Server

To have the client automatically register in Windows Autopilot during deployment, you need a few scripts. The server-side script mentioned previously, running as a web service, which handles device registration and group assignment. And a few client-side scripts that do the following:

  • Upload group name, computer name, and the Autopilot hardware hash to the remote webservice
  • Shows the PSD splash screen with status progress while the sever does it's magic
  • Clean (remove) the leftover PSD components on the client

Follow these steps to prepare the PSD Deployment Server

  1. Download the Autopilot scripts from our GitHub Repo: https://github.com/DeploymentResearch/DRFiles/tree/master/Scripts/CloudImagingPart4
  2. Download the latest Get-WindowsAutoPilotInfo.ps1 script from PowerShell Gallery.
  3. Copy the following scripts to the PSDResources\Autopilot folder of your PSD deployment share.
    Get-WindowsAutoPilotInfo.ps1
    PSDAutopilotDeviceRegistration.ps1
    PSDCleanupForAutopilot.ps1
    PSDStartLoaderAutopilot.psm1
  4. Copy the PSDPrepareForWindowsAutopilot.ps1 script to the scripts folder of your PSD deployment share.
  5. Add the Invoke-PSDAutopilotRegistration.ps1 and Invoke-PSDGetCurrentAutopilotJob.ps1 scripts to your RESTful api. If using RestPS. you add it to the POST folder in your RestPS root/endpoints folder. In my lab, it was E:\RestPS\endpoints\POST.
  6. Modify the Invoke-PSDAutopilotRegistration.ps1 with your Intune tenant, app registration client id, and client secret.
Invoke-PSDAutopilotRegistration.ps1 copied to the RestPS folder structure.

Step #7 – Configure the PSD task sequence

The final step is to configure the PSD task sequence to download the client-side scripts, and configure the unattend.xml to run them.

Note: In this example, the task sequence runs the script directly after the WinPE phase reboot, in the specialize pass, but you can also run the scripts in audit mode + Sysprep if you want PSD to perform additional customizations, such as installing applications or running Windows Update.

To further minimize interference from Windows itself, I'm forcing the machine to deploy into Audit mode, where the Autopilot registration happens.

1. Create a new PSD task sequence using the PSD Standard Client Task Sequence template.

2. From the sample files, copy the Unattend.xml file to the <PSD task Sequence ID> folder inside the PSD Deployment share Control folder.

The Task Sequence folder inside of the Control folder.

3. Modify the new PSD task sequence with the following

4. After the Configure action, add a Run Command Line action named Prepare for Windows Autopilot with the following command line:

PowerShell.exe -File %SCRIPTROOT%\PSDPrepareForWindowsAutopilot.ps1

5. Remove the existing Setup Operating System and Custom Tasks groups.

The modified Windows Autopilot task sequence.

Step #8 – Start the Deployment

Once the setup is complete, you're ready to start the deployment. Don't forget to select the correct Intune group in the PSD Deployment Wizard.

Selecting the Windows Autopilot group in Intune.

About the author

Johan Arwidmark

5 3 votes
Article Rating
Subscribe
Notify of
guest
2 Comments
Newest
Oldest Most Voted
Christoph Wijns
Christoph Wijns
4 months ago

Hello Johan,

I don't find Invoke-PSDGetCurrentAutopilotJob.ps1 on Github

Can you please help


>