This post describes the actions to create a Windows 10 Autopilot Profile via Powershell. I am always trying to automate as much as possible to reduce repeating actions. Now it is time to automate my Windows 10 Autopilot deployment.

Firstly, I need to make a shoutout to Rudy Ooms and his blog (Call4Cloud). I got the idea from him and used a piece of his code. You can find the basis for a full Windows 10 Autopilot deployment in this Github repo. This is for advanced Powershell and Graph API users.

Damien Van Robaeys helped make this script even more efficient. Shoutout to you too!

I explain, in a detailed manner, how you can create your Windows 10 Autopilot Profile via Powershell.

Now there is only 1 step involved. Run the script below.

Create Dynamic Group, an Autopilot Profile and Assign the profile

Firstly, save this code a .ps1 file:

param (

# ***************************************************************************************
# 									Check for module part	
# ***************************************************************************************

#Checking for correct modules and installing them if needed
$InstalledModules = Get-InstalledModule
$Module_Name = "MSAL.PS"
If ($ -notcontains $Module_Name) {
	Write-Host "Installing module $Module_Name"
	Install-Module $Module_Name -Force
Else {
	Write-Host "$Module_Name Module already installed"

#Importing Module
Write-Host "Importing Module $Module_Name"
Import-Module $Module_Name

# ***************************************************************************************
# 									Authentication part	
# ***************************************************************************************

#Connecting to Azure AD to Create the Group
# Write-Host "Connecting to Azure AD, fill the credential prompt"		
$myToken = Get-MsalToken -ClientId d1ddf0e4-d672-4dae-b554-9d5bdfd93547 -RedirectUri "urn:ietf:wg:oauth:2.0:oob" -Interactive

# ***************************************************************************************
# 									Create group part	
# ***************************************************************************************
##DynamicGroupRule Properties:
$DynamicGroupRule = "(device.devicePhysicalIds -any _ -eq ""[OrderID]:$OrderID"")"
# Creating group
$Group_URL = ""	
$group = @{
	"displayName" = $DynamicGroupName;
	"description" = "This is used Windows 10 Autopilot Device with the OrderID $OrderID";
	"groupTypes" = @("DynamicMembership");
	"mailEnabled" = $False;
	"mailNickname" = "AutoPilotGroup-$OrderID";
	"membershipRule" = $DynamicGroupRule;
	"membershipRuleProcessingState" = "On";
	"securityEnabled" = $True

$requestBody = $group | ConvertTo-Json #-Depth 5
$Create_group = Invoke-RestMethod -Headers @{Authorization = "Bearer $($myToken.AccessToken)" }  -Uri $Group_URL -Method POST -Body $requestBody -ContentType 'application/json'
$Group_ID = $

# Write-Host "Group created! Save this Object ID: $($CreateDynamicGroup.Id) in a notepad for later use" -ForegroundColor Green
Write-Host "Group created: $Group_ID!" -ForegroundColor Green

# ***************************************************************************************
# 									Create profile part	
# ***************************************************************************************
$AutopilotProfileDescription = "$AutopilotProfileName Azure AD Join AutoPilot Profile"
$Profile_Body = @{
	"@odata.type"                          = "#microsoft.graph.azureADWindowsAutopilotDeploymentProfile"
	displayName                            = "$($AutopilotProfileName)"
	description                            = "$($AutopilotProfileDescription)"
	language                               = 'os-default'
	extractHardwareHash                    = $false
	enableWhiteGlove                       = $true
	outOfBoxExperienceSettings             = @{
		"@odata.type"             = "microsoft.graph.outOfBoxExperienceSettings"
		hidePrivacySettings       = $true
		hideEULA                  = $true
		userType                  = 'Standard'
		deviceUsageType           = 'singleuser'
		skipKeyboardSelectionPage = $false
		hideEscapeLink            = $true
	enrollmentStatusScreenSettings         = @{
		'@odata.type'                                    = "microsoft.graph.windowsEnrollmentStatusScreenSettings"
		hideInstallationProgress                         = $true
		allowDeviceUseBeforeProfileAndAppInstallComplete = $true
		blockDeviceSetupRetryByUser                      = $false
		allowLogCollectionOnInstallFailure               = $true
		customErrorMessage                               = "An error has occured. Please contact your IT Administrator"
		installProgressTimeoutInMinutes                  = "45"
		allowDeviceUseOnInstallFailure                   = $true
} | ConvertTo-Json		
$Profile_URL = ""
$Create_Profile = Invoke-RestMethod -Headers @{Authorization = "Bearer $($myToken.AccessToken)" }  -Uri $Profile_URL -Method POST -Body $Profile_Body -ContentType 'application/json'
$Get_Profile_ID = $Create_Profile.ID

# ***************************************************************************************
# 									Assign profile part	
# ***************************************************************************************
$Assignment_Body = @"

$Profile_Assignment_URL = "$Profile_URL/$($Get_Profile_ID)/assignments"
Invoke-RestMethod -Headers @{Authorization = "Bearer $($myToken.AccessToken)" }  -Uri $Profile_Assignment_URL -Method POST -Body $Assignment_Body -ContentType 'application/json'
Write-Host "ProfilE created and assign to the group!" -ForegroundColor Green

After that, use this code to run the file and add the parameters:

.\Function_Create-AutoPilotDynamicGroup.ps1 -DynamicGroupName NielsKokTech_AutoPilot_Dynamic -OrderID NielsKokTech 

As a result, this is shown:

Fill the credential prompt with an account that has the proper permissions:

After that, this is the output and everything is done!

This is the group created by the script:

Furthermore, this script creates an Azure AD joined Windows 10 Autopilot profile. if you want to edit the properties of the profile, please edit the $Body in the file above.

After that, the Windows 10 Autopilot Profile is created according to the $Body in the Powershell Script:

That’s how you create Windows 10 Autopilot profile and assign it via Powershell.

Other posts

Want to create an Autopilot manually? Check out these posts:

Azure AD Joined profile

Hybrid AD Joined profile

33 thoughts on “Create Autopilot Profile via Powershell”
    1. I really would love to use that script but I have a problem with -ClientId d1ddf0e4-d672-4dae-b554-9d5bdfd93547, I replace your ClientID with mine but realize I do not have the proper one so it failed can you help me on that part ? What do I need to do or where do I get the right one..
      Your help is appreciated.

      1. Hi James,

        You don’t need to change the client id. This is a general Intune Powershell App Rep object ID which is the same for each tenant. After that, you should just be able to run the script. Which error are you getting?


    2. Hi there, it’s a brilliant script, but would love to know how to modify it for Hybrid as per below question ..any ideas ?
      Hi Mauberley,

      How did you change the script so that the autopilot profile is Join to Azure AD as β€œHybrid Azure AD joined” (versus Azure AD joined)


        1. hey Niels,
          Thanks for replaying, i did see and use you second link already which created the domain join configuration profile – works fantastic also !
          What i was more getting at is this article set’s up the AUTOPILOT profile as join type Azure AD Join
          I’m after how to setup the AUTOPILOT profile as join type Hybrid Azure AD joined
          hoping that makes sense ?

          1. Hi John,

            I understand, thanks for elaborating.

            You need to edit the script which creates the Azure AD Joined AutoPilot profile to use this parameter set:

            $params = @{
            “@odata.type” = “#microsoft.graph.activeDirectoryWindowsAutopilotDeploymentProfile”
            displayName = “dfsgsdf”
            description = “”
            deviceNameTemplate = “”
            language = “os-default”
            enableWhiteGlove = $false
            deviceType = “windowsPc”
            extractHardwareHash = $false
            roleScopeTagIds = @(
            hybridAzureADJoinSkipConnectivityCheck = $false
            outOfBoxExperienceSettings = @{
            deviceUsageType = “singleUser”
            hideEscapeLink = $true
            hidePrivacySettings = $true
            hideEULA = $true
            userType = “standard”
            skipKeyboardSelectionPage = $true

            In stead of the Azure AD Joined parameter set.

            I hope you can change it yourself.

            if not, let me know.


        2. Thank you so much Neil (no reply button on the fix script you gave me for some reason) replying here ..
          the line microsoft.graph.activeDirectoryWindowsAutopilotDeploymentProfile is the one i needed !!
          brilliant!! thank you !!

  1. This script was helpfull and easy to use for a Powershell dummy like me :). Made some small customizations to include a custom deviceName template into the Create Profile Part.
    $DeviceNameTemplate = “$OrderID-%SERIAL%”
    deviceNameTemplate = “$($DeviceNameTemplate)”
    Running the script works great.
    I have one question, I have to create almost 80 Dep Profiles because of the deviceNames that we have per region, company, branch.
    i.e. ABC, DEF, XYZ
    How can I modify the ps to read the entries from an excel sheet into an array and then to just create the profiles from the input list.
    The AADGroup Name = ABC-WindowsAutoPilot
    OrderID = ABC
    AutoPilotProfileName = ABC

    1. Hi Mario,

      Thanks for your e-mail. That is possible but I need to figure out some variables via the Graph. I will update the post with the extra variables later on.

      Stay tuned!


  2. For me the sec group gets created but the script errors out at the “$Create_Profile = Invoke-RestMethod”
    Invoke-RestMethod : The remote server returned an error: (400) Bad Request.
    At C:\******.ps1:*****
    + … e_Profile = Invoke-RestMethod -Headers @{Authorization = “Bearer $($m …
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-RestMethod], WebExc
    + FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeRestMethodCommand

    Invoke-RestMethod : The remote server returned an error: (400) Bad Request.
    At C:\****************\*********.ps1:****
    + Invoke-RestMethod -Headers @{Authorization = “Bearer $($myToken.Acces …
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-RestMethod], WebExc
    + FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeRestMethodCommand

    Any ideas ? It seems to say something wrong with body, but I don’t think so, have checked and colleague also checked.
    I read something about it maybe being permissions ?

    1. Hi Mauberley,

      I have used this yesterday. Could you maybe try to download the template again?

      Since, in my opinion, this should work.


      1. Hi Niels, thanks for your prompty reply, in the meantime I managed to fix it. It was due to me changing the language to a variable. This works, but you have to enter the region code eg ‘fr-FR’ not ‘French (France)’ as it displays in Intune, and not fr-fr either which I also tried (it’s case sensitive).
        So all good now ;).

        Whilst we’re here, do you know any way to create Device Configuration profiles using PowerShell ? Specifically, the Domain Join config template. We have a lot of companies in our organisation (+150) and we put each one’s clients in a separate OU. Creating the profiles and sec groups using your script was already a great help, but being able to automate the Domain Join Config profile would be next level ;). I’ve had a look at the Powershell commands like Get-IntuneDeviceConfigurationPolicy, but doesn’t seem to be pertinent.

        Thanks again.

        1. Hi Mauberley,

          Good to hear that things worked out!

          That is a nice subject for my next blog. Stay tuned. Will write it probably this week.

          Thanks mate,

  3. Oh and yes I did modify the script above so it creates a Hybrid profile, and that part works fine. I should mention that before any confusion arises from my talking about Domain Join config templates πŸ˜‰

    1. Hi Mauberley,

      How did you change the script so that the autopilot profile is Join to Azure AD as “Hybrid Azure AD joined” (versus Azure AD joined)


  4. Great work Niels, thank you for sharing with the community! We are working on how to rename Autopilot devices to our company standard naming convention for Hybrid Azure-AD Joined devices. Any sugguestions are insight would be greatly appreciated.


  5. Hello Niels,

    I already saw that script but i am looking for a autopilot deployment profile with just the azure ad join changed by the hybrid azure join πŸ™‚

    Kind regards,


  6. Hi,
    I have created a ESP with this command:
    $Body = @{
    “@odata.type” = “#microsoft.graph.windows10EnrollmentCompletionPageConfiguration”
    displayName = “$($EnrollmentPageName)”
    description = “$($EnrollmentPageName) Azure AD Join AutoPilot Enrollment Status Page”
    deviceEnrollmentConfigurationType = ‘windows10EnrollmentCompletionPageConfiguration’
    showInstallationProgress = $true
    blockDeviceSetupRetryByUser = $false
    allowDeviceResetOnInstallFailure = $true
    allowLogCollectionOnInstallFailure = $true
    customErrorMessage = “Setup could not be completed. Please try again or contact your support person for help.”
    installProgressTimeoutInMinutes = 45
    allowDeviceUseOnInstallFailure = $false
    allowNonBlockingAppInstallation = $true
    installQualityUpdates = $true
    trackInstallProgressForAutopilotOnly = $true
    disableUserStatusTrackingAfterFirstUser = $true
    } | ConvertTo-Json

    $URL = “”
    $Data = Invoke-RestMethod -Headers @{Authorization = “Bearer $($myToken.AccessToken)” } -Uri $URL -Method POST -Body $Body -ContentType ‘application/json’
    It works fine, but how do I assign it to a group?

Leave a Reply

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