Skip to content

Exchange Online certificate authentication on Linux

directorcia edited this page Oct 14, 2026 · 1 revision

o365-connect-exo-cert-linux.ps1 creates a certificate for app-only Exchange Online authentication, can provision the corresponding Entra application and Exchange permissions, and connects to Exchange Online from the current PowerShell session.

The script is intended for Linux and requires PowerShell 7.4 or later. On Windows, use o365-connect-exo-cert.ps1 instead.

What the script does

Choose exactly one of these modes for each invocation:

Mode Operation
-GenerateLocalCertificate Creates a self-signed RSA-2048/SHA-256 certificate, exports the public certificate as a .cer, and exports the private key as a password-protected .pfx. Does not require PowerShell modules unless provisioning is also requested.
-UseCertificateAuth Loads a PFX into memory, validates it, and connects to Exchange Online using app-only certificate authentication. The connection is available in the PowerShell process that ran the script.

-ProvisionEntraApp can be combined with certificate generation to perform one-time tenant setup. It creates or reuses an Entra application, uploads the public certificate, assigns the Exchange Exchange.ManageAsApp application role, creates the application's service principal if necessary, and adds that principal to the Exchange Organization Management role group. This grants full Exchange administration; use it only when that level of access is intended.

Provisioning requires an administrator who can consent to the requested Microsoft Graph application-management permissions and manage Exchange role groups. It uses device-code sign-in for Microsoft Graph and Exchange Online and is not available in headless mode. The script checks that the Graph and Exchange sign-ins are for the same tenant and that the supplied organization domain is an accepted domain before changing Exchange RBAC.

Requirements

  • Linux and PowerShell 7.4 or later.
  • For connection and provisioning, ExchangeOnlineManagement 3.5.0 or later.
  • For -ProvisionEntraApp, Microsoft.Graph.Authentication 2.0.0 or later, plus an administrator able to complete both device-code sign-ins and authorize the setup operations.
  • Network access to the PowerShell Gallery when required modules need to be installed, and to Microsoft Graph and Exchange Online.

When prompts are enabled, missing modules are installed for the current user; sudo is not needed. Headless runs require the modules to be installed already.

Storage and security

By default, the script stores certificate files in:

$XDG_DATA_HOME/ciaops/exo

If XDG_DATA_HOME is not set to an absolute path, it uses ~/.local/share/ciaops/exo. The default profile map is:

$XDG_CONFIG_HOME/ciaops/exo/o365-exo-cert-auth.json

If XDG_CONFIG_HOME is not set to an absolute path, it uses ~/.config/ciaops/exo/o365-exo-cert-auth.json.

Storage directories are restricted to owner-only mode 700; files created by the script are restricted to owner read/write mode 600, independent of the umask. Symbolic links are rejected in storage paths. Custom output and profile directories must be dedicated to this script because their permissions are also restricted to 700.

The PFX is encrypted with a nonempty password. The password is not saved in the profile. Supply it interactively, pass a SecureString, or provide the name of a process environment variable containing the password. Environment variables are not a secret vault and may be accessible to other processes running as the same user; prefer retrieving a SecureString from a secret vault in automation. Do not treat ConvertFrom-SecureString output on Linux as equivalent to Windows DPAPI protection.

During connection, the script rejects a PFX that is a symbolic link or has permissions broader than owner read/write, checks its private key and validity, and imports it with an ephemeral key-storage setting. It disposes of the in-memory certificate when the script finishes. Keep the PFX private and store a backup securely; the .cer contains only the public certificate.

-enableLog writes a transcript under the private certificate data directory. Provisioning transcripts may contain short-lived device codes, so protect and remove logs according to your organization's handling policy.

Typical setup

Run these commands in a PowerShell session on Linux. Replace the tenant domain with the primary .onmicrosoft.com domain for your tenant:

./o365-connect-exo-cert-linux.ps1 `
  -GenerateLocalCertificate `
  -ProvisionEntraApp `
  -Tenant contoso.onmicrosoft.com

The script prompts for a PFX password and for administrator device-code sign-ins. -Organization defaults to -Tenant for this provisioning flow; provisioning requires the primary .onmicrosoft.com organization domain. The app display name defaults to the generated certificate subject, and the saved profile name defaults to the app display name.

The script prints the .cer and .pfx paths and thumbprint. When provisioning completes, it saves a profile containing the tenant, organization, app ID, certificate thumbprint, and PFX path. It does not save the PFX password. New application permissions and Exchange RBAC changes can take 15–30 minutes to replicate.

Generate a certificate without provisioning

./o365-connect-exo-cert-linux.ps1 -GenerateLocalCertificate

The defaults are subject O365-EXO-AppAuth, a two-year lifetime, and the default certificate directory. Use -GeneratedCertSubject, -GeneratedCertYearsValid (1–100), -GeneratedCertOutputPath, and -GeneratedPfxPassword to customize generation. The public .cer must be registered with an Entra application that has the appropriate Exchange application permission and Exchange RBAC assignment before it can be used to connect.

Connect using the saved profile

After provisioning and allowing time for permission replication, run:

./o365-connect-exo-cert-linux.ps1 `
  -UseCertificateAuth `
  -Tenant contoso.onmicrosoft.com

The script selects the matching profile and prompts for its PFX password. If there is more than one matching profile, specify -ProfileName. -Tenant filters profiles by their tenant or organization value.

Connect using explicit values

To bypass profile lookup, supply all three connection values:

$pfxPassword = Read-Host 'PFX password' -AsSecureString
./o365-connect-exo-cert-linux.ps1 `
  -UseCertificateAuth `
  -Organization contoso.onmicrosoft.com `
  -AppId 11111111-2222-3333-4444-555555555555 `
  -CertificateFilePath "$HOME/.local/share/ciaops/exo/certificate.pfx" `
  -CertificatePassword $pfxPassword

The PFX path must identify an owner-only file. Optionally pass -CertificateThumbprint to require that the PFX thumbprint matches an expected value.

Using it in automation

For a noninteractive connection, first provision the application and profile interactively and ensure the required modules are installed. Then retrieve the password from your secret manager as a SecureString in the same PowerShell job and use:

./o365-connect-exo-cert-linux.ps1 `
  -UseCertificateAuth `
  -ProfileName 'EXO automation' `
  -CertificatePassword $pfxPassword `
  -noprompt `
  -noupdate

-noprompt also has the alias -Headless. In this mode the script cannot install missing modules, prompt for a password, check for module updates, or run provisioning. If a SecureString is not passed, set -CertificatePasswordEnvironmentVariable to the name of an environment variable injected into the process by the scheduler or secret manager. The value is read from the process environment and is not printed or stored.

The Exchange connection does not persist across processes. Run this script in the same PowerShell process or job that will execute Exchange cmdlets, for example:

./o365-connect-exo-cert-linux.ps1 -UseCertificateAuth -ProfileName 'EXO automation' -CertificatePassword $pfxPassword -noprompt -noupdate
Get-EXOMailbox -ResultSize 10

Parameters at a glance

Parameter Purpose
-GenerateLocalCertificate Generate a certificate and export .cer and encrypted .pfx files.
-UseCertificateAuth Connect to Exchange Online using certificate authentication.
-ProvisionEntraApp During generation, provision the Entra application and Exchange access. Requires interactive administrator sign-in.
-GeneratedCertSubject Generated certificate common name; default O365-EXO-AppAuth.
-GeneratedCertYearsValid Certificate lifetime in years; default 2, allowed range 1–100.
-GeneratedCertOutputPath Dedicated certificate output directory.
-GeneratedPfxPassword SecureString password for a generated PFX. If omitted, the script prompts unless headless mode is active.
-CertificateFilePath Existing encrypted PFX path for connection; takes precedence over the path in a profile.
-CertificatePassword SecureString PFX password.
-CertificatePasswordEnvironmentVariable Name of a process environment variable to use when a password parameter is omitted.
-CertificateThumbprint Optional expected certificate thumbprint; also checked when provided by a profile.
-CertificateMapPath Profile JSON path. The file may be an array or an object with a profiles property.
-Tenant Tenant ID/domain for provisioning, or a tenant/organization filter for profile lookup.
-Organization Organization's primary .onmicrosoft.com domain for provisioning; can also be supplied explicitly for connection.
-AppId Entra application client ID for an explicit connection.
-ProfileName Profile name to select.
-AppDisplayName Application display name during provisioning; defaults to the generated certificate subject.
-SetupClientId Optional tenant-approved public client ID for Microsoft Graph device sign-in.
-noprompt / -Headless Disable prompts; requires passwords and modules to be supplied/preinstalled and cannot be combined with provisioning.
-noupdate Skip the Exchange module Gallery update check.
-enableLog Write a timestamped transcript in the private certificate data directory.

Troubleshooting notes

  • No matching profile: check the -Tenant, -Organization, and -ProfileName filters, or provide -Organization, -AppId, and -CertificateFilePath together for an explicit connection.
  • Headless password or module error: pass a SecureString or configure -CertificatePasswordEnvironmentVariable, and install the required modules for the current user before running the script.
  • PFX permission error: set the PFX permissions to owner read/write only, for example chmod 600 -- /path/to/certificate.pfx.
  • Certificate thumbprint or validity error: confirm the selected PFX, expected thumbprint, and certificate dates.
  • Provisioned app cannot connect immediately: allow 15–30 minutes for Entra permissions and Exchange RBAC changes to replicate.
  • Connection disappears: run the connection script and Exchange cmdlets in the same PowerShell process; the connection ends when that process exits.

Clone this wiki locally