How to Set Up Certificate Authentication for PowerShell (Microsoft 365)

By Mark D. Albin, MS

A junior-admin-friendly guide to secure Microsoft 365 automation, from IT Master Services. Part 1 of 3.

If your PowerShell scripts connect to Microsoft 365 with a client secret — a long password pasted into a script, a config file, or a scheduled task — you're carrying real risk. Secrets get copied, checked into repositories, left in spreadsheets, and forgotten until they leak. The modern, far safer approach is certificate-based authentication: the script proves its identity with a certificate whose private key never leaves the machine, and nothing password-like is stored in the script at all.

The core idea: instead of a shared secret, you upload the public half of a certificate to Microsoft Entra, and keep the private half protected on the computer that runs your automation. The script references the certificate by its thumbprint — which is just an ID, not a password.

This is Part 1 of a three-part series:

  • Part 1 (this guide): create the certificate and configure the Microsoft Entra app registration.
  • Part 2: convert scripts from client secrets to certificates and connect to Microsoft Graph, Exchange Online, and SharePoint PnP.
  • Part 3: rotate and renew certificates, and troubleshoot authentication problems.

This guide is for PowerShell automation authentication only. Do not use it to create website TLS/SSL certificates — that's a different job.

Key Concepts (in Plain English)

TermWhat it means
CER fileThe public half of the certificate. This is what you upload to Entra. On its own it cannot authenticate.
PFX fileA backup that contains the private key. Treat it like a password — protect it with a strong password and secure storage.
ThumbprintThe unique ID PowerShell uses to find the certificate in the Windows certificate store.
Certificate storeWhere Windows keeps certificates, e.g. Cert:\CurrentUser\My or Cert:\LocalMachine\My.
Private keyThe secret part of the certificate. The account that runs the script must be able to access it.

Prerequisites

  • You're signed in as the Windows account that will run the scripts — or you know which account the scheduled task will use.
  • Local administrator rights (if you need to create folders or change permissions).
  • A certificate naming convention. This guide uses the example M365-Automation-2026.
  • A secure place to store the PFX password (never in a script).
  • Access to the Microsoft Entra admin center with permission to manage app registrations and grant admin consent (or someone who can).

CurrentUser vs LocalMachine: for most scheduled tasks that run as a specific account, creating the certificate under CurrentUser is simplest — as long as the task runs as that same account. Use LocalMachine when multiple accounts need it, and make sure the run account has permission to the private key.

Part A — Create the Certificate

Step 1: Create a working folder

Create a folder to hold your exported certificate files and notes.

New-Item -Path "C:\mycertificates" -ItemType Directory -Force
Test-Path "C:\mycertificates"   # Expected: True

Step 2 (optional): Lock down the folder

Because this folder may hold PFX backups, restrict it to administrators. If you're unsure about NTFS permissions, review this with a senior admin first — don't remove access for the account that maintains the folder.

$path = "C:\mycertificates"
$acl = Get-Acl $path
$acl.SetAccessRuleProtection($true, $false)
$admins = New-Object System.Security.AccessControl.FileSystemAccessRule("Administrators","FullControl","ContainerInherit,ObjectInherit","None","Allow")
$system = New-Object System.Security.AccessControl.FileSystemAccessRule("SYSTEM","FullControl","ContainerInherit,ObjectInherit","None","Allow")
$acl.SetAccessRule($admins)
$acl.SetAccessRule($system)
Set-Acl -Path $path -AclObject $acl

Step 3: Create the self-signed certificate

Open PowerShell as the account that will run the automation. This creates a 24-month certificate in the current user's store.

$CertName = "M365-Automation-2026"
$Cert = New-SelfSignedCertificate `
    -Subject "CN=$CertName" `
    -CertStoreLocation "Cert:\CurrentUser\My" `
    -KeySpec Signature `
    -KeyExportPolicy Exportable `
    -KeyLength 2048 `
    -KeyAlgorithm RSA `
    -HashAlgorithm SHA256 `
    -NotAfter (Get-Date).AddMonths(24)

$Cert | Select-Object Subject, Thumbprint, NotBefore, NotAfter

Copy the Thumbprint. You'll use it later with Connect-MgGraph, Connect-ExchangeOnline, and other certificate-aware modules. (For LocalMachine, change the store path to Cert:\LocalMachine\My.)

Step 4: Export the public CER file

The CER holds only the public key and is safe to upload to Entra.

$CerPath = "C:\mycertificates\M365-Automation-2026.cer"
Export-Certificate -Cert $Cert -FilePath $CerPath

Step 5: Export the password-protected PFX backup

The PFX contains the private key. Protect it with a strong password and store it securely.

$PfxPath = "C:\mycertificates\M365-Automation-2026.pfx"
$PfxPassword = Read-Host "Enter a strong PFX password" -AsSecureString
Export-PfxCertificate -Cert $Cert -FilePath $PfxPath -Password $PfxPassword

Never hard-code the PFX password in a script. Use Read-Host, a password vault, or another approved secure process.

Step 6: Verify the private key exists

This is the check that saves you hours of confusion later.

Get-ChildItem Cert:\CurrentUser\My |
    Where-Object Thumbprint -eq $Cert.Thumbprint |
    Select-Object Subject, Thumbprint, NotAfter, HasPrivateKey

HasPrivateKey must show True. If it shows False, authentication will fail because the machine can't sign the request.

Part B — Configure the Microsoft Entra App Registration

Now you'll tell Microsoft Entra to trust this certificate, and grant the app exactly the permissions it needs.

Step 1: Open the app registration

In the Microsoft Entra admin center, go to Identity → Applications → App registrations and open your automation app registration (check All applications if it isn't listed under owned apps). From the Overview page, record the Application (client) ID and Directory (tenant) ID — these identify the app and tenant. They're not passwords, but treat them as configuration data.

Step 2: Upload the public certificate

Open Certificates & secrets → Certificates → Upload certificate, browse to C:\mycertificates, and select the .cer file from Part A. Add a description (e.g. M365-Automation-2026) and confirm it appears with the correct thumbprint and expiration date.

Upload the CER only. Never upload or share the PFX.

Step 3: Grant least-privilege API permissions

Add only the permissions the automation actually needs. For unattended scripts, use Application permissions (not Delegated — those require a signed-in user).

WorkloadExample permissionsNotes
Graph reportingUser.Read.All, Group.Read.All, Directory.Read.AllPrefer read-only where possible.
Graph administrationUser.ReadWrite.All, DeviceManagementManagedDevices.Read.AllConfirm least privilege before granting write.
Exchange OnlineExchange.ManageAsAppAlso needs an Exchange RBAC role assignment.
SharePoint (PnP)Sites.Selected or Sites.FullControl.AllPrefer Sites.Selected where practical.

Under API permissions → Add a permission, choose the API (Microsoft Graph, Office 365 Exchange Online, or SharePoint), select Application permissions, pick what you need, and add them.

Step 4: Grant admin consent

Application permissions don't take effect until an administrator consents. On the API permissions page, review the list carefully, click Grant admin consent for [tenant], confirm, and verify the Status column shows Granted.

Step 5: Validate end-to-end

From the computer that has the certificate's private key, run this — replacing the placeholders with your values:

$AppId      = "00000000-0000-0000-0000-000000000000"
$TenantId   = "00000000-0000-0000-0000-000000000000"
$Thumbprint = "PASTE_CERTIFICATE_THUMBPRINT_HERE"

Connect-MgGraph -ClientId $AppId -TenantId $TenantId -CertificateThumbprint $Thumbprint
Get-MgContext
Disconnect-MgGraph

Get-MgContext should show an AppOnly authentication context and should not prompt for a username or password. If it does, you've got certificate authentication working.

Common Mistakes and Fixes

SymptomCauseFix
Scheduled task can't find the certificateCreated under a different user profileCreate/import the certificate under the task's account, or use LocalMachine with correct private-key permissions.
Authentication fails; only the CER exists locallyThe private key is missingImport the PFX into the correct certificate store.
Connect command fails on a valid-looking thumbprintHidden spaces/characters copied from the portalPaste into Notepad first, or strip non-hex characters before use.
Command connects but returns "access denied"Missing API permission or admin consentAdd the correct Application permission and grant admin consent.
Certificate expiredPast the NotAfter dateCreate a replacement and upload it to the app registration (covered in Part 3).
Security best practices
  • No client secrets for production automation — use certificates.
  • Grant only the API permissions each script needs; document why each is granted.
  • Record the thumbprint and expiration date, and schedule a rotation reminder before it expires.
  • Protect and restrict access to PFX backups; never commit them to source control.
  • Keep the app's owners current and appropriate.

What's Next

You now have a certificate created, its private key verified, and a Microsoft Entra app registration configured to trust it with least-privilege permissions. In Part 2, we'll convert real scripts from client secrets to certificates and connect to Microsoft Graph, Exchange Online, and SharePoint PnP. In Part 3, we'll cover rotating certificates without downtime and troubleshooting.

Want your Microsoft 365 automation set up securely — or a broader security review? Explore our Managed IT Services and Microsoft 365 Services, and see our related guides on why MFA is valuable and Conditional Access.

References

Certificate authentication for PowerShell Microsoft 365 automation | IT Master Services