Secure your Microsoft 365 automation by removing shared secrets from your scripts. Part 2 of 3.
In Part 1 you created a certificate and configured a Microsoft Entra app registration to trust it. Now it's time to put it to work: convert your existing scripts from client secrets to certificate authentication, and connect to Microsoft Graph, Exchange Online, and SharePoint PnP the secure way.
The goal is simple — eliminate shared secrets stored in scripts, config files, scheduled tasks, and password spreadsheets. The certificate's thumbprint replaces the secret, and the thumbprint is just an ID, not a password.
Before you change anything
- Confirm the script currently uses a client secret, password, or stored credential.
- Confirm the Entra app registration has the certificate uploaded (Part 1).
- Confirm the local computer has the certificate's private key installed (
HasPrivateKey = True).
- Confirm the required API permissions exist and admin consent was granted.
- Make a backup copy of the script before editing it.
Part A — Convert the Script
Step 1: Find the secret-based code
Look for a connection block like this — and for variables named ClientSecret, Secret, Password, AppSecret, or Credential.
# Example only - this is the pattern you are REPLACING
$ClientSecret = "plain-text-secret-value"
$SecureSecret = ConvertTo-SecureString $ClientSecret -AsPlainText -Force
$Credential = New-Object System.Management.Automation.PSCredential($AppId, $SecureSecret)
Connect-MgGraph -TenantId $TenantId -ClientSecretCredential $Credential
Also check scheduled task arguments, external config files (JSON, XML, TXT, PS1, PSM1, CSV), and any runbooks or documentation that still reference the old secret.
Step 2: Replace the connection block
Swap the secret for a certificate thumbprint. This tells PowerShell which local certificate (and private key) to use.
$TenantId = "00000000-0000-0000-0000-000000000000"
$AppId = "00000000-0000-0000-0000-000000000000"
$CertificateThumbprint = "PASTE_CERTIFICATE_THUMBPRINT_HERE"
Connect-MgGraph `
-TenantId $TenantId `
-ClientId $AppId `
-CertificateThumbprint $CertificateThumbprint
The certificate must be installed in a store visible to the Windows account that runs the script. If a scheduled task runs as a different account, test while signed in as that account.
Step 3: Add a pre-flight certificate check
A junior admin shouldn't have to troubleshoot blindly. Add this before the connection command so the script fails with a clear message when the certificate is missing or expired.
$CertificateThumbprint = "PASTE_CERTIFICATE_THUMBPRINT_HERE"
$Cert = Get-ChildItem Cert:\CurrentUser\My | Where-Object Thumbprint -eq $CertificateThumbprint
if (-not $Cert) {
throw "Certificate $CertificateThumbprint was not found in Cert:\CurrentUser\My."
}
if (-not $Cert.HasPrivateKey) {
throw "Certificate $CertificateThumbprint was found, but has no private key. Import the PFX under the script-running account."
}
if ($Cert.NotAfter -lt (Get-Date)) {
throw "Certificate $CertificateThumbprint expired on $($Cert.NotAfter). Rotate the certificate."
}
if ($Cert.NotAfter -lt (Get-Date).AddDays(30)) {
Write-Warning "Certificate $CertificateThumbprint expires on $($Cert.NotAfter). Schedule rotation."
}
Step 4: Remove the old secret — safely
- Confirm the script works with certificate authentication in a test run.
- Remove the secret variable from the script and from any config files.
- Remove secret values from scheduled task arguments and saved credential/vault entries no longer needed.
- Only after every dependent script is migrated, remove or expire the old client secret in the Entra app registration.
Do not delete the old secret until you know every script that shares the app registration has been updated and tested. If several scripts share one app, verify each before removing the secret.
Step 5: Test as the run account
If the script runs manually, test it manually. If it runs from Task Scheduler, test it from Task Scheduler.
- Script starts without prompting for a password.
- The Graph/Exchange/PnP connection completes successfully.
- The script performs its expected read/write action, and the log confirms success.
- No secret values remain in the script or its command-line arguments.
Part B — Connection Patterns (Graph, Exchange, PnP)
These are working certificate-based connection patterns. Define your values once, then use them with each module. Replace every placeholder before running these in production.
$TenantId = "00000000-0000-0000-0000-000000000000"
$AppId = "00000000-0000-0000-0000-000000000000"
$Thumbprint = "PASTE_CERTIFICATE_THUMBPRINT_HERE"
$TenantName = "tenant.onmicrosoft.com"
$SiteUrl = "https://tenant.sharepoint.com/sites/SiteName"
Microsoft Graph PowerShell
Use Graph for Entra ID users, groups, devices, audit data, reports, and much of Microsoft 365 administration.
Install-Module Microsoft.Graph -Scope CurrentUser
Import-Module Microsoft.Graph.Authentication
Connect-MgGraph -ClientId $AppId -TenantId $TenantId -CertificateThumbprint $Thumbprint
Get-MgContext # should show AppOnly - no login prompt
Get-MgUser -Top 5 -Property DisplayName,UserPrincipalName |
Select-Object DisplayName, UserPrincipalName
Disconnect-MgGraph
Exchange Online PowerShell
Use Exchange Online for mailbox, transport, and recipient tasks. App-only Exchange also needs the Exchange.ManageAsApp permission plus an Exchange RBAC role assignment.
Install-Module ExchangeOnlineManagement -Scope CurrentUser
Import-Module ExchangeOnlineManagement
Connect-ExchangeOnline -AppId $AppId -CertificateThumbprint $Thumbprint -Organization $TenantName
Get-EXOMailbox -ResultSize 5 | Select-Object DisplayName, PrimarySmtpAddress
Disconnect-ExchangeOnline -Confirm:$false
SharePoint PnP PowerShell
Use PnP for SharePoint Online site, list, library, and permissions automation. Modern PnP app-only authentication uses a certificate — a client secret is not supported for this unattended scenario.
Install-Module PnP.PowerShell -Scope CurrentUser
Import-Module PnP.PowerShell
Connect-PnPOnline -Url $SiteUrl -ClientId $AppId -Tenant $TenantName -Thumbprint $Thumbprint
Get-PnPWeb | Select-Object Title, Url
Disconnect-PnPOnline
A reusable script header
Wrap your automation with strict-mode, error handling, and transcript logging so failures are easy to diagnose — especially from Task Scheduler.
#requires -Version 5.1
Set-StrictMode -Version Latest
$ErrorActionPreference = "Stop"
$LogFolder = "C:\Logs\M365-Automation"
New-Item -Path $LogFolder -ItemType Directory -Force | Out-Null
$LogFile = Join-Path $LogFolder ("ScriptName-{0}.log" -f (Get-Date -Format "yyyyMMdd-HHmmss"))
Start-Transcript -Path $LogFile
try {
# Connection and automation commands go here
}
catch {
Write-Error $_
throw
}
finally {
Stop-Transcript
}
Common Errors and Fixes
| Symptom | Cause | Fix |
Connect-MgGraph can't find the certificate | Wrong store or wrong user context | Verify the certificate exists in Cert:\CurrentUser\My for the run account. |
| Exchange connects but a cmdlet fails | App lacks Exchange permission or RBAC role | Verify Exchange.ManageAsApp and the Exchange role assignment. |
| PnP connection fails | Wrong tenant/site URL or missing SharePoint permission | Verify the URL, tenant name, certificate, and app permissions. |
| Works manually but not in Task Scheduler | Task runs as a different Windows account | Install/import the certificate under the task account, or use LocalMachine with proper private-key permissions. |
| Only updated the script, not the scheduled task account | The task runs under a different profile | Ensure the certificate is available to the task's account. |
Document the migration
For each converted script, record the script name, the old auth method (client secret), the new method (certificate thumbprint), the app registration, the test result, and where the backup/rollback copy lives. Good records make audits and future rotations painless.
What's Next
Your scripts now authenticate with a certificate and no longer carry secrets. In Part 3, we'll cover rotating and renewing the certificate without downtime, and a practical troubleshooting and incident-response playbook for when authentication breaks.
Missed the setup steps? Start with Part 1: create the certificate and configure Microsoft Entra. Need a hand securing your Microsoft 365 automation? See our Managed IT Services and Microsoft 365 Services.
References