Stop using client secrets for unattended Microsoft Graph PowerShell scripts
Verified on: PowerShell 7.4+, Microsoft.Graph SDK
When automating administrative tasks across Microsoft 365 tenants—like offboarding scripts, license audits, or Teams provisioning—many technicians still generate a client secret in an Entra App Registration and paste it directly into scheduled tasks or RMM script variables.
This creates two major headaches:
- Plaintext Credential Exposure: Client secrets can easily leak into PowerShell transcripts, monitoring agent logs, process dumps, or local disk caches. Anyone with read access to the automation host can harvest the secret.
- The Operational Expiration Trap: Entra client secrets expire after a maximum of 24 months. When they expire, scripts fail silently in the middle of the night, often breaking critical business workflows before anyone notices.
The enterprise-grade solution is certificate-based authentication (CBA) using the Windows certificate store. The private key remains locked inside the local machine store (or TPM), and PowerShell authenticates using only the certificate thumbprint.
Here is the exact 3-step workflow to configure it:
Step 1: Generate the Certificate on the Automation Host
Run this in an elevated PowerShell session on your script runner / automation server:
# Create a 2048-bit self-signed certificate valid for 3 years
$cert = New-SelfSignedCertificate `
-Subject "CN=Automation-MgGraph-Runner" `
-CertStoreLocation "Cert:\LocalMachine\My" `
-KeyExportPolicy NonExportable `
-KeySpec Signature `
-KeyLength 2048 `
-KeyAlgorithm RSA `
-HashAlgorithm SHA256 `
-NotAfter (Get-Date).AddYears(3)
# Export the public key (.cer) to upload to Entra ID
Export-Certificate -Cert $cert -FilePath "C:\Staging\Automation-MgGraph-Runner.cer"
# Copy the thumbprint for your script
$cert.Thumbprint
Setting -KeyExportPolicy NonExportable prevents standard users from dumping the private key from memory or exporting a PFX file.
Step 2: Upload the Public Key to Entra ID
- In the Microsoft Entra admin center, open App registrations and select your application.
- Go to Manage > Certificates & secrets > Certificates.
- Click Upload certificate, select
Automation-MgGraph-Runner.cer, and save.
Step 3: Connect Headlessly in Your Script
In your automated PowerShell script, authenticate without passing any passwords, tokens, or plaintext secrets:
$ClientId = "11111111-2222-3333-4444-555555555555"
$TenantId = "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee"
$Thumbprint = "9F8E7D6C5B4A3928170F1E2D3C4B5A69788796A5"
Connect-MgGraph `
-ClientId $ClientId `
-TenantId $TenantId `
-CertificateThumbprint $Thumbprint `
-NoWelcome
# Example query to verify connection
Get-MgOrganization | Select-Object DisplayName, Id
The Microsoft.Graph module queries Cert:\LocalMachine\My (falling back to Cert:\CurrentUser\My) to sign the token request locally. If an attacker gains read access to the script, they obtain only the public Application ID and thumbprint—useless without access to the local certificate store.