If you manage Microsoft 365, sooner or later you need to connect to Exchange Online PowerShell. The admin center is fine for one mailbox and painful for hundreds; PowerShell reads and changes thousands in seconds. This guide covers the whole path, from a clean install to secure, automated connections.
Everything here uses the current REST-based module, not the retired Basic Auth endpoint, so the commands work in 2026 and pass a modern security review. We also flag the mistakes that lock admins out: most connection failures come from the same two or three causes.
📋 Free: the M365 Audit Checklist (50 points)
Before you script anything, see where your tenant actually stands.
🎯 What you need before you connect to Exchange Online PowerShell
Check three things before you start: PowerShell 7 (or Windows PowerShell 5.1), a network that allows outbound HTTPS on port 443, and an account with an Exchange admin role. Most failures trace back to the role.
PowerShell 7 is the better choice: it is cross-platform and faster. The module still runs on Windows PowerShell 5.1 if that is all you have. On a Mac or a Linux box, install PowerShell 7 first; the cmdlets behave the same on every platform.
Use a dedicated admin account rather than your everyday mailbox. It keeps risky sessions away from daily work and makes auditing cleaner. Turn on multi-factor authentication for it, since the module expects modern authentication by default.
Your execution policy must let the module load. On a locked-down workstation, run PowerShell as administrator once and set the policy to RemoteSigned. Behind a corporate proxy, the connection may also need the proxy address.
In short: install the module once with Install-Module ExchangeOnlineManagement, then run Connect-ExchangeOnline -UserPrincipalName you@domain.com and complete the MFA prompt. For scripts and scheduled jobs, use certificate-based app-only authentication instead of a password. Use a dedicated admin account with the least privilege that fits, and disconnect when you finish.
📦 Install the Exchange Online PowerShell module
The module is called ExchangeOnlineManagement and lives in the PowerShell Gallery. You install it once per machine and update it from time to time. Run the command below in an elevated PowerShell window.
# Install for your user (no admin rights needed)
Install-Module -Name ExchangeOnlineManagement -Scope CurrentUser
# Or install for all users on the machine (run as admin)
Install-Module -Name ExchangeOnlineManagement -Scope AllUsers
# Check the version you have
Get-Module -ListAvailable ExchangeOnlineManagementIf the gallery is not trusted yet, PowerShell asks you to confirm; answer yes and the install takes under a minute. Behind a proxy, mark the gallery as trusted with Set-PSRepository and try again. On an offline server, download the module on a connected machine and copy it across.
Update-Module ExchangeOnlineManagement pulls the newest release. Microsoft ships fixes and new cmdlets often, and a stale module is the most common hidden cause of failures, so update it before you troubleshoot anything.
🔌 Connect to Exchange Online PowerShell: the core command
With the module installed, one cmdlet opens a session. Pass your admin sign-in name: a browser window appears, you complete MFA, and the prompt returns ready for work.
# Import the module (optional - it auto-loads on first use)
Import-Module ExchangeOnlineManagement
# Connect with your admin UPN; a modern-auth window opens for MFA
Connect-ExchangeOnline -UserPrincipalName admin@contoso.com
# Confirm the session is live
Get-ConnectionInformationThe session stays open until you close it or it times out. Because the module talks REST, it is faster and more stable than the old remote sessions.
A few parameters help in special cases. -ShowBanner:$false hides the startup banner in scripts. On a server with no browser, -Device gives you a code to enter on a phone or another computer.
Connect to Exchange Online PowerShell with MFA
MFA needs no special switch anymore. The module triggers modern authentication itself and the browser prompt handles the second factor. Conditional Access policies apply here too, so the admin shell respects the same guardrails as the rest of Microsoft 365.
🔐 Connect to Exchange Online PowerShell with app-only auth
A scheduled task cannot answer an MFA prompt. For automation, use app-only authentication with a certificate: an app registered in Microsoft Entra ID, holding an Exchange role and a certificate, signs in with no password and no human.
Setup takes four steps. Register an application in Entra ID. Grant it the Exchange.ManageAsApp API permission with admin consent. Assign it a suitable Exchange role, ideally a custom least-privilege one. Create a certificate and upload its public key to the app registration.
# App-only connection for scripts (no interactive prompt)
Connect-ExchangeOnline `
-AppId "00000000-0000-0000-0000-000000000000" `
-CertificateThumbprint "A1B2C3D4E5F6..." `
-Organization "contoso.onmicrosoft.com"This is the safe way to run jobs at night: there is no stored password to steal, and the certificate expires on a schedule you control. A self-signed certificate made with New-SelfSignedCertificate lasts one year by default, so put its renewal in the calendar, or the job stops without warning.
📨 Connect to Security & Compliance PowerShell too
The same module reaches the Security & Compliance center, where you manage retention, eDiscovery and audit searches. The command is a sibling of the main one.
# Connect to the Security & Compliance PowerShell endpoint
Connect-IPPSSession -UserPrincipalName admin@contoso.com
# Example: list retention policies
Get-RetentionCompliancePolicy | Select Name, EnabledYou can hold both sessions at once, which helps during an investigation. Each cmdlet belongs to one endpoint and the two sets do not overlap. Disconnect both when you finish.
🧩 Module versions: EXO V3 REST versus legacy Basic Auth
Older guides still show the retired approach. Basic Auth and the remote-session model are gone; the current module (V3) is REST-based, faster, and works with MFA out of the box. Here is how they compare.
| What changed | Legacy (retired) | EXO V3 (current) |
|---|---|---|
| Sign-in | Basic Auth, password only | Modern auth with MFA |
| Transport | WinRM remote session | REST over HTTPS |
| Speed | Slow on bulk reads | Fast, bulk-optimized |
| Cmdlet prefix | Get-Mailbox | Get-EXOMailbox (faster) |
| Status in 2026 | Blocked | Supported |
New cmdlets matter for big tenants. Get-EXO* cmdlets were built for bulk reads and runs reports far faster than the classic cmdlets. Keep the classic ones for one-off changes and the Get-EXO* set for reporting across thousands of mailboxes.
🛠️ Useful commands once you connect to Exchange Online PowerShell
Once the session is live, the real work begins. Here are the cmdlets you will use every week; prefer the Get-EXO* versions for reporting.
Across the tenants we manage, the most common error is an old script that still calls the retired endpoint. The fix is nearly always the same: update the module, switch to Connect-ExchangeOnline, and the job runs again. If a scheduled task broke recently, look there first.
# List every mailbox (fast, REST-based cmdlet)
Get-EXOMailbox -ResultSize Unlimited | Select DisplayName, PrimarySmtpAddress
# Check who has full access to a shared mailbox
Get-EXOMailboxPermission -Identity "sales@contoso.com"
# Export mailbox sizes to CSV for a report
Get-EXOMailbox -ResultSize Unlimited |
Get-EXOMailboxStatistics |
Select DisplayName, TotalItemSize |
Export-Csv .\mailbox-sizes.csv -NoTypeInformationFrom here you can grant permissions, set forwarding or export reports to CSV, and the cmdlets pipe cleanly into one-liners. Test any change on one mailbox before you run it across the tenant.
🔑 Use a managed identity for Azure-hosted scripts
A certificate still has to be rotated. When the script runs inside Azure, a managed identity removes even that: the platform holds the credential and your code never sees a secret.
Enable a managed identity on the Azure resource, such as an Automation account or a Function. Grant that identity the Exchange role it needs, as you would for an app registration. The script then connects with the -ManagedIdentity switch, with no thumbprint or password anywhere.
With nothing stored, nothing can leak, and no certificate expires at 2 a.m. For a recurring job hosted in Azure, use a managed identity; keep certificates for scripts that run where Azure identities cannot reach.
📇 Real admin tasks you will run after you connect
A handful of tasks come up almost every week, and each one is a single cmdlet.
Mailbox permissions top the list. Add-MailboxPermission gives a person access to a shared mailbox with the AccessRights you choose. Set-MailboxAutoReplyConfiguration sets an out-of-office reply for someone on leave.
Mail flow comes next. Add-DistributionGroupMember adds someone to a distribution group, and Set-Mailbox with the ForwardingSmtpAddress parameter sets forwarding. Converting a leaver’s mailbox to shared takes one line, so the whole offboarding can live in one script.
Reporting closes the loop: licence usage, mailbox sizes or forwarding rules, exported to CSV and dated. Auditors get consistent evidence, and saved scripts run the same way every time.
⏰ Automate the connection on a schedule
Once a script works by hand, schedule it. On a server, Task Scheduler calls PowerShell at a set time. In the cloud, Azure Automation runs the same script with a managed identity and no stored secret.
The pattern is the same on either host: connect with app-only authentication, do the job, disconnect. With no password and no prompt it runs unattended for months, as long as the certificate is renewed before it expires.
🔄 Disconnect the session cleanly
When the work is done, close the session on purpose. An open session wastes a connection slot and keeps privileged access alive longer than needed. One command handles it.
# Close the Exchange Online session
Disconnect-ExchangeOnline -Confirm:$falseIn a script, put that line in a finally block so the session closes even when the job fails. Stale sessions also count against throttling, which this avoids.
⚠️ Troubleshooting common connection errors
Most connection problems fall into a short list. Work down this table before you reinstall anything; the cause is usually a role, a policy or a stale module.
| Symptom | Likely cause | Fix |
|---|---|---|
| “Access denied” after sign-in | Account lacks an Exchange role | Assign an Exchange admin role in Entra |
| The cmdlet is not recognized | Module not imported or not installed | Run Install-Module, then Import-Module |
| Sign-in window never appears | Old module still loaded | Close PowerShell, update the module |
| Blocked by Conditional Access | Policy excludes the location or device | Adjust the policy or use a compliant device |
| App-only fails silently | Certificate or API permission missing | Recheck the thumbprint and the granted role |
If none of these apply, Get-ConnectionInformation shows the live session state and often reveals a session that expired; reconnecting clears it. The message “Basic authentication is disabled” means the script uses the retired method: update the module and switch to Connect-ExchangeOnline. An error about throttling means waiting a minute and retrying.
✅ Security best practices for Exchange Online PowerShell
A PowerShell session is powerful, and these habits keep that power from becoming a risk without slowing you down.
Require MFA on every admin account and use a dedicated admin identity. Assign the smallest RBAC role that does the job; a help-desk task rarely needs global rights. Scripts should use certificates, never stored passwords. Disconnect when you finish so no privileged session lingers.
Microsoft documents every parameter in the Exchange Online PowerShell module guide, which lists new parameters as each release adds them.
📋 Connect to Exchange Online PowerShell: a quick reference
Here is the whole connect to Exchange Online PowerShell flow in one place, to keep near your console.
- Install the module:
Install-Module ExchangeOnlineManagement. - Connect:
Connect-ExchangeOnline -UserPrincipalName you@domain.com. - Complete the MFA prompt in the browser window.
- Run your cmdlets, ideally the faster
Get-EXO*set. - Disconnect:
Disconnect-ExchangeOnline.
That covers the daily case. For automation, replace step two with the app-only command and keep the rest.
🌐 Connect to Exchange Online PowerShell from Mac or Linux
PowerShell 7 is cross-platform, so the same cmdlets run on macOS and Linux and a Mac admin connects exactly like a Windows admin. Only the PowerShell install differs.
| Platform | Install PowerShell 7 |
|---|---|
| Windows | winget install Microsoft.PowerShell |
| macOS | brew install –cask powershell |
| Linux | Use your distro package manager |
On a Mac, install PowerShell 7 with Homebrew, then the module as usual, and run the same connect command. A browser tab opens for sign-in and MFA works without extra setup. Linux follows the same steps through its package manager.
A headless Linux server has no browser, so use the device-code flow. The module prints a short code and you finish sign-in on a phone or laptop.
🔁 Switch between multiple Microsoft 365 tenants
Consultants and managed service providers work across many tenants, and the module can hold several sessions at once. A command prefix keeps each tenant’s cmdlets separate; without one, the sessions blur and mistakes follow.
With prefixes, a command never runs against the wrong tenant by accident, and the prompt stays readable with three or four clients open. Disconnect each client’s session on its own when you are done with it.
🎚️ Use a least-privilege RBAC role, not Global Admin
Connecting as a Global Administrator is tempting because everything just works, and it is exactly what attackers hope for: a leaked global session can rewrite the whole tenant. Grant the smallest role that does the task.
In the tenants we audit, the riskiest finding is an app registration holding far more rights than it uses. Scope each app to one Exchange role, and a leaked certificate stays a small incident.
Exchange uses role-based access control, so rights can be scoped tightly. A help-desk operator may only need to read mailboxes and reset a few settings; a custom role group with just those rights covers daily work.
The same rule applies to app registrations. An unattended app with one Exchange role limits the blast radius if its certificate ever leaks.
📊 Build a report after you connect to Exchange Online PowerShell
A first report shows what the shell can do. Most admins start with mailbox sizes or sign-in settings, which answer real questions. The pattern is always read, filter, export.
Read the mailboxes, filter for the condition you care about, and export the result to CSV. To list every mailbox without an archive, pipe Get-EXOMailbox into a Where-Object filter and out to Export-Csv; the file lands in your working folder, ready for a spreadsheet. The same pattern answers questions about licences, forwarding rules or sign-in settings.
Save the script and rerun it any month, or schedule it so the report lands in your inbox on its own. A half-day of clicking becomes one command.
🚑 Fix: Connect-ExchangeOnline is not recognized
This is the error admins hit most. It means PowerShell cannot find the cmdlet, for one of three reasons: the module is not installed, it is installed but not loaded in this session, or the window was opened before the install finished.
Work through them in order. Get-Module -ListAvailable ExchangeOnlineManagement confirms the install; if it returns nothing, install the module as shown earlier. When it lists a version, Import-Module ExchangeOnlineManagement loads it, and the connect command resolves.
A fresh window fixes most remaining cases: close PowerShell completely and reopen it, since a stale session can hold an old path. On a managed workstation, also check that the execution policy lets the module load.
🎛️ Key Connect-ExchangeOnline parameters to know
A handful of parameters cover almost every connection. Each one solves a specific case.
| Parameter | What it does | When to use it |
|---|---|---|
| -UserPrincipalName | Signs in as a named admin | Everyday interactive work |
| -Device | Shows a code for sign-in | Servers with no browser |
| -ShowBanner:$false | Hides the startup banner | Clean script output |
| -Prefix | Scopes cmdlets per tenant | Multiple tenants at once |
| -AppId + -CertificateThumbprint | App-only sign-in | Unattended automation |
| -ManagedIdentity | Uses an Azure identity | Scripts hosted in Azure |
📚 More for IT Admins
🔍 See what a single cmdlet cannot tell you
PowerShell checks one setting at a time. Our automated review reads 50 security settings across your tenant in minutes.
❓ Exchange Online PowerShell: Frequently Asked Questions
Install the ExchangeOnlineManagement module, then run Connect-ExchangeOnline with your admin UPN and complete the MFA prompt.
You need the ExchangeOnlineManagement module (V3) from the PowerShell Gallery. The old Basic Auth path is retired and no longer connects.
Yes. Use app-only authentication with a certificate, or a managed identity when the script runs inside Azure. Neither stores a password.
The account usually lacks an Exchange admin role. Assign the right role in Microsoft Entra ID, then reconnect and the cmdlets work.