I need a VM connected to the customer’s tenant for Endpoint Manager testing. This involves deploying a Windows 10 or 11 VM, changing hardware settings (Secure Boot/TPM/Checkpoint settings), and registering it for Autopilot. This blog post will show you how to automate the process as much as possible.
What does the script do?
The script will run the following steps:
- Ask for a VM name
- Ask for the number of CPU cores
- Ask for the amount of RAM in GBs (Static and not Dynamic)
- Ask for the HDD size in GBs
- Show a list of ISO files you specified in the $ISOPath variable at the top of the list, and select the one that you want to use for installing the VM
- Show a list of your VM switches, and select the one that you want to use for the VM
- Create the VM with all the settings (Secure Boot/TPM/Checkpoints/CPU/RAM/HDD/ISO and will connect a Console session to the VM. You might need to reset the VM for the “Press any key to boot from CD or DVD” prompt if you’re not fast enough.
- While running through the basic installation tasks (Selecting Pro or Enterprise, accepting License Terms, and formatting the disk), the script will pause until you press Enter when you’re at the region selection screen. At this moment, the VM will mount the intune.iso file.
- When the ISO is mounted, you can press Shift-F10, switch to d:\, run autopilot.cmd, register the VM as an Autopilot device, and shut down the VM when ready.
You will then have a VM ready for Endpoint Manager testing 🙂
Preparations
Azure App Registration
In a previous blog post (here), I already covered this, but the steps are as follows:
- Go to App Registrations
- Select New Registration
- Enter “Autopilot Registration” as the name, and select Register.
- Select API Permissions on the left side and select Add a permission
- Select Microsoft Graph
- Select Application permissions
- Search for DeviceManagementServiceConfig.ReadWrite.All, select the checkbox and select Add Permissions.
- Select Grant admin consent for xxxxx.onmicrosoft.com and select Yes
- Select Certificates & secrets on the left side and select New client secret
- Enter “Autopilot Registration Secret” as a description. For example, select how long the client secret should be valid (I selected 24 months) and click Add
- Select the copy icon behind the value column and copy it somewhere safely (A password manager or database)
- Select Overview on the left side, copy the Application (client) ID plus the Directory (tenant) ID, and save them with the value you copied in the previous step.
Intune Script ISO
During the deployment, the script will dismount the Windows installation ISO and mount an Intune.ISO file which contains the two scripts below. The steps for adding this to an ISO file are:
- Create an autopilot.cmd in a temporary directory containing this command line:
powershell.exe -executionpolicy bypass -file .\autopilot.ps1 - Create an autopilot.ps1 in the same temporary directory containing the command lines below, and replace XXX with the values from the previous chapter in which you registered the Azure App:
Install-PackageProvider -Name NuGet -MinimumVersion 2.8.5.201 -Confirm:$false -Force:$true
Install-Script get-windowsautopilotinfo -Confirm:$false -Force:$true
get-windowsautopilotinfo -Online -TenantId xxxx -AppId xxxx -AppSecret xxxx
shutdown.exe /s /t 10 - Download and install the AnyToISO program (Direct Link). The free version works with files not bigger than a regular CD size (870 MB). In our case, that’s not a problem. We only need 2Kb 🙂
- Start the AnyToIso program after installation and follow these steps:
Select the Folder to ISO tab
Select Browse for Folder and select your temporary folder where the .cmd and .ps1 are saved
select Choose ISO and browse and enter a destination .iso filename
Select Make ISO

Running the script
Below are the steps you will see when running the script (Run it as Administrator). Before starting the script, please configure the two settings at the top of the script to your file locations:
#ISO Paths $ISOPath = 'D:\ISO' $IntuneISO = 'D:\ISO\intune.iso'
Enter the desired VM Name, Cores, RAM, and HDD size:
Hyper-V Role is installed, continuing... Please enter the name of the VM to be created, for example W11Intune: PowerShellisfun Please enter the amount of cores, for example 2: 4 Enter Memory in Gb's, for example 4: 8 Enter HDD size in Gb's, for example 40: 40
Select the desired ISO file and click on Ok:

Select the desired VM Switch and click on Ok:

The VM will now be created and configured with all the settings, the Console connection will be launched, and you can start the initial installation steps until the VM is on the region settings screen.
Note: You might need to reset the VM if you’re not in time for the “Press any key to boot from CD or DVD” prompt.
Using C:\Data\Hyper-V\PowerShellisfun as Virtual Machine location... Configuring settings on PowerShellisfun... Starting VM PowerShellisfun, press Enter to continue when you are on the language selection screen after completing the inital setup steps. Connecting to console now.... Press Enter to continue...:
When you have arrived at this screen:

You can switch back to your PowerShell prompt and press Enter to continue to see the next steps:
Press Shift-F10 on the console of VM PowerShellisfun, switch to d:\ and run d:\autopilot.cmd to upload hardware hash to Intune. The VM will shutdown when done! Press Enter when the VM has shutdown to stop this script and disconnect the Intune ISO file from VM PowerShellisfun Press Enter to continue...:
Switch back to your VM, press Shift-F10, switch to d:\, and run autopilot.cmd, registering the VM as an Autopilot device and shut down the VM when ready.
Switch to D:\ and run autopilot.cmd:

Wait for the device to be imported:

Import done, VM will shut down:

When the VM is shut down, switch back to the script and press Enter to eject the intune.iso and finish the script:
Ejecting Intune ISO file from VM PowerShellisfun Done, the deployment took 0 hours, 19 minutes and 15 seconds
And you’re done. The Windows installation is done, including Autopilot registration 🙂
Note: Please wait 5 minutes to power the VM again. It does take a few minutes after registering Autopilot for it to be processed in Dynamic Groups attached to your Deployment profile.
The script
Below is the script, don’t forget to change the ISO variables to your locations 🙂
Update: Robert Clark made a few adjustments. Thanks!
– Update script to not throw an error when enabling TPM and to place VMs in a folder
#Requires -RunAsAdministrator #ISO Paths $ISOPath = 'D:\ISO' $IntuneISO = 'D:\ISO\intune.iso' #Start a stopwatch to measure the deployment time $stopwatch = [System.Diagnostics.Stopwatch]::StartNew() #Detect if Hyper-V is installed if ((Get-WindowsOptionalFeature -FeatureName Microsoft-Hyper-V-All -Online).State -ne 'Enabled') { Write-Warning ("Hyper-V Role and/or required PowerShell module is not installed, please install before running this script...") } else { Write-host ("Hyper-V Role is installed, continuing...") -ForegroundColor Green } #Set VM Parameters $VMname = Read-Host 'Please enter the name of the VM to be created, for example W11Intune' if ((Get-VM -Name $VMname -ErrorAction SilentlyContinue).count -ge 1) { Write-Warning ("VM {0} already exists on this system, aborting..." -f $VMname) return } $VMCores = Read-Host 'Please enter the amount of cores, for example 2' [int64]$VMRAM = 1GB * (read-host "Enter Memory in Gb's, for example 4") [int64]$VMDISK = 1GB * (read-host "Enter HDD size in Gb's, for example 40") $VMdir = (get-vmhost).VirtualMachinePath + "\Virtual Machines\" + $VMname $VMDiskDir = (get-vmhost).VirtualHardDiskPath $ISO = Get-Childitem $ISOPath *.ISO | Out-GridView -OutputMode Single -Title 'Please select the ISO from the list and click OK' if (($ISO.FullName).Count -ne '1') { Write-Warning ("No ISO, script aborted...") return } $SwitchName = Get-VMSwitch | Out-GridView -OutputMode Single -Title 'Please select the VM Switch and click OK' | Select-Object Name if (($SwitchName.Name).Count -ne '1') { Write-Warning ("No Virtual Switch selected, script aborted...") return } #Create VM directory try { New-Item -ItemType Directory -Path $VMdir -Force:$true -ErrorAction SilentlyContinue | Out-Null } catch { Write-Warning ("Couldn't create {0} folder, please check VM Name for illegal characters or permissions on folder..." -f $VMdir) return } finally { if (test-path -Path $VMdir -ErrorAction SilentlyContinue) { Write-Host ("Using {0} as Virtual Machine location..." -f $VMdir) -ForegroundColor Green } } #Create VM with the specified values try { New-VM -Name $VMname ` -SwitchName $SwitchName.Name ` -Path $VMdir ` -Generation 2 ` -Confirm:$false ` -NewVHDPath "$($VMDiskDir)\$($VMname).vhdx" ` -NewVHDSizeBytes ([math]::Round($vmdisk * 1024) / 1KB) ` -ErrorAction Stop ` | Out-Null } catch { Write-Warning ("Error creating {0}, please check logs and make sure {0} doesn't already exist..." -f $VMname) return } finally { if (Get-VM -Name $VMname -ErrorAction SilentlyContinue | Out-Null) { write-host ("Created {0})..." -f $VMname) -ForegroundColor Green } } #Configure settings on the VM, CPU/Memory/Disk/BootOrder/TPM/Checkpoints try { Write-Host ("Configuring settings on {0}..." -f $VMname) -ForegroundColor Green #VM Settings Set-VM -name $VMname ` -ProcessorCount $VMCores ` -StaticMemory ` -MemoryStartupBytes $VMRAM ` -CheckpointType ProductionOnly ` -AutomaticCheckpointsEnabled:$false ` -ErrorAction SilentlyContinue ` | Out-Null #Add Harddisk Add-VMHardDiskDrive -VMName $VMname -Path "$($VMDiskDir)\$($VMname).vhdx" -ControllerType SCSI -ErrorAction SilentlyContinue | Out-Null #Add DVD with iso and set it as bootdevice Add-VMDvdDrive -VMName $VMName -Path $ISO.FullName -Passthru -ErrorAction SilentlyContinue | Out-Null $DVD = Get-VMDvdDrive -VMName $VMname $VMHD = Get-VMHardDiskDrive -VMName $VMname Set-VMFirmware -VMName $VMName -FirstBootDevice $VMHD Set-VMFirmware -VMName $VMName -FirstBootDevice $DVD Set-VMFirmware -VMName $VMname -EnableSecureBoot:On #Enable TPM Set-VMKeyProtector -VMName $VMname -NewLocalKeyProtector Enable-VMTPM -VMName $VMname #Enable all integration services Enable-VMIntegrationService -VMName $VMname -Name 'Guest Service Interface' , 'Heartbeat', 'Key-Value Pair Exchange', 'Shutdown', 'Time Synchronization', 'VSS' } catch { Write-Warning ("Error setting VM parameters, check settings of VM {0} ..." -f $VMname) return } #Start VM and wait until VM is at language selection screen Write-Host ("Starting VM {0}, press Enter to continue when you are on the language selection screen after completing the inital setup steps. `nConnecting to console now...." -f $VMname) -ForegroundColor Green Start-VM -VMName $VMname vmconnect.exe localhost $VMName Pause #Add Intune ISO Set-VMDvdDrive -VMName $VMname -Path $IntuneISO Write-Host ("Press Shift-F10 on the console of VM {0}, switch to d:\ and run d:\autopilot.cmd to upload hardware hash to Intune. The VM will shutdown when done!" -f $VMname) -ForegroundColor Green Write-Host ("Press Enter when the VM has shutdown to stop this script and disconnect the Intune ISO file from VM {0}" -f $VMname) -ForegroundColor Green pause Write-Host ("Ejecting Intune ISO file from VM {0}" -f $VMname) -ForegroundColor Green Set-VMDvdDrive -VMName $VMname -Path $null #The end, stop stopwatch and display the time that it took to deploy $stopwatch.Stop() Write-Host "Done, the deployment took $($stopwatch.Elapsed.Hours) hours, $($stopwatch.Elapsed.Minutes) minutes and $($stopwatch.Elapsed.Seconds) seconds" -ForegroundColor Green
Download the script(s) from GitHub here
Pingback: Blogpost – Create Hyper-V VM and enroll it in Autopilot automatically – 247 TECH
Pingback: Endpoint Manager Newsletter – 26th August 2022 – Andrew Taylor
Pingback: PowerShell is fun :) Overview of 2022 posts