Skip to content

Fix national/sovereign cloud exports hitting commercial Graph endpoint (#117) - #122

Open
Eduard Arbona (earbona23) wants to merge 1 commit into
microsoft:mainfrom
earbona23:fix/national-cloud-graph-batch-endpoint
Open

Eduard Arbona (earbona23) wants to merge 1 commit into
microsoft:mainfrom
earbona23:fix/national-cloud-graph-batch-endpoint

Conversation

@earbona23

Copy link
Copy Markdown

Problem

On a national/sovereign cloud tenant (GCC-High / USGov, USGovDoD, China, ...) Export-Entra fails with:

401 Unauthorized
{"error":{"code":"InvalidAuthenticationToken","message":"InvalidCloudInstance", ...}}
POST https://graph.microsoft.com/v1.0/$batch

even though Connect-EntraExporter/Connect-MgGraph -Environment 'USGov' authenticated correctly. Rolling back to 2.0.7 works. (Fixes #117)

Root cause

src/internal/Invoke-GraphBatchRequest.ps1 hardcodes the base Graph URI:

$uri = "https://graph.microsoft.com"
$requestUri = "$uri/$graphVersion/`$batch"

That absolute URI is handed to Invoke-MgRestMethod, which targets it verbatim instead of resolving against the connected environment's Graph host. So every batch request (and the whole export, since 3.x batches everything) goes to the commercial cloud regardless of the environment you connected to — the token is valid, but for the wrong cloud instance → InvalidCloudInstance. The paginated @odata.nextLink host stripping on line ~332 was hardcoded to the same commercial host.

Fix

Resolve the Graph endpoint from the currently connected environment and use it for both the $batch URI and the nextLink host stripping:

$mgContext = Get-MgContext
if ($mgContext -and $mgContext.Environment) {
    $graphEndpoint = (Get-MgEnvironment -Name $mgContext.Environment -ErrorAction SilentlyContinue).GraphEndpoint
}
if (-not $graphEndpoint) { $graphEndpoint = "https://graph.microsoft.com" }

This defers the endpoint list to the Graph SDK's own environment table (Get-MgEnvironment), so USGov → graph.microsoft.us, USGovDoD → dod-graph.microsoft.us, China → microsoftgraph.chinacloudapi.cn, and any future sovereign cloud the SDK adds all work with no further changes. Commercial cloud behavior is unchanged, and an unresolvable environment falls back to the commercial endpoint.

Only Microsoft.Graph.Authentication cmdlets already required by the module are used (Get-MgContext, Get-MgEnvironment) — no new dependency.

Verification

  • Parser.ParseFile — no syntax errors.

  • PSScriptAnalyzer — no new findings on the changed lines (only pre-existing repo-wide alias/Write-Host warnings remain).

  • Functional test dot-sourcing the function with mocked Get-MgContext/Get-MgEnvironment/Invoke-MgRestMethod, asserting the resulting $batch URI per environment:

    Environment Resolved $batch URI
    USGov https://graph.microsoft.us/v1.0/$batch
    USGovDoD https://dod-graph.microsoft.us/v1.0/$batch
    China https://microsoftgraph.chinacloudapi.cn/v1.0/$batch
    Global https://graph.microsoft.com/v1.0/$batch
    (unresolvable) https://graph.microsoft.com/v1.0/$batch (fallback)

Related: #118 (updating Connect-EntraExporter's sovereign cloud handling) is addressed separately.

Invoke-GraphBatchRequest hardcoded https://graph.microsoft.com as the base
URI for the $batch endpoint (and for stripping the host from paginated
nextLink URLs). Because that absolute URI is passed to Invoke-MgRestMethod,
the SDK targets it verbatim instead of the connected environment's Graph
host. On a national/sovereign cloud (USGov, USGovDoD, China, ...) every
batch request therefore goes to the commercial cloud and fails with
401 InvalidCloudInstance, even though Connect-MgGraph -Environment
authenticated correctly.

Resolve the Graph endpoint from the connected environment via
(Get-MgEnvironment -Name (Get-MgContext).Environment).GraphEndpoint, with a
fallback to the commercial endpoint when it can't be resolved. This defers
the endpoint list to the Graph SDK's own environment table, so new sovereign
clouds are supported without further changes. The paginated nextLink host is
stripped using the same resolved endpoint.

Fixes microsoft#117
@earbona23

Eduard Arbona (earbona23) commented Sep 10, 2026 •

Copy link
Copy Markdown
Author

Sam Erde (@SamErde) Merill Fernando (@merill) — this fixes the endpoint issue filed in #117: Connect-EntraExporter builds the Graph base URL from the commercial cloud regardless of the environment passed, so sovereign/national tenants export against graph.microsoft.com instead of their own endpoint.

The change is small and the companion docs PR is #123, which covers #118. Both are green and merge cleanly. Whenever there's a window for triage, I'm around to adjust anything.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approval recommended

No unresolved review comments remain, and all reviewed changes preserve fallback behavior.

Pull request overview

Fixes sovereign-cloud exports by resolving the Microsoft Graph endpoint for the connected environment.

Changes:

  • Uses environment-specific endpoints for batch requests and pagination.
  • Preserves commercial-cloud fallback behavior.
File summaries
File Description
src/internal/Invoke-GraphBatchRequest.ps1 Adds environment-aware Graph endpoint resolution.
Review details
  • Files reviewed: 1/1 changed files
  • Comments generated: 0
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

@SamErde Sam Erde (SamErde) left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Contributing Review: Recommend Approval

Reviewed commit 89cd337f9dd5d1ba464d5ebacd365294d5796add.1

The change addresses #117's hardcoded-commercial-endpoint failure by resolving the batch host from the active Graph environment, including continuation requests.

Evidence

  • Invoked the exact changed function with recording Graph mocks for Global, USGov, USGovDoD, China, and BleuCloud, each using v1.0 and beta.
  • All 10 two-page scenarios sent both requests to the expected cloud's batch endpoint, converted nextLink to a relative batch URL, and returned both results.
  • Reviewed the existing retry/error paths around the changed code; the patch does not change permission requests, token handling, or the exported data model.
  • No changed source parse errors or material new regression found in the supported-environment paths.

The fallback to commercial Graph when environment metadata cannot be resolved remains a limitation: this review does not claim that an unresolvable custom environment will export correctly. The verified fix is for environments resolved by the installed Graph SDK.

Validation limits: No live tenant authentication or export was performed. The only recorded check on this head is a passing CLA check; that is not functional CI evidence. This is a contributing technical review, with merge/release decisions left to the maintainers.


Footnotes

  1. Agent: OpenAI Codex (1 agent). Model: gpt-6-astra. Reasoning effort: high, verified from this review session's metadata. Skill: engineering:code-review. Tools: GitHub API/CLI, Git, PowerShell 7.6.7 source analysis and isolated mocked probes, Microsoft documentation. ↩

@earbona23

Copy link
Copy Markdown
Author

Thanks for the thorough review and for exercising all five environments, Sam Erde (@SamErde). Nothing else is pending on my side; this and #123 are ready whenever a maintainer with merge rights has a window.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

USGov environment using commercial endpoints

3 participants