Upload Windows Autopilot hardware hash easily

Retrieving the hardware hash for a new laptop or VM involves a few steps. Starting PowerShell, configuring the execution policy, installing the get-windowsautopilot script, answering a few prompts, and entering your credentials to upload it to your environment. In this blog post, I will show you how to minimize the number of steps needed.

App registration

To avoid entering credentials during the process, you must register an app in Azure. Follow these steps for that:

  • 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, please 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.

Creating the scripts

Now that we have an application registration that we can use for authenticating, we can create two script files that you can put on a USB drive which you can launch and will take care of getting the hardware hash and uploading to your tenant. Copy the contents below and save them as autopilot.cmd and autopilot.ps1, for example, on a USB drive. (I changed the IDs to xxxx. You need to replace them with the IDs which you saved when creating the app registration, of course 🙂 )

Autopilot.cmd

powershell.exe -executionpolicy bypass -file .\autopilot.ps1

Autopilot.ps1

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

Running the autopilot.cmd

When your device is on the first OOBE (Out Of Box Experience) screen, the one with the language selection, you can follow these steps:

  • Press Shift-F10 to get to a command prompt
  • Go to your USB drive by entering E: (This could be different in your case)
  • Enter “autopilot.cmd” to start the script

The autopilot.ps1 starts, installs the NuGet provider, downloads the get-windowsautopilot script, connects to the tenants using the app registration details, and uploads the hardware hash. When done, it shutdowns the system in ten seconds, and your system is ready to go start an Autopilot installation!

The uploaded hardware hash in Endpoint Manager from my test tenant:

Adding a Group Tag

You can add Group tags to the script if you’re using Group tags for deployment profiles. Change the autopilot.ps1 on your USB drive to the one below: (Added the -GroupTag parameter. I used VMware as an example)

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 -GroupTag VMware
shutdown.exe /s /t 10

34 thoughts on “Upload Windows Autopilot hardware hash easily

  1. Pingback: Blogpost – Upload Windows Autopilot hardware hash easily – 247 TECH

  2. Pingback: Deploy a Hyper-V VM and register it for Autopilot automatically using PowerShell | PowerShell is fun :)

  3. Kindly provide script and steps to implement in SCCM OSD task sequence to upload hardware hash to intune with multiple Group tag

    • I think all of the scripting parts is already in this blog, the shutdown part should be removed in a task sequence…I’m not an SCCM man, but I did see a few examples online about gathering it to a CSV which requires manual action. My script in this blog post uploads it automatically with the app registration details, Group Tag is possible also but not sure how you can specify which group tag for which deployment 😉

    • It takes a little bit, but you can apply a clean image, install config manager, then run the script and pass through an argument for the group tag after it boots to the OS and sets up config manager (the argument could be based on input in the UI++ or if you just have self-deploy and user driven profiles then a model check or something to ensure TPM 2.0 is enabled). Then what I was doing was applying the clean image again and using a post action to reboot to OOBE because even after using the Prepare Windows for Capture step to get rid of the client, it would still show up as hybrid. I also add a sleep step to the script at the end for about 5 minutes to make sure the correct autopilot profile is assigned.

  4. Hey Harm! Thanks so much for this useful information and instructions! I was able to replicate it and it works! Question for you: Do you think this is possible to deploy this script through Intune?

  5. Thank you so much for this useful information and instructions! We were able to replicate this and works great locally! Question for you: Do you think this script can be deployed through Intune? We have a ton of existing devices in our environment and want to mass upload the hash without touching individual devices.

    • Yes, you could deploy the script using Intune using the Scripts pane in Devices but don’t forget to remove the shutdown line 😉 By deploying it as s script, not a Win32 package, it will only run once if succesful. Assign it to one device and see if that works and then you can assign it to more devices.

      Those devices in your environment, are they joined to Intune using Hybrid or Workplace join? There is a setting in the deployment profile to convert devices to Autopilot devices

  6. I noticed Get-WindowsAutopilotInfo now has an AssignedComputerName parameter and I was wondering if there was a way to upload that alongside the group tag with this method? The main pain point for autopilot right now is the naming scheme but being able to use UI++ to collect the site and asset number to create the computer name and pass that along to the script would be great and allow for the auto import of devices to our asset management system too by using the first part of the name for the site and the last part of the asset number.

    • You can adjust the autopilot.ps1 script with that parameter of course, you could wrap a script around it to call the get-windowsautopilotinfo.ps1 script with a parameter… Site and asset sounds like SCCM? No experience in that myself 🙂

      • Sorry, site probably wasn’t the best word to use. I’m at a school district, so the naming scheme I would be shooting to replicate from SCCM would be the three letter initials for the individual schools followed by the 5 digit asset number for internal tracking. I also thought this was the upload hash script that pushes the hash and group tag using MSGraph. I had no idea you could use an App ID and Secret with get-windowsautopilotinfo, so I’m definitely switching to your method since it simplifies everything and solves my problem, lol.

    • 😊You could also use multiple Deployment profiles based on dynamic groups that are filled with group tags. In the profile you can specify the first few letters and a randy number between a certain range. Option 😅

    • I did something similar, my method was once it was autopiloted and given the right tag I then had a Deployment profile assigned to a group with dynamic membership rule containing the tag, the profile allowed me to pre-provision the machines so as they were in the group the profile was set to name the machine so I had our naming convention L-EXO-%serial% and it used the device serial number to temporarily name and then you can always rename afterwards once device is in intune.

  7. Thank you so much for this useful information and instructions. I have one question related to secrets key and AppID, In current scenario secrets key and AppID is visible and can be compromised. how we can avoid that.

    • Thank you 🙂 And I understand your point, the API permissions are there and can be used. I think using the SecretManagement or Azure Key vault could be an option to store and retrieve those credentials from, having to type an unlock password for that would be something I guess…

      Will put that on my To-Do list !

      • I have one question related to secrets key and AppID, In current scenario secrets key and AppID is visible and can be compromised. how we can avoid that.

        I would appriciate you if you can help in this regard.

        Thanks,
        Manu Kamboj

  8. It’s not working here. What are I doing wrong:

    powershell.exe -executionpolicy bypass -file D:\Autopilot.ps1
    Name Version Source Summary —- ——- —— ——- nuget 2.8.5.208 https://onege… NuGet provider for the OneGet meta-package manager Connected to Intune tenant 5c885ec7-c6cf-45b9-ac4c-f657fa82845f using app-based authentication (Azure AD authentication not supported)
    Gathered details for device with serial number: 7DDXPN3
    Add-AutopilotImportedDevice : System.Net.Http.HttpRequestException: 401 Unauthorized
    {“error”:{“code”:”UnknownError”,”message”:”{\”ErrorCode\”:\”Forbidden\”,\”Message\”:\”{\r\n \\”version\\”: 3,\r\
    \n \\”Message\\”: \\”An error has occurred – Operation ID (for customer support): 00000000-0000-0000-0000-000000000
    000 – Activity ID: bd548cc9-84b4-4747-b50c-72ddf471fdea – Url: https://fef.msub01.manage.microsoft.com/DeviceEnrollment
    FE_2305/StatelessDeviceEnrollmentFEService/deviceManagement/importedWindowsAutopilotDeviceIdentities?api-version=5022-1
    2-08\\”,\r\n \\”CustomApiErrorPhrase\\”: \\”\\”,\r\n \\”RetryAfter\\”: null,\r\n \\”ErrorSourceService
    \\”: \\”\\”,\r\n \\”HttpHeaders\\”: \\”{\\\\”WWW-Authenticate\\\\”:\\\\”Bearer realm=\\\\\\\\”
    urn:intune:service,f2f6fa41-932f-4d25-9e56-14ec49d3405a,f0f3c450-59bf-4f0d-b1b2-0ef84ddfe3c7,3e9c57b9-808d-4aa0-9500-4b
    2d369279e7\\\\\\\\”\\\\”}\\”\r\n}\”,\”Target\”:null,\”Details\”:null,\”InnerError\”:null,\”InstanceAnnotat
    ions\”:[]}”,”innerError”:{“date”:”2023-05-31T12:16:37″,”request-id”:”bd548cc9-84b4-4747-b50c-72ddf471fdea”,”client-requ
    est-id”:”bd548cc9-84b4-4747-b50c-72ddf471fdea”}}}
    At C:\Program Files\WindowsPowerShell\Scripts\Get-WindowsAutoPilotInfo.ps1:331 char:17
    + … imported += Add-AutopilotImportedDevice -serialNumber $
    .’Device Seri …
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : NotSpecified: (:) [Write-Error], WriteErrorException
    + FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException,Add-AutopilotImportedDevice

  9. Hi Harm!! Firtstly thanks for this. However when i try to run the script now it comes up with error , has anything changed?

  10. Hello, what do you use the shutdown command for?
    We have a deployment with AzureAd-registered devices and local users, we want to move them to AzureAd-Joined profiles with Autopilot, we have to factory reset these devices to make the migration?

    • I used the shutdown command so that you don’t have to do it yourself 😉 This is so that when you turn it on, it will start the Autopilot process correctly. (This part is done on a clean / fresh installation in the first screen (Shift-F10) after deployment)

      You could also join the machine to your Azure AD from the Settings/Accounts menu. That way, you will also get Intune packages/settings, etc. But the user could choose to be an admin then. That’s not what you want. (Or you should do it for them and choose that the account is a normal user)

      Uploading the hardware hash, factory reset/wipe with Windows 11 ISO USB, and enrolling into Autopilot is better. Intune manages clean machines and everything on it, no things that the local (Admin?) users have put on there…

  11. Hi, I received an error “Connect-MgGraph:The provided access token has expired. Set a valid access token to -AccessToken parameter and try again”. Any ideas about what is happening?

      • Created a new App Registration in my tenant, used that App Registration to upload a hardware-hash for one of my VMs… It just works? I don’t know what’s going on, did you try another network? (Firewall issue perhaps? Conditional Access, can you check the sign-in logs?)

  12. Hey Harm, I tried the same app on a virtual machine and it worked as expected. Probably it’s a problem with my physical laptop. I’ll try to format it and try again. Thank You for your support.

  13. Failing with below error with the 3.9 version

    Administrator:
    E: \Autopi10tLlK>powershe11. exe -executionpolicy
    bypass -file
    Source
    . \autopi10tLlK . PSI
    Summary
    Name
    nuget
    Version
    2.8.s. 288
    https : //onege. .
    NuGet provider for the OneGet meta-package manager
    Installing module WindowsAutopi10tIntune
    Connected to Intune tenant 49e84289-ß89e-4bdd-ac8c-22aeßßSf43d6 using app-based authentication (Azure AD authentication not s
    upported)
    New- Ci mSession
    The WinRM client cannot process the request. If the authentication scheme is different from Kerberos,
    or if the client computer is not joined to a domain, then HTTPS transport must be used or the destination machine must
    be added to the TrustedHosts configuration setting. Llse winrm. cmd to configure TrustedHosts. Note that computers in
    the TrustedHosts list might not be authenticated. You can get more information about that by running the following
    command: winrm help config.
    At C: \Program PSI :218 char:15
    $session
    New- CimSession -ComputerName Scamp -Credential $Credentia .
    + Categorylnfo
    + FullyQua1ifiedErrorId
    + PSComputerName
    . NotEnab1ed: ( : ) [New-CimSession], CimException
    HRESLILT 8x883388e4,Microsoft . Management . Infrastructure. CimCmd1ets . NewCimSessionCommand
    . ITAUK
    Get-Cimlnstance .
    Cannot bind argument to parameter ‘CimSession’ because it is null.
    At C: \Program PSI : 223 char:42
    $serial
    (Get-Cimlnstance -CimSession $session -Class V,’in32
    + Categorylnfo
    + FullyQua1ifiedErrorId
    . InvalidData: ( : ) [Get-Cimlnstance], Parameter8indingVa1idationException
    . ParameterArgumentVa1idationErrorNu11NotA110wed ,Microsoft . Management . Infrastructure. CimCm
    dlets . GetCimInstanceCommand
    Get-Cimlnstance .
    Cannot bind argument to parameter ‘CimSession’ because it is null.
    At C: \Program PSI : 226 char:45
    $devDetai1
    + Categorylnfo
    (Get-Cimlnstance -CimSession $session -Namespace .
    . InvalidData: ( : ) [Get-Cimlnstance], Parameter8indingVa1idationException
    + FullyQua1ifiedErrorId
    . ParameterArgumentVa1idationErrorNu11NotA110wed ,Microsoft . Management . Infrastructure. CimCm
    dlets . GetCimInstanceCommand
    Get-Cimlnstance .
    Cannot bind argument to parameter ‘CimSession’ because it is null.
    At C: \Program PSI : 248 char: 38
    $cs = Get-Cimlnstance -CimSession $session -Class Win32 C .
    + Categorylnfo
    + FullyQua1ifiedErrorId
    . InvalidData: ( : ) [Get-Cimlnstance], Parameter8indingVa1idationException
    . ParameterArgumentVa1idationErrorNu11NotA110wed ,Microsoft . Management . Infrastructure. CimCm
    dlets . GetCimInstanceCommand

    • As you can see in the comment just above your one, I tried it yesterday and worked out fine. Did you modify it perhaps? I see cimsession things, are you doing this remotely to another client?

  14. Hi,
    I am getting the error
    Add-AutopilotImportedDevice : Microsoft.Graph.PowerShell.Authentication.Helpers.HttpResponseException: Response Status code does not indicate success: Unauthorized (Unauthorized)

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.