Self-hosting
Two unusual properties drive the choice: the app hosts PowerShell in-process with warm, long-lived runspace pools (so it must stay warm and is memory-heavy), and it signs into Exchange with a Managed Identity (so it wants Azure compute - MI only works there).
Recommendation: Azure Container Apps, with App Service as the simpler alternative.
| Option | Verdict | Why |
|---|---|---|
| Azure Container Apps | Recommended | Container-native; native Managed Identity; ingress idle timeout configurable to 30 min (vs App Service’s fixed ~240s). Set minReplicas ≥ 1 so the warm pools survive. |
| Azure App Service (Linux container) | Simpler alternative | Native MI; Always On keeps pools warm; flat predictable price; matches the config below. Hard ~240s request ceiling. |
| AKS | Only if already on Kubernetes | Full control, heaviest ops. |
| Azure Functions / serverless | Not a fit | The 230s ceiling + cold-start/stateless model fights the warm-pool design. |
Reliability essentials (any platform): keep it warm (minReplicas ≥ 1 / Always On); 2-4 GiB
memory headroom (PowerShell + EOM + pools); ≥ 2 instances for HA - stateless between requests, so
no session affinity; wire /readyz (real pool probe) as readiness and /healthz as liveness;
Managed Identity for Exchange Online + a certificate (from Key Vault) for Purview/IPPS -
IPPS has no MI path; put Front Door / APIM in front for WAF/TLS/CORS.
Production config:
{ "ExchangeOnline": { "Organization": "<tenant>.onmicrosoft.com", "ConnectionMode": "SystemAssignedManagedIdentity", "PoolSize": 3 }, "AzureAd": { "Instance": "https://login.microsoftonline.com/", "TenantId": "<tenant-guid>", "ClientId": "<app-id>", "Audience": "api://<app-id>" }, "License": { "Key": "<from Key Vault>" }}Assign Exchange.ManageAsApp + a directory role to the host’s managed identity. No client secrets
in production.
Indicative cost (Container Apps, US list/PAYG): ~$35-75/mo for a lean single-replica pilot,
~$110-185/mo for production HA (2 replicas + Front Door) - a low-volume-but-stays-warm profile,
so you pay for 1-2 small always-on replicas, not per request. The Dockerfile, the Microsoft.App
Bicep, identity wiring, the deploy flow, and the full cost breakdown are in the
Azure Container Apps reference.

