maik.ing | the terminal garden
2 days ago

Scribble: Get-WindowsAutopilotInfo, the Graph API, and the "Need Admin Approval" Trap

Welcome back to the Terminal Garden! Today, we're taking a look at a true classic from my daily IT life—a typical case of Building, Breaking, and Automating.

The scenario is simple: A new notebook is unboxed, you are sitting in the Windows OOBE (Out-of-Box Experience), you open the console, and you just want to quickly upload the hardware hash to Microsoft Intune via script. It's supposed to be an absolute standard procedure—until Microsoft Entra ID suddenly decides to batten down the hatches.

💥 The Problem: AADSTS90094 during Autopilot Upload

A colleague, officially assigned the Intune Administrator role in the tenant, prepares the device and runs the well-known command:

PowerShell

Get-WindowsAutopilotInfo.ps1 -Online

The interactive Microsoft sign-in window pops up, credentials are entered—but instead of a successful upload in green text, this roadblock appears:

Need admin approval
Microsoft Graph Command Line Tools needs permission to access resources in your organisation that only an admin can grant.
Error Code: 90094

🕵️‍♂️ The Illusion of the Global Admin

The crazy part: If you test the exact same command as a Global Administrator on your own machine, everything runs flawlessly. Why?

Under the hood, the script uses the first-party app Microsoft Graph Command Line Tools. As a Global Admin, you've often unknowingly granted the permissions (scopes) requested by the script for your own account in the past (User Consent), or you simply have the inherent rights to accept them on the fly.

The regular Intune Admin, however, hits an invisible wall. Entra ID is merciless here: If even a single permission requested by the script is missing from the global organizational approval (Tenant-wide Admin Consent), the entire login attempt is blocked.

🛠️ The Fix: Stop Guessing, Start Reading!

Instead of blindly clicking together permissions in the Azure Portal, playing app registration roulette, or digging through cryptic JSON logs, we can use PowerShell to simply ask the script itself what it actually wants.

Since the Autopilot script sits open-source on the local drive, we can pull the required scopes directly from the code. Just run this command locally:

PowerShell

Get-Content (Get-Command Get-WindowsAutopilotInfo.ps1).Path | Select-String "Scopes"

Depending on the script version, the output will look something like this:

Plaintext

Connect-MgGraph -Scopes "DeviceManagementServiceConfig.ReadWrite.All", "DeviceManagementManagedDevices.ReadWrite.All", "Device.ReadWrite.All", "Group.ReadWrite.All", "GroupMember.ReadWrite.All"

There is our culprit in black and white! In most cases, it's exactly the group permissions (Group.ReadWrite.All, GroupMember.ReadWrite.All) that are missing from the global consent for this app.

Rolling Out the Permissions Tenant-Wide

To finally cut the Gordian knot for all authorized employees in the tenant, we (as a Global Admin) need to grant these scopes globally once:

1. Disconnect the existing session:

To avoid caching issues, we first toss out any old tokens.

PowerShell

Disconnect-MgGraph

2. Reconnect with the exact scopes:

We now use the exact list of rights the script spit out earlier.

PowerShell

Connect-MgGraph -Scopes "DeviceManagementServiceConfig.ReadWrite.All", "DeviceManagementManagedDevices.ReadWrite.All", "Device.ReadWrite.All", "Group.ReadWrite.All", "GroupMember.ReadWrite.All"

3. Grant global consent:

The sign-in window opens. Here, we log in with our Global Admin account. In the following consent prompt comes the most crucial step: Check the box for "Consent on behalf of your organization" and click Accept.

⚠️ The Most Important Final Step: Clear the Cache!

If your colleague now enthusiastically runs the command again in the still-open OOBE window, they will very likely run into an error again.

The reason is simple: The Windows Web Account Manager (WAM) and the Graph session still have the old, blocked token hanging in the background cache.

The solution: Hard reboot the notebook in OOBE via the power button or console command (shutdown /r /t 0). The device will simply boot back to the language selection screen. After that, freshly open the console via Shift + F10, start the script—and the upload will go through smoothly.

Happy Automating!

powered by Scribbles