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.
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 #1: You can also use the Autopilot for existing devices scenario for assigning machines to Intune directly during imaging, but I wanted to get additional control of the process, like verifying group membership and Windows Autopilot profile assignment, hence the approach described in this post. Basically making sure the Intune side of things are ready, before booting the machine into the Windows Autopilot experience (OOBE).
Note #2: 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 Internet, as well as P2P via BranchCache which keeps the Azure download cost down to a minimum.
Disclaimer: While this solution does work, as far as my testing goes, its more 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 either comment below, or contact me on LinkedIn at https://www.linkedin.com/in/jarwidmark.
For this setup you'll be using the "classic" user-based Windows Autopilot scenario, where the machine will be pre-registered in Intune, added to a device group that have applications and profiles deployed to it. But, you are configuring your MDT/PSD task sequence, and server side scripts, to care of all that for you during deployment. So that you, or the end user, only have to do the following:
- Boot the machine into the cloud imaging platform, MDT/PSD in this case.
- Assign a computer name, and select an Intune group in the deployment wizard.
- Start the deployment, then read a book, or watch an episode of your favorite TV show. While you are doing that, the computer will deploy Windows 10 over Internet, create the hardware hash file, upload it to Intune, assign the computer to the correct security group in Intune, assign the correct computer name in Intune, run sysprep, and after reboot, stop at the OOBE experience that is Windows Autopilot.
- After half an hour or so, come back to the computer, and in the Windows Autopilot OOBE screen, type in your user name and password, and let Windows Autopilot deploy the Intune profiles, assigned applications etc.
Step #1 – Setup Your Cloud Imaging Server
Details for setting up your cloud imaging server is found in part 2 in this blog post series. Here is the link: Cloud OS Deployment, Part 2 – Bare Metal Deployment via MDT from the Cloud.
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:
To connect 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 run on the PSD deployment server only, you can added the secret key directly in the script, safe from prying eyes. This is what the Microsoft Graph connection section looks in the script (obviously you need to replace it with your information):
# Set Authentication info for to Microsoft Graph $tenant = "yourtenant.onmicrosoft.com" $authority = "https://login.windows.net/$tenant" $AppID = "your-app-GUID" $AppSecret = "your-app-secret"
Step #4 – Setup RestPS as a Service
Since you are going to run scripts during deployment that authenticates against Microsoft Graph, you want to run those scripts protected on your deployment server, via a web service, instead of running them on the actual client. For that purpose I recommend that you setup RestPS on your deployment server, which allows you to run PowerShell scripts as a service (on the server itself).
Details for setting up RestPS as a service is beyond the scope for this blog post, but my good friend Mikael Nystrom (@mikael_nystrom), has an excellent guide here: Nice to Know – Running RestPS as a Service.
Step #5 – Add the Autopilot Automation Scripts
To have the client automatically register in Windows Autopilot during deployment, you need two scripts. The server side script running as a web service, which is doing the device registration and group assignment. And the client side script that tells the webservice what to do.
- Install the WindowsAutopilotIntune module from PowerShell Gallery on your deployment server. This will also install a few depending modules.
- Install the Get-WindowsAutoPilotInfo.ps1 script from PowerShell Gallery, and copy it to the scripts folder of your PSD deployment share.
- Navigate to DRFiles/Scripts/CloudImagingPart4 at master · DeploymentResearch/DRFiles (github.com), download the following files, and copy them to the scripts folder of your PSD deployment share.
- From the same link, download the Invoke-PSDAutopilotRegistration.ps1 script, and copy it to the POST folder in your RestPS root/endpoints folder. In my lab it was E:\RestPS\endpoints\POST.
- Modify the Invoke-PSDAutopilotRegistration.ps1 with your Intune tenant, application, and client secret.
Step #6 – Modify the MDT/PSD Deployment Wizard
The current PSD deployment wizard does not have a dropdown for Intune Group, so I modified it to make the Intune group selection easy. But you can set the custom task sequence variable I use for the group name in anyway you want. The PSDAutopilotDeviceRegistration.ps1 script is simply looking for the value of the Roles task sequence variable.
If you want to use PSD wizard I used, you can download the below files, and replace in your PSD setup.
Step #7 – Configure MDT/PSD with a Finish Action
To make sure the machine does a final reboot after the task sequence completed, I added in the following rule to the CustomSettings.ini file:
Step #8 – Force Deployment into Audit mode
To minimize interference from Windows itself, I'm forcing the machine to deploy into Audit mode, where the Autopilot registration happens. in MDT/PSD this is done by using an Audit mode unattend.xml template. Simply copy the below example, and replace the unattend.xml your PSD task sequence is using with this template:
Note: Since the PSD platform currently has no native support for Audit mode deployments, I simply hard-coded the temporary admin password in the unattend.xml template. The Sysprep process removes it anyway.
Step #9 – Configure the PSD task sequence
The final step is to configure the PSD task sequence to run the client side script, that in turn triggers the server side script via the RestPS webservice, to do the device registration in Intune. In addition I also added in script that prevent Windows updates as well as updates Windows Store application, since they are likely to break Sysprep.
To further minimize interference from Windows itself, I'm forcing the machine to deploy into Audit mode, where the Autopilot registration happens.
In my PSD task sequence I added the following:
1. After the Configure action, add a run command line action named "Disable Windows Store Updates and Consumer Features" with the following command line:
PowerShell.exe -ExecutionPolicy Bypass -File "%SCRIPTROOT%\PSDDisableWindowsStoreUpdates.ps1"
2. After the Disable Windows Store Updates and Consumer Features action, add a run command line action named "Disable Windows Updates" with the following command line:
PowerShell.exe -ExecutionPolicy Bypass -File "%SCRIPTROOT%\PSDDisableWindowsUpdates.ps1"
3. After the Windows Update Pass 2 action, add a run command line action named "Register device for Windows Autopilot (may take up to 10 minutes)" with the following command line:
PowerShell.exe -ExecutionPolicy Bypass -File "%SCRIPTROOT%\PSDAutopilotDeviceRegistration.ps1"
4. After the Register device for Windows Autopilot (may take up to 10 minutes) action, add a run command line action named "Run Sysprep" with the following command line:
PowerShell.exe -ExecutionPolicy Bypass -File "%SCRIPTROOT%\PSDAutopilotDeviceRegistration.ps1"
5. Make sure there are no other commands after the Run Sysprep action.