How to Connect to Exchange Online PowerShell (Including GCC High)
If you’ve searched for “connect-exchangeonline,” you’re probably staring at a PowerShell prompt right now. You need to manage mailboxes, tweak transport rules, configure mail flow, or automate something that clicking through the Exchange admin center is too slow for.
Microsoft’s documentation gives you the cmdlet reference. What it doesn’t give you is a clean walkthrough of which authentication method to use, how certificate-based auth actually works for Exchange (it’s different from Graph), or how to make any of it work in GCC High. That’s what this guide is for.
One thing upfront: Basic Auth is dead. Microsoft retired it in October 2022. If you’re following a guide that shows New-PSSession with -Authentication Basic or Get-Credential piped into a remote session, that guide is obsolete. The Exchange Online Management module with modern auth is the only supported path now.
Install the Module
Before you connect, you need the Exchange Online Management module installed. Check if you already have it:
Get-Module ExchangeOnlineManagement -ListAvailable If that returns nothing, install it:
Install-Module ExchangeOnlineManagement -Scope CurrentUser Version matters. The V3 module (3.0+) uses REST-based cmdlets by default — they’re faster, don’t depend on WinRM, and don’t have the old 5-concurrent-session limit. If you have an older version installed:
Update-Module ExchangeOnlineManagement You want V3 or later. If you’re still on V2, you’re using legacy Remote PowerShell (RPS) sessions under the hood, which are slower and have connection limits.
Interactive Authentication (The Quick Way)
This is what you use when you’re sitting at your desk running commands manually:
Connect-ExchangeOnline -UserPrincipalName admin@contoso.com A browser window opens. You sign in. MFA is handled automatically. You’re connected.
Unlike Microsoft Graph, you don’t specify scopes. Exchange Online uses RBAC (Role-Based Access Control) roles instead of Graph API scopes. What you can do after connecting depends entirely on which Exchange roles are assigned to your account — Exchange Administrator, Recipient Management, Mail Recipients, etc.
To verify your connection:
Get-ConnectionInformation This shows your connected account, organization, connection method, and whether you’re using REST or RPS. Run this after connecting to confirm you’re where you think you are.
Role requirements: You need the Exchange Administrator role in Entra ID, or specific Exchange RBAC roles assigned in the Exchange admin center. Global Admin works too, but it’s overkill for Exchange management.
PowerShell 7 notes: On PS7, browser-based SSO is the default. If you’re working in a headless environment or SSH session where a browser can’t open, use -Device for device code flow (sign in on another device). If you want to enter credentials directly in the terminal instead of a browser, use -InlineCredential.
Certificate-Based Authentication (For Automation)
Interactive auth doesn’t work for scheduled tasks, Azure Automation runbooks, or any scenario where nobody is sitting at a browser. For that, you need an app registration with a certificate.
Step 1: Create an App Registration
This is the same process as setting up certificate auth for Microsoft Graph. In the Entra admin center:
- Go to Identity > Applications > App registrations > New registration
- Name it something descriptive (e.g., “Exchange Automation - Mail Flow Reports”)
- Set supported account types to Single tenant
- Click Register
- Note the Application (client) ID and Directory (tenant) ID
Step 2: Add Permissions and Assign an Exchange Role
This is where Exchange differs from Graph. You need to do two things:
In the app registration, go to API permissions > Add a permission > APIs my organization uses and search for “Office 365 Exchange Online.” Add the
Exchange.ManageAsAppapplication permission. Grant admin consent.Assign an Exchange Administrator role to the service principal. This is the step people miss. Unlike Graph (where API permissions alone are sufficient), Exchange requires the service principal to have an actual Entra ID directory role — typically Exchange Administrator. Go to Identity > Roles & administrators > Exchange Administrator > Add assignments and add your app’s service principal.
Without step 2, your certificate auth will connect successfully but every cmdlet will return (403) Forbidden.
Step 3: Create and Upload a Certificate
Generate a self-signed certificate:
$cert = New-SelfSignedCertificate -Subject "CN=ExchangeAutomation" `
-CertStoreLocation "Cert:CurrentUserMy" `
-KeyExportPolicy Exportable `
-KeySpec Signature `
-KeyLength 2048 `
-NotAfter (Get-Date).AddYears(2)
Export-Certificate -Cert $cert -FilePath ".ExchangeAutomation.cer" Upload the .cer file to your app registration under Certificates & secrets > Certificates > Upload certificate.
Step 4: Connect
Connect-ExchangeOnline -CertificateThumbprint $cert.Thumbprint `
-AppId "your-app-id" `
-Organization "contoso.onmicrosoft.com" No browser prompt. No interactive sign-in. The certificate authenticates the app directly.
Cross-platform note: -CertificateThumbprint only works on Windows because it reads from the Windows certificate store. On Linux or macOS, use -CertificateFilePath instead and point it to a .pfx file:
Connect-ExchangeOnline -CertificateFilePath "./ExchangeAutomation.pfx" `
-CertificatePassword (ConvertTo-SecureString "your-password" -AsPlainText -Force) `
-AppId "your-app-id" `
-Organization "contoso.onmicrosoft.com" Managed Identity Authentication (Azure Only)
If your script runs in Azure — Automation Account, Azure Function, Azure VM — managed identities are the cleanest option. No certificates or secrets to manage at all:
Connect-ExchangeOnline -ManagedIdentity -Organization "contoso.onmicrosoft.com" That’s it for system-assigned managed identities. For user-assigned managed identities, add the account ID:
Connect-ExchangeOnline -ManagedIdentity `
-ManagedIdentityAccountId "your-managed-identity-client-id" `
-Organization "contoso.onmicrosoft.com" Important: The managed identity still needs the Exchange Administrator role assigned to it in Entra ID — same as certificate-based auth. The managed identity eliminates credential management, not role requirements.
REST vs. RPS Sessions
The V3 module defaults to REST-based connections. This matters more than you might think:
REST (default in V3+):
- Faster cmdlet execution
- No WinRM dependency
- No concurrent session limits
- Works on PowerShell 7 without extra configuration
RPS (legacy Remote PowerShell):
- Limited to 5 concurrent sessions per tenant
- Requires WinRM on Windows
- Some cmdlets haven’t been ported to REST yet
If a cmdlet fails on REST with a confusing error, try adding -UseRPSSession to your Connect-ExchangeOnline call. If the cmdlet works with RPS, it just hasn’t been ported to REST yet. Microsoft is gradually moving all cmdlets to REST, but a few edge cases still require RPS.
Connect-ExchangeOnline -UserPrincipalName admin@contoso.com -UseRPSSession Only use this when you need it — REST is better in every other way.
If You’re in GCC High
Everything above works in GCC High with one critical addition: you must specify the Exchange environment.
Interactive in GCC High
Connect-ExchangeOnline -UserPrincipalName admin@contoso.us `
-ExchangeEnvironmentName O365USGovGCCHigh Without -ExchangeEnvironmentName O365USGovGCCHigh, the module tries to authenticate against the commercial endpoint. Your GCC High credentials won’t work there. You’ll get a token acquisition error that looks like an auth failure when it’s really just pointing at the wrong cloud.
Certificate-Based in GCC High
Connect-ExchangeOnline -CertificateThumbprint "your-thumbprint" `
-AppId "your-app-id" `
-Organization "contoso.onmicrosoft.com" `
-ExchangeEnvironmentName O365USGovGCCHigh Managed Identity in GCC High
Connect-ExchangeOnline -ManagedIdentity `
-Organization "contoso.onmicrosoft.com" `
-ExchangeEnvironmentName O365USGovGCCHigh What the Flag Actually Changes
When you set the environment to O365USGovGCCHigh, the module switches all its endpoints:
| Commercial | GCC High | |
|---|---|---|
| Exchange endpoint | outlook.office365.com | outlook.office365.us |
| Authentication | login.microsoftonline.com | login.microsoftonline.us |
| Azure portal | portal.azure.com | portal.azure.us |
The Environment Values
The flag name is -ExchangeEnvironmentName and the values aren’t intuitive:
| Cloud | -ExchangeEnvironmentName Value |
|---|---|
| Commercial | O365Default (default — don’t need to specify) |
| GCC | O365Default (same as commercial) |
| GCC High | O365USGovGCCHigh |
| DoD | O365USGovDoD |
GCC uses the same endpoints as commercial — only tenant-level configurations differ. GCC High and DoD use completely separate infrastructure.
Every Module Has Its Own Flag
This is where government cloud PowerShell gets confusing. Every Microsoft PowerShell module has a different parameter name and different values for the same concept. Here’s the cheat sheet:
| Module | Parameter | GCC High Value |
|---|---|---|
| Exchange Online | -ExchangeEnvironmentName | O365USGovGCCHigh |
| Microsoft Graph | -Environment | USGov |
| Azure (Az) | -Environment | AzureUSGovernment |
| PnP PowerShell | -AzureEnvironment | USGovernmentHigh |
| SharePoint Online | -Url | https://contoso-admin.sharepoint.us |
Five modules, four different parameter names, four different values. Nobody publishes this table, so you end up guessing or searching each module’s docs individually.
App Registrations in GCC High
When you create the app registration for certificate-based auth, you create it in the Azure Government portal (portal.azure.us), not the commercial portal. The process is identical, but the app exists in the government cloud. If you accidentally create the app in the commercial portal, you’ll get AADSTS700016: Application not found — the app exists in a different cloud than your tenant.
PowerShell Profile Tip
If you work in GCC High daily, set the environment as a default so you never forget it:
# Add to your PowerShell profile ($PROFILE)
$PSDefaultParameterValues['Connect-ExchangeOnline:ExchangeEnvironmentName'] = 'O365USGovGCCHigh' Now every Connect-ExchangeOnline call in that shell session defaults to GCC High without you specifying it. You can combine this with the same trick for Microsoft Graph to cover both modules.
Delegated Access (CSP / GDAP)
If you’re an MSP managing client tenants through a GDAP relationship:
Connect-ExchangeOnline -UserPrincipalName admin@partner.com `
-DelegatedOrganization customer.onmicrosoft.com This connects to the customer’s Exchange Online tenant using your partner credentials. You need a GDAP relationship with the Exchange Administrator role assigned.
For GCC High customers, add the environment flag:
Connect-ExchangeOnline -UserPrincipalName admin@partner.us `
-DelegatedOrganization customer.onmicrosoft.com `
-ExchangeEnvironmentName O365USGovGCCHigh Common Errors and Fixes
“The term ‘Connect-ExchangeOnline’ is not recognized”
The module isn’t installed. Run Install-Module ExchangeOnlineManagement -Scope CurrentUser and try again. If it’s installed but not recognized, try Import-Module ExchangeOnlineManagement explicitly — PowerShell module auto-loading occasionally fails.
Token acquisition errors / “AADSTS” errors during sign-in
Usually one of three things: you’re connecting to the wrong cloud (missing -ExchangeEnvironmentName), your account doesn’t have the right role, or Conditional Access policies are blocking the sign-in. Check which cloud your tenant is in — if you’re in GCC High vs. commercial, you need the environment flag.
“Fail to create a runspace because you have exceeded the maximum number of connections”
You’ve hit the 5-session limit for RPS connections. This only affects legacy RPS sessions, not REST. Fix it two ways: disconnect old sessions with Disconnect-ExchangeOnline -Confirm:$false, or switch to REST by removing the -UseRPSSession flag (or updating to V3 where REST is default).
“(403) Forbidden” on cmdlets after connecting with a certificate
Your app registration is missing the Exchange Administrator role. Having Exchange.ManageAsApp API permission isn’t enough — Exchange requires an actual Entra directory role assigned to the service principal. Go to Entra ID > Roles & administrators > Exchange Administrator and add your app.
“AADSTS700016: Application with identifier ‘xxx’ was not found”
Your app registration doesn’t exist in the tenant you’re connecting to. In GCC High, this almost always means you created the app in the commercial portal (portal.azure.com) instead of the government portal (portal.azure.us). The app needs to exist in the same cloud as your tenant.
“The term ‘Update-ModuleManifest’ is not recognized”
You’re missing PowerShellGet or PackageManagement modules, which the Exchange Online module depends on for REST-based connections. Update them:
Install-Module PowerShellGet -Force
Install-Module PackageManagement -Force Then restart PowerShell and try again.
Disconnecting
When you’re done:
Disconnect-ExchangeOnline -Confirm:$false The -Confirm:$false suppresses the “are you sure?” prompt — essential in scripts. Without it, your automated script will hang waiting for confirmation that nobody is there to give.
If you’re using RPS sessions: closing PowerShell without disconnecting leaves the sessions open on Microsoft’s side. They count against your 5-session limit until they expire (typically 15 minutes). If you’re hitting session limits, make sure your scripts always disconnect in a finally block:
try {
Connect-ExchangeOnline -UserPrincipalName admin@contoso.com
# Your Exchange commands here
}
finally {
Disconnect-ExchangeOnline -Confirm:$false
} REST connections don’t have this problem — they’re stateless.
Which Method Should You Use?
| Scenario | Method | Why |
|---|---|---|
| Ad-hoc admin tasks at your desk | Interactive | Simple, uses your identity and MFA |
| Scheduled scripts on a server | Certificate-based | No secrets to leak, no human needed |
| Azure Automation / Functions | Managed Identity | Zero credential management |
| MSP managing client tenants | Interactive + -DelegatedOrganization | GDAP-based cross-tenant access |
If you’re in GCC High, add -ExchangeEnvironmentName O365USGovGCCHigh to every single one of these.
Need help connecting Exchange Online PowerShell to GCC High, building mail flow automation for your government tenant, or migrating to GCC High in the first place? That’s what we do. Whether it’s CMMC compliance consulting, managed compliance services, or hands-on PowerShell automation, we work in government cloud environments every day.