Give PIM Manager your own address (custom host name)
Written by the PIM Manager team for PIM Manager 2.4.576 · 2026-10-10
Every PIM Manager gets a generated address from Azure Container Apps, for example
ca-pim-manager.<generated-name>.<region>.azurecontainerapps.io. This guide gives it a second address in your own
domain, for example pim-manager.contoso.com or pim-manager.corp.contoso.local.
One script does it: Set-PimManagerCustomHost.ps1. What it does depends on how your environment was built:
| Your environment | Example name | Certificate | DNS |
|---|---|---|---|
| Private (internal): the PIM Manager has a private IP in your network | pim-manager.corp.contoso.local or pim-manager.contoso.com |
Your own certificate (Key Vault or PFX file) | An A record to the environment’s private IP: written by the script into an existing Azure Private DNS zone, or printed for you to add to your AD DNS |
| Public (external): the PIM Manager is reached over the internet | pim-manager.contoso.com |
A free managed certificate from Azure | A CNAME and a TXT record in your public DNS, which you create |
A public environment cannot use a private-only name. Azure proves you own the name by looking it up in public DNS before it issues the certificate. A name such as
pim-manager.corp.contoso.localcan never pass that check, so the script refuses it on a public environment (it refuses names ending in.local,.lan,.internal,.intranet,.corp,.home,.localdomainand.private). For a public environment, use a public subdomain you own, or keep the generated address. A private name needs a private (internal) environment; see Install in private mode.
What you get
- The PIM Manager answers on your name, with a certificate for that name.
- The generated address keeps working. The script adds the name; it does not remove or change the generated one.
- Sign-in works on the new name: the script adds
https://<your name>/.auth/login/aad/callbackto the reply URLs of the PIM Manager’s sign-in app registration. - The name is added to the PIM Manager’s list of known host names (
PIM_MANAGER_HOSTNAMES). Links in notification mail then use your name. See Mail links for when that switch happens. - A stable address. The generated address changes if the environment is ever rebuilt; your name does not (you re-run this script after a rebuild, see After an environment rebuild).
What this guide does not cover
- The access request portal (the RFA broker,
ca-pim-rfa) runs as its own app with its own generated address. This script does not give it a custom name, and no other PIM script does today. Not yet automated. - The MCP endpoint (
/mcp) is served by the PIM Manager itself, so it is reached on the new name too (https://pim-manager.contoso.com/mcp). It needs no extra step: its token check is tied to the app registration, not to the host name.
Prerequisites
| What | Private environment | Public environment |
|---|---|---|
| A PIM Manager that is installed and signs in | yes | yes |
A name in a domain you control, at least three labels (name.domain.tld), not inside the environment’s own azurecontainerapps.io domain |
yes | yes, and it must be a public name |
| A certificate for that exact name (or a wildcard that covers it), with its private key | yes: in Key Vault (-KeyVaultName + -KeyVaultCertName; PFX or PEM) or a PFX file (-PfxPath, -PfxPassword) |
no, Azure issues a free one |
| Clients trust the certificate’s issuer (for example your internal CA, deployed to admin devices) | yes | automatic |
| DNS | an Azure Private DNS zone that your name belongs to (for pim-manager.corp.contoso.local: corp.contoso.local or contoso.local) that already exists, or an AD DNS zone where your DNS admin adds one A record |
access to your public DNS to add a CNAME and a TXT record |
| A route from the machine running the script | to management.azure.com, graph.microsoft.com, login.microsoftonline.com, and <vault>.vault.azure.net when the certificate is in Key Vault |
the same, without the vault |
| PowerShell 7 (Windows PowerShell 5.1 also works, except for a PEM certificate in Key Vault) and the PIM Manager release package | yes | yes |
No Azure CLI and no PowerShell modules. Every call is a REST call to Azure Resource Manager, Microsoft Graph and
(for a Key Vault certificate) the vault. The script signs in in the browser to one tenant, the one you pass in
-TenantId, and refuses to continue if the session belongs to any other tenant. If Invardia support runs it for you,
it uses your tenant’s Invardia Support app session instead.
Run it from the release package folder that Install-Invardia (or the guided install) downloaded and verified:
.\tools\setup\Set-PimManagerCustomHost.ps1. It loads the engine libraries next to it, so it does not work as a single
downloaded file. Its documentation page is https://invardia.com/docs/pim/scripts/Set-PimManagerCustomHost/.
Rights
| Right | Where | Needed for |
|---|---|---|
| Contributor | the PIM resource group | adding the name and the certificate to the PIM Manager app and its environment, and setting PIM_MANAGER_HOSTNAMES |
| Private DNS Zone Contributor | the resource group of the private DNS zone (-PrivateDnsResourceGroup, default the PIM resource group) |
private environment with -Dns Auto or PrivateDnsZone: listing the zones there, writing the A record into the existing zone and the VNet links. The script never creates the zone. |
| Network Contributor (or the VNet join right) | each virtual network in -LinkVnetIds |
linking the zone to those networks, only for links that do not exist yet |
| Key Vault Secrets User | the vault named in -KeyVaultName |
reading the certificate. Its PFX (or PEM, converted to PFX in memory) goes straight into the upload and is never written to disk. |
| Application Administrator, or owner of the PIM Manager’s sign-in app registration | Microsoft Entra ID | adding the reply URL. Skip with -SkipEasyAuth if someone else adds it (see Step 4). |
| Your DNS administrator | AD DNS (-Dns AdDns) or public DNS |
adding the record(s) the script prints. PIM writes nothing to these. |
Who runs what
| Who | What |
|---|---|
| PKI administrator (private only) | Issues the certificate for the name and puts it in Key Vault, or hands over a PFX. |
| Azure administrator | Runs the script: plan first, then the real run. |
| DNS administrator | Private zone: creates the Azure Private DNS zone if it does not exist yet. AD DNS: adds the one printed A record. Public: adds the printed CNAME and TXT records. |
| Entra administrator | Only if the Azure administrator cannot update the sign-in app registration: adds the reply URL. |
Step 0: Decide and collect
| Decision | Your value (example) | Parameter |
|---|---|---|
| Tenant, subscription, PIM resource group | <tenant-id>, <subscription-id>, rg-pim |
-TenantId -SubscriptionId -ResourceGroup |
| The name | pim-manager.corp.contoso.local (private) or pim-manager.contoso.com (public) |
-HostName |
| PIM Manager app name, if you changed it | ca-pim-manager (default) |
-ManagerApp |
| Certificate (private only) | Key Vault kv-pim-contoso, certificate pim-manager-corp-contoso-local; or .\pim-manager.pfx |
-KeyVaultName -KeyVaultCertName, or -PfxPath -PfxPassword |
| DNS mode | Auto (private: Azure Private DNS zone; public: print the public records), PrivateDnsZone, AdDns, or None |
-Dns |
| Private DNS zone location and links | rg-dns; hub and PIM VNet resource ids |
-PrivateDnsResourceGroup -LinkVnetIds |
| AD DNS server name, only to fill in the printed lines | dc01.corp.contoso.local |
-AdDnsServer |
| The DNS zone the name lives in, only when the default below is wrong | contoso.local |
-DnsZone |
How the zone is chosen.
- Azure Private DNS zone: the script lists the private DNS zones in
-PrivateDnsResourceGroupand uses the longest one your name ends with. The rest of the name is the record. With onlycontoso.localthere,pim-manager.corp.contoso.localbecomes recordpim-manager.corpincontoso.local. Ifcorp.contoso.localexists too, it wins and the record ispim-manager. - AD DNS: the script cannot see your AD zones. It assumes the name minus its first label (
corp.contoso.local), says so in the output, and tells you to pass-DnsZone contoso.localwhen your zone is a different parent. -DnsZonesets the zone explicitly in both modes. It must be a parent of the name.
Private (internal) environment
Step 1: Put the certificate in place (PKI administrator)
Issue a certificate whose subject or SAN is your name (or a wildcard covering it), with its private key.
- Key Vault: import it as a certificate, PFX (PKCS #12) or PEM. The script reads the certificate’s secret: a PFX is uploaded as it is, a PEM is converted to PFX in memory (this needs PowerShell 7; Windows PowerShell 5.1 stops with a message). Give the account running the script Key Vault Secrets User on the vault, and make sure the machine running the script can reach the vault (vault firewall or private endpoint).
- PFX file: copy it to the machine running the script. You pass the password as a SecureString.
Make sure the admin devices that will open the PIM Manager trust the issuing CA.
Step 2a: DNS with an Azure Private DNS zone (-Dns Auto or PrivateDnsZone)
The script writes the A record only into a zone that already exists in -PrivateDnsResourceGroup (default: the PIM
resource group): the longest zone there that your name ends with, or -DnsZone (see How the zone is chosen).
PIM never creates a zone named after your domain. A private zone corp.contoso.local linked to a
VNet answers for every name in corp.contoso.local on that VNet, so your other names in that domain would stop
resolving there. Create it only if no other DNS serves that domain for those networks.
If no zone fits, the plan (Step 3) prints what to create (shown here for the name minus its first label), and the real run binds the name but writes no DNS:
PIM did NOT create the Azure Private DNS zone 'corp.contoso.local' (it does not exist in resource group 'rg-dns').
A private zone named after your domain answers for EVERY name in corp.contoso.local on each VNet linked to it -- create it
only if no other DNS serves corp.contoso.local for those VNets. Otherwise add A pim-manager.corp.contoso.local -> 10.50.0.x in the DNS that does.
To use a private zone: create zone 'corp.contoso.local' (or any parent zone of the name) in 'rg-dns', then re-run this
script -- it picks the longest existing zone the name ends with (or -DnsZone) and adds:
A pim-manager.corp.contoso.local -> 10.50.0.x
link corp.contoso.local -> <vnet id> (registration off)
then check (expect 10.50.0.x): Resolve-DnsName pim-manager.corp.contoso.local -Type A
When the zone exists, the script:
- writes the A record (
pim-managerincorp.contoso.local, orpim-manager.corpincontoso.local) → the environment’s static private IP. It reads the record first and writes it only when it is not already exactly that one address. The record set is written whole, so any other address on that record is replaced. - links the zone to each VNet in
-LinkVnetIdsthat is not linked to it yet, with auto-registration off. A VNet that is already linked under any link name is left alone. New links are namedlink-<vnet name>.
Include every network whose clients must resolve the name: usually the hub (where your DNS resolver lives) and the PIM VNet. If your on-premises DNS forwards to an Azure DNS Private Resolver, add a conditional forwarder for the zone too.
Step 2b: DNS with Active Directory DNS (-Dns AdDns)
PIM writes nothing to your AD DNS and needs no DNS Server tools (RSAT). It prints, before anything is changed and
also under -WhatIf:
- the one A record to add:
pim-manager.corp.contoso.local→ the environment’s static IP, in your existing zone (PIM creates no zone and never adds a wildcard). Without-DnsZonethe script assumes the zonecorp.contoso.localand prints a line saying so; if your zone iscontoso.local, re-run with-DnsZone contoso.localand the record becomespim-manager.corpincontoso.local; - a ready-to-paste
Add-DnsServerResourceRecordAline and adnscmdline (with your server name if you passed-AdDnsServer); - the check to run afterwards:
Resolve-DnsName pim-manager.corp.contoso.local -Type A, expecting the static IP.
Your DNS administrator adds that record. The script still binds the name and updates the PIM Manager; only the DNS step is yours.
Step 3: Plan (changes nothing)
Key Vault certificate, Azure Private DNS zone in the hub’s DNS resource group:
$hub = '/subscriptions/<hub-subscription-id>/resourceGroups/rg-connectivity/providers/Microsoft.Network/virtualNetworks/vnet-hub'
$pim = '/subscriptions/<subscription-id>/resourceGroups/rg-pim/providers/Microsoft.Network/virtualNetworks/vnet-pim'
.\tools\setup\Set-PimManagerCustomHost.ps1 -SubscriptionId <subscription-id> -TenantId <tenant-id> -ResourceGroup rg-pim `
-HostName pim-manager.corp.contoso.local -KeyVaultName kv-pim-contoso -KeyVaultCertName pim-manager-corp-contoso-local `
-Dns PrivateDnsZone -PrivateDnsResourceGroup rg-dns -LinkVnetIds $hub,$pim -WhatIf
PFX file and AD DNS instead:
$pw = Read-Host 'PFX password' -AsSecureString
.\tools\setup\Set-PimManagerCustomHost.ps1 -SubscriptionId <subscription-id> -TenantId <tenant-id> -ResourceGroup rg-pim `
-HostName pim-manager.corp.contoso.local -PfxPath .\pim-manager.pfx -PfxPassword $pw `
-Dns AdDns -AdDnsServer dc01.corp.contoso.local -WhatIf
The plan reads the PIM Manager app and its environment, then prints:
- one line such as
custom name pim-manager.corp.contoso.local on a private environment: certificate = keyvault, DNS = privatezone; - the DNS record:
DNS A pim-manager.corp.contoso.local -> 10.50.0.x; - whether the private zone exists (and, if not, what to create), or the AD DNS lines;
What if: Performing the operation "custom host name ..." on target "ca-pim-manager"andpreview only -- nothing was changed.
Refusals you may see in the plan, and what they mean:
| Message (shortened) | Fix |
|---|---|
needs at least three labels |
Use name.domain.tld. |
is inside the environment's own default domain |
Pick a name in your own domain. |
an INTERNAL (private-only) environment cannot validate a free managed certificate |
Give -KeyVaultName + -KeyVaultCertName, or -PfxPath. |
the environment has no static private IP |
The environment is not built the way the private DNS step expects. Use -Dns None and point your DNS yourself, or ask support. |
Step 4: Apply
Run the same command without -WhatIf. In order:
- adds the name to the PIM Manager app (if it is not there yet);
- uploads your certificate to the Container Apps environment, under a name derived from the host name
(
pim-manager-corp-contoso-local), and binds the name to it (SNI); - writes the private DNS record and links (Step 2a), or reminds you that PIM wrote nothing to AD DNS (Step 2b);
- adds the name to
PIM_MANAGER_HOSTNAMESon the PIM Manager. This creates a new revision, so the PIM Manager restarts once; - adds
https://pim-manager.corp.contoso.local/.auth/login/aad/callbackto the sign-in app registration.
It ends with == done: https://pim-manager.corp.contoso.local.
If the account cannot update the app registration, run with -SkipEasyAuth and ask an Entra administrator to add
the reply URL above to the PIM Manager’s sign-in app registration (Authentication > Web > Redirect URIs). Until then,
sign-in on the new name fails with a redirect-URI mismatch; the generated address still works.
Every step checks what exists first, so a failed run is fixed and re-run with the same command.
Public (external) environment
Step 1: Plan and get the records (changes nothing)
.\tools\setup\Set-PimManagerCustomHost.ps1 -SubscriptionId <subscription-id> -TenantId <tenant-id> -ResourceGroup rg-pim `
-HostName pim-manager.contoso.com -WhatIf
No certificate parameters: on a public environment Azure issues a free managed certificate. The plan prints the two records for your public DNS:
DNS CNAME pim-manager.contoso.com -> ca-pim-manager.<generated-name>.<region>.azurecontainerapps.io
DNS TXT asuid.pim-manager.contoso.com -> <verification id of the PIM Manager app>
The TXT record proves you own the name; the CNAME points the name at the PIM Manager. The verification id belongs to this app. If the app is ever recreated, it changes: take it from a fresh plan, never from an old note.
Running without -WhatIf and without -PublicDnsReady prints the same records and stops with
Create the CNAME and TXT records above in your public DNS, then re-run with -PublicDnsReady. Nothing is changed.
Step 2: Create the records (DNS administrator)
In the public DNS zone contoso.com, create:
CNAME pim-manager→ the generated address shown in the plan;TXT asuid.pim-manager→ the verification id shown in the plan.
Check from any machine that both resolve publicly before Step 3:
Resolve-DnsName pim-manager.contoso.com -Type CNAME
Resolve-DnsName asuid.pim-manager.contoso.com -Type TXT
Step 3: Apply
.\tools\setup\Set-PimManagerCustomHost.ps1 -SubscriptionId <subscription-id> -TenantId <tenant-id> -ResourceGroup rg-pim `
-HostName pim-manager.contoso.com -PublicDnsReady
In order:
- adds the name to the PIM Manager app;
- requests the free managed certificate (CNAME validation) and waits for it, up to 20 minutes. If it does not issue,
the run stops with
are the CNAME and TXT (asuid) records in public DNS?; check the records and re-run; - binds the name to that certificate;
- adds the name to
PIM_MANAGER_HOSTNAMES(a new revision, one restart); - adds
https://pim-manager.contoso.com/.auth/login/aad/callbackto the sign-in app registration (or skip with-SkipEasyAuth, as in the private case).
Azure renews the managed certificate itself while the CNAME stays in place.
-Dns Noneon a public environment only means the plan prints no records for you. The free managed certificate still validates through public DNS, so the script still stops until you pass-PublicDnsReady, and names the CNAME and TXT records it needs.
Verify
From a machine that should reach the PIM Manager (inside your network for a private environment):
Resolve-DnsName pim-manager.corp.contoso.local -Type A # private: the environment's static IP (10.50.0.x)
Resolve-DnsName pim-manager.contoso.com # public: CNAME to ...azurecontainerapps.io
Invoke-WebRequest https://pim-manager.contoso.com/ -MaximumRedirection 0 -SkipHttpErrorCheck |
Select-Object StatusCode, @{n='Location';e={$_.Headers.Location}} # 302 to login.microsoftonline.com -- never 200
Then:
- Open
https://<your name>in the browser. The certificate is valid for the name (no warning), and sign-in returns to the PIM Manager on your name. - Open the generated address. It still works.
- Check the setting the PIM Manager uses for mail links (next section).
In the Azure portal you can also see the result: Container App ca-pim-manager > Custom domains shows the name as
Secured, and Containers > Environment variables shows PIM_MANAGER_HOSTNAMES.
Mail links
Notification mail (from the engine, the scheduler and the PIM Manager) builds its Open in PIM Manager link from the setting ManagerUrl. The PIM Manager records it the first time a signed-in person opens it, when it is empty.
- If ManagerUrl was recorded automatically as the generated address, it is switched once to your name the next time someone signs in to the PIM Manager after this change (on any of its names).
- If someone set ManagerUrl by hand to another value, it is never overwritten. Change it yourself in the PIM Manager’s Settings.
The access request portal’s own link (RfaSettings.portalUrl) is not affected; see What this guide does not cover.
After an environment rebuild
A rebuild creates a new Container Apps environment and a new PIM Manager app, so the binding and the certificate in
the environment are gone, and a private environment usually gets a new static IP. Run this script again with the same
parameters. It rewrites the private DNS record to the new IP, re-uploads or re-requests the certificate, and re-adds
the name and reply URL where they are missing. For a public environment, take the new verification id from a fresh plan
and update the TXT record first. Rebuild-PimEnvExternal.ps1 also has a -CustomDomain parameter that binds a public
name during the rebuild itself.
A normal re-deploy or nightly update does not remove the name: it updates the existing PIM Manager and keeps its custom domains, its environment variables and the existing reply URLs.
Change or remove the name
Re-running the script with a different -HostName adds a second name next to the first one; there is no rename.
To change the name: run the script for the new name (Steps above), check it works, then remove the old one as below.
To remove a name, run the script with -Remove (plan it first with -WhatIf):
.\tools\setup\Set-PimManagerCustomHost.ps1 -SubscriptionId <subscription-id> -TenantId <tenant-id> -ResourceGroup rg-pim `
-HostName pim-manager.corp.contoso.local -Remove -WhatIf
Without -WhatIf it:
- removes the name from the PIM Manager app (the other names stay);
- deletes the certificate the script created for that name (
pim-manager-corp-contoso-local) from the environment, only when no other name uses it. If Azure refuses because another app still binds it, the script warns and moves on; - removes the name from
PIM_MANAGER_HOSTNAMES(a new revision); - removes
https://<name>/.auth/login/aad/callbackfrom the sign-in app registration (not with-SkipEasyAuth); - prints the DNS record(s) to delete. PIM deletes no DNS record and never a zone: your DNS administrator deletes them;
- reminds you to check ManagerUrl in Settings (step 6 below).
By hand, if you cannot run the script, in this order:
| # | Where | What to do |
|---|---|---|
| 1 | Azure portal > Container App ca-pim-manager > Custom domains |
Delete the name. |
| 2 | Azure portal > Container Apps environment > Certificates | Delete the certificate named after the host name (for example pim-manager-corp-contoso-local): under Bring your own certificates for a private environment, under Managed certificate for a public one. |
| 3 | Container App ca-pim-manager > Containers > Environment variables |
Remove the name from PIM_MANAGER_HOSTNAMES (comma-separated); delete the variable if it becomes empty. Saving creates a new revision. |
| 4 | Microsoft Entra ID > App registrations > the PIM Manager’s sign-in app > Authentication | Remove https://<name>/.auth/login/aad/callback. Keep the generated address’s reply URL. |
| 5 | DNS | Private zone: delete the A record, and the zone and its links only if nothing else uses them. AD DNS: delete the A record. Public: delete the CNAME and the asuid TXT record. |
| 6 | PIM Manager > Settings | If ManagerUrl points at the removed name, set it to the address people should use, or clear it so it is recorded again on the next sign-in. |
Rollback
| Situation | What to do |
|---|---|
| The run failed part-way | Fix the cause and re-run the same command. Every step checks what exists first. |
| Sign-in on the new name fails with a redirect-URI error | The reply URL was not added (-SkipEasyAuth, or no Entra right). Add it (Step 4 of the private case), or re-run without -SkipEasyAuth as an Application Administrator. |
| The certificate is not trusted on admin devices | Deploy your issuing CA to those devices. Use the generated address meanwhile. |
| The name does not resolve | Private zone: check the zone exists, the record points at the static IP, and the zone is linked to the network your clients resolve through. AD DNS: check the printed record was added in the right zone. Public: check the CNAME. |
| You want the name gone | Run the script with -Remove; see Change or remove the name. |