A retention program survives an audit when the system, not a person, can prove four things: what was kept, why it was kept, for exactly how long, and that disposal happened on schedule with a named reviewer attached. Most Microsoft 365 tenants fail all four. They fail in one of two directions — keeping too little (a spoliation finding when litigation arrives and the mail is gone) or keeping everything forever (every stale document is discoverable, every over-retained personal record is a GDPR/DPDP storage-limitation violation, and eDiscovery review costs scale with the corpus you never deleted). Microsoft Purview Data Lifecycle Management and Records Management are the two portal solutions that fix this, and they share one engine: retention policies (container-level), retention labels (item-level), and records (labels that lock). The perennial failure mode is that someone picks the wrong control on day one, then fights the principles of retention — Purview’s precedence rules — for the next two years.
This article builds the program end to end at expert depth: when a policy beats a label and when it cannot, how adaptive scopes replace brittle inclusion lists, how auto-apply stamps labels using sensitive information types, KQL queries, and trainable classifiers, how event-based retention starts clocks you cannot know in advance (“7 years after the contract expires”), what a record and a regulatory record actually lock, and how multi-stage disposition review produces the proof-of-disposal evidence an auditor accepts. Just as important, it goes under the floorboards: where retained content physically lives (the SharePoint Preservation Hold library, Exchange Recoverable Items, the Teams SubstrateHolds folder), which timer jobs move it, and how retention coexists with Litigation Hold and eDiscovery holds.
Everything is built in the durable, reviewable place: Security & Compliance PowerShell and the Microsoft Graph records management API. The portal (purview.microsoft.com → Solutions → Records Management / Data Lifecycle Management) has an equivalent for almost all of it, but code is what you check into git, diff in a pull request, and re-run across tenants. By the end you can design the label taxonomy, wire the automation, predict precedence outcomes on paper before the Managed Folder Assistant proves you right, and hand an auditor a disposition trail instead of a shrug.
What problem this solves
Retention in Microsoft 365 is not a backup feature and not an archive feature — it is a legal-defensibility feature. Without a deliberate program, four failure patterns show up, usually all at once, usually discovered during litigation or a regulator’s records request:
| Program failure | What it looks like in the tenant | Consequence |
|---|---|---|
| No retention at all | Users hard-delete mail; SharePoint recycle bins purge at 93 days; departed users’ OneDrives deleted after 30 days | Spoliation exposure; adverse-inference rulings; failed SOX/SEC/FDA records requests |
| Keep-everything-forever | One org-wide “retain indefinitely” policy applied in a panic in 2019 | Discovery corpus grows unbounded; GDPR Art. 5(1)(e)/DPDP storage-limitation findings; eDiscovery review costs explode |
| Wrong control chosen | Container policies where per-item review was required; records where plain labels sufficed; -Regulatory $true “to be safe” |
No disposition evidence; locked content nobody can fix; irreversible labels blocking remediation |
| Untested precedence | Three overlapping policies plus labels; nobody can say when an item actually deletes | “Why didn’t it delete?” tickets; deletion certifications signed on guesswork |
| No proof of disposal | Items expire and vanish silently with no reviewer, no export, no audit trail | Auditor treats disposal as unverifiable; certification fails even though deletion happened |
The people who hit this are records managers, compliance officers, and the M365 platform engineers who inherit their requirements. The moment your organization is regulated (financial services under SEC 17a-4, pharma under GxP, anyone under GDPR/DPDP with defined retention schedules) or litigating, “we have versioning and a recycle bin” stops being an answer. What breaks without this knowledge is subtle: retention appears to work — labels show up, policies distribute — but the first disposition cycle produces no evidence, the first event-based clock never starts because a metadata column was empty, and the first legal hold interacts with a delete-label in a way nobody predicted.
Learning objectives
By the end of this article you can:
- Choose correctly between a retention policy, a retention label, a record, and a regulatory record for any stated requirement, and defend the choice against the capability matrix.
- Predict the outcome when multiple policies and labels touch one item by applying the four principles of retention, including how eDiscovery holds and Priority Cleanup sit outside them.
- Design adaptive scopes (user, site, group) with attribute and KQL queries, and know when static scopes with their 100-site/1,000-mailbox caps are still the right call.
- Build auto-apply policies on sensitive information types, KQL searchable properties, trainable classifiers, and cloud attachments — validated in simulation mode before enforcement.
- Wire event-based retention end to end: event types,
EventAgeInDayslabels, asset ID columns, and events fired from an HR/CLM system via Security & Compliance PowerShell or the Graph records management API with application permissions. - Configure multi-stage disposition review (up to 5 stages, reviewer permissions, auto-approval), and export proof of disposition that survives an audit for up to 7 years.
- Explain exactly where retained content lives per workload — Preservation Hold library, Recoverable Items subfolders, SubstrateHolds — with the quotas and timer-job latencies that govern each.
- Monitor the program with Content explorer, Activity explorer, the unified audit log, and
Export-ContentExplorerData/Get-ReviewItems, and license it correctly (which features are E3 vs E5).
Prerequisites & where this fits
You should be comfortable with Microsoft 365 admin fundamentals: what Exchange Online mailboxes, SharePoint sites, OneDrive accounts, and Microsoft 365 Groups are; how to run PowerShell 7 with the ExchangeOnlineManagement module; and roughly how eDiscovery searches work. Familiarity with KQL (Keyword Query Language) helps for auto-apply and adaptive site scopes. You do not need prior Purview records experience — but this is an Expert-level article, so concepts arrive fast and the tables are the reference you will return to.
Where it sits: this is the data-lifecycle pillar of the KloudVin Microsoft 365 compliance track. It assumes the classification groundwork from Sensitivity Labels in Microsoft Purview: Auto-Labeling, Encryption, Co-Authoring, and Container Inheritance (sensitivity labels classify and protect; retention labels govern lifecycle — they are siblings, not competitors) and pairs with Conducting Investigations with Microsoft Purview eDiscovery (Premium): Holds, Collections, and Review Sets, because holds and retention share the same preservation plumbing. The DLP corpus in Building Microsoft Purview DLP Policies for Endpoint and Exchange reuses the same sensitive information types you will meet in auto-apply conditions.
| You should already know | Why it matters here | Where to build it |
|---|---|---|
| Sensitivity labels & SITs | Auto-apply reuses SITs; InformationProtectionLabelId KQL targets sensitivity labels |
Purview auto-labeling deep dive |
| eDiscovery holds & content search | Holds trump retention; ComplianceTag KQL validates labeling |
eDiscovery (Premium) investigations |
| Exchange mail flow & mailbox anatomy | Recoverable Items is where mail retention physically happens | Exchange Online mail flow deep dive |
| SharePoint/OneDrive sharing & site model | PHL lives per site; site deletion is blocked under retention | SharePoint & OneDrive external sharing governance |
| Teams architecture (group vs user mailboxes) | Teams retention is substrate-based and policy-only | Teams governance & lifecycle |
Connect once before any of the code below. Note the module requirement — the Security & Compliance endpoint is REST-backed in current module versions (remote PowerShell for this endpoint is retired), and it is a different session from Connect-ExchangeOnline:
# ExchangeOnlineManagement v3.x (REST-backed) — required for all cmdlets in this article
Install-Module ExchangeOnlineManagement -Scope CurrentUser
Import-Module ExchangeOnlineManagement
# Security & Compliance PowerShell — distinct endpoint from Connect-ExchangeOnline
Connect-IPPSSession -UserPrincipalName admin@kloudvin.com
Core concepts
Three controls, one engine. Internalize the capability split first — every design decision downstream is a consequence of this table.
A retention policy is assigned to locations (all Exchange mailboxes, these 40 SharePoint sites, all Teams chats). Every item in the location inherits the same retain/delete behavior implicitly. Nothing is stamped on the item; remove the location from the policy and the behavior evaporates (after a grace period). A retention label is stamped on an individual item — one label per item, travelling with it — and only a label can do the premium moves: disposition review, records declaration, event-based clocks, per-item durations, and file plan metadata. A record is not a third object; it is a label setting (IsRecordLabel) that locks the labeled item against deletion and (while locked) editing. A regulatory record is the same setting escalated to near-WORM: nobody, including admins, can remove the label, unlock the item, or shorten the clock.
| Capability | Retention policy | Retention label |
|---|---|---|
| Granularity | Whole location (container), implicit | Individual item, explicit stamp |
| Retain content | Yes | Yes |
| Delete content at end | Yes | Yes |
| Retain then delete | Yes | Yes |
| Per-item retention period | No — one setting per policy | Yes — the label carries its own clock |
| Start clock from created / modified | Yes (policy-level) | Yes |
| Start clock from labeled date | No | Yes (TaggedAgeInDays) |
| Start clock from an event | No | Yes (EventAgeInDays) |
| Disposition review at end | No | Yes |
| Declare record / regulatory record | No | Yes |
| File plan descriptors (citation, authority) | No | Yes |
| Applied by | System, by container | User (published), library default, or auto-apply |
| Travels if item moves | No — location-bound | Yes, within the workload (copies do NOT inherit) |
| Teams / Viva Engage messages | Yes (policy-only workloads) | No |
| Adaptive scopes | Yes | Yes (label policies scope adaptively) |
| Preservation Lock | Yes | Yes (on the label policy) |
| Proof for auditors | Policy existence + audit | Per-item label + disposition evidence |
Second mental model: retention is copy-on-write preservation, not a vault. A Keep action never stops a user from pressing Delete or Save — it guarantees that a copy survives out of sight (Preservation Hold library in SharePoint/OneDrive, Recoverable Items in Exchange, SubstrateHolds for Teams) until every applicable clock expires. The user experience barely changes; the storage bill and the eDiscovery index do. The single exception is a record, which surfaces the preservation into the UI by blocking delete outright.
Third: retention labels and sensitivity labels are constantly confused, and the confusion causes real design errors (like expecting retention labels to have a priority order — they don’t):
| Dimension | Sensitivity label | Retention label |
|---|---|---|
| Question it answers | How confidential is this? | How long must this live, and how does it die? |
| Can encrypt / watermark | Yes | No |
| Priority order between labels | Yes — ordered list, higher wins | None — one label per item, no ranking |
| Multiple per item | One sensitivity + one retention can coexist | One retention label only |
| Auto-apply replaces an existing label | Can, per policy priority | Never — auto-apply skips already-labeled items |
| Container support (sites/teams) | Yes (container labels) | No — items only |
| Where configured | Information Protection | Data Lifecycle / Records Management |
Because retention labels have no priority order, an auto-apply policy never overwrites an existing label, never replaces a record label, and a wrong label at scale means manual relabeling. This one constraint shapes the whole taxonomy: fewer, better-designed labels beat a sprawling catalog.
| Term | One-line definition | Where it lives |
|---|---|---|
| Retention policy | Container-level retain/delete rule for one or more locations | Purview DLM → Policies |
| Retention label | Item-level lifecycle stamp with action + duration + clock | Purview Records Management → File plan |
| Label policy (publish) | Makes labels available for users/defaults in workloads | DLM / RM → Label policies |
| Auto-apply policy | Stamps a label on matching content, no user involved | RM → Label policies (auto) |
| Record | Label setting that locks delete (and edit while locked) | IsRecordLabel $true |
| Regulatory record | Record + irreversible label, no unlock, no shortening | -Regulatory $true |
| Adaptive scope | Query-based membership (users/sites/groups) for policies | RM/DLM → Adaptive scopes |
| Event type / event | Trigger category and its firing instance for event-based clocks | RM → Events |
| Disposition review | Human approval gate at end of retention (labels only) | RM → Disposition |
| Preservation Hold library (PHL) | Hidden per-site library holding preserved SPO/OD copies | Each SharePoint/OneDrive site |
| Recoverable Items | Hidden Exchange mailbox tree holding preserved mail | Each mailbox (30→100 GB quota) |
| SubstrateHolds | Hidden mailbox folder retaining Teams/Viva messages | User/group mailboxes |
| Managed Folder Assistant (MFA) | Exchange timer process enforcing retention on mailboxes | Runs at least once per 7 days |
| Principles of retention | The four-level precedence algorithm when controls collide | Evaluated per item |
| Preservation Lock | Makes a policy restrictive: can extend/add, never remove/disable | -RestrictiveRetention $true |
Choosing the control: policies, labels, and where each applies
The location matrix
Not every workload supports every control. Teams and Viva Engage messages are policy-only — no labels, ever — and they demand their own dedicated policies (a Teams location cannot share a policy with Exchange/SharePoint locations). This is the first table to consult when someone hands you a retention schedule:
| Location | Retention policy | Publish labels | Auto-apply labels | Where content is actually held |
|---|---|---|---|---|
| Exchange mailboxes | Yes | Yes | Yes | Recoverable Items (user mailbox) |
| SharePoint classic & communication sites | Yes | Yes | Yes | Preservation Hold library (per site) |
| OneDrive accounts | Yes | Yes | Yes | Preservation Hold library (per OD site) |
| Microsoft 365 Group mailboxes & sites | Yes | Yes | Yes | Recoverable Items + PHL (group resources) |
| Teams channel messages | Yes (Teams-only policy) | No | No | Group mailbox → SubstrateHolds |
| Teams chats + Copilot interactions | Yes (Teams-only policy) | No | No | User mailboxes → SubstrateHolds |
| Teams private channel messages | Yes (own location) | No | No | Channel members’ mailboxes → SubstrateHolds |
| Viva Engage community messages | Yes | No | No | Community (group) mailboxes |
| Viva Engage user messages | Yes | No | No | User mailboxes |
| Exchange public folders | Yes | No | No | Public folder mailboxes |
| Skype for Business (legacy) | Yes | No | No | User mailboxes |
Two structural notes. First, Copilot interactions (prompts and responses) are stored in user mailboxes and ride the “Teams chats and Copilot interactions” location — if your program predates Copilot, re-check that policy’s intent before an AI-governance review asks. Second, private channel messages live in the member mailboxes, not the team’s group mailbox, which is why they are a separate location and why deleting the group does not delete private-channel history.
Static scopes and their hard limits
A static scope is either org-wide (“All” for a location) or a hand-maintained inclusion/exclusion list. The lists have hard caps that enterprise tenants hit fast:
| Limit | Value | Bites when |
|---|---|---|
| SharePoint sites per policy (includes + excludes) | 100 | Any per-site program beyond a pilot |
| OneDrive accounts per policy (specific) | 100 | Per-user OD retention at scale |
| Exchange mailboxes per policy (specific) | 1,000 | Departmental mailbox scoping |
| Microsoft 365 Groups per policy | 1,000 | Group/Teams estate scoping |
| Retention labels per tenant | 1,000 | Sprawling file plans (design smaller) |
| Policies per tenant (all compliance policy types combined, incl. retention + DLP) | 10,000 | Rare, but policy-per-site anti-patterns get there |
| Org-wide (“All”) policies | Cheap and cap-free | The default when no per-container nuance exists |
The classic anti-pattern: 100-site cap hit, so the team clones the policy — “Contracts-Retain-7y-Policy-04” — and now four policies drift independently. That is exactly the problem adaptive scopes (next section) were built to end.
The decision table
| Requirement as stated | Correct control | Why |
|---|---|---|
| “Keep everything in every mailbox 7 years” | Org-wide retention policy (Exchange, static All) | No per-item nuance; cheapest to operate |
| “Delete Teams chats after 30 days” | Teams-only retention policy | Teams is policy-only |
| “Contracts: keep 7 years after expiry, Legal signs off before deletion” | Label: EventAgeInDays + disposition review |
Event clock + review = label-only features |
| “Finance statements are records, 10 years” | Label with IsRecordLabel $true, auto-applied |
Immutability is a label setting |
| “SEC 17a-4 WORM for broker-dealer comms” | Regulatory record label (+ counsel sign-off) | Only regulatory records approach WORM |
| “Everything in sites tagged Department=Legal” | Adaptive site scope + policy or label policy | Query-based membership, no 100-site cap |
| “Users choose how long their drafts live” | Published labels (manual) | Human judgment is the classifier |
| “Anything with credit card numbers kept 3 years” | Auto-apply label on SIT condition | Content-based, no user reliance |
| “Legal matter — freeze everything for these 12 custodians” | eDiscovery hold, not retention | Holds are for litigation; release when matter closes |
| “Prove disposal to the auditor” | Label + disposition review + audit export | Only labels produce disposition evidence |
Creating policies in PowerShell
An org-wide keep-then-delete policy for Exchange/SharePoint/OneDrive — note the split: New-RetentionCompliancePolicy is the container (locations), New-RetentionComplianceRule carries the retention math for policies (for labels, the math lives on the label itself):
# Container: locations
New-RetentionCompliancePolicy -Name "Org-Baseline-Keep7y" `
-ExchangeLocation All -SharePointLocation All -OneDriveLocation All `
-ModernGroupLocation All
# Rule: the retention math (policy-level, applies to everything in the locations)
New-RetentionComplianceRule -Policy "Org-Baseline-Keep7y" `
-RetentionComplianceAction KeepAndDelete `
-RetentionDuration 2555 `
-ExpirationDateOption CreationAgeInDays
Teams demands its own policy, and several rule parameters are invalid for it:
New-RetentionCompliancePolicy -Name "Teams-Chat-30d" `
-TeamsChatLocation All
# Teams rules: no ExpirationDateOption (always from message creation),
# no ApplyComplianceTag, no ContentMatchQuery
New-RetentionComplianceRule -Policy "Teams-Chat-30d" `
-RetentionComplianceAction Delete `
-RetentionDuration 30
| Rule parameter | Valid for | Values / format | Gotcha |
|---|---|---|---|
RetentionComplianceAction |
Policies (all locations) | Keep, Delete, KeepAndDelete |
Delete alone = delete-only, no protection before |
RetentionDuration |
Policies | Days, or Unlimited |
7 years = 2555; leap years are your rounding problem |
ExpirationDateOption |
Exchange/SPO/OD/Groups rules | CreationAgeInDays, ModificationAgeInDays |
Invalid for Teams/Viva (always creation-based) |
PublishComplianceTag |
Label policies | Comma-list of label names | Makes labels available; applies nothing |
ApplyComplianceTag |
Auto-apply rules | One label name | Mutually exclusive with PublishComplianceTag; not for Teams |
ContentMatchQuery |
Auto-apply rules | KQL string | eDiscovery index semantics (see auto-apply section) |
ContentContainsSensitiveInformation |
Auto-apply rules | Array of SIT hashtables | Supports minCount/maxCount per SIT |
Policy lifecycle: disable, exclude, delete — and the grace periods
What happens when you stop retaining is as audit-relevant as retaining. Exchange applies a delay hold — after any hold/retention removal, content stays preserved about 30 more days so an admin mistake is recoverable; SharePoint similarly keeps a released site’s PHL content for a ~30-day grace window before cleanup.
| Operation | Command | Effect | Reversible? |
|---|---|---|---|
| Disable policy | Set-RetentionCompliancePolicy -Identity X -Enabled $false |
Stops enforcement; locations released after grace | Yes — re-enable |
| Exclude one location | Set-RetentionCompliancePolicy -AddSharePointLocationException ... |
That container released (grace applies) | Yes |
| Delete policy | Remove-RetentionCompliancePolicy |
All locations released; preserved copies become eligible for cleanup after the delay window | Policy gone; content already purged is gone |
| Delete a label in use | Remove-ComplianceTag |
Blocked while the label is referenced by a policy; record labels applied to content resist deletion | Fix references first |
| Preservation-locked policy | Set-RetentionCompliancePolicy -RestrictiveRetention $true |
Can add locations and extend duration; cannot remove locations, shorten, disable, or delete — ever | No. One-way. |
# Preservation Lock — read the table above twice before running this
Set-RetentionCompliancePolicy -Identity "Org-Baseline-Keep7y" -RestrictiveRetention $true
Preservation Lock exists for regulators (SEC 17a-4 requires that even admins cannot weaken retention). Treat it like -Regulatory $true: a deliberate, counsel-approved, one-way door. A locked policy with a typo in its duration is a permanent typo you can only extend around.
Adaptive vs static scopes
Adaptive scopes replace inclusion lists with queries. You define a membership query once — “users where Department equals Finance and Country equals India”, “sites where the URL starts with /sites/contracts” — and Purview re-evaluates membership on a rolling basis (roughly daily; budget a few days for initial population). Policies then bind to the scope instead of to 100 hand-picked sites.
| Dimension | Static scope | Adaptive scope |
|---|---|---|
| Membership | Hand-maintained list or “All” | Query, auto-refreshed (~daily) |
| Caps | 100 sites / 1,000 mailboxes / 1,000 groups per policy | No inclusion caps — the headline feature |
| Licensing | E3 sufficient | E5 / E5 Compliance territory |
| Joiner/mover/leaver handling | Manual edits, forever | Attribute change → scope change automatically |
| Trainable-classifier auto-apply | Supported | Not supported — classifier policies need static scopes |
| Inactive mailbox behavior | Included mailbox stays retained when user deleted | Query must still match the (inactive) object — validate before relying on it |
| Failure mode | Stale lists; policy clones | Wrong/empty attributes → silently empty scope |
| Best for | Org-wide baselines; small fixed pilots; classifier policies | Departmental/regional/lifecycle-based programs at scale |
Three scope types, three query surfaces:
| Scope type | Targets (when bound in a policy) | Query language | Example attributes |
|---|---|---|---|
| User | Exchange mailboxes, OneDrive accounts, Teams chats, Viva user messages | Attribute conditions or raw OPATH | Department, Office, Country, UPN, Alias, CustomAttribute1–15 |
| SharePoint sites | SharePoint sites (not group sites’ mail) | KQL over indexed site properties | SiteURL, site name, RefinableString00–99 |
| Microsoft 365 Groups | Group mailboxes & sites, Teams channel messages, Viva community messages | Attribute conditions | Name, display name, description, email |
| (advanced, all types) | Same as above | Raw query (-RawQuery) |
Anything the simple builder can’t express |
The user-scope attribute set is worth enumerating because it is the entire design surface for people-based retention — if HR does not populate the attribute, the scope is fiction:
| User attribute (portal name) | Entra/Exchange property | Typical retention use |
|---|---|---|
| Department | Department |
Departmental schedules (Finance 10y, Marketing 3y) |
| Country or region | CountryOrRegion |
Jurisdictional schedules (India DPDP vs EU GDPR) |
| Office / City / State / Postal code | Office, City, StateOrProvince, PostalCode |
Site/region carve-outs |
| Job title | Title |
Role-based (all “Trader” titles → SEC schedule) |
| First name / Last name / Display name | FirstName, LastName, DisplayName |
Rarely — brittle |
| Email addresses / Alias / UPN | EmailAddresses, Alias, UserPrincipalName |
Domain-based scoping (subsidiaries) |
| Custom attributes 1–15 | CustomAttribute1..15 |
The workhorse: HR system stamps CustomAttribute7 = "REG-RETAIN" |
Operators in the simple builder are deliberately few — is equal to, is not equal to, starts with, is not starts with — so anything fancier goes to the advanced (raw) query:
# User scope: Finance users in India, via the documented hashtable form
$filter = @{
Conditions = @(
@{ Name = 'Department'; Operator = 'Equals'; Value = 'Finance' },
@{ Name = 'CountryOrRegion'; Operator = 'Equals'; Value = 'India' }
)
Conjunction = 'And'
}
New-AdaptiveScope -Name "Finance-IN-Users" -LocationType User -FilterConditions $filter
# Site scope: every contracts site, present and future
New-AdaptiveScope -Name "Contract-Sites" -LocationType Site `
-RawQuery 'SiteURL:"https://kloudvin.sharepoint.com/sites/contracts*"'
# Bind a policy to scopes instead of static locations
New-RetentionCompliancePolicy -Name "Finance-Mail-10y" `
-AdaptiveScopeLocation "Finance-IN-Users" -Applications "User:Exchange"
New-RetentionComplianceRule -Policy "Finance-Mail-10y" `
-RetentionComplianceAction KeepAndDelete -RetentionDuration 3650 `
-ExpirationDateOption CreationAgeInDays
Operational gotchas that surface in every adaptive rollout: membership is only viewable in the portal (scope → Scope details), so build a validation habit there — Get-AdaptiveScope shows the definition, not the members. An empty scope raises no error; the policy simply protects nothing, which is why the first validation step after creating any adaptive policy is confirming a known-member appears. And because trainable-classifier auto-apply cannot ride adaptive scopes, classifier programs keep a static-scope lane in the design.
Retention label anatomy: actions, clocks, and the file plan
A retention label is three decisions — an action, a duration, and a clock (RetentionType) — plus optional escalations (record, regulatory, review, event binding) and file plan metadata. The clock is the decision people get wrong most, because two of the four options look interchangeable and are not:
RetentionType |
Clock starts | Right for | The gotcha |
|---|---|---|---|
CreationAgeInDays |
Item created | Contracts from signature, statements, fixed-life docs | For long-lived agreements, “created” ≠ “concluded” — see event-based |
ModificationAgeInDays |
Last modified — resets on every edit | Working documents (“delete 2y after last touch”) | A frequently edited doc never ages out; deliberate choice only |
TaggedAgeInDays |
Label applied | Cloud attachments; “clock starts at classification” schedules | Relabeling restarts nothing — one label at a time |
EventAgeInDays |
External event fires | Employee departure, contract expiry, product EOL | Clock is paused indefinitely until the event — items are held, not aging |
RetentionAction |
During retention | At end of retention | Use when |
|---|---|---|---|
Keep |
Preserved (copy-on-write) | Nothing — item stays, becomes normally deletable | Minimum-retention obligations with no disposal mandate |
KeepAndDelete |
Preserved | Deleted — or routed to disposition review / relabel if configured | The standard records pattern |
Delete |
No protection | Deleted when older than duration | Hygiene labels (“purge drafts > 1y”); it is a broom, not a shield |
Keep + RetentionDuration Unlimited |
Preserved forever | Never ends | Permanent records; pairs with review-based unwinding later |
End-of-retention routing (for KeepAndDelete) has three exits configured on the label: delete automatically, start a disposition review, or (wizard option) apply a different label — label-to-label chaining, useful for “active 3y → archive 7y” schedules where the second stage carries different behavior.
# Standard label: keep HR content 5 years from last modification
New-ComplianceTag -Name "HR-Keep-5yr" `
-RetentionAction Keep `
-RetentionDuration 1825 `
-RetentionType ModificationAgeInDays `
-Comment "Employee working docs; retain 5 years from last edit"
# Contract label: 7 years from creation, then delete (no review)
New-ComplianceTag -Name "Contract-Keep7" `
-RetentionAction KeepAndDelete `
-RetentionDuration 2555 `
-RetentionType CreationAgeInDays
File plan descriptors
Descriptors turn a flat label list into a file plan — reportable by department, category, and the exact legal citation that justifies each duration. Auditors ask “why 7 years?”; the citation column is the answer. All six are free-text but should be governed vocabulary:
| Descriptor | PowerShell key | Purpose | Example |
|---|---|---|---|
| Reference ID | FilePlanPropertyReferenceId |
Your schedule’s row number | FIN-TAX-004 |
| Business function/department | FilePlanPropertyDepartment |
Ownership rollups | Finance |
| Category | FilePlanPropertyCategory |
Schedule grouping | Tax |
| Sub category | FilePlanPropertySubcategory |
Finer grouping | Indirect tax |
| Authority type | FilePlanPropertyAuthority |
Kind of obligation | Regulatory |
| Provision/citation | FilePlanPropertyCitation |
The legal anchor | IRS 26 USC 6501 |
$fp = ConvertTo-Json @{ Settings = @(
@{ Key = "FilePlanPropertyReferenceId"; Value = "FIN-TAX-004" },
@{ Key = "FilePlanPropertyDepartment"; Value = "Finance" },
@{ Key = "FilePlanPropertyCategory"; Value = "Tax" },
@{ Key = "FilePlanPropertyCitation"; Value = "IRS-6501" }
)}
New-ComplianceTag -Name "Tax-Record-7yr" -RetentionAction KeepAndDelete `
-RetentionDuration 2555 -RetentionType CreationAgeInDays `
-IsRecordLabel $true -FilePlanProperty $fp
The portal’s file plan page also supports CSV import/export — the sane way to author 60 labels from a legal-approved spreadsheet and to keep the spreadsheet as the source of truth.
What you can change after shipping a label
Label mutability is asymmetric, and the one-way doors are exactly where remediation plans die:
| Label property | Editable after creation? | Notes |
|---|---|---|
| Name | No — fixed at creation | Descriptions/comments are editable; name is the identity |
| Retention duration (standard label) | Yes | Takes effect on the next processing cycle |
| Retention duration (record label) | Yes — extend; treat shortening as a governance event | Regulatory: extend only, never shorten |
| Action (Keep ↔ KeepAndDelete) | Yes for standard labels | Not on regulatory records |
IsRecordLabel off → on |
Yes (escalate) | On → off: no. Once a record label, always a record label |
-Regulatory |
Never removable | And the label resists deletion once applied |
| Event type binding | Design-time decision | Changing trigger semantics mid-life invalidates fired clocks — rebuild instead |
| Multi-stage reviewers | Rename stages, swap reviewers | Cannot reorder or remove stages — order is forever |
| File plan descriptors | Yes | Safe to enrich continuously |
Records and regulatory records: what actually locks
Marking a label as a record (IsRecordLabel $true) changes the user contract: delete is blocked outright, the label cannot be removed by users, and edits are governed by a lock/unlock toggle (SharePoint/OneDrive). A regulatory record removes even the escape hatches. This matrix — action by action — is the heart of the records conversation with your business stakeholders, because “make it a record” sounds free until you read the middle columns:
| Action on the item | Standard retention label | Record (locked) | Record (unlocked) | Regulatory record |
|---|---|---|---|---|
| Edit content | Allowed | Blocked | Allowed (versions kept) | Blocked |
| Edit properties/metadata | Allowed | Allowed | Allowed | Blocked |
| Delete the item | Allowed (copy preserved behind the scenes) | Blocked | Blocked | Blocked |
| Copy the item | Allowed (copy carries no label) | Allowed | Allowed | Allowed |
| Remove the label | Allowed (with rights) | Blocked | Blocked | Blocked — everyone, forever |
| Change to another label | Allowed | Blocked for users | Blocked for users | Blocked |
| Unlock for editing | n/a | Yes — record versioning | (is the unlocked state) | Never |
| Shorten the retention period (label admin) | Yes | Governance decision | Governance decision | Never — extend only |
| Delete the containing site/mailbox | Held per policy rules | Resists deletion | Resists deletion | Container cannot be deleted while it holds regulatory records |
The nuance in row one of the standard-label column is the most misunderstood behavior in Purview: a plain retain-label does not stop deletion in the UI. The user deletes, the item disappears from the library, and the preserved copy lands in the Preservation Hold library. Stakeholders who wanted “users can’t delete” wanted a record, not a label — put this table in front of them before building.
Record versioning: the unlock mechanism
SharePoint and OneDrive records support record versioning. Every record carries a Record status property (Locked/Unlocked) in the details pane. Unlocking preserves the currently locked version — a copy lands in the Records folder inside the Preservation Hold library, tamper-proof — then normal editing resumes with version history; re-locking freezes the latest version as the new record. Exchange has no unlock concept: an email record simply cannot be deleted or relabeled, which is usually fine since sent mail is not edited anyway.
# A record label: financial statements, 7 years from creation, then reviewed deletion
New-ComplianceTag -Name "Record-Financials-7yr" `
-RetentionAction KeepAndDelete `
-RetentionDuration 2555 `
-RetentionType CreationAgeInDays `
-IsRecordLabel $true
Regulatory records: the one-way door
Because a regulatory record is effectively irreversible, the option is hidden from the label wizard until you enable it tenant-wide — itself an audited action:
# Auditable: logs "Enabled regulatory record option for retention labels"
Set-RegulatoryComplianceUI -Enabled $true
Get-RegulatoryComplianceUI # verify
New-ComplianceTag -Name "RegRecord-SEC17a4-7yr" `
-RetentionAction KeepAndDelete `
-RetentionDuration 2555 `
-RetentionType CreationAgeInDays `
-IsRecordLabel $true `
-Regulatory $true
| Difference | Record | Regulatory record |
|---|---|---|
| Remove label after application | Admins via governed process | Nobody |
| Unlock/edit cycle | Yes (record versioning) | No |
| Shorten retention after application | Possible (governed) | No — extend only |
| Auto-apply policy support | Yes | No — publish and apply deliberately |
| Wizard availability | Always | Only after Set-RegulatoryComplianceUI |
| Mistake recovery | Relabel via admin path | None. Rebuild-around only. |
| Genuine need | Most regulated retention | WORM-grade obligations (e.g., SEC 17a-4 style) |
Treat -Regulatory $true as a legal artifact, not a technical toggle: most regulated programs need records (defensible retention + reviewed disposal), not regulatory records (immutability). The real-world scenario later in this article is a cautionary tale of “regulatory, to be safe.”
Publishing vs auto-apply: getting labels onto content
A label does nothing until a label policy scopes it to content. Two shapes: publish (humans decide) and auto-apply (conditions decide). Most programs run both — publish the whole taxonomy for judgment calls, auto-apply the high-confidence patterns.
| Dimension | Publish | Auto-apply |
|---|---|---|
| Who applies the label | User (Outlook/OWA/SPO/OD details pane), or a library/folder default | The service, on condition match |
| Conditions | None — availability only | SITs, KQL, trainable classifiers, cloud attachments |
| Replaces existing labels | User can change (non-record) labels | Never — skips labeled items |
| Latency to usable | SPO/OD ~1 day; Exchange up to 7 days | Up to 7 days per matching pass |
| Simulation | n/a | Yes — run before enforcement |
| Human error surface | High (wrong/no label chosen) | Low, but condition bugs scale to millions of items |
| License | E3 for manual application | E5-tier |
# Publish the taxonomy for manual use and defaults
New-RetentionCompliancePolicy -Name "Publish-Records-Taxonomy" `
-ExchangeLocation All -SharePointLocation All -OneDriveLocation All
New-RetentionComplianceRule -Policy "Publish-Records-Taxonomy" `
-PublishComplianceTag "Contract-Keep7,Tax-Record-7yr,HR-Keep-5yr"
Published labels surface as: the Apply retention label item menu in SharePoint/OneDrive, per-item and per-folder application in Outlook (a folder-level label acts as a default for new items), and — the highest-leverage manual pattern — a default label on a SharePoint library, folder, or document set, which stamps new items (and sweeps existing unlabeled ones) with zero user action. Library defaults are the honest middle ground between “trust users” and “build classifiers.”
| Where labels appear / timing | Latency after publishing | Notes |
|---|---|---|
| SharePoint / OneDrive details pane | ~1 day | Also available as library/folder/document-set default |
| Outlook / OWA | Up to 7 days | Mailbox needs ≥ 10 MB of data before labels sync — empty test mailboxes mislead |
| Teams files tab | With SPO | It is SharePoint underneath |
| Auto-apply matching pass | Up to 7 days | And only unlabeled items are touched |
Auto-apply condition 1 — sensitive information types
Same SIT engine as DLP: instance counts and confidence tune precision. Critical asymmetry: for Exchange, SIT-based auto-apply evaluates only messages sent or received after the policy exists — it does not crawl mailboxes at rest. SharePoint and OneDrive get both existing and new items.
New-RetentionCompliancePolicy -Name "Auto-PII-Records" `
-ExchangeLocation All -SharePointLocation All -OneDriveLocation All
New-RetentionComplianceRule -Policy "Auto-PII-Records" `
-ApplyComplianceTag "Record-Financials-7yr" `
-ContentContainsSensitiveInformation @(
@{ Name = "U.S. Social Security Number (SSN)"; minCount = "1" },
@{ Name = "Credit Card Number"; minCount = "1" }
)
Auto-apply condition 2 — KQL keywords and searchable properties
ContentMatchQuery runs against the same index as eDiscovery content search — which makes it the tool that can reach Exchange data at rest, and the reason KQL is the standard workaround when SIT-based policies can’t retro-label old mail.
New-RetentionCompliancePolicy -Name "Auto-Legal-NDA" `
-SharePointLocation All -ExchangeLocation All
New-RetentionComplianceRule -Policy "Auto-Legal-NDA" `
-ApplyComplianceTag "Contract-Keep7" `
-ContentMatchQuery '(nda OR "non disclosure agreement") AND (filetype:doc* OR filetype:pdf)'
| KQL rule | Works | Does not work | Consequence |
|---|---|---|---|
| Prefix wildcard | contract* |
— | Matches contract, contracts, contractual |
| Suffix/substring wildcard | — | *tract, *trac* |
Redesign the query; the index is prefix-only |
| SharePoint properties | Predefined managed properties + RefinableString00–99, RefinableDate00–19 |
Crawled/custom properties directly | Map your column to a refiner first, then query it |
| Target items by sensitivity label | InformationProtectionLabelId:<GUID> |
Label display names | GUID from Get-Label | Format-Table DisplayName,Guid |
| Verify labeling afterwards | ComplianceTag:"Contract-Keep7" in content search |
— | Your post-deployment validation query |
| Exchange at-rest coverage | KQL queries evaluate mailbox content | SIT conditions (new mail only) | KQL for backfill, SIT for go-forward |
Auto-apply condition 3 — trainable classifiers
Trainable classifiers match kinds of documents (contracts, source code, resumes, invoices, financial statements…) rather than patterns. Microsoft ships dozens pre-trained; custom ones need seed items (tens to a few hundred positive samples) plus a test pass. Two operational constraints define where they fit: configure classifier conditions in the portal wizard (the rule’s classifier parameter is reserved for internal use), and classifier policies cannot use adaptive scopes — static only. For Exchange, classifier evaluation looks back about six months, not the whole mailbox corpus.
| Classifier fact | Value | Design consequence |
|---|---|---|
| Pre-trained examples | Agreements, Source code, Finance, Invoices, Resumes, Legal affairs, HR, IT, Procurement, Tax | Pilot with built-ins before training custom |
| Custom training input | Seed samples (order of 50–500 positives) + test items | Budget curation time; garbage seeds = garbage matches |
| Scope support | Static only | Keep a static lane in adaptive-first designs |
| Exchange lookback | ~6 months | Not a backfill tool for old mail — use KQL |
| Config surface | Portal auto-apply wizard | Keep the policy under change control by name/screenshot; PS shows the policy, not the model |
Auto-apply condition 4 — cloud attachments
The cloud attachments condition labels the copy of a file at the moment it is shared in Exchange or Teams — the compliance snapshot of “what did we send them.” Pair it with a TaggedAgeInDays label so the clock runs from the share, which is the only timestamp that means anything for that copy.
Simulation mode, always
Run SIT and KQL auto-apply in simulation mode first (portal: Label policies → policy → View simulation). It behaves like -WhatIf against data at rest: matched counts and item samples, no stamping. Tune instance counts and query precision there, then enforce. Two more rollout rules: propagation takes up to seven days per pass, and if multiple auto-apply policies match one item, you get one of the labels — there is no priority system, so design conditions to be mutually exclusive rather than hoping for a tiebreaker.
Event-based retention: clocks that start later
Some clocks cannot start on a date you know in advance: “7 years after the employee leaves”, “10 years after the product is discontinued”, “7 years after the contract expires”. Event-based retention is a three-object dance — an event type (the trigger category), a label whose clock is EventAgeInDays bound to that type, and an event fired later whose asset ID query scopes exactly which labeled items it touches. Until the event fires, labeled items are held indefinitely: the clock is paused, not ticking.
| Step | Object | Cmdlet / API | Key detail |
|---|---|---|---|
| 1. Define the trigger category | Event type | New-ComplianceRetentionEventType |
One per business trigger, not per instance |
| 2. Bind a label to it | Label with EventAgeInDays |
New-ComplianceTag -EventType |
Duration counts from the event date |
| 3. Label the content | Publish / auto-apply / default | Label policies | Populate the asset ID column at the same time |
| 4. Fire the event | Event | New-ComplianceRetentionEvent / Graph |
Asset query resolves which items start aging |
| 5. Processing | — | Asynchronous | Budget days for start dates to stamp; MFA/timer jobs take over |
# 1. Event type
New-ComplianceRetentionEventType -Name "Employee Departure" `
-Comment "Starts the retention clock when an employee leaves"
# 2. Label bound to it — clock pauses until the event
New-ComplianceTag -Name "HR-Keep-7yr-After-Departure" `
-RetentionAction KeepAndDelete `
-RetentionDuration 2555 `
-RetentionType EventAgeInDays `
-EventType "Employee Departure"
# 4. Fire the event when it happens; asset queries scope the blast radius
Get-ComplianceRetentionEventType | Format-Table Name,Guid
New-ComplianceRetentionEvent -Name "Departure - E12345 - 2026-06" `
-EventType "Employee Departure" `
-SharePointAssetIdQuery "EmployeeId:E12345" `
-EventDateTime "06/01/2026"
The asset ID is metadata on the content: for SharePoint/OneDrive, the purpose-built ComplianceAssetId column (added when event-based labels are in play) or any custom indexed column mapped to a managed property (ContractId, ProductCode); for Exchange, a keyword query evaluated against the message. Per-workload mechanics:
| Workload | Asset query parameter | What it evaluates | Prerequisite that actually fails in practice |
|---|---|---|---|
| SharePoint / OneDrive | -SharePointAssetIdQuery |
Property:Value against indexed columns (ComplianceAssetId:E12345, ContractId:KV-4471) |
Column populated and crawled/mapped before the event fires |
| Exchange | -ExchangeAssetIdQuery |
Keyword/KQL match on the message | Mail must actually contain the token (subject/body/property) |
| Both, query omitted | — | Every item carrying any label of that event type starts aging | The classic mass-clock-start accident — always scope events |
Security & Compliance PowerShell is one automation surface; the Microsoft Graph records management API is the other, and it is what lets an HR or contract-lifecycle system fire events with application permissions (RecordsManagement.ReadWrite.All) — no human clicking a button:
POST https://graph.microsoft.com/v1.0/security/triggers/retentionEvents
Content-Type: application/json
{
"displayName": "Contract Expiry - KV-4471",
"description": "Fired by CLM webhook on contract close-out",
"retentionEventType@odata.bind":
"https://graph.microsoft.com/v1.0/security/triggerTypes/retentionEventTypes/<eventType-guid>",
"eventQueries": [
{ "queryType": "files", "query": "ContractId:KV-4471" },
{ "queryType": "messages", "query": "ContractId:KV-4471" }
],
"eventTriggerDateTime": "2026-05-31T00:00:00Z"
}
| Event-based gotcha | Why it bites | Defense |
|---|---|---|
| Asset column empty at fire time | Query resolves nothing; clocks never start; items held forever | Make column population part of the labeling workflow; sample-audit before events |
| Label applied after the event fired | Late-labeled items miss the start date | Label first, fire second; re-fire a scoped event for stragglers |
| Event cannot be “un-fired” | A wrong EventDateTime starts real deletion clocks |
Gate event-firing automation behind validation of date + query |
| Un-scoped event (no asset query) | Starts the clock for all items with that event type’s labels | Peer-review every event; automation should refuse empty queries |
| Processing latency assumed instant | Start-date stamping is asynchronous (days) | Verify with Get-ComplianceRetentionEvent and spot-check item expiry dates |
| One event type per label | A label listens to exactly one trigger category | Model triggers before labels; renaming semantics mid-life = rebuild |
How retention works inside each workload
Retention is enforced by per-workload preservation machinery, and every “retention is broken” ticket is really a question about this machinery.
SharePoint and OneDrive: the Preservation Hold library
Each site under any retention (policy, label, or hold) gets a hidden Preservation Hold library (.../PreservationHoldLibrary), visible to site collection admins. It is copy-on-write in action:
| Trigger | What happens | Where the content sits | User-visible? |
|---|---|---|---|
| First edit of an item under retain | Original copied to PHL (once; versioning covers subsequent edits) | PHL | No |
| User deletes an item under retain | Item moved to PHL | PHL | Gone from library; preserved |
| Record (locked) delete attempt | Blocked with error | Stays in place | Yes — the point |
| Record unlocked | Locked version copied to PHL Records folder | PHL + live item | Details-pane toggle |
| End of retention, item still in library, delete action | Item moves to site Recycle Bin (93-day two-stage) | Recycle bin → purge | Standard recycle flow |
| End of retention, copies in PHL | Purged permanently by the cleanup timer job (runs on a ~7-day cadence) | Gone | No |
| Policy released from site | PHL content kept through a ~30-day grace window, then eligible for cleanup | PHL → purge | No |
Two operational facts with budget implications: the PHL counts against the site’s storage quota, so high-churn sites under long retain grow invisibly (the real-world scenario later has numbers); and a site under retention cannot be deleted — admins get an explicit error until the site is excluded or the policy released.
Exchange: Recoverable Items
Every mailbox carries a hidden Recoverable Items folder tree; retention and holds work by routing deleted/edited items through it and letting the Managed Folder Assistant (MFA) — which processes each mailbox at least once every 7 days — enforce the math:
| Subfolder | What lands there | Governing setting / behavior |
|---|---|---|
Deletions |
Items a user deletes from Deleted Items (“soft delete”) | User-recoverable; RetainDeletedItemsFor (default 14 days, max 30) |
Versions |
Copy-on-write originals of edited items under hold/retention | Not user-visible |
Purges |
Hard-deleted items (“Recover deleted items” purge) | Purged by MFA after the window — unless held |
DiscoveryHolds |
Purged items preserved because a hold/retention applies | Kept until every hold/clock releases |
Audits / Calendar Logging |
Mailbox audit + calendar repair logs | Housekeeping, not retention |
| (whole tree) quota | 30 GB default → 100 GB when hold/retention applies; auto-expanding archive continues beyond | Watch on litigious mailboxes |
| Delay hold | ~30-day preservation after any hold/retention removal | The “oops” window |
Deleted users follow the same logic upward: delete a user whose mailbox is under retention or hold and Exchange converts it into an inactive mailbox — retained, searchable by eDiscovery, license-free — for as long as the retention lasts. Inactive mailboxes are the mechanism behind “keep leavers’ mail 7 years” and one more reason adaptive scopes must be validated against departed users (the scope query has to keep matching the inactive object, or use a static policy for the leaver schedule).
Teams and Viva Engage: the substrate
Teams messages are retained via hidden mailbox folders — a SubstrateHolds folder inside Recoverable Items — because chat’s compliance copy lives in Exchange even though the service of record is Teams:
| Message type | Compliance copy lives in | Retention location to configure |
|---|---|---|
| 1:1 and group chats | Each participant’s user mailbox | Teams chats + Copilot interactions |
| Copilot prompts/responses | User mailbox | Teams chats + Copilot interactions |
| Standard & shared channel messages | Team’s group mailbox | Teams channel messages |
| Private channel messages | Channel members’ user mailboxes | Teams private channel messages |
| Meeting recordings/files | OneDrive/SharePoint | The file locations, not Teams locations |
| Viva Engage community / user messages | Community (group) / user mailboxes | The two Viva Engage locations |
Teams-specific truths worth pinning: retention rules for Teams are a distinct rule type (ApplyComplianceTag, ContentMatchQuery, ExpirationDateOption are all invalid); the minimum Teams retention/deletion period is 1 day; and when retention deletes a message, removal from the client lags the substrate by design — users may see messages for a few days after the compliance copy is gone. eDiscovery searches the substrate, so the compliance answer is always the substrate’s, not the client’s.
The latency reference
Retention is eventually consistent everywhere. Calibrate expectations (and test plans) against the real cadences:
| Operation | Typical | Budget |
|---|---|---|
| Policy distribution to locations | Hours | Up to 7 days (-DistributionDetail to check) |
| Published labels visible in SPO/OD | ~1 day | 1 day |
| Published labels visible in Outlook | Days | Up to 7 days (+10 MB mailbox precondition) |
| Auto-apply matching pass | Days | Up to 7 days per pass |
| Adaptive scope membership refresh | ~Daily | Few days initial population |
| MFA mailbox processing | ~1 day | At least once per 7 days |
| PHL cleanup timer job | Weekly-ish | Within 7 days of expiry |
| Disposition-approved permanent deletion | Days | Within ~15 days of final approval |
| Teams client message removal after retention delete | 1–3 days | Up to ~7 days |
| Content explorer count refresh | ~1 day | Up to a few days |
The principles of retention: which control wins
When several policies and a label touch one item, Purview resolves the outcome through four ordered principles. Memorize the order — it is the source of most “why didn’t it delete?” and “why is it still here?” tickets:
- Retention wins over deletion. If anything says keep, the item is not permanently purged while that keep is active. A competing delete action is suspended, not cancelled.
- The longest retention period wins. Among competing keep durations, the item lives until the longest one expires.
- Explicit wins over implicit for deletions. An item-level label’s delete action beats a location policy’s delete action; among policies only, a specifically scoped policy beats an org-wide one.
- The shortest deletion period wins. Only reached when the levels above cannot decide: the earliest applicable deletion date governs.
Work the algorithm top-down for every contested item — it terminates at the first level that produces a decision:
| # | Controls in play | Walk the principles | Outcome |
|---|---|---|---|
| 1 | Org policy: keep 10y · Label: delete at 7y | P1: keep active → no purge at 7y; P2: longest keep = 10y; P3: label’s delete is the explicit delete | Deletion staged at 7y (moves out of sight), purged only at 10y |
| 2 | Policy A: keep 5y · Policy B: delete at 3y | P1: keep active → survives year 3; P2: keep ends at 5y; then the delete is free to run | Retained 5y, then deleted |
| 3 | Policy: delete at 10y · Label: delete at 5y | P1: no keep anywhere; P3: label (explicit) beats policy | Deleted at 5y |
| 4 | Policy A: delete at 3y · Policy B: delete at 7y (both org-wide) | P1/P2: no keep; P3: tie (both implicit); P4: shortest | Deleted at 3y |
| 5 | Label: record, keep-and-delete 7y · eDiscovery hold on the site | Holds sit above the principles | Nothing purges until the hold releases; then the label finishes its math |
Row 5 is the boundary of the model: eDiscovery and litigation holds sit above all four principles, and one deliberate feature cuts through everything — Priority Cleanup, the E5 escape hatch that can force expedited deletion of sensitive content (think: a leaked credential file replicated everywhere) over retention settings and even eDiscovery holds, gated behind its own approval workflow. It exists precisely because the precedence model is otherwise airtight.
| Layer (top wins) | Examples | Released by | Can anything below purge content? |
|---|---|---|---|
| Priority Cleanup (deliberate override) | Approved expedited deletion of sensitive items | Completion of the approved cleanup | It is the purge — bypasses holds + retention |
| Legal holds | eDiscovery (Standard/Premium) case holds; Litigation Hold (Set-Mailbox -LitigationHoldEnabled $true) |
Closing/releasing the hold (30-day delay hold follows) | No |
| Preservation-locked retention policies | SEC 17a-4-style locked policies | Never (extend/add only) | Not before the locked clock expires |
| Retention policies + labels | Everything in this article | Policy/label lifecycle | Per the four principles |
| Workload housekeeping | Recycle bins, RetainDeletedItemsFor, versioning trims |
n/a | Only content nothing above claims |
Interplay with litigation hold and eDiscovery
Retention and legal holds share the same physical plumbing — PHL, Recoverable Items, SubstrateHolds — but answer different questions. Retention is governance: schedule-driven, permanent, ends in disposal. A hold is litigation posture: matter-driven, indefinite, ends in release. The operational rules of coexistence:
- A hold blocks every purge. An item at end of retention with a delete action, sitting under any hold, waits. Disposition review items under hold are approved but not destroyed until release — reviewers see the approval; the purge quietly defers.
- Release is when retention math resumes. After a hold releases (plus the ~30-day delay hold), MFA and the SharePoint timer jobs re-evaluate: anything whose retention already expired becomes eligible for deletion on the next pass. Releasing a two-year-old hold can trigger a wave of deletions — brief Legal before releasing, not after.
- Holds are not a retention program. Tenants that “solved” retention by putting every mailbox on Litigation Hold bought unbounded Recoverable Items growth, no disposition evidence, and an eDiscovery corpus that grows forever. Use holds for matters, retention for schedules; the deep dive on cases, custodians, and review sets is in Conducting Investigations with Microsoft Purview eDiscovery (Premium).
- Searches see the substrate. Content search / eDiscovery reach PHL copies, Recoverable Items, and SubstrateHolds — which is exactly why
ComplianceTag:"<label>"searches are your labeling validation tool, and why “the user deleted it” is rarely the end of a story.
Disposition review: the human checkpoint
Disposition review is available only on retention labels. At end of retention, instead of silent deletion, items park in a queue on the Disposition page and named reviewers decide their fate — the checkpoint auditors ask for by name. Design constraints first, because two of them are irreversible:
| Design element | Limit / rule | Irreversible? |
|---|---|---|
| Review stages per label | Up to 5, consecutive | Order fixed: can rename stages and swap reviewers; cannot reorder or remove |
| Reviewers per stage | Up to 10 — users or mail-enabled security groups (Microsoft 365 Groups not supported) | Editable |
| Auto-approval window | Optional, 7–365 days (wizard defaults to 14); no action → advances, final stage → disposal | Editable |
| Scope of a reviewer’s queue | Own pending items only, unless in the records-manager group | Config via Enable-ComplianceTagStorage |
| Proof-of-disposition retention | Disposition evidence available up to 7 years after disposal | — |
| Post-approval purge | Permanent deletion within ~15 days of final approval | — |
The MultiStageReviewProperty JSON schema is exact (this mirrors the documented format — note the reviewer addresses are written bare inside the brackets):
$review = '{"MultiStageReviewSettings":[' +
'{"StageName":"Records Manager","Reviewers":[recmgr@kloudvin.com]},' +
'{"StageName":"Legal","Reviewers":[legal@kloudvin.com,gc@kloudvin.com]}' +
']}'
New-ComplianceTag -Name "Contract-Review-7yr" `
-RetentionAction KeepAndDelete `
-RetentionDuration 2555 `
-RetentionType CreationAgeInDays `
-MultiStageReviewProperty $review `
-ReviewerEmail recmgr@kloudvin.com
Permissions are the most common reason a disposition program silently fails — reviewers are named on the label but never granted the role, and the queue looks empty to them:
| Role / setting | Grants | Who needs it | Trap |
|---|---|---|---|
| Disposition Management role | See and act on disposition items | Every reviewer | In the Records Management role group — not included for Global Admins by default |
| Content Explorer Content Viewer | Preview item content (not just metadata) in the mini-review pane | Reviewers who must read before approving | Without it, reviewers approve blind |
| Records-manager visibility group | See all pending dispositions, not just own queue | Records management team | Set via Enable-ComplianceTagStorage -RecordsManagementSecurityGroupEmail |
| Unified audit log enabled | Disposition events recorded at all | The tenant, before the first review | Enable at least a day before you need evidence |
| “Add reviewers” during review | Adds people to a stage | Reviewers escalating | Does not grant them the role — pair with role group membership |
# Records-manager group sees every pending disposition (mail-enabled security group)
Enable-ComplianceTagStorage -RecordsManagementSecurityGroupEmail dispositionreviewers@kloudvin.com
In the queue, each reviewer has exactly four moves:
| Reviewer action | Effect | Audit trail |
|---|---|---|
| Approve disposal | Advances to the next stage; at the final stage, marks for permanent deletion (within ~15 days) | “Approved disposal” event (auto-approvals surface as the same event) |
| Relabel | Item exits this label’s lifecycle and adopts the new label’s settings | Relabel event with actor |
| Extend | Suspends the review for the extension; afterwards the review restarts from stage 1 | Extension event with new date |
| Add reviewers | Adds people to the current stage (role still required) | Reviewer-added event |
Proof of disposition is the payoff. The Disposition page keeps a Disposed items view per label — item, reviewer (or auto-approval), timestamp, stage history — exportable as CSV, with evidence available up to 7 years. Records deleted without review (labels with automatic deletion) surface under Records disposed, so even the unreviewed path leaves a trail. At scale, pull the queue and the evidence programmatically:
# Page through pending (or disposed) review items for a label
$label = Get-ComplianceTag "Contract-Review-7yr"
Get-ReviewItems -TargetLabelId $label.Guid -Disposed $false
# The audit events behind the evidence (Exchange Online session)
Connect-ExchangeOnline
Search-UnifiedAuditLog -StartDate (Get-Date).AddDays(-90) -EndDate (Get-Date) `
-FreeText "disposal" -ResultSize 500 |
Select-Object CreationDate, UserIds, Operations
One interplay rule worth restating: an approved item under an eDiscovery hold is approved but not purged — the deletion executes after the hold releases. Your evidence shows the approval date; the purge date follows the hold.
Monitoring and validation: proving the program works
Configuration is not validation. A retention program is validated by observing labeled counts, label activity, and disposition evidence — three different tools, three different questions:
| Tool | Question it answers | Where / how | Access needed | Freshness |
|---|---|---|---|---|
| Content explorer | What is labeled, where, how much? — counts per label per location, drill-down to items | Purview → Data classification → Content explorer; Export-ContentExplorerData |
Content Explorer List Viewer (+ Content Viewer for content) | ~1 day, budget a few |
| Activity explorer | What labeling activity is happening? — label applied/changed/removed, by whom, 30-day view | Purview → Data classification → Activity explorer | Same family of data-classification roles | Near-real-time to hours |
| Disposition page | What is pending disposal, what was disposed, by whom? | Records Management → Disposition; Get-ReviewItems |
Disposition Management role | Event-driven |
| Unified audit log | Who did what to labels/policies/records? — the forensic trail | Audit search; Search-UnifiedAuditLog |
Audit Reader; audit enabled | Minutes to hours |
| Content search (KQL) | Did the label land exactly where intended? | eDiscovery search: ComplianceTag:"<label>" |
eDiscovery Manager | Index latency |
# Bulk-export labeled-item inventory per label/workload
Export-ContentExplorerData -TagType Retention -TagName "Contract-Review-7yr" `
-Workload SharePoint -PageSize 100
# Distribution health — the unglamorous check that catches broken policies
Get-RetentionCompliancePolicy -DistributionDetail |
Format-Table Name, Mode, Enabled, DistributionStatus
DistributionStatus should read Success. Pending beyond 7 days or Error means locations never received the policy — Set-RetentionCompliancePolicy -Identity <name> -RetryDistribution is the first-line fix, and the troubleshooting table below carries the rest.
PowerShell & Graph quick reference
Everything in this article, one lookup surface. Cmdlets are Security & Compliance PowerShell (Connect-IPPSSession) unless noted; Graph rows use the records management API under /security (permissions RecordsManagement.Read.All / RecordsManagement.ReadWrite.All, delegated and application — the application flavor is what makes unattended event-firing possible):
| Surface | Command / endpoint | Purpose |
|---|---|---|
| PowerShell | New/Get/Set/Remove-ComplianceTag |
Retention labels (actions, clocks, records, review JSON, file plan) |
| PowerShell | New/Get/Set/Remove-RetentionCompliancePolicy |
Policy containers; -DistributionDetail, -RetryDistribution, -RestrictiveRetention |
| PowerShell | New/Get/Set/Remove-RetentionComplianceRule |
Policy math, PublishComplianceTag, ApplyComplianceTag, SIT/KQL conditions |
| PowerShell | New/Get/Set/Remove-AdaptiveScope |
Query-based scopes (-FilterConditions, -RawQuery) |
| PowerShell | New/Get-ComplianceRetentionEventType |
Event trigger categories |
| PowerShell | New/Get-ComplianceRetentionEvent |
Fire/inspect events (asset ID queries, event date) |
| PowerShell | Set/Get-RegulatoryComplianceUI |
Unhide the regulatory-record option (audited) |
| PowerShell | Enable/Get-ComplianceTagStorage |
Label storage init + records-manager visibility group |
| PowerShell | Get-ReviewItems |
Page disposition queue/evidence for a label |
| PowerShell | Export-ContentExplorerData |
Bulk labeled-item inventory |
| PowerShell (EXO) | Search-UnifiedAuditLog, Set-Mailbox -LitigationHoldEnabled |
Audit evidence; litigation hold |
| Graph | GET/POST /security/labels/retentionLabels |
Labels as code (behaviorDuringRetentionPeriod: retain / retainAsRecord / retainAsRegulatoryRecord) |
| Graph | GET/POST /security/triggerTypes/retentionEventTypes |
Event types |
| Graph | GET/POST /security/triggers/retentionEvents |
Fire events from HR/CLM systems with app permissions |
Licensing: what E3 buys and where E5 starts
Retention licensing follows one rule of thumb: if the label applies itself, reacts to an event, or a human reviews the disposal, you are in E5 territory. Manual/static basics are E3. Per-user licensing means you license the users whose content benefits, and enforcement is per-feature:
| Capability | Microsoft 365 E3 | E5 / E5 Compliance add-on |
|---|---|---|
| Org-wide & static retention policies (all workloads incl. Teams) | Yes | Yes |
| Retention labels, manually applied by users | Yes | Yes |
| Default label on a SharePoint library/folder/document set | No | Yes |
| Auto-apply (SIT / KQL / trainable classifier / cloud attachments) | No | Yes |
| Adaptive policy scopes | No | Yes |
| Event-based retention | No | Yes |
| Records & regulatory records (Records Management solution) | No | Yes |
| Disposition review + proof of disposition | No | Yes |
| Trainable classifiers | No | Yes |
| Priority Cleanup | No | Yes |
| Content explorer (full drill-down) / Activity explorer | Limited | Yes |
| Audit retention | 180 days | 1 year (10-year with add-on license) |
The E5 Compliance add-on (~USD 12/user/month list) on top of E3 is the usual records-program path — materially cheaper than full E5 when the driver is compliance alone. Validate against Microsoft’s service-description licensing guidance before an Enterprise Agreement true-up; feature-to-SKU mapping is the one thing in this article that changes without an engineering announcement.
Architecture at a glance
Picture the program as four planes stacked from intent to evidence, with your content flowing through the middle. The control plane is where intent lives: the file plan of retention labels (each carrying action, duration, clock, record flag, reviewer stages, citations), the policies that project them — publish policies, auto-apply policies with their SIT/KQL/classifier conditions, and container retention policies — and the scopes (static lists or adaptive queries over users, sites, and groups) that decide where each policy lands. Event types sit here too, as named sockets waiting for the business to fire a trigger.
The distribution plane fans that intent out asynchronously — hours to seven days — into every in-scope workload, where the enforcement plane does the physical work with machinery you never see in the UI: SharePoint and OneDrive preserve edited and deleted copies in each site’s Preservation Hold library and sweep it with a weekly-cadence timer job; Exchange routes deletions and copy-on-write versions through the Recoverable Items subtree (Deletions, Versions, Purges, DiscoveryHolds) under the Managed Folder Assistant’s ≤7-day cycle; Teams and Viva Engage messages ride hidden SubstrateHolds folders in user and group mailboxes. Every contested item is resolved by the four principles of retention, with eDiscovery and litigation holds parked above the whole calculation and Priority Cleanup as the sole sanctioned bypass. When a clock expires, the end-of-retention router sends each item down exactly one path: silent deletion, relabel to a successor label, or the disposition review queue.
The top layer is the evidence plane, and it is the reason the whole stack exists: Content explorer answers what is labeled where, Activity explorer answers what labeling just happened, the Disposition page holds pending queues and up to seven years of disposed-item proof, and the unified audit log binds every approval, relabel, extension, and regulatory-record enablement to an identity and a timestamp. An auditor never sees your PowerShell; they see this plane. Design downward from the evidence you must produce, and the rest of the architecture chooses itself.
Real-world scenario: the contract repository that almost purged itself
Meridian Forge Industries (fictional but assembled from real engagements), a multinational manufacturer — 38,000 seats, E3 + E5 Compliance add-on — ran its contract repository across 63 SharePoint sites: roughly 410,000 agreements, 2.1 TB live. Legal’s requirement read simply: retain each contract 7 years after it expires, then delete with Legal sign-off.
The platform team’s first build had three defects that compounded. They used CreationAgeInDays labels — which would delete contracts 7 years after signature, not expiry; a 12-year master service agreement would have been purged five years into its own term. They set -Regulatory $true “to be safe,” making every label irreversible and blocking the corrective relabel. And they scoped with static site lists, hitting the 100-site cap at site 101 and cloning the policy — by discovery time, four near-identical policies had drifted apart. The near-miss surfaced in month nine, when a paralegal noticed active MSAs showing expiry dates inside the disposition horizon: about 18,400 active contracts were on a deletion clock. The regulatory flag turned a one-week relabel into a five-month program.
The rebuild had four moves. First, standard records (not regulatory) on an event clock: counsel confirmed the obligation required defensible retention and reviewed disposal — not WORM immutability — so irreversibility was a liability, not a feature.
New-ComplianceRetentionEventType -Name "Contract Expiration"
New-ComplianceTag -Name "MSA-Record-7yrAfterExpiry-Review" `
-RetentionAction KeepAndDelete -RetentionDuration 2555 `
-RetentionType EventAgeInDays -EventType "Contract Expiration" `
-IsRecordLabel $true `
-MultiStageReviewProperty '{"MultiStageReviewSettings":[{"StageName":"Records Manager","Reviewers":[recmgr@meridianforge.com]},{"StageName":"Legal","Reviewers":[legal@meridianforge.com]}]}'
Second, an adaptive site scope (SiteURL:"…/sites/contracts*") replaced the four cloned policies with one — new contract sites join automatically. Third, their contract-lifecycle system already stamped a ContractId column on every document set, so its “contract closed” webhook now fires the Graph retentionEvents call with application permissions — no human in the loop, roughly 900 events a month. Fourth, they sized the invisible cost: with record-versioning churn, the Preservation Hold libraries grew about 34 GB/month across the estate; they budgeted ~400 GB/year of SharePoint storage (~₹34,000/year at list add-on pricing) rather than discovering it as a quota incident.
Twelve months on: the first disposition cycle processed 3,120 expired contracts through the two-stage review (41 extended, 6 relabeled to a litigation label, the rest approved), the CSV export plus audit events satisfied the external auditor in a single session, and the runbook’s first line is the lesson: the clock (RetentionType) is the design decision; the record flag is a separate, sparing one; and -Regulatory $true is a one-way door you almost never need.
Advantages and disadvantages
| Advantages | Disadvantages / costs |
|---|---|
| Defensible, evidence-backed disposal — reviewer, timestamp, 7-year proof | The premium features (auto-apply, events, disposition, records) are E5-tier money |
| One engine across Exchange, SharePoint, OneDrive, Teams, Viva | Teams/Viva are policy-only — no labels, no review, separate policies |
| Auto-apply + adaptive scopes remove human classification and list maintenance | Everything is eventually consistent (1–7 days) — painful to test, easy to misjudge |
| Event-based clocks model real obligations (“after expiry”) | Whole new failure surface: empty asset columns, unscoped events, un-fireable mistakes |
| Records/regulatory records give graded immutability up to near-WORM | Regulatory records and Preservation Lock are irreversible by design — mistakes are permanent |
| Copy-on-write preservation is invisible to users | …and to storage budgets: PHL consumes site quota; Recoverable Items needs the 100 GB/archive path |
| Precedence model is deterministic and predictable on paper | Only if someone actually models it; overlapping controls without design = two-year precedence war |
The honest summary: Purview retention is the strongest native records capability in any collaboration suite, and every strength is a loaded gun pointed at the team that skips design. The features that make it auditable (irreversibility, human review, evidence) are exactly the features that punish improvisation.
Hands-on lab: a miniature records program
Runs in any tenant with E5 or an E5 Compliance trial (Purview trials are enable-able from the admin center). Blast radius is one test SharePoint site. Requires the Compliance Administrator role (plus Records Management for step 7).
1. Connect and initialize.
Connect-IPPSSession -UserPrincipalName admin@kloudvin.com
Enable-ComplianceTagStorage # idempotent; first-run initialization for labels
2. Create an event type and three labels — standard, event-bound record with review, and a delete-only hygiene label:
New-ComplianceRetentionEventType -Name "Lab Contract Expiration" -Comment "Lab trigger"
New-ComplianceTag -Name "Lab-Keep-1yr" -RetentionAction Keep `
-RetentionDuration 365 -RetentionType CreationAgeInDays
New-ComplianceTag -Name "Lab-Contract-Record" -RetentionAction KeepAndDelete `
-RetentionDuration 2555 -RetentionType EventAgeInDays `
-EventType "Lab Contract Expiration" -IsRecordLabel $true `
-MultiStageReviewProperty '{"MultiStageReviewSettings":[{"StageName":"Review","Reviewers":[admin@kloudvin.com]}]}'
New-ComplianceTag -Name "Lab-Purge-Drafts-90d" -RetentionAction Delete `
-RetentionDuration 90 -RetentionType ModificationAgeInDays
3. Verify the labels landed with the right anatomy — expected output shape:
Get-ComplianceTag | Where-Object Name -like "Lab-*" |
Format-Table Name, RetentionAction, RetentionDuration, RetentionType, IsRecordLabel
# Name RetentionAction RetentionDuration RetentionType IsRecordLabel
# ---- --------------- ----------------- ------------- -------------
# Lab-Keep-1yr Keep 365 CreationAgeInDays False
# Lab-Contract-Record KeepAndDelete 2555 EventAgeInDays True
# Lab-Purge-Drafts-90d Delete 90 ModificationAgeInDays False
4. Publish to a single test site (create https://kloudvin.sharepoint.com/sites/retention-lab first):
New-RetentionCompliancePolicy -Name "Lab-Publish" `
-SharePointLocation "https://kloudvin.sharepoint.com/sites/retention-lab"
New-RetentionComplianceRule -Policy "Lab-Publish" `
-PublishComplianceTag "Lab-Keep-1yr,Lab-Contract-Record,Lab-Purge-Drafts-90d"
5. Add a KQL auto-apply policy for PDFs mentioning NDA, same site only:
New-RetentionCompliancePolicy -Name "Lab-AutoApply-NDA" `
-SharePointLocation "https://kloudvin.sharepoint.com/sites/retention-lab"
New-RetentionComplianceRule -Policy "Lab-AutoApply-NDA" `
-ApplyComplianceTag "Lab-Keep-1yr" `
-ContentMatchQuery '("non disclosure" OR nda) AND filetype:pdf'
6. Wait out distribution, then validate (labels in the site’s details pane can take ~a day; auto-apply up to 7):
Get-RetentionCompliancePolicy -DistributionDetail |
Where-Object Name -like "Lab-*" |
Format-Table Name, Enabled, DistributionStatus # expect: Success
In the site: upload a doc, details pane → Apply retention label → Lab-Contract-Record, then try to delete the file — SharePoint blocks it with a record error. That error is the lab’s proof-of-concept moment. Toggle Record status to Unlocked in the details pane, edit, re-lock; as site admin, note the Preservation Hold library now exists.
7. Fire the event and watch the clock start (asynchronous — allow days, verify via the label’s expiry column in the library view or content search):
New-ComplianceRetentionEvent -Name "Lab Expiry - TEST-001" `
-EventType "Lab Contract Expiration" `
-SharePointAssetIdQuery "ComplianceAssetId:TEST-001" `
-EventDateTime (Get-Date).ToString("MM/dd/yyyy")
(For the query to resolve, set TEST-001 in the labeled item’s Asset Id field — the column appears on record-labeled items — before firing.)
8. Validate with search + audit: an eDiscovery content search for ComplianceTag:"Lab-Contract-Record" should return the labeled item; Search-UnifiedAuditLog -FreeText "Lab-Contract-Record" (EXO session) shows the label lifecycle events.
9. Teardown — order matters (rules → policies → labels), and the record label resists deletion while applied, so unlock and remove the label from the test item first (as admin), or simply delete the whole test site after removing the policies:
"Lab-Publish","Lab-AutoApply-NDA" | ForEach-Object {
Remove-RetentionCompliancePolicy -Identity $_ -Confirm:$false
}
"Lab-Keep-1yr","Lab-Contract-Record","Lab-Purge-Drafts-90d" | ForEach-Object {
Remove-ComplianceTag -Identity $_ -Confirm:$false
}
Event types with no dependent labels can then be removed in the portal. Total cost: nothing beyond licensing — retention has no meters.
Common mistakes & troubleshooting
The playbook. Symptoms are phrased the way tickets arrive:
| # | Symptom | Root cause | Confirm | Fix |
|---|---|---|---|---|
| 1 | Labels missing in Outlook a day after publishing | Exchange label sync takes up to 7 days; mailbox needs ≥10 MB | Check a seasoned mailbox; Get-RetentionCompliancePolicy -DistributionDetail |
Wait the window; test with a real mailbox, not an empty lab one |
| 2 | Auto-apply labeled nothing | Policy still in simulation; or items already labeled (auto-apply never replaces); or 7-day pass pending | Portal → Label policies → policy status; sample items’ current labels | Turn on after simulation review; accept existing labels or relabel deliberately |
| 3 | Auto-apply missed old email (SIT condition) | SIT-based Exchange evaluation covers new messages only | Compare hit dates vs policy creation date | Add a KQL (ContentMatchQuery) policy for the at-rest backfill |
| 4 | Event fired; clocks never started | Asset column empty/not indexed at fire time; or label applied after the event | Get-ComplianceRetentionEvent; check the column value + search ContractId:X |
Populate/index the column; re-fire a scoped event |
| 5 | Event started clocks on far too much | Event fired with no asset query — hit every item with that event type’s labels | Review the event’s definition | No un-fire exists: remediate via relabel/extend; make automation refuse empty queries |
| 6 | “Why didn’t it delete?” | Something still says keep: longer policy, delay hold, eDiscovery hold, PHL/Recoverable Items pipeline latency | Walk the four principles; check holds; check MFA/timer cadence (≤7d) | Usually working as designed — document the resolution date; release stale holds |
| 7 | “Why is it still visible in Teams?” | Client removal lags substrate deletion by days | Compliance copy gone from a content search but visible in client | Wait; the substrate is the compliance answer |
| 8 | Can’t delete a SharePoint site | Site under a retention policy/hold | Error message names a hold; Get-RetentionCompliancePolicy locations |
Exclude the site (mind the ~30-day grace) or release the hold, then delete |
| 9 | Can’t delete a retention label | Referenced by a policy; or a record/regulatory label applied to content | Error text; Get-RetentionComplianceRule | ? {$_.PublishComplianceTag -match "X"} |
Remove from rules first; records: remove from content (regulatory: never) |
| 10 | Disposition queue empty for the reviewer | Missing Disposition Management role (Global Admin doesn’t include it); or audit was off; or label lacks review config | Check role group membership; Get-ComplianceTag | fl *Review* |
Add to Records Management role group; enable audit a day before relying on it |
| 11 | Reviewer sees metadata but no content preview | Missing Content Explorer Content Viewer role | Role group audit | Grant the viewer role to the reviewer group |
| 12 | Regulatory record option absent from the wizard | Tenant UI flag not enabled | Get-RegulatoryComplianceUI |
Set-RegulatoryComplianceUI -Enabled $true — after counsel signs off |
| 13 | Recoverable Items quota alarms on held mailboxes | Long holds + churn against the 100 GB hold quota | Get-MailboxFolderStatistics -FolderScope RecoverableItems |
Enable auto-expanding archive; review hold sprawl |
| 14 | Site storage ballooning with no visible growth | PHL accumulation under retain (it counts against site quota) | Site admin → PHL size; storage metrics | Budget it; shorten retain where legal allows; move high-churn content out of records sites |
| 15 | Adaptive-scope policy protects nobody | Scope query matches nothing (attribute blank/misspelled); classifier policy incompatible with adaptive scope | Portal → scope → Scope details membership | Fix source attributes; static scope for classifier policies |
| 16 | DistributionStatus: Error on a policy |
Transient distribution failure to one or more locations | Get-RetentionCompliancePolicy -DistributionDetail | fl *Distribution* |
Set-RetentionCompliancePolicy -Identity X -RetryDistribution |
Best practices
- Model precedence on paper before shipping anything. Every item’s outcome under the four principles should be predictable from your design doc; if two controls overlap “accidentally,” the design isn’t finished.
- Fewer labels, better labels. One label per item, no priority order, no auto-replacement: taxonomy sprawl is unrecoverable at scale. A file plan with 15 well-cited labels beats 90 aspirational ones.
- Choose the clock first.
RetentionTypeis the design decision; action and duration are parameters. Every “retention disaster” story in this article is really a wrong-clock story. - Records sparingly, regulatory records almost never. Escalate immutability only when the obligation demands it; the restriction matrix is the stakeholder conversation, not an afterthought.
- Simulate every auto-apply policy and read the sample matches, not just the counts. Precision bugs scale to millions of items after enforcement.
- Automate event firing from the system of record (HR, CLM) via Graph with application permissions — and make the automation refuse empty asset queries and future-dated typos.
- Treat asset ID population as part of labeling, not a separate project. An event-based label without its column is a paused clock forever.
- Enable audit and the records-manager group before the first disposition, not after. Evidence you didn’t capture cannot be re-created.
- Validate distribution and membership after every change:
-DistributionDetail, adaptive scope membership, aComplianceTag:content search. Retention fails silently; your checks must not. - Budget the invisible storage — PHL against site quota, Recoverable Items against the 100 GB hold quota — as line items, not surprises.
- Keep holds and retention in separate mental (and RACI) lanes: Legal owns holds and their release; Records owns schedules and disposal. Releasing a hold is a change with deletion consequences — treat it like one.
- Everything as code in git: labels, policies, scopes, event types. The portal is for viewing and disposition review; PowerShell/Graph is for change.
Security notes
- Least-privilege the records roles. Disposition Management, Records Management, and the data-classification viewer roles are powerful and narrowly scoped by design — grant them via dedicated mail-enabled security groups, never by widening Global Admin, and audit membership quarterly.
- Guard the Graph automation identity.
RecordsManagement.ReadWrite.Allas an application permission can fire retention events tenant-wide (i.e., start deletion clocks). Certificate credentials in Key Vault, no client secrets in pipelines, and conditional access / workload identity protections on the app. - Protect the audit trail itself. Disposition defensibility rests on the unified audit log — confirm it’s enabled, know your retention (180 days standard, 1 year E5, 10-year add-on), and export evidence for anything that must outlive it.
- Watch for staged-deletion abuse. An insider with label-admin rights could shorten durations or approve dispositions to destroy evidence. The audited actions (“Approved disposal”, regulatory-UI enablement, label setting changes) plus Insider Risk Management policies close that loop.
- Preservation Lock and regulatory records are security controls against admins — including future you. That is their value and their danger; both belong behind a documented, counsel-approved change gate.
- Retention is not access control. A retained document is still shareable; pair lifecycle labels with sensitivity labels and the SharePoint/OneDrive sharing governance controls for confidentiality.
Cost & sizing
Retention itself is unmetered — no per-policy or per-GB-processed charges. The bill is licensing plus the storage the preservation machinery quietly consumes.
Licensing dominates. At list prices (hedge for agreement/region): Microsoft 365 E3 ≈ USD 36/user/month (~₹3,000) covers static policies and manual labels; the E5 Compliance add-on ≈ USD 12/user/month (~₹1,000) on top of E3 unlocks the entire records program (auto-apply, adaptive scopes, events, records, disposition); full E5 ≈ USD 57/user/month (~₹4,800) if you’re taking security and analytics anyway. For a 5,000-seat organization, the add-on path is roughly ₹50 lakh/year — the number to defend with the “cost of the alternative” framing: one adverse spoliation finding or one over-retention regulatory penalty typically exceeds it.
Storage is the sleeper. PHL consumes SharePoint site quota: a contracts estate with record versioning and steady churn can add tens of GB monthly (Meridian Forge: ~34 GB/month, ~400 GB/year ≈ ₹34,000/year at ~USD 0.20/GB/month list for add-on SharePoint storage). Exchange is gentler — Recoverable Items’ 100 GB hold quota and auto-expanding archives are included — but litigious mailboxes need monitoring, not faith. Right-sizing levers, in order of impact: shorten retain durations to the legal minimum (the citation column keeps you honest), keep high-churn working content out of record-labeled libraries, use Delete-only hygiene labels to shrink the corpus that longer controls must carry, and review hold sprawl quarterly — holds are the storage cost that never expires on its own.
Interview & exam questions
1. When do you need a retention label instead of a retention policy? The moment the requirement includes any of: disposition review, records/regulatory records, event-based timing, per-item durations, or file plan metadata — those are label-only capabilities. Policies are the right tool for uniform container-wide retain/delete with no per-item nuance.
2. Walk through the principles of retention for: org-wide policy keep-10y plus a label delete-at-7y. Retention wins over deletion, so nothing purges at year 7; longest retention wins, so the item is preserved to year 10; the label’s delete is explicit, so deletion is staged by the label at 7 (item leaves user view) but the purge completes only when the 10-year keep expires.
3. Why can’t you fix a mislabeled regulatory record, and what’s the design lesson? Regulatory records block label removal, relabeling, unlocking, and retention shortening for everyone, permanently — remediation is rebuild-around, not repair. Lesson: -Regulatory $true only for genuine WORM-grade obligations, confirmed by counsel, never “to be safe.”
4. A SIT-based auto-apply policy isn’t labeling five-year-old email. Why, and what’s the fix? For Exchange, SIT conditions evaluate only messages sent/received after the policy exists — no at-rest crawl. Backfill with a KQL ContentMatchQuery policy, which runs against the eDiscovery index including mailbox data at rest.
5. What are the three objects of event-based retention and the classic failure between them? Event type (trigger category), label with EventAgeInDays bound to it, and the event fired later with an asset ID query. Classic failure: the asset column (ComplianceAssetId/custom property) is unpopulated or unindexed when the event fires, so the query resolves nothing and the clocks stay paused forever.
6. What physically happens when a user deletes a document under a retain label in SharePoint? The item moves into the site’s hidden Preservation Hold library — invisible to users, visible to site collection admins, counted against site quota — and stays until every applicable retention clock expires, after which the cleanup timer job (≈7-day cadence) purges it.
7. Where do Teams chat compliance copies live, and what can’t Teams retention do? In hidden SubstrateHolds folders inside user mailboxes (channel messages: the group mailbox; private channels: member mailboxes). Teams locations are policy-only: no retention labels, no disposition review, no auto-apply, and rules can’t use ExpirationDateOption — clocks always run from message creation.
8. Differentiate a record and a locked record’s editability, and describe record versioning. A record blocks delete always; while locked it also blocks content edits. Unlocking (SharePoint/OneDrive) copies the locked version into the PHL’s Records folder as tamper evidence, allows normal versioned editing, and re-locking freezes the latest version as the new record. Exchange records have no unlock concept.
9. A disposition reviewer named on the label sees an empty queue. Top two causes? Missing the Disposition Management role (it lives in the Records Management role group and is not implied by Global Admin), and scoping — by default reviewers see only their own stage’s items; org-wide visibility requires membership in the group set via Enable-ComplianceTagStorage -RecordsManagementSecurityGroupEmail.
10. How does an eDiscovery hold interact with a label whose retention expired? The hold sits above the principles of retention: the item is not purged, and an approved disposition defers execution until the hold releases (plus the ~30-day delay hold). Releasing an old hold can therefore trigger a deletion wave — a change to coordinate with Legal.
11. Static vs adaptive scopes — give the two hard reasons each still exists. Static: no E5 dependency, and trainable-classifier auto-apply policies require them. Adaptive: no 100-site/1,000-mailbox caps and query-driven membership that survives joiner/mover/leaver churn without list maintenance.
12. What evidence exists that disposal actually happened? The Disposition page’s Disposed items (reviewer/auto-approval, timestamp, stage history — exportable CSV, retained up to 7 years), Records disposed for unreviewed record deletions, Get-ReviewItems -Disposed $true for programmatic pulls, and unified audit events (“Approved disposal” et al.) tying each action to an identity.
Cert mapping: this domain is examined in SC-401 (Information Security Administrator) — the retention, records management, and disposition objectives that carried over when SC-400 retired — and at survey depth in MS-102 (Microsoft 365 Administrator) under compliance implementation. Questions 2, 4, 5, and 9 are the styles both exams love: precedence walk-throughs, condition-scope asymmetries, and role-gotchas.
Quick check
- An item carries a label that deletes at 5 years while an org-wide policy keeps for 7. When is it purged, and which principles decide?
- Name the four
RetentionTypeclocks and the one that can keep an item alive forever unintentionally. - Your event fired yesterday; nothing is aging. Give two likely causes.
- True or false: a standard retain-label prevents users from deleting a file in SharePoint.
- Which two records-program features are irreversible by design?
Answers
- Purged at year 7. Principle 1 (retention wins) suspends the label’s year-5 delete; principle 2 (longest wins) carries it to 7; principle 3 made the label’s delete the governing delete action once retention lapsed.
CreationAgeInDays,ModificationAgeInDays,TaggedAgeInDays,EventAgeInDays. The trap isModificationAgeInDays— every edit resets it, so a frequently edited document never ages out.- The asset ID column was empty or not indexed when the event’s query ran, or the items were labeled after the event fired (late-labeled items miss the start date). Also acceptable: event processing is asynchronous — days, not minutes.
- False. The user deletes normally; a preserved copy lands in the Preservation Hold library. Only a record label blocks deletion in the UI.
- Regulatory records (label can never be removed, unlocked, or shortened) and Preservation Lock on a policy (can extend/add locations, never remove, disable, or delete).
Glossary
- Retention policy — container-level rule assigning retain/delete behavior to whole locations; nothing stamped on items.
- Retention label — item-level lifecycle stamp (action + duration + clock); one per item; the carrier of all premium records features.
- Record — label setting (
IsRecordLabel) that blocks deletion and, while locked, editing; supports lock/unlock with record versioning in SharePoint/OneDrive. - Regulatory record — irreversible record: no label removal, no unlock, no shortening; enabled tenant-wide via
Set-RegulatoryComplianceUI. - Principles of retention — the four-level precedence algorithm: retention over deletion → longest retention → explicit over implicit deletion → shortest deletion.
- Adaptive scope — query-based policy membership (User/Site/Group types) refreshed ~daily; removes static inclusion caps.
- Auto-apply policy — label policy that stamps matching content via SITs, KQL, trainable classifiers, or cloud attachments; never replaces an existing label.
- Simulation mode — dry run for auto-apply: matched counts and samples against data at rest before enforcement.
- Event-based retention —
EventAgeInDayslabels whose clocks start when a business event fires, scoped by asset ID queries. - ComplianceAssetId — the SharePoint column purpose-built to carry the asset identifier event queries resolve against.
- Disposition review — label-only human approval gate at end of retention; up to 5 stages × 10 reviewers; produces exportable proof retained up to 7 years.
- Preservation Hold library (PHL) — hidden per-site SharePoint/OneDrive library holding preserved copies; counts against site quota.
- Recoverable Items — hidden Exchange folder tree (Deletions, Versions, Purges, DiscoveryHolds) where mail retention physically operates; 30→100 GB quota under hold.
- SubstrateHolds — hidden mailbox folder retaining Teams and Viva Engage message compliance copies.
- Managed Folder Assistant (MFA) — Exchange’s retention processor; touches every mailbox at least once per 7 days.
- Delay hold — ~30-day preservation window Exchange applies after any hold/retention removal.
- Preservation Lock —
-RestrictiveRetention $true; policy can be extended/broadened but never weakened, disabled, or deleted. - Priority Cleanup — the governed E5 override that can purge sensitive content past retention settings and eDiscovery holds.
Next steps
You can now design the taxonomy, predict precedence, automate the clocks, and hand over disposal evidence. Build outward:
- Next: Conducting Investigations with Microsoft Purview eDiscovery (Premium): Holds, Collections, and Review Sets — the litigation layer that sits above your principles-of-retention math.
- Related: Sensitivity Labels in Microsoft Purview: Auto-Labeling, Encryption, Co-Authoring, and Container Inheritance — the classification sibling;
InformationProtectionLabelIdties the two programs together. - Related: Building Microsoft Purview DLP Policies for Endpoint and Exchange — the same SIT engine, pointed at exfiltration instead of lifecycle.
- Related: Implementing Microsoft Teams Governance: Naming Policies, Expiration, Access Reviews, and Sensitivity Labels — container lifecycle for the workload your retention policies can only treat as messages.
- Related: Deploying Microsoft Purview Insider Risk Management — detecting the staged-deletion behavior your audit trail records.