Exchange Online PowerShell is the essential tool for Microsoft 365 administrators to manage mailboxes, configure mail flow rules, and automate tasks that aren't available in the Microsoft 365 Admin Center GUI. This comprehensive guide shows you exactly how to connect to Exchange Online PowerShell using the ExchangeOnlineManagement module.
Prerequisites for Exchange Online PowerShell
Before you can connect to Exchange Online PowerShell, ensure you have:
- Operating System: Windows 10/11, Windows Server 2016+, or macOS/Linux with PowerShell 7
- PowerShell Version: 5.1 or higher (Windows), 7.0.3+ (cross-platform)
- Administrative Access: Local admin rights to install modules
- Microsoft 365 Account: Exchange Administrator or Global Administrator role
- Network Access: Outbound HTTPS (port 443) to Microsoft 365 endpoints
To check your PowerShell version, run:
$PSVersionTable.PSVersion
Install ExchangeOnlineManagement Module
The Install-Module -Name ExchangeOnlineManagement command downloads and installs the Exchange Online PowerShell module from the PowerShell Gallery.
Step 1: Open PowerShell as Administrator
- Click Start and type PowerShell
- Right-click Windows PowerShell and select Run as administrator
- Click Yes on the User Account Control prompt
Step 2: Install the ExchangeOnlineManagement Module
Run the following command to install the Exchange Online Management module:
Install-Module -Name ExchangeOnlineManagement
If prompted about an untrusted repository (PSGallery), type Y and press Enter to proceed.
For a silent installation that auto-accepts prompts:
Install-Module -Name ExchangeOnlineManagement -Force -AllowClobber -Scope CurrentUser
Step 3: Verify the Installation
Confirm the module installed correctly:
Get-Module ExchangeOnlineManagement -ListAvailable
You should see output showing the module name, version (3.x.x), and installation path.
Step 4: Import the Module (Optional)
While not always required, explicitly importing the module can help with troubleshooting:
Import-Module ExchangeOnlineManagement
Connect to Exchange Online PowerShell
There are several methods to connect to Exchange Online PowerShell depending on your authentication requirements.
Method 1: Connect with Modern Authentication (Recommended)
For accounts with or without MFA, use the standard connection command:
Connect-ExchangeOnline -UserPrincipalName [email protected]
A browser window opens for Microsoft authentication. Complete sign-in and any MFA prompts. Once authenticated, you'll see a confirmation message in PowerShell.
Method 2: Connect Exchange Online PowerShell with MFA
If Multi-Factor Authentication is required, the same command works:
Connect-ExchangeOnline -UserPrincipalName [email protected] -ShowProgress $true
The -ShowProgress parameter displays connection status. Complete the MFA challenge (authenticator app, SMS, phone call) in the browser window.
Method 3: Connect to a Specific Tenant
For MSPs or multi-tenant administrators:
Connect-ExchangeOnline -UserPrincipalName [email protected] -DelegatedOrganization clientdomain.onmicrosoft.com
Method 4: Certificate-Based Authentication (Unattended Scripts)
For automation and scheduled tasks, use certificate-based authentication to avoid storing passwords:
Connect-ExchangeOnline `
-CertificateThumbprint "ABCD1234567890ABCD1234567890ABCD12345678" `
-AppId "12345678-1234-1234-1234-123456789012" `
-Organization "yourdomain.onmicrosoft.com"
Prerequisites for certificate-based auth:
- Register an application in Azure AD (Entra ID)
- Generate or obtain a certificate
- Upload the public certificate to the Azure AD app
- Install the private certificate on the machine running scripts
- Grant the app Exchange.ManageAsApp API permission
Method 5: Connect Using Access Token
For advanced scenarios with custom authentication:
Connect-ExchangeOnline -AccessToken $token -Organization "yourdomain.onmicrosoft.com"
Verify Your Exchange Online Connection
After connecting, verify the session is active:
Get-ConnectionInformation
Test your access by listing mailboxes:
Get-Mailbox -ResultSize 10
Or check your own mailbox:
Get-Mailbox -Identity [email protected]
Disconnect from Exchange Online PowerShell
Always disconnect when finished to free up sessions and maintain security:
Disconnect-ExchangeOnline -Confirm:$false
The -Confirm:$false parameter prevents the confirmation prompt. Microsoft limits concurrent sessions (3 per user), so disconnecting is essential.
Common Connect-ExchangeOnline Errors and Solutions
Error: "The term 'Connect-ExchangeOnline' is not recognized"
Cause: The ExchangeOnlineManagement module isn't installed or loaded.
Solution:
# First, try importing the module
Import-Module ExchangeOnlineManagement
# If that fails, install or reinstall
Install-Module -Name ExchangeOnlineManagement -Force -AllowClobber
# Then import
Import-Module ExchangeOnlineManagement
Error: "AADSTS50076 - Due to a configuration change made by your administrator"
Cause: Your tenant requires MFA but you're using basic authentication.
Solution: Use Modern Authentication with the browser-based sign-in:
Connect-ExchangeOnline -UserPrincipalName [email protected]
Error: "New-ExoPSSession: Access Denied" or "Access to OrgId was denied"
Cause: Your account lacks Exchange Online administrative permissions.
Solution: In Microsoft 365 Admin Center, assign one of these roles to your account:
- Exchange Administrator (recommended)
- Global Administrator
- Exchange Recipient Administrator (limited permissions)
Error: "Unable to load DLL 'sni.dll'"
Cause: Missing .NET Framework components or architecture mismatch.
Solution:
# Update to .NET Framework 4.7.2 or higher
# Or install PowerShell 7:
winget install Microsoft.PowerShell
# Then run commands in PowerShell 7
pwsh
Install-Module -Name ExchangeOnlineManagement
Error: "The WinRM client cannot process the request"
Cause: WinRM service issues or configuration problems.
Solution:
# Run as Administrator
Enable-PSRemoting -Force
Set-Item WSMan:\localhost\Client\TrustedHosts -Value "*" -Force
Restart-Service WinRM
Error: "Connect-ExchangeOnline: One or more errors occurred"
Cause: Network connectivity, proxy, or firewall issues.
Solution:
- Test connectivity to Microsoft 365:
Test-NetConnection outlook.office365.com -Port 443
Test-NetConnection login.microsoftonline.com -Port 443
- If behind a proxy, configure PowerShell:
[System.Net.WebRequest]::DefaultWebProxy.Credentials = [System.Net.CredentialCache]::DefaultNetworkCredentials
Error: "The request channel timed out"
Cause: Network latency or MFA authentication took too long.
Solution:
- Complete MFA within 2 minutes of the prompt
- Check network connectivity
- Try the
-UseRPSSessionparameter as a fallback:
Connect-ExchangeOnline -UserPrincipalName [email protected] -UseRPSSession
Useful Exchange Online PowerShell Commands
Once connected, here are common administrative tasks:
Mailbox Management
# List all mailboxes
Get-Mailbox -ResultSize Unlimited
# Get specific mailbox details
Get-Mailbox -Identity [email protected] | Format-List
# Create a shared mailbox
New-Mailbox -Shared -Name "Support Team" -DisplayName "Support Team" -Alias support
# Grant Full Access to a mailbox
Add-MailboxPermission -Identity [email protected] -User [email protected] -AccessRights FullAccess
Mail Flow Rules
# List all transport rules
Get-TransportRule
# Create a disclaimer rule
New-TransportRule -Name "Email Disclaimer" -ApplyHtmlDisclaimerText "Confidential message" -ApplyHtmlDisclaimerLocation Append
Distribution Groups
# List all distribution groups
Get-DistributionGroup
# Create a new distribution group
New-DistributionGroup -Name "Marketing Team" -Members [email protected],[email protected]
Best Practices for Exchange Online PowerShell
Security Best Practices:
- Use MFA-enabled admin accounts for interactive sessions
- Use certificate-based authentication for automation (no stored passwords)
- Disconnect sessions when not in use
- Monitor admin activity in Azure AD audit logs
Performance Best Practices:
- Use
-ResultSizeparameter to limit query results - Filter server-side with
-Filterinstead of client-sideWhere-Object - Batch operations rather than running commands one at a time
Maintenance Best Practices:
- Update the ExchangeOnlineManagement module monthly:
Update-Module -Name ExchangeOnlineManagement
- Test scripts in a lab environment before production
- Document your automation scripts and their certificate dependencies
Government Cloud Connections (GCC, GCC High, DoD)
Microsoft 365 Government customers must connect to different endpoints than commercial tenants. Use the -ExchangeEnvironmentName parameter to specify your government cloud.
GCC (Government Community Cloud)
GCC uses the same endpoints as commercial Microsoft 365:
# GCC uses standard connection (same as commercial)
Connect-ExchangeOnline -UserPrincipalName [email protected]
GCC High
GCC High requires explicit environment specification and uses different endpoints:
# Connect to GCC High environment
Connect-ExchangeOnline -UserPrincipalName [email protected] -ExchangeEnvironmentName O365USGovGCCHigh
For certificate-based authentication in GCC High:
Connect-ExchangeOnline `
-CertificateThumbprint "ABCD1234567890ABCD1234567890ABCD12345678" `
-AppId "12345678-1234-1234-1234-123456789012" `
-Organization "agency.onmicrosoft.us" `
-ExchangeEnvironmentName O365USGovGCCHigh
DoD (Department of Defense)
DoD environments use the most restricted endpoints:
# Connect to DoD environment
Connect-ExchangeOnline -UserPrincipalName [email protected] -ExchangeEnvironmentName O365USGovDoD
Government Cloud Environment Names
| Environment | -ExchangeEnvironmentName Value | Tenant Domain |
|---|---|---|
| Commercial | O365Default (or omit parameter) | .onmicrosoft.com |
| GCC | O365Default | .onmicrosoft.com |
| GCC High | O365USGovGCCHigh | .onmicrosoft.us |
| DoD | O365USGovDoD | .onmicrosoft.mil |
| China (21Vianet) | O365China | .partner.onmschina.cn |
| Germany | O365GermanyCloud | .onmicrosoft.de |
Certificate Requirements for Government Tenants
Government cloud app registrations have additional requirements:
- Azure Government Portal: Register apps at portal.azure.us (not portal.azure.com)
- Certificate lifetime: Some agencies require maximum 1-year certificate validity
- FIPS compliance: Use FIPS 140-2 compliant certificate generation
- PIV/CAC integration: Consider smart card certificate authentication for user access
Hybrid Exchange Scenarios
Organizations with hybrid Exchange deployments (on-premises Exchange coexisting with Exchange Online) require additional connection patterns.
Connect to Both Environments
Manage on-premises and cloud mailboxes in the same session:
# Connect to Exchange Online
Connect-ExchangeOnline -UserPrincipalName [email protected]
# Connect to on-premises Exchange (separate session)
$OnPremSession = New-PSSession -ConfigurationName Microsoft.Exchange `
-ConnectionUri http://exchange-server.contoso.local/PowerShell/ `
-Authentication Kerberos
Import-PSSession $OnPremSession -Prefix OnPrem -DisableNameChecking
With the -Prefix OnPrem parameter, on-premises cmdlets are prefixed to avoid conflicts:
Get-Mailbox= Exchange Online mailboxGet-OnPremMailbox= On-premises mailbox
Remote Mailbox Management
Create and manage remote mailboxes (on-premises objects that point to cloud mailboxes):
# Enable remote mailbox for existing on-premises user
Enable-OnPremRemoteMailbox -Identity "John.Doe" -RemoteRoutingAddress "[email protected]"
# Create new remote mailbox
New-OnPremRemoteMailbox -Name "Jane Smith" -UserPrincipalName [email protected] `
-RemoteRoutingAddress "[email protected]" `
-PrimarySmtpAddress "[email protected]"
# Move mailbox from on-premises to cloud
New-MoveRequest -Identity "[email protected]" -Remote -RemoteHostName "hybrid.contoso.com" `
-TargetDeliveryDomain "contoso.mail.onmicrosoft.com" -RemoteCredential $OnPremCred
Hybrid Mail Flow Troubleshooting
Diagnose mail flow issues in hybrid environments:
# Check hybrid configuration status
Get-HybridConfiguration
# Verify organization relationship
Get-OrganizationRelationship | Format-List
# Test hybrid mail flow
Test-MigrationServerAvailability -ExchangeRemoteMove -RemoteServer "hybrid.contoso.com" `
-Credentials $OnPremCred
# Check inbound/outbound connectors
Get-InboundConnector | Where-Object {$_.ConnectorType -eq "OnPremises"}
Get-OutboundConnector | Where-Object {$_.ConnectorType -eq "OnPremises"}
# Verify send connector for hybrid
Get-OnPremSendConnector | Where-Object {$_.AddressSpaces -like "*mail.onmicrosoft.com*"}
Common Hybrid Scenarios
| Task | On-Premises Command | Exchange Online Command |
|---|---|---|
| Create cloud mailbox | Enable-RemoteMailbox | New-Mailbox |
| Move to cloud | New-MoveRequest | Monitor with Get-MoveRequest |
| Move to on-premises | - | New-MoveRequest -Outbound |
| Convert to shared | - | Set-Mailbox -Type Shared |
Bulk Operations and Throttling Management
Exchange Online enforces throttling limits to ensure service stability. Understanding these limits is essential for large-scale operations.
Exchange Online Throttling Limits
| Resource | Limit | Scope |
|---|---|---|
| Concurrent connections | 3 | Per user |
| Cmdlet execution | 10,000 | Per 10-minute window |
| Result set size | 1,000 | Default for Get- cmdlets |
| Runspace lifetime | 1 hour | Per session |
Handling Large Result Sets
Always use -ResultSize to control data retrieval:
# Get all mailboxes (may hit throttling for large tenants)
Get-Mailbox -ResultSize Unlimited
# Better: Page through results
$pageSize = 1000
$offset = 0
$allMailboxes = @()
do {
$batch = Get-Mailbox -ResultSize $pageSize -Filter "RecipientTypeDetails -eq 'UserMailbox'" | Select-Object -Skip $offset
$allMailboxes += $batch
$offset += $pageSize
Write-Progress -Activity "Fetching mailboxes" -Status "$($allMailboxes.Count) retrieved"
} while ($batch.Count -eq $pageSize)
Server-Side Filtering (Critical for Performance)
Filter data on the server, not the client:
# Bad: Client-side filtering (downloads all mailboxes first)
Get-Mailbox -ResultSize Unlimited | Where-Object {$_.RecipientTypeDetails -eq "SharedMailbox"}
# Good: Server-side filtering (only downloads matching results)
Get-Mailbox -ResultSize Unlimited -RecipientTypeDetails SharedMailbox
# More efficient filtering examples
Get-Mailbox -Filter "CustomAttribute1 -eq 'Sales'"
Get-Mailbox -Filter "WhenCreated -gt '2024-01-01'"
Get-DistributionGroup -Filter "ManagedBy -eq '[email protected]'"
Batch Processing with Throttle Handling
Process large operations with built-in retry logic:
# Bulk mailbox modification with throttle handling
$mailboxes = Get-Mailbox -ResultSize Unlimited -RecipientTypeDetails UserMailbox
$processed = 0
$total = $mailboxes.Count
foreach ($mbx in $mailboxes) {
$processed++
Write-Progress -Activity "Processing mailboxes" -Status "$processed of $total" -PercentComplete (($processed / $total) * 100)
try {
Set-Mailbox -Identity $mbx.Identity -AuditEnabled $true -ErrorAction Stop
}
catch {
if ($_.Exception.Message -like "*throttling*" -or $_.Exception.Message -like "*exceeded*") {
Write-Warning "Throttled. Waiting 60 seconds..."
Start-Sleep -Seconds 60
# Retry
Set-Mailbox -Identity $mbx.Identity -AuditEnabled $true
}
else {
Write-Error "Failed for $($mbx.Identity): $_"
}
}
# Proactive delay to avoid throttling (adjust based on operation)
if ($processed % 100 -eq 0) {
Start-Sleep -Seconds 5
}
}
Parallel Execution with REST Cmdlets
The V3 module's REST-based cmdlets support parallel operations:
# Enable REST cmdlets (default in V3)
Connect-ExchangeOnline -UserPrincipalName [email protected]
# Process mailboxes in parallel using PowerShell 7's ForEach-Object -Parallel
$mailboxes = Get-EXOMailbox -ResultSize Unlimited -Properties DisplayName, PrimarySmtpAddress
$mailboxes | ForEach-Object -Parallel {
# Each iteration runs in parallel
Get-EXOMailboxStatistics -Identity $_.Identity
} -ThrottleLimit 10 # Limit concurrent operations
Connection Pooling for Long-Running Scripts
Maintain healthy connections during extended operations:
# Check connection health
function Test-ExchangeConnection {
try {
$null = Get-EXOMailbox -ResultSize 1 -ErrorAction Stop
return $true
}
catch {
return $false
}
}
# Reconnect if needed
function Ensure-ExchangeConnection {
param($UPN)
if (-not (Test-ExchangeConnection)) {
Write-Warning "Connection lost. Reconnecting..."
Disconnect-ExchangeOnline -Confirm:$false -ErrorAction SilentlyContinue
Connect-ExchangeOnline -UserPrincipalName $UPN -ShowProgress:$false
}
}
# Use in long-running scripts
$adminUPN = "[email protected]"
Connect-ExchangeOnline -UserPrincipalName $adminUPN
$mailboxes = Get-EXOMailbox -ResultSize Unlimited
$count = 0
foreach ($mbx in $mailboxes) {
$count++
# Check connection every 500 operations
if ($count % 500 -eq 0) {
Ensure-ExchangeConnection -UPN $adminUPN
}
# Your operation here
Get-EXOMailboxStatistics -Identity $mbx.Identity
}
Monitoring Throttling Status
Track your API usage to avoid hitting limits:
# Get current throttling information
Get-ThrottlingPolicy | Select-Object ThrottlingPolicyScope, *Cutoff*
# Monitor PowerShell session health
Get-ConnectionInformation | Format-List
# Check remaining budget (not always available)
$session = Get-PSSession | Where-Object {$_.ConfigurationName -eq "Microsoft.Exchange"}
$session.Runspace.ConnectionInfo