In environments with internal PKI and Exchange Online, publishing S/MIME certificates centrally can save a lot of manual work. This PowerShell script exports public user S/MIME certificates from Active Directory, stores them as .cer files, and then writes them to Exchange Online mailbox attributes so they are available through the Global Address List (GAL). S/MIME in Exchange Online is used for message signing and encryption, and publishing the public certificate helps other users find the recipient’s encryption certificate more easily.learn.microsoft+2
One practical reason for this approach is that users often should not be given the permissions required to publish their own certificate data to Exchange Online mailbox attributes. Microsoft community discussions and support answers note that updating those attributes can require elevated Exchange permissions, which makes a central administrative process the safer option.
How the script works
The script runs in two phases. In the first phase, it queries the internal Windows Certification Authority with certutil, filters issued certificates for the required template, checks whether they are still valid, and exports the matching public certificates from Active Directory to .cer files. Because the certificate list is read from the CA database, the script should run on the internal Windows CA server, or at least on a system that can query that CA directly with the necessary permissions.
In the second phase, the script connects to Exchange Online using app-only certificate authentication. It reads the exported .cer files, converts them into the format expected by Exchange Online, and assigns them to the mailbox with Set-Mailbox by writing the UserSMimeCertificate and UserCertificate values. That makes the public certificate available for GAL-based lookup in Exchange Online.
What you need to change
Before using the script in your own environment, adjust the environment-specific variables and connection settings.
| Variable | Purpose |
|---|
| Variable | Purpose |
|---|---|
CertPath | Folder used to temporarily store the exported .cer files. |
LogPath | Path of the transcript log file. |
CertThumb | Thumbprint of the certificate used for Exchange Online app-only authentication. learn.microsoft |
AppID | Entra ID application ID used to connect to Exchange Online. learn.microsoft |
Organization | Your Microsoft 365 tenant name, for example contoso.onmicrosoft.com. learn.microsoft |
| Certificate template filter | Replace *TGUserCryptGPO* with the template name used by your internal CA. |
The required PowerShell modules must also be installed, especially ADObjectCertificate and ExchangeOnlineManagement. In addition, the executing account and app registration need the necessary permissions in Active Directory, on the CA, and in Exchange Online. Certificate-based Exchange Online connections also require the authentication certificate to be installed on the machine where the script runs.
S/MIME and the GAL
S/MIME uses public key cryptography. For encrypted email, the sender needs access to the recipient’s public certificate, while the private key remains with the certificate owner. Publishing the public S/MIME certificate to the GAL makes it easier for internal recipients to find the correct certificate when they want to encrypt mail.
This script only works with the public certificate data. It does not export or upload any private key material, which is exactly how this process should work. In other words, the script helps distribute the public encryption certificate in Exchange Online while the user keeps control of the private key locally.
Why this is useful
This approach is especially useful in hybrid or PKI-based environments where certificates are issued internally but Exchange Online is used for mailboxes and address book access. Instead of relying on each user to publish a certificate manually, the process can be centralized, standardized, and automated. That reduces user effort and ensures a more consistent S/MIME rollout across the organization.
GitHub download
Download the script here: GitHub repository