A Cleaner Way to Connect PowerShell to SharePoint Online

image

Connect-PnPOnline with a browser sign-in is fine when you’re sitting at the keyboard. It becomes a problem the moment you’re not. The script that worked beautifully on your laptop refuses to run unattended. The scheduled job that was meant to tidy up orphaned sites overnight quietly does nothing, because it’s still waiting for someone to type a password. And the moment conditional access tightens on the admin account you’ve been quietly using for automation, every script that touches SharePoint behaves like it’s been thrown out a window.

The fix has existed. The setup hasn’t.

Certificate-based app authentication for SharePoint Online has been supported by Microsoft for years. The mechanics are well documented. The trouble has always been the assembly — generate a cert, export the public key, register an app in Entra ID, paste the right GUIDs in the right boxes, find Sites.FullControl.All in the API permissions list, grant admin consent, copy the thumbprint somewhere you won’t lose it, and verify the tenant ID in three different places along the way. By the time you’ve finished, you’ve forgotten which client you were doing it for.

So I’ve written a script that does the whole sequence end to end:

  • Generates a self-signed RSA-2048 certificate in your local certificate store

  • Creates the Entra ID app registration

  • Uploads the certificate and grants Sites.FullControl.All with admin consent

  • Provisions the service principal and adds Application.Read.All on Graph so the app can read its own metadata back

  • Resolves your tenant’s SharePoint root URL automatically from the Graph verified-domains call

  • Saves tenant, app ID, site URL, and thumbprint into a JSON profile so future connections need almost no parameters

What’s normally half an hour of clicking between Entra, the SharePoint admin centre, and a Notepad full of half-remembered GUIDs runs in about ninety seconds.

I’ve been written a new script — https://github.com/directorcia/Office365/blob/master/o365-connect-pnp-cert.ps1

with full documentation here – https://github.com/directorcia/Office365/wiki/Connect-to-SharePoint-Online-with-Certificates

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.

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-pnp-cert.ps1 -GenerateLocalCertificate -ProvisionEntraApp -Tenant 'yourtenant.onmicrosoft.com'

You’ll be prompted to sign in — 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). You need a Global Admin account.

Where this earns its keep across a client base

After that first run, connecting to a tenant looks like this:

.\o365-connect-pnp-cert.ps1 -UseCertificateAuth -Tenant ‘contoso.onmicrosoft.com’

No password. No browser. No MFA prompt. The profile file is the bit that pays you back across an MSP book. One script lives in your tooling folder, each client has its own certificate and entry in the JSON map, and Task Scheduler can finally drive things like site collection audits, sharing reports, lifecycle cleanup on Teams-connected sites, and external-user reviews without anyone watching it run. Filter by tenant or site URL on the command line and the same script services twenty different customers without you ever editing it.

One honest caveat

When you’ve just provisioned a brand-new app, give Entra fifteen to thirty minutes for the role grants to replicate before your first cert-based connect. It’s the single most common reason a fresh setup looks broken when it isn’t. The script flags this on the way out, but it’s worth saying twice.

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.

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 PnP 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.

The change is a quiet one. You stop thinking about who is signing in and start thinking about which certificate is presenting itself. Once your SharePoint automation is no longer at the mercy of someone else’s MFA settings or a password rotation policy, the kind of work you’re willing to schedule expands. That’s the real win — not the ninety seconds saved on setup, but the chores you finally get around to doing.

Leave a comment