30-second answer
Connect-PnPOnline -Url https://contoso-admin.sharepoint.com -Interactive -ClientId $clientId
$sites = Get-PnPTenantSite
"$($sites.Count) sites enumerated by this identity"Start with the denominator, not the count. An agent inventory is a number over a population, and the population is whatever your identity could see.
What this proves
How many agents were found, in how many sites, by one identity, at one moment. Every one of those four qualifiers is load bearing.
What it does not prove
- How many agents exist. Sites this identity cannot open contribute nothing, and their number is not knowable from inside the run.
- That zero means none. A site with no agents and a site you could not read return the same empty result. Treating the second as the first is inferring success from an absence.
- That the number is still true. Anyone who can create a file in a site can create an agent in it, so this is a photograph rather than a state.
- Anything derived from a count of zero. The governance engine tried publishing a derived field, agents without declared sources, and then removed it from the collector, the validation output and the fixtures. A zero on that field conflates four different situations that deserve four different reactions: the capability being absent, the properties being omitted, the arrays being genuinely empty, and the definition being unreadable. An agent count is not a scope, and the field is recorded in the module as not coming back.
- What an agent reaches. Three questions hide under "agent
governance", and they have three different sources of truth: what an
agent MAY reach is the sources in its definition, and omitting both
source arrays is the widest state, not the narrowest, because such an
agent reaches everything the asking user can already see; who may USE
it is the
.agentfile's SharePoint permissions; what it DID reach is the licensed audit-derived access report, with its own documented limits. An inventory answers none of the three; it tells you where to go and ask.
PowerShell
$clientId = '00000000-0000-0000-0000-000000000000'
Connect-PnPOnline -Url https://contoso-admin.sharepoint.com -Interactive -ClientId $clientId
$sites = Get-PnPTenantSite
$read = 0
$refused = 0
$agents = @()
foreach ($site in $sites) {
try {
Connect-PnPOnline -Url $site.Url -Interactive -ClientId $clientId
$agents += Get-PnPCopilotAgent
$read++
}
catch {
$refused++
}
}
[pscustomobject]@{
SitesEnumerated = $sites.Count
SitesRead = $read
SitesRefused = $refused
AgentsFound = $agents.Count
}The catch is not defensive programming. A refusal is a result, and a
script that swallows it silently reports a smaller number as if it were a
smaller reality.
Example output
SitesEnumerated SitesRead SitesRefused AgentsFound
--------------- --------- ------------ -----------
412 389 23 17Seventeen agents across three hundred and eighty-nine sites, with twenty-three sites unread and an unknown number never enumerated. That sentence is the finding. The number seventeen on its own is not.
Explanation
Microsoft gives two ways to find agents, and both have the same boundary written into them.
The first is search: agents are .agent files, so searching for *.agent
finds them, and the documentation states that "the results only include agent
files that you have permission to access". Submit-PnPSearchQuery reaches the
same index.
The second is the SharePoint Advanced Management agent insights report, which a SharePoint administrator generates. The documentation is candid about what that costs and gives: it needs the licence, and it notes that the output "might include agent files that the site owners and site admins don't have access to". A higher privilege sees more, and it is still a specific privilege seeing a specific amount.
There is no view from nowhere. Every path to this inventory is a path through an identity, which is why the honest artefact is not a count but a count with its denominator and its refusals attached.
That is also why the enumeration above deliberately does not filter. Filtering before counting hides the population, and the population is the part that makes the count mean something.
It counts one kind of agent, and there are two.
Get-PnPCopilotAgent reads .agent files in SharePoint. An agent built in
Agent Builder from the Copilot chat surface is not one of those files: it is
created at m365.cloud.microsoft/agents/new, it is not written to a SharePoint
library, and it does not appear in this inventory or in a SharePoint search for
its own name. Attempted on 2026-08-21 against a tenant holding a newly created
Agent Builder agent, a Graph-backed SharePoint and OneDrive search for the
agent's exact name returned only unrelated files.
That result establishes what the query matched and nothing more. What it does support is narrower and useful: a count from this page is a count of SharePoint agents, and reporting it as the number of agents in a tenant is a claim the method cannot carry.
Agents created in Agent Builder are administered elsewhere, in Manage agents for Microsoft 365 Copilot in Integrated Apps in the Microsoft 365 admin center, which is also where an administrator controls whether Agent Builder is available at all. Whether the two populations overlap in a given tenant is read there, not inferred from this count.
Production considerations
- This is a read. Nothing here creates, edits or removes an agent, and the administrative report cmdlets are not on this page precisely because the one that produces a report writes tenant state.
- Record the refusals with the result, in the same object. A coverage figure kept in a separate file is a coverage figure nobody reads.
- A delegated run and an administrative run answer different questions. Neither is the true one. Say which was used.
- Re-running it later is the point. A single inventory tells you what was there; two tell you what changed, and change is where the governance value in this surface actually is.
Related governance rules
None. There is nothing documented that says how many agents an organisation should have, or where they should live, so any threshold would be invented and any pass would be meaningless. The inventory is evidence, and it is worth collecting long before it is worth judging.
References
- Monitor agent usage in SharePoint
- Insights report on agents in SharePoint
- Manage access to agents in SharePoint
Found something wrong? Suggest a correction. The article source is not public; the engine it cites is.
What this answer underwrites
The engine reads these Microsoft operations to collect evidence, so what is established here is what those collectors rest on.