Route legacy AzureAD and MSOnline PowerShell modules through GraphWarden

The legacy AzureAD and MSOnline PowerShell modules are deprecated by Microsoft but still widely deployed in enterprise automation. Both modules can be routed through GraphWarden with the same override pattern as Microsoft.Graph: acquire a proxy JWT, pass it to Connect-AzureAD or Connect-MsolService, and existing cmdlets flow through the proxy. This page also flags the endpoint differences that matter when planning a migration.

AzureAD v2.x and MSOnline v1.x through the proxy (maintenance path)

Prerequisites

- Windows PowerShell 5.1 (the MSOnline module is a PS 5.1-only module; AzureAD works on 5.1 and on PowerShell 7 with the `Windows PowerShell Compatibility` layer) - `AzureAD` module v2.x (`Install-Module AzureAD -Scope CurrentUser`) OR `MSOnline` module v1.x (`Install-Module MSOnline -Scope CurrentUser`) - A GraphWarden proxy URL reachable from the script host - A Proxy Client ID and Proxy Client Secret issued by GraphWarden App Admin for the App Identity that represents this script
Microsoft has deprecated both the `AzureAD` and `MSOnline` modules. New development SHOULD use `Microsoft.Graph` (see the [PowerShell quickstart](./quickstart)). This page covers routing existing scripts through GraphWarden so they can keep running during a migration window — not as a long-term recommendation.

Migrate a legacy AzureAD or MSOnline script with an AI assistant

Help me route an existing PowerShell script that uses the AzureAD or MSOnline module through GraphWarden, and plan a migration to Microsoft.Graph.

My script currently calls Connect-AzureAD or Connect-MsolService with credential-based auth against Azure AD directly.

I need:
1. The pattern to acquire a proxy JWT from GraphWarden's /proxy/token endpoint
2. A Connect-AzureAD -AadAccessToken invocation that routes through the proxy
3. A mapping from my current AzureAD/MSOnline cmdlets to Microsoft.Graph equivalents so I can plan the migration

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

Ask me for my proxy URL, proxy credentials, and which legacy cmdlets the script relies on.

Reference: llms.txt

Why this page exists

Enterprise PowerShell automation written between 2016 and 2020 overwhelmingly targeted the AzureAD and MSOnline modules. Many of those scripts are still in production — they run under scheduled tasks, service accounts, and runbooks that compliance owners cannot rewrite overnight. Routing them through GraphWarden unblocks the audit-and-ruleset story without forcing a same-week migration.

The load-bearing fact: both modules speak HTTP to Azure AD or legacy Azure AD Graph (graph.windows.net), and both accept an externally-acquired access token via a connect-time parameter. That is the seam GraphWarden uses.

AzureAD module through GraphWarden

The AzureAD module exposes -AadAccessToken on Connect-AzureAD. When you pass a token, the module skips its own interactive / device-code flow and uses what you supplied for every subsequent cmdlet. GraphWarden issues a proxy JWT from /proxy/token; the AzureAD cmdlets then call through the proxy with that JWT as the Authorization: Bearer header.

# 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. Force TLS 1.2 — Windows PowerShell 5.1 defaults to older protocols.
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12

# 3. Acquire a proxy JWT from the GraphWarden token endpoint (not Azure AD).
$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
    }

# 4. Connect-AzureAD accepts a pre-acquired token via -AadAccessToken.
#    The module uses this token for every cmdlet that follows.
Connect-AzureAD `
    -AadAccessToken $TokenResponse.access_token `
    -AccountId      'service-principal-upn@contoso.onmicrosoft.com'

# 5. Existing cmdlets work unchanged — now routed through GraphWarden.
Get-AzureADUser -Top 1 | Select-Object ObjectId, DisplayName, UserPrincipalName

The AccountId parameter is a display-only value for the AzureAD module's session context — it does not affect authentication. Use the UPN of the service principal or account you want shown in Get-AzureADCurrentSessionInfo output.

`AzureAD` cmdlets call the older Azure AD Graph API (`graph.windows.net`), not Microsoft Graph (`graph.microsoft.com`). Your GraphWarden ruleset must have endpoint coverage for the Azure AD Graph paths your script touches; if your proxy was scoped to Microsoft Graph only, some cmdlets will return `404 Not Found` or pass through with no ruleset matching. Verify endpoint coverage with your GraphWarden administrator before migrating a production script.

MSOnline module through GraphWarden

The MSOnline module is older than AzureAD: it predates the standardised -AadAccessToken parameter and targets the legacy MSOnline service endpoint (provisioningapi.microsoftonline.com) for most of its cmdlets. Connection uses Connect-MsolService, which accepts -AdGraphAccessToken and -MsGraphAccessToken parameters for externally-acquired tokens.

# Same token-acquisition block as above — shown abridged here.
$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
    }

# Connect-MsolService wants TWO tokens — one for Azure AD Graph and one for
# Microsoft Graph. Passing the same proxy JWT for both is the pragmatic choice
# when the proxy is the authority for everything.
Connect-MsolService `
    -AdGraphAccessToken $TokenResponse.access_token `
    -MsGraphAccessToken $TokenResponse.access_token

# Existing cmdlets — some route through the proxy, some do not (see callout below).
Get-MsolUser -MaxResults 1 | Select-Object ObjectId, UserPrincipalName
MSOnline cmdlets that query the legacy provisioning endpoint (`provisioningapi.microsoftonline.com`) are NOT routed through GraphWarden — that endpoint is outside the Microsoft Graph and Azure AD Graph namespaces the proxy intercepts. Only the cmdlets that transit the Azure AD Graph endpoint (for example, `Get-MsolUser`, `Get-MsolGroup`) participate in ruleset enforcement. For full coverage, migrate the affected cmdlets to `Microsoft.Graph` where every cmdlet maps to a Microsoft Graph endpoint the proxy controls.

The migration priority is therefore MSOnline first (partial proxy coverage), then AzureAD (full Azure AD Graph coverage but deprecated), then Microsoft.Graph (fully covered and the long-term supported surface).

Migration guide (AzureAD / MSOnline to Microsoft.Graph)

A rough cmdlet map for the common enterprise tasks. Exact parameter shapes differ — consult the Microsoft.Graph cmdlet reference before running these against production.

Legacy cmdlet Microsoft.Graph equivalent
Get-AzureADUser Get-MgUser
Get-AzureADGroup Get-MgGroup
Get-AzureADGroupMember Get-MgGroupMember
New-AzureADGroup New-MgGroup
Get-MsolUser Get-MgUser
Get-MsolRoleMember Get-MgDirectoryRoleMember
Set-MsolUserLicense Set-MgUserLicense
Connect-MsolService Connect-MgGraph

Once a script is on Microsoft.Graph, point it at the proxy using the Microsoft.Graph module page — the MICROSOFT_GRAPH_API_ENDPOINT environment-variable override is cleaner than the -AadAccessToken pattern shown on this page.

Troubleshooting

The failure modes below cover the common surprises when running legacy modules against GraphWarden for the first time.

AADSTS* error from Connect-AzureAD or Connect-MsolService

The module fell back to its own interactive auth flow — usually because the -AadAccessToken / -AdGraphAccessToken parameter was not passed, or because the Invoke-RestMethod call to /proxy/token returned an error that was not checked. Inspect $TokenResponse.access_token before the Connect call; if it is empty, the token request failed (401 from the proxy means the Proxy Client ID or Secret does not match what App Admin stored).

403 Forbidden from an AzureAD cmdlet (e.g. Get-AzureADUser)

A rule in the ruleset bound to your App Identity returned a block verdict on an Azure AD Graph path. The response body names the matched rule. Confirm that your ruleset has endpoint coverage for graph.windows.net paths — a ruleset scoped to Microsoft Graph only will NOT match Azure AD Graph paths, so either the request falls through (which looks like a generic 403) or the cmdlet hits an unproxied endpoint. Widen the ruleset or migrate the cmdlet.

MSOnline cmdlet succeeds but no audit entry appears

The cmdlet targeted the legacy provisioning endpoint (provisioningapi.microsoftonline.com), which GraphWarden does NOT intercept. The request bypassed the proxy and hit Microsoft directly. This is not a failure — it is the documented behaviour — but it means ruleset enforcement is silently skipped for that cmdlet. Migrate the specific cmdlet to Microsoft.Graph to regain audit coverage.

Windows PowerShell 5.1 raises a TLS 1.2 error on Invoke-RestMethod

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

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

PowerShell 7+ negotiates TLS 1.2+ by default. Note that the MSOnline module is PS 5.1 only, so the TLS override is mandatory for any MSOnline script.

Token expires mid-script (502 / 401 after an hour)

Proxy JWTs expire after roughly one hour. Long-running scripts should wrap the token acquisition in a helper function that re-requests on 401, then call Disconnect-AzureAD / Disconnect-MsolService and reconnect with the fresh token. AzureAD and MSOnline do not support silent token refresh — the connection must be rebuilt.

Last reviewed:

Last reviewed: .