Quick Connect (TL;DR)
If you already have Exchange Administrator (or Global Administrator) rights and PowerShell 5.1+ on Windows or PowerShell 7+ on macOS/Linux, the full install-and-connect flow is three commands. Run PowerShell as Administrator:
Install-Module -Name ExchangeOnlineManagement -Force -AllowClobber -Scope CurrentUser
Import-Module ExchangeOnlineManagement
Connect-ExchangeOnline -UserPrincipalName admin@yourdomain.com
A browser window will open for Microsoft 365 sign-in (including MFA prompts). When the session ends, disconnect cleanly:
Disconnect-ExchangeOnline -Confirm:$false
For unattended scripts and automation, use certificate-based authentication instead — see the certificate auth section below. Detailed prerequisites, verification steps, and troubleshooting follow.
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 admin@yourdomain.com
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 admin@yourdomain.com -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 admin@clientdomain.com -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 admin@yourdomain.com
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 admin@yourdomain.com
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 admin@yourdomain.com -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 user@domain.com | 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 sharedmailbox@domain.com -User admin@domain.com -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 user1@domain.com,user2@domain.com
Microsoft 365 Admin PowerShell Toolkit
Production-ready scripts for Exchange Online, Teams, Intune, license reporting, Conditional Access export, and DNS verification.
M365 Admin Toolkit — 9 PowerShell scripts + quick reference guide
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 admin@agency.gov
GCC High
GCC High requires explicit environment specification and uses different endpoints:
# Connect to GCC High environment
Connect-ExchangeOnline -UserPrincipalName admin@agency.gov -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 admin@agency.mil -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 admin@contoso.com
# 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 "john.doe@contoso.mail.onmicrosoft.com"
# Create new remote mailbox
New-OnPremRemoteMailbox -Name "Jane Smith" -UserPrincipalName jane.smith@contoso.com `
-RemoteRoutingAddress "jane.smith@contoso.mail.onmicrosoft.com" `
-PrimarySmtpAddress "jane.smith@contoso.com"
# Move mailbox from on-premises to cloud
New-MoveRequest -Identity "user@contoso.com" -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 'admin@contoso.com'"
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 admin@contoso.com
# 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 = "admin@contoso.com"
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