vysovsky.com / guides / connect

Connecting to Exchange Online and Microsoft Graph

Module installation, interactive sign-in with MFA, delegated access across customer tenants, unattended app-only authentication, and what the common connection errors actually mean.

Last reviewed June 2026. Covers the Exchange Online Management V3 module and the Microsoft Graph PowerShell SDK.

Every command catalog on this site assumes a working connection, and in practice the connection is where a surprising share of tickets die. This page covers both modules end to end, written for the realities of MSP work: MFA on every admin account, several customer tenants a day, and a mix of PowerShell 5.1 and 7 across technician machines.

Exchange Online PowerShell

Install the module

From an elevated or CurrentUser-scoped session

Install-Module ExchangeOnlineManagement -Scope CurrentUser

-Scope CurrentUser avoids needing local admin rights, which matters on locked-down technician machines. The module runs on both Windows PowerShell 5.1 and PowerShell 7; PowerShell 7 is the better experience and is where Microsoft's testing effort goes.

On older Windows PowerShell 5.1 installs, the install can fail with "Unable to resolve package source" because the session is not using TLS 1.2. Fix it for the session, then install again:

[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
Install-Module ExchangeOnlineManagement -Scope CurrentUser

Connect interactively

Connect-ExchangeOnline -UserPrincipalName admin@contoso.com

A browser window opens for sign-in, MFA included. Supplying -UserPrincipalName is optional but skips the account-picker step. On a server with no browser, or when the browser window refuses to appear, fall back to device code flow:

Connect-ExchangeOnline -Device

This prints a code and a URL; complete the sign-in on any other device. It is also the practical workaround when conditional access or an overzealous browser profile breaks the normal pop-up.

Delegated access to customer tenants

With GDAP or older delegated admin relationships in place, connect to a customer tenant using your partner credentials:

Connect-ExchangeOnline -UserPrincipalName tech@msp.com -DelegatedOrganization customer.onmicrosoft.com

The value for -DelegatedOrganization is the customer's onmicrosoft.com domain or tenant ID. Confirm which tenant a session is pointed at before changing anything; with several windows open this is the single most valuable habit in multi-tenant work:

Get-ConnectionInformation | Select-Object UserPrincipalName, Organization, State

App-only authentication for automation

Unattended scripts authenticate as an app registration with a certificate. The app needs the Exchange.ManageAsApp application permission (admin consented) and an Exchange role assigned to its service principal; then:

Connect-ExchangeOnline -AppId $appId -CertificateThumbprint $thumb -Organization contoso.onmicrosoft.com

Certificates replace stored passwords entirely. If an old script embeds credentials for a basic-auth session, it is both broken and a finding: basic authentication to Exchange Online PowerShell no longer works at all.

Disconnect when done

Disconnect-ExchangeOnline -Confirm:$false

Exchange Online limits concurrent PowerShell connections per admin. Sessions abandoned by closing the window without disconnecting count against that limit until they time out, which is how "Fail to create a runspace because you have exceeded the maximum number of connections allowed" happens on a busy day. Disconnecting properly avoids it; if you are already locked out, wait for the stale sessions to expire or clear them from another session.

Microsoft Graph PowerShell

Install the module

Install-Module Microsoft.Graph -Scope CurrentUser

The meta-module pulls in 30+ sub-modules and takes a while. On Windows PowerShell 5.1, loading the entire SDK can also hit the 4096-function session limit, producing the baffling "function capacity 4096 has been exceeded" error. Both problems have the same answer: install only the sub-modules you use.

Leaner install covering most helpdesk work

Install-Module Microsoft.Graph.Authentication, Microsoft.Graph.Users, Microsoft.Graph.Groups, Microsoft.Graph.Identity.DirectoryManagement -Scope CurrentUser

If the function-capacity error appears anyway on 5.1, raise the limit at the top of the script or move to PowerShell 7, where the limit is far higher:

$MaximumFunctionCount = 32768

Connect with explicit scopes

Connect-MgGraph -Scopes "User.Read.All","Group.Read.All" -NoWelcome

Graph grants a session only the scopes requested at connect time. This is the single biggest mental shift from the retired MSOnline and AzureAD modules, which gave you everything your role allowed. Request the scopes each job needs; every command in the Entra ID builder lists its required scopes for exactly this reason. To see what the current session holds:

Get-MgContext | Select-Object Account, TenantId, Scopes

To connect to a specific customer tenant rather than your home tenant, add -TenantId with the customer's tenant ID or onmicrosoft.com domain. Device code flow is available here too with -UseDeviceCode.

App-only authentication

Graph automation uses an app registration with application permissions (admin consented) and a certificate:

Connect-MgGraph -ClientId $appId -TenantId $tenantId -CertificateThumbprint $thumb

App-only sessions hold the application permissions granted to the app, not delegated scopes, so -Scopes is not used. Grant the narrowest application permissions the script needs; an automation app with Directory.ReadWrite.All is a standing risk in every tenant it touches.

Disconnect

Disconnect-MgGraph

As with Exchange, make this the habit between tenants. A cached Graph token pointing at the wrong customer is how a "quick check" lands in the wrong directory.

Common connection errors and what they mean

ErrorCause and fix
The term 'Connect-ExchangeOnline' is not recognizedModule not installed or not imported in this session. Install-Module ExchangeOnlineManagement, then start a fresh session. On 5.1, also check the install actually succeeded past the TLS issue below.
Unable to resolve package source 'PSGallery'Windows PowerShell 5.1 defaulting to old TLS. Set TLS 1.2 for the session ([Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12) and retry.
Running scripts is disabled on this systemExecution policy. For the current session only: Set-ExecutionPolicy -Scope Process RemoteSigned. Avoid weakening the machine-wide policy on shared technician boxes.
Fail to create a runspace... exceeded the maximum number of connectionsToo many concurrent Exchange sessions for this admin, usually from closed-without-disconnect windows. Disconnect-ExchangeOnline religiously; wait out stale sessions if already capped.
Insufficient privileges to complete the operation (Graph)The session lacks a needed scope, or the scope was never admin-consented. Disconnect-MgGraph, reconnect with the missing scope added, and check Get-MgContext afterwards.
Need admin approval (during Graph sign-in)The requested scope requires admin consent in that tenant and the signing-in account cannot grant it. A Global Admin or Privileged Role Admin must consent, or pre-consent the Graph PowerShell app for the scopes your team uses.
Function capacity 4096 has been exceeded (Graph on PS 5.1)The full Graph SDK overflows 5.1's function limit. Import only needed sub-modules, raise $MaximumFunctionCount, or use PowerShell 7.
Assembly with same name is already loaded (Graph)Two Graph module versions in one session, typically after an update. Start a fresh session; uninstall older versions with Uninstall-Module if it persists.
Browser window never appears for sign-inDefault browser misconfiguration, a broken WebView, or a server core box. Use device code flow: Connect-ExchangeOnline -Device or Connect-MgGraph -UseDeviceCode.
Basic authentication is disabledA legacy script using New-PSSession with -Authentication Basic. That pattern is permanently dead; rewrite the connection with Connect-ExchangeOnline. See the migration guide.

A clean session pattern for multi-tenant work

The discipline that prevents wrong-tenant incidents costs four lines: connect with the tenant named explicitly, verify, work, disconnect. As a habit it looks like this:

Connect-ExchangeOnline -UserPrincipalName tech@msp.com -DelegatedOrganization customer.onmicrosoft.com
Get-ConnectionInformation | Select-Object Organization, State   # confirm before touching anything
# ... do the work ...
Disconnect-ExchangeOnline -Confirm:$false

The same shape applies to Graph with Connect-MgGraph -TenantId, Get-MgContext and Disconnect-MgGraph. Once connected, the Exchange and Entra ID builders on this site generate the commands for the actual work.