Route a PowerShell script through GraphWarden

A PowerShell script using Microsoft.Graph cmdlets connects to GraphWarden by passing a custom access token and a Graph endpoint override. After Connect-MgGraph, every cmdlet you already use (Get-MgUser, New-MgGroup, and the rest) works unchanged. This page shows the complete setup.

Microsoft.Graph v2.x on PowerShell 5.1 or 7+

Prerequisites

- PowerShell 5.1 or 7+ - `Microsoft.Graph` module v2.x — install once with `Install-Module Microsoft.Graph -Scope CurrentUser` - A GraphWarden proxy URL reachable from the machine running the script - A Proxy Client ID and Proxy Client Secret issued by GraphWarden App Admin for the App Identity that represents this script

Route a PowerShell script with an AI assistant

Route my PowerShell script using Connect-MgGraph through GraphWarden.

My script currently calls Connect-MgGraph with client-credential auth against https://graph.microsoft.com.

I need:
1. The tested pattern to acquire a token from the GraphWarden proxy's token endpoint
2. A Connect-MgGraph invocation that uses that token against the proxy as the Graph endpoint
3. A sanity check that Get-MgContext confirms the endpoint is the proxy

Reference documentation: https://graphwarden.com/llms.txt

Ask me for my proxy URL and proxy credentials.

Reference: llms.txt

The two overrides

A direct-to-Graph PowerShell script does two things: it calls Connect-MgGraph (which acquires a token from Azure AD) and then issues cmdlets that hit https://graph.microsoft.com. To route through GraphWarden you override both.

  • Token acquisition — post your Proxy Client ID and Proxy Client Secret to POST {proxy-host}/proxy/token (per the proxy architecture — recon #210). The response is a proxy JWT; you pass it to Connect-MgGraph as -AccessToken.
  • Graph endpointConnect-MgGraph normally targets https://graph.microsoft.com. Microsoft.Graph v2.x exposes -Environment (for the set of named clouds Microsoft ships) and honours the MICROSOFT_GRAPH_API_ENDPOINT environment variable for custom endpoints. Setting that variable to your proxy URL before calling Connect-MgGraph points every subsequent cmdlet at the proxy.
The exact `Connect-MgGraph` override syntax depends on the `Microsoft.Graph` module version. The sample below targets v2.x; recon #214 is the primary source for endpoint-override behaviour. If you are pinned to v1.x, the `-AccessToken` parameter accepts a plain string rather than a `SecureString` — check your module with `Get-Module Microsoft.Graph -ListAvailable`.

Complete script (client-credentials flow)

The script below reads three environment variables, acquires a proxy JWT, and runs a single verification call. It is copy-paste runnable once the three variables are set. Inline comments flag the GraphWarden-specific lines.

# 1. Configuration — read from the environment, never hardcode secrets.
$ProxyUrl      = $env:GRAPHWARDEN_PROXY_URL      # e.g. https://proxy.example.com
$ClientId      = $env:GRAPHWARDEN_CLIENT_ID      # Proxy Client ID from App Admin
$ClientSecret  = $env:GRAPHWARDEN_CLIENT_SECRET  # Proxy Client Secret from App Admin

if (-not $ProxyUrl -or -not $ClientId -or -not $ClientSecret) {
    throw "Set GRAPHWARDEN_PROXY_URL, GRAPHWARDEN_CLIENT_ID, and GRAPHWARDEN_CLIENT_SECRET before running."
}

# 2. Acquire a proxy JWT via client_credentials against the proxy token endpoint.
#    Authority is the proxy, NOT Azure AD. See recon #210.
$TokenResponse = Invoke-RestMethod `
    -Method Post `
    -Uri "$ProxyUrl/proxy/token" `
    -ContentType 'application/x-www-form-urlencoded' `
    -Body @{
        grant_type    = 'client_credentials'
        client_id     = $ClientId
        client_secret = $ClientSecret
    }

$SecureToken = ConvertTo-SecureString -String $TokenResponse.access_token -AsPlainText -Force

# 3. Point Microsoft.Graph at the proxy BEFORE Connect-MgGraph. The env var is
#    read when the connection is established; setting it afterwards has no effect.
$env:MICROSOFT_GRAPH_API_ENDPOINT = $ProxyUrl

# 4. Connect using the proxy JWT. -NoWelcome suppresses the banner so scripts stay quiet.
Connect-MgGraph -AccessToken $SecureToken -NoWelcome

# 5. Verification call — standard cmdlet, now routed through GraphWarden.
Get-MgUser -Top 1 | Select-Object Id, DisplayName, UserPrincipalName

The important line is Connect-MgGraph -AccessToken $SecureToken. Everything after that is standard Microsoft.Graph — cmdlets compose request URIs against the endpoint set in MICROSOFT_GRAPH_API_ENDPOINT, so Get-MgUser issues GET {proxy-host}/v1.0/users with the proxy JWT attached.

Verifying the connection

Get-MgContext returns the current connection state. Confirm the endpoint is the proxy, not the public Graph host.

$context = Get-MgContext

Write-Host "Account:          $($context.Account)"
Write-Host "AuthType:         $($context.AuthType)"
Write-Host "Graph endpoint:   $([Microsoft.Graph.PowerShell.Authentication.GraphSession]::Instance.GraphEndpoint)"

if ($env:MICROSOFT_GRAPH_API_ENDPOINT -and
    $env:MICROSOFT_GRAPH_API_ENDPOINT -ne 'https://graph.microsoft.com') {
    Write-Host "Routing through GraphWarden: $env:MICROSOFT_GRAPH_API_ENDPOINT"
} else {
    Write-Warning "MICROSOFT_GRAPH_API_ENDPOINT is not set — cmdlets will hit Microsoft Graph directly."
}

The $env:MICROSOFT_GRAPH_API_ENDPOINT check is the quickest way to catch a forgotten override; the SDK property confirms what the module actually resolved at connection time.

Running your existing script

Once the connection is established every cmdlet you already use flows through the proxy. You do not rewrite your script — Get-MgUser, New-MgGroup, Set-MgUserLicense, and the other cmdlets compose the same request URIs, and the proxy enforces the ruleset bound to your App Identity on each call.

One reminder: keep the Connect-MgGraph call at the top of your script and acquire a fresh proxy JWT on each script run. Proxy JWTs expire after roughly one hour; for long-running scripts, wrap the token acquisition in a helper function that refreshes on 401.

Troubleshooting

The five failure modes below cover the common onboarding surprises when wiring a PowerShell script against GraphWarden for the first time.

AADSTS* error from Connect-MgGraph

The script is still authenticating against Azure AD instead of the proxy — usually because -AccessToken was not passed (so Connect-MgGraph fell back to interactive / device-code sign-in) or because the Proxy Client ID and Proxy Client Secret are wrong. Verify the two values copied from GraphWarden App Admin match the App Identity for this script, and confirm Invoke-RestMethod against /proxy/token returned a 200 with an access_token field.

403 Forbidden from Get-MgUser

A rule in the ruleset bound to your App Identity returned a block verdict. The response body names the matched rule. Review the ruleset in GraphWarden App Admin — check the match pattern, the conditions, and the scopes your App Identity was granted. The What-If Simulator replays the request without touching production Graph.

502 Bad Gateway

The proxy is reachable but Microsoft Graph returned a non-2xx upstream response. Check the proxy's health endpoint and Graph's status page; retry with the same payload after a short backoff.

Cmdlet appears to hit graph.microsoft.com directly

The MICROSOFT_GRAPH_API_ENDPOINT environment variable was not set before Connect-MgGraph, or was set in a parent process that the PowerShell session did not inherit. Run Get-MgContext and compare the reported endpoint against the proxy URL. If the variable is missing, set it explicitly in the script (as shown in the sample above) rather than relying on session inheritance.

PowerShell 5.1 raises a TLS 1.2 error

Windows PowerShell 5.1 defaults to TLS 1.0 / 1.1 on older .NET Framework versions. GraphWarden serves TLS 1.2+. Add the one-liner below before Invoke-RestMethod:

[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12

PowerShell 7+ negotiates TLS 1.2+ by default and does not need this workaround.

Last reviewed:

Last reviewed: .