Blogging

The Label That Never Fired: Diagnosing Retention Policies with Zero Coverage

The Label That Never Fired: Diagnosing Retention Policies with Zero Coverage

A retention label exists. It is published. It is enabled. And when someone finally asks the obvious question — what is it actually retaining? — the answer comes back as nothing. No items held, no disposition activity, no visible effect. The label is present in the tenant and absent from the record.

This is a common enough situation that it deserves a name and a procedure. Call it zero coverage: a retention policy or label that is configured and active but has no demonstrable set of items under its control. The instinct is to treat this as a policy-authoring problem — rewrite the rule, republish the label, wait. That instinct is usually wrong. Zero coverage is ambiguous by construction. “No items retained” can mean at least four different things, and each has a different, reversible fix. The work is to eliminate the cheapest explanations first, using artifacts you can export and inspect.

What follows is a triage order, not a tutorial on creating retention policies. It assumes Microsoft 365 and Purview as the working platform, because that is where the exportable evidence is best documented, but the diagnostic logic applies wherever a retention rule is supposed to attach to content and the attachment cannot be observed.

First, define the terms as the platform defines them

A retention policy applies retention settings to a scope of locations — mailboxes, SharePoint sites, OneDrive accounts, Teams channels. A retention label is applied to individual items or containers and carries the retention settings with it. A hold is the mechanism that prevents deletion; a retention policy or a retaining label creates one. A hold GUID is the identifier the platform uses internally to represent that hold on a mailbox. These distinctions matter because zero coverage looks different depending on which object you are inspecting.

Microsoft’s own guidance on identifying mailbox holds sets out the properties to read and what their values mean. That page is the primary source for most of the checks below, and it is worth reading in full rather than working from memory.

Step 1: Rule out deliberate exclusion before assuming failure

The most common reason an organization-wide retention policy appears not to apply to a mailbox is that the mailbox has been explicitly excluded from it. This is not a bug. It is a documented configuration, and it leaves a marker.

When you inspect the InPlaceHolds property on a mailbox, hold GUIDs carry prefixes that indicate their type. A GUID beginning with -mbx means the mailbox has been explicitly excluded from an organization-wide policy. Microsoft’s documentation states this directly: “If a GUID starts with -mbx, it means the mailbox has been explicitly excluded from an organization-wide policy.”

So before you conclude that a label never fired, check whether the mailbox was ever in scope. An exclusion is a deliberate act, often made years earlier by someone who has since left, and it is invisible in the policy’s own settings page. It is visible in the hold inventory. That is the first reason the exportable artifact matters more than the dashboard.

Step 2: Distinguish “no policy” from “no label applied”

If the per-mailbox hold list is empty, the documentation is explicit about the next move: “If InPlaceHolds is empty, check for organization-wide retention policies” at the organization configuration level. An empty per-mailbox list does not mean no retention applies. It means no retention is attached at the mailbox level, and the organization-level configuration is where the answer lives.

The second distinction is between a policy that exists and a label that was applied. These are different questions. A mailbox can be covered by a retention policy and still have no retaining label applied to any item. The platform exposes this separately. The ComplianceTagHoldApplied property tells you whether a retaining label has been applied to at least one item: “If ComplianceTagHoldApplied is True, the mailbox is treated as on hold because a retention label that retains content has been applied to at least one item.”

Read that carefully. It is a boolean about whether at least one item carries a retaining label. If it is false, the label has not fired anywhere in that mailbox — not because the policy is broken, but because nothing has been labeled. That is a coverage problem at the point of application, not at the point of policy definition, and the fix is different: you are looking at labeling adoption, not policy scope.

Step 3: Trace the GUID back to a named policy and its scope

A finding of zero coverage is only actionable if it is attributable. “The system isn’t retaining anything” is not a finding. “Policy X, scoped to these 40 sites, has no items under hold” is a finding.

The GUID is the bridge. Retention policy GUIDs typically begin with mbx, skp, or grp. To match one to a named policy, strip the prefix and any suffix such as :1, :2, or :3, then query the policy with distribution detail. The documentation describes the result: “This shows the name of the retention policy and the content locations it’s scoped to.”

Do this for every GUID in the inventory, not just the one you are investigating. The point of the exercise is to build a table in which every hold is named and scoped, so that the next zero-coverage question can be answered by lookup rather than by investigation.

Step 4: Treat reporting surfaces as evidence with an expiry date

Here is where most zero-coverage diagnoses go wrong. A dashboard shows zero, and the dashboard is treated as ground truth about the present. It is not. It is a snapshot of a window that has already closed.

Microsoft’s own training material on monitoring label usage is candid about the lag. New or updated items can take up to 7 days to appear in Data explorer, and for SharePoint files, updates can take up to 14 days. Activity Explorer stores data for up to 30 days, and the documentation advises exporting and archiving it for long-term auditing. Purview posture reports are gathered on a 30-day rolling-window basis, and the documentation recommends saving reports as PDF for future reference.

The practical consequence: a zero in a report is a hypothesis about the recent past, not a measurement of the present. If a label was published three days ago, a zero is expected and tells you nothing. If a label was published eight months ago and the report still shows zero, that is a finding — but only if you can show the report window actually covered the period since publication. The export taken at diagnosis time is the artifact that survives; the dashboard view does not.

The Export feature in Data explorer creates a CSV file of the current view. That is the artifact to keep. It is small, it is inspectable, and it can be reconciled against the hold inventory later.

Step 5: Check the ceiling — coverage is counted per policy, not per label name

This is the step most often skipped, and it produces the most misleading zeros.

Retention policies have per-policy item limits. For static scopes, a retention policy can include a maximum of 100 SharePoint sites and 100 OneDrive accounts. A tenant supports a maximum of 1,000 retention labels, and a single tenant can have a maximum of 10,000 policies across configurations, including retention, DLP, information barriers, eDiscovery holds, In-Place Holds, and sensitivity labels.

The documentation is explicit about the workaround and its cost: “Because these limitations are per policy, if you need to use specific inclusions or exclusions that result in going over these numbers, you can create additional policies that have the same retention settings.” It also notes that multiple policies result in higher administrative overhead, and recommends adaptive scopes instead.

Now consider what this means for a label name. If an organization has 2,000 SharePoint sites requiring a ten-year retention, the documentation’s own worked example requires 20 retention policies, each including 100 sites, all carrying the same settings. The label name is one string. The policies are twenty objects. Coverage must be counted per policy and per scope, then summed. A report that counts by label name will show either a partial number that looks like full coverage or a zero that looks like total failure, depending on which policy the report happened to sample.

This is the single most important structural point in the diagnosis: a label name is not a unit of coverage. The unit is the policy-scope pair. Any reconciliation that does not preserve that granularity will produce a wrong answer.

Step 6: Where the label carries a records disposition, check that the instruction is machine-implementable

Some retention labels exist to implement a records disposition — a schedule item that says how long records are kept and what happens at the end. When such a label never fires, the cause may not be in the platform at all.

NARA’s General Records Schedules provide mandatory disposition instructions for records common to federal agencies. Use of the GRS is mandatory; agencies must use the GRS unless they can justify an agency-specific schedule. Transmittal 35, issued in May 2024, revised a set of disposition instructions with a stated purpose: to make them machine-implementable. The transmittal defines the term precisely. “Machine-implementable instructions must have only one retention type for the computer to know what to do.” And a retention type “identifies the point in time when retention starts, either at the point of creation (an age- or creation-based retention, such as ‘Destroy when 3 years old’) or when a certain event occurs (an event-based retention, such as ‘Destroy 3 years after final action’).”

The diagnostic implication is direct. If a schedule item carries more than one retention type, or an event trigger the platform cannot evaluate, then a label built to implement it has nothing unambiguous to fire on. The platform cannot fix that. It must be fixed upstream, in the schedule or in the mapping between the schedule and the label configuration. Blaming the retention engine for a non-machine-implementable instruction is a category error, and it wastes the remediation budget on the wrong layer.

Two further NARA points bear on scope design. The GRS introduction advises that administrative records should be maintained separately from program records, and that if they cannot be economically segregated, the entire file must be kept for the period approved for the program records. That is a retention consequence of mixed scope, and it is the kind of thing that makes a label’s coverage look wrong when it is in fact behaving as the schedule requires. Separately, NARA regulations require agencies to disseminate GRS changes within six months of receipt — which means the schedule a label was built against may have moved since the label was configured.

What the reconciliation artifact should look like

The output of this triage is not a report to management. It is a working artifact, and it should be small enough to keep and re-run.

Build a GUID-keyed join between two exports: the hold inventory (GUID, prefix type, mailbox or location, exclusion marker, label-hold flag) and the label coverage export (policy name, scope, item count, export timestamp). Join on GUID. The reason to key on GUID rather than on policy name is that GUIDs survive renaming, and renaming is the most common reason a “missing” label is later found to exist. A policy that was renamed last quarter will not match a name-based join, and the resulting zero will be an artifact of the join, not of the tenant.

Keep the export timestamp on every row. A coverage figure without a timestamp cannot be reconciled against a publication date, and without that reconciliation you cannot distinguish lag from failure.

Microsoft provides a sample script that generates a report of eDiscovery case holds and a separate report listing eDiscovery cases that have no holds. That script is scoped to eDiscovery, not to retention labels, and it should not be presented as a retention coverage tool. But the pattern it demonstrates — export the holds, export the gaps, keep both — is the right pattern, and it is worth adapting rather than inventing.

Where the standards fit, and where they do not

It is tempting to reach for a controlled-vocabulary standard here. ISO 25964 and SKOS define how labels and terms relate within a thesaurus, and taxonomy drift — the slow divergence between the term a policy was written against and the term content is actually tagged with — is a real failure mode in classification schemes. But the sources retrieved for this analysis do not establish the specific ISO 25964 or SKOS provisions, and it would be dishonest to assert them from memory. The honest position is that vocabulary standards are relevant to the labeling layer and not to the hold layer, and that the diagnostic procedure above does not depend on them.

Dublin Core is a different case, because its terms are documented and retrievable. It defines accessRights as information about who can access a resource or an indication of its security status, noting that access rights may include restrictions based on privacy, security, or other policies. It defines conformsTo as an established standard to which the described resource conforms. Those two properties are useful as a discipline: a retention label that implements a schedule item is, in effect, asserting that an item conforms to a disposition authority, and the access restriction is part of what the label is supposed to encode. If your metadata model cannot express either, the label has nowhere to record what it did, and the coverage question becomes unanswerable by design.

An FAQ, because these questions come up

My label shows zero in the report but I know items are labeled. What is happening? Check the report window against the label’s publication date first. Ingestion lag of up to 7 days, and up to 14 days for SharePoint file updates, is documented. If the window covers the period and the count is still zero, check whether the report is counting by label name across multiple policies — the per-policy split described above can make a partially covered label look empty.

Can I tell from the mailbox alone whether a retention label applied? Partly. ComplianceTagHoldApplied tells you whether a retaining label has been applied to at least one item. It does not tell you which label, how many items, or whether the label is the one you are investigating. For that you need the label coverage export.

Why does the documentation keep saying to export? Because the reporting surfaces have stated retention windows. Activity Explorer keeps 30 days. Posture reports use a 30-day rolling window. A diagnosis performed today against a dashboard cannot be re-examined next year unless someone exported it. The export is the audit trail.

Is a zero-coverage label always a problem? No. A label published last week with zero coverage is behaving normally. A label published eight months ago, in scope, with no exclusions, and still at zero is a finding. The difference is the reconciliation against publication date and scope, which is why the artifact matters more than the number.

Where to stop

The triage order is: exclusion marker, then organization-level policy, then label-hold flag, then GUID-to-policy trace, then reporting lag, then per-policy ceiling, then machine-implementability of the underlying disposition. Each step is cheaper than the next, and each produces an exportable artifact. When one of them explains the zero, stop. The remaining steps are not more thorough; they are a different diagnosis.

The calm version of this argument is that zero coverage is not evidence of failure. It is evidence of ambiguity, and ambiguity is resolved by ordering the explanations and keeping the exports that eliminate them. The label that never fired is usually a label that was never in scope, or never applied, or counted in a way that could not see it. Those are three different problems with three different fixes, and the only way to tell them apart is to look at what you can export.