30-second answer

Collection needs an Entra ID app registration and its client id. There is no default and there is no way around it, and the reason is a change in PnP.PowerShell rather than a choice made here.

Then choose one of two modes. Delegated signs a person in, interactively or with a device code, and the run sees what that person sees. Application-only authenticates the registration itself with a certificate, and the run sees what the tenant granted the application. They are not two prompts for the same thing, and the evidence records which one produced it.

Why --client-id is required

PnP.PowerShell removed its own multi-tenant application in 2.12.0. The release notes give the reason as the deprecation and shutdown of the PnP Management Shell.

A connection with no client id anywhere fails before it reaches the network:

Text
Please specify a valid client id for an Entra ID App Registration

Sources, both checked 2026-08-09, and verified against PnP.PowerShell 3.3.0: the PnP.PowerShell changelog and the default client id article.

Why the collector will not read it from the environment

The module itself accepts a default client id, configured by a cmdlet or by an environment variable. This collector does not use either, and there are two separate reasons.

Evidence has to say which identity observed it. A value read from an ambient environment variable is one nobody can name afterwards, and provenance that cannot be named is not provenance.

The read-only gate is a regex over every file. A regex cannot tell a mention from a call, so naming the configuring cmdlet in the collector would mean loosening the pattern that proves nothing in the tree mutates a tenant. Loosening it is how a real write slips in.

Device code sign in

For a host with no browser:

PowerShell
m365-governance collect sites \
  --client-id <id> \
  --tenant-url https://<tenant>-admin.sharepoint.com \
  --output ./evidence/ \
  --device-login

Application-only, with a certificate

For an unattended run, and for a run that must see the tenant rather than one person's view of it:

PowerShell
m365-governance collect owners \
  --client-id <id> \
  --tenant-id <tenant-id> \
  --certificate-path ./app.pfx \
  --certificate-password-env M365_GOVERNANCE_CERT_PASSWORD \
  --site-url https://<tenant>.sharepoint.com/sites/<site> \
  --output ./evidence.json

A PFX. PnP.PowerShell 3.3.0's app-only parameter set takes ClientId, Tenant, CertificatePath and CertificatePassword; it has no separate private-key file, so a certificate and key have to be packaged together first. A certificate with no password is supported: leave the option out.

The password is referenced, not written. --certificate-password-env takes the name of an environment variable, and the collector reads it in its own process. There is deliberately no option that takes the password itself: an argument lives in the shell history, and in the process list of every user on the machine, for as long as the command runs.

One mode per run. Naming both, or half of one, is refused before anything reaches the network: a certificate together with --device-login, a certificate without --tenant-id, a --tenant-id without a certificate, a password variable that is unset, a certificate file that is not there.

Connecting is not being authorised

Connect-PnPOnline succeeds with zero permissions granted. Connecting establishes who you are; what you may read is decided afterwards, by the directory, when a command asks for something. A script that checks the connection did not throw and then reports "connection verified" is verifying authentication and reporting authorisation.

The two identities also differ in what they can resolve, and they differ quietly. On a group-connected site read twice within a minute, a delegated session returned the administrating group; an application-only identity holding Sites.Read.All returned an empty list, with no error at all. An empty result is not a smaller version of a full one, and which identity produced a document is part of what the document says.

Where the credentials go

Nowhere near us. Authentication happens between you and Microsoft, with an identity you register in your own tenant. pH7x Systems receives no credentials, no token and no evidence: see the trust model for where the software runs, what it talks to, and what reaches us.

Which identity, and how much of it

The identity travels into every report:

Text
- Identity: application, scopes: Sites.Read.All

Two consequences follow, and both belong in the decision about what to grant.

Read only is the whole requirement. Nothing under the collector tree calls a mutating cmdlet, and CI proves it by parsing every file. An identity with write permissions grants more than the tool can use.

What the identity cannot see does not appear. A site absent from a sites collection is a site this identity could not enumerate, not a site that does not exist. Under-scoping produces a report that understates the estate while looking complete.