If you still rely on Connect-ExchangeOnline with a username, password, and an MFA prompt, you already know the pain. Scripts break overnight. Scheduled tasks fail when a token expires. Service accounts get flagged by conditional access. And the moment someone enables MFA on the admin account you’ve been quietly using, your automation falls over.
I’ve been written a new script —
https://github.com/directorcia/Office365/blob/master/o365-connect-exo-cert.ps1
with full documentation here:
https://github.com/directorcia/Office365/wiki/Connect-to-Exchange-Online-with-Certificates
— that swaps all of that for certificate-based app authentication. There’s nothing exotic about the underlying approach; Microsoft has supported it for years. What’s been missing is a clean, one-shot way to set it up without spending an afternoon clicking through the Entra portal. That’s what this script gives me, and I think it earns its place in any MSP’s toolkit.
What the Script Actually Does
There are two modes, controlled by switches.
-GenerateLocalCertificate creates a self-signed RSA-2048 certificate in your current user’s certificate store, exports the public key as a .cer file, and optionally exports a password-protected .pfx. By default it’s valid for two years. That’s the local side of the handshake.
-UseCertificateAuth is the everyday mode. You tell it which tenant to connect to — or let it look up the details in a profile map file — and it signs into Exchange Online using that certificate. No password. No browser. No MFA dialog.
The clever bit is the third option: combining -GenerateLocalCertificate with -ProvisionEntraApp -Tenant 'contoso.onmicrosoft.com'. In a single run, the script will generate the local certificate, authenticate to Microsoft Graph via a device-code flow, create the Entra ID app registration if it doesn’t exist, upload the certificate, grant Exchange.ManageAsApp and Application.Read.All with admin consent, create the matching service principal, sign you into Exchange Online to add the app to the Organization Management role group, and save the tenant, app ID, and certificate thumbprint to a JSON profile file so future connections don’t need any of those parameters.
That’s a job that normally takes twenty minutes of clicking, copying GUIDs, and second-guessing whether the right role got assigned. The script does it in about ninety seconds.
Getting Started
If you’re new to certificate auth, the first run is the one that matters. Drop the script onto an admin machine, open PowerShell, and run:
.\o365-connect-exo-cert.ps1 -GenerateLocalCertificate -ProvisionEntraApp -Tenant 'yourtenant.onmicrosoft.com'
You’ll be prompted to sign in twice — once via device code for the Graph permissions (which if you use the –copydevicecodetoclipboard, option will put the required device code straight into the clipboard to paste into the request), then again with Connect-ExchangeOnline so the script can add the app to the role group. Both need a Global Admin account. After that, every future run is just:
.\o365-connect-exo-cert.ps1 -UseCertificateAuth -Tenant 'yourtenant.onmicrosoft.com'
No prompts. No browser. The script reads the tenant, app ID, and thumbprint from o365-exo-cert-auth.json (saved to parent directory), finds the certificate in your local store, builds a signed JWT, and you’re in. One caveat worth flagging: when you’ve just provisioned a brand-new app, give it fifteen to thirty minutes for role assignments to replicate before you try to connect. The script warns about this in its output, but it’s the single most common reason a fresh setup looks broken when it isn’t.
If you’re managing more than one tenant, the profile file is where this really earns its keep. Each provisioning run appends or updates an entry, so you can ask for a connection by -ProfileName, -Tenant, or -Organization and the script picks the right credentials. When several profiles match, it lists them and lets you choose.
Why Certificates Beat Passwords
The security argument is the easy one. A certificate’s private key never leaves the machine that generated it. Nothing crosses the wire that an attacker could intercept and replay. There’s no shared secret to rotate across a team, no admin password sitting in a vault that someone might extract, and no MFA bypass to engineer because the flow doesn’t involve a user account at all.
Permissions are scoped too. The app holds only Exchange.ManageAsApp and read-only access to application metadata. If the certificate is ever compromised, you remove the key credential from the app registration and the access is gone — no password reset required, no impact on any human admin account.
The script enforces TLS 1.2, refuses to assign RBAC if the EXO session has landed in the wrong tenant, warns when the certificate is within thirty days of expiry, and keeps the device-code value off the clipboard by default to avoid leaks on RDP or shared sessions. Small things, but they add up.
Why It’s a Win for Automation
Certificate auth is what makes unattended Exchange Online work actually unattended. A scheduled task running at 2 a.m. doesn’t have a human to click “Approve” on an MFA prompt. With this approach, you point Task Scheduler at the script with -noprompt, pass the tenant, and walk away.
For an MSP, that becomes a per-tenant capability rather than a per-admin one. One profile file, one shared script, separate certificates per tenant or per admin machine — and now mailbox audits, distribution group cleanup, shared mailbox provisioning, and any of the other recurring chores you keep meaning to automate can run on a timer instead of waiting for a quiet Friday afternoon. Pair it with a Power Automate flow or a daily Copilot summary in Teams, and you’ve got reporting that lands in front of the right people without anyone signing in.
Where I’d Take It Next
If you’ve never moved off interactive sign-in for Exchange Online, this is the path I’d take. Spend half an hour standing it up against a test tenant. Get comfortable with the profile file. Then start moving your scheduled work over, one job at a time. The shift from “who’s signing in?” to “which certificate is presenting itself?” is a quiet one, but once your automation stops breaking every time an admin’s MFA settings change, you won’t go back.