Record Sharing, Access Teams & Entra ID Group Teams in Dataverse: A Step-by-Step Walkthrough (Part 4)

In Part 1 we set up row- and column-level security for Jordan alone. In Part 2 we replaced individual assignment with HR Team and drew a Business Unit boundary between HR and Finance. In Part 3 we gave Morgan manager-level visibility through Security Role scoping, the Parent:Child BU access level, Hierarchical Security (Manager Hierarchy), and covered why Contoso chose Manager Hierarchy over Position Hierarchy.

Every access path built so far has one thing in common: it’s structural. A user sees a record because of who owns it, which team they belong to, which Business Unit they sit in, or where they sit in the reporting line. All of that is decided at design time, before any specific record exists.

This post is about the case that doesn’t fit that mould — a one-off collaborator from another department who needs exactly one record, not a role. Dataverse has two purpose-built mechanisms for that: record Sharing and Access Teams. It also finally makes good on something flagged back in Parts 2 and 3: replacing Sam’s direct Finance Self-Service assignment with a Microsoft Entra ID group team, so Finance’s Dataverse access starts managing itself.


Where We Left Off

At the end of Part 3, the Contoso environment had:

UserBusiness UnitTeamSecurity Role sourceColumn Profile sourceCan see Salary?
AlexRootSystem Administrator (direct)Bypassed✓ Always
JordanContoso - HRHR TeamEmployee Self-Service (via team)HR Salary Access (via team)✓ Own row + team row
MorganContoso - HRHR TeamEmployee Self-Service (via team) + HR Manager Self-Service (direct)HR Salary Access (via team)✓ Own + Jordan + Riley + team row
RileyContoso - HR TraineesHR Trainee Self-Service (direct)None✓ Own row only
SamContoso - FinanceFinance Self-Service (direct)None✗ Blank

Every access grant in this table is structural — ownership, team membership, Business Unit, or hierarchy. Sam is still assigned directly, exactly as Part 2 left him, and flagged twice since as “the natural next step.”


The Plan

  1. Use record Sharing to give Sam one-off, read-only visibility into a single HR record — and see exactly why that grant works given Sam’s current role
  2. Formalize that pattern with an Access Team, so reviewers can be added to and removed from a specific record directly from the form, without anyone touching the Share dialog
  3. Retire Sam’s direct Finance Self-Service assignment in favour of a Microsoft Entra ID (Azure AD) security group team, so Finance’s Dataverse access follows an Entra ID group Contoso’s IT team already maintains
  4. Pull every access path introduced across the series — ownership, Business Unit, hierarchy, sharing, access teams, group teams — into one final map of exactly why Sam sees exactly one HR row and nothing else

The Problem Sharing and Access Teams Solve

Contoso runs a quarterly compensation review. Before a salary change is finalised, someone in Finance signs off on that specific record — not on HR’s salary data generally. This quarter, Sam needs to review Jordan’s row. Sam doesn’t need Morgan’s row, Riley’s row, or any other HR record — just this one, and only enough access to read it.

None of the tools built so far actually fit:

  • Raising Sam’s Read access level to Business Unit or Parent:Child BU would show Sam every HR salary record, not just Jordan’s — a serious overshare for a single sign-off.
  • Adding Sam to HR Team hands him Employee Self-Service and HR Salary Access wholesale, every quarter, forever — the exact scaling problem Part 2 was built to solve, now working against you.
  • Hierarchical Security doesn’t apply. Sam isn’t Jordan’s manager and never will be; it’s scoped to the reporting line, not to a cross-department review workflow.

What Sam actually needs is a grant scoped to one record, independent of Business Unit, ownership, or the org chart. That’s what Sharing and Access Teams are for.


Record Sharing — the One-Off Escape Hatch

Sharing is the most granular access mechanism in Dataverse: a specific user or team, a specific record, a specific set of access rights — Read, Write, Delete, Append, Append To, Assign, Share — chosen individually, independent of any Security Role.

Give Jordan the Share Privilege

Before Jordan (or Morgan) can share anything, someone needs the Share privilege on the table. Right now Employee Self-Service has Share set to None — Part 1 didn’t need it.

Go to Security roles → open Employee Self-Service → find Employee Salary → set Share to User → Save.

User-level Share means a holder can only share rows they personally own — not anyone else’s, and not the whole Business Unit. That’s deliberately narrow: this privilege is about letting Jordan hand out access to their own record, not turning Jordan into a second admin.

Share Jordan’s Row With Sam

Log in as Jordan. Open Jordan’s Employee Salary row → command bar → Share+ Add a user or team → search for Sam → tick Read only, leaving Write, Delete, Append, Append To, Assign, and Share unticked → confirm.

Verify

Switch to Sam’s browser window and refresh the Employee Salary table. Sam now sees two rows:

  • Sam’s own Finance row — full Create/Read/Write, via Finance Self-Service
  • Jordan’s row — visible, but Edit and Delete are unavailable; the share only granted Read

Morgan’s row and Riley’s row are still invisible to Sam. Sharing is surgical — it touches exactly the record it names, nothing else, and the Business Unit boundary between Finance and HR holds everywhere the share doesn’t explicitly reach.

What About the Salary Column?

This is the two-layer principle from Part 1 showing up again. Sam has row-level access to Jordan’s record through the share — but Sam has no Column Security Profile granting access to the Salary column. The HR Salary Access profile was assigned to HR Team in Part 2; Sam is not a member of that team and has never been added to the profile individually.

The result: Sam can see Jordan’s row, but the Salary column is blank — exactly the same ”✗ Blank” behaviour Sam sees on his own Finance row. The row-level gate (sharing) and the column-level gate (Column Security Profile) are evaluated independently, and both must pass for a value to be visible. Sharing a record does not bypass column security, and column security does not block row-level visibility — they are orthogonal.

For Contoso’s quarterly review, this is actually the right outcome. Sam needs to verify the existence of a salary record and confirm non-salary details (department, start date, etc.) — not see the salary figure itself. If Sam did need the Salary value, Alex would need to add Sam to the HR Salary Access profile (or a separate, narrower profile) independently of the share. That’s a deliberate, auditable decision — not something that leaks through automatically because a row was shared.

Why This Actually Worked

This is worth pausing on, because it’s easy to assume sharing is a self-contained override. It isn’t. Dataverse runs two checks before showing Sam that row:

  1. Privilege check — does Sam’s Security Role grant any Read privilege at all on Employee Salary? Yes: Finance Self-Service sets Read to User, scoped to Sam’s own records.
  2. Access check — does Sam specifically have rights to this record? Ordinarily no — Jordan’s row isn’t Sam’s and isn’t in Sam’s Business Unit. The share is what supplies a “yes” here, for this one record only.

Both checks have to pass. If Sam’s Read privilege on Employee Salary had instead been set to None — no Read at all, at any scope — sharing Jordan’s row with him would have done nothing. Sam would still see nothing, because Dataverse never gets past the first check to even consult the share. Sharing extends the reach of a privilege the recipient already holds; it doesn’t manufacture one from nothing. See Sharing and assigning and How access to a record is determined for the underlying mechanics.

Revoking a Share

Log back in as Jordan → open the row → Share → select Sam → Remove → confirm. Refresh as Sam: Jordan’s row is gone. Nothing about Sam’s role, Business Unit, or team membership changed — the share was the only thing granting that visibility, and removing it was the only thing needed to take it away.

Where Sharing Runs Out

This works cleanly for one record and one reviewer. It does not scale to “every compensation-review record, every quarter, for whichever Finance approver is assigned that cycle.” Repeating the Share dialog per record, per person, per quarter is exactly the kind of manual overhead Part 2 eliminated for role assignment — and Dataverse has a purpose-built answer for it on the sharing side too: Access Teams.


Access Teams — Sharing That Scales to a Group

An Access Team doesn’t own records and can’t be assigned a Security Role — Microsoft’s own guidance is explicit that access teams don’t own records and don’t hold roles. Instead, a record is shared with the team, and the team is granted specific access rights on it — the same Read/Write/Delete/Append/Append To/Assign/Share vocabulary as a manual share, just applied to a group instead of one person at a time.

What makes Access Teams worth the extra setup over the Share dialog is the template: a reusable definition of exactly which access rights get granted, wired directly into the record’s form so anyone can add or remove a reviewer without ever opening the Share dialog by hand.

Enable Access Teams on the Table

Open the maker portal at make.powerapps.comTablesEmployee SalaryProperties → expand Advanced options → toggle Access Teams to OnSave.

This is the same Properties pane where column security was enabled in Part 1 — the toggle lives alongside the other table-level settings.

This is a one-way switch worth taking seriously. Enabling Access Teams on a table is a structural change to that table’s definition, not a per-record setting — treat it the same way Part 2 treated table ownership type: a deliberate, upfront decision rather than something to toggle casually in a production environment.

Create the Access Team Template

Go to the Power Platform admin center → your environment → SettingsTemplatesAccess team templates → select + New:

FieldValue
NameEmployee Salary Reviewers
TableEmployee Salary
Access RightsRead only — leave Write, Append, Append To, Assign, Share, and Delete unticked

Save and close. Notice there’s no Create option on the list at all — access team members can never create records through the team’s grant; creating a record always requires the member’s own Security Role to include Create. An access team can only extend rights to records that already exist.

Add the Access Team Control to the Form

A template alone doesn’t add anything to a record’s form — you have to place it. Open the Employee Salary main form in the form designer → add a sub-grid → set its Table to Users, its Default View to Associated Record Team Members, and bind it to the Employee Salary Reviewers template → Save → Publish.

Every Employee Salary record now shows an Employee Salary Reviewers list alongside the standard fields — see Create a team template and add it to an entity form for the full solution-packaging version of these steps if you want this to travel between environments.

Diagram: the Employee Salary form showing the standard fields plus a new Employee Salary Reviewers list; an arrow shows a user being added to the list which triggers a per-record system-managed team and a Read-only share of that one row Adding someone to the Employee Salary Reviewers list on a record shares that one row with a system-managed team created just for it

Add Sam Through the Access Team Instead of the Share Dialog

Log in as Jordan (or Morgan — either already holds Read and Share on the row). Open Jordan’s row → in the new Employee Salary Reviewers list → + Add → search for Sam → Add.

Nothing about Sam’s Security Role changed. What happened instead: Dataverse created a system-managed access team scoped to this one record and this one template, added Sam as its only member, and shared the row with that team at Read — exactly the access right the template specifies. If a second HR row later needs the same reviewer, adding Sam there creates (or reuses) a separate, unrelated per-record team; the two are never connected.

Verify

Refresh as Sam. Same outcome as the manual share earlier: Jordan’s row appears, Read-only, alongside Sam’s own Finance row. Morgan’s row and Riley’s row remain invisible — an Access Team only ever reaches the specific records it’s been attached to, nothing wider.

The Salary column on Jordan’s row is still blank for Sam — the same column-security behaviour observed during the manual share. The Access Team grants row-level Read through sharing; it does not add Sam to the HR Salary Access Column Security Profile. Those are still two independent gates.

Use Check Access to See Why

Every record’s command bar has a Check Access option. Open Jordan’s row as Sam → Check Access → enter Sam’s name. The dialog reports exactly which access paths grant Sam visibility: the per-record access team share providing Read, and Sam’s own Finance Self-Service role providing the baseline privilege. This is considerably faster than manually re-deriving access from the role, team, and BU configuration, and it’s the first tool to reach for whenever access behaviour doesn’t match expectations.

Remove Sam From the Access Team

Remove Sam from the Employee Salary Reviewers list on Jordan’s row, the same way you’d remove any sub-grid item. This unshares the row from the per-record team; refresh as Sam and Jordan’s row is gone again.

Why the Share Privilege Bump Mattered Here Too

This is the payoff of the earlier detour into manual sharing: adding someone to a record’s Access Team is Dataverse performing a share on your behalf, using the rights baked into the template. That’s why whoever does the adding — Jordan or Morgan — needed Share privilege on the table in the first place, and why Sam still needed his own baseline User-level Read on Employee Salary (already in place via Finance Self-Service) for the grant to mean anything at all. Neither mechanism creates a privilege from nothing; both extend the reach of one the recipient already holds. The caller must hold Share plus the rights in the template, and the person being added needs at least Basic (User) Read on the table for either mechanism to do anything at all.


Owner Teams vs Access Teams vs Microsoft Entra Group Teams

Part 2 covered Owner Teams. This post adds Access Teams and is about to add a third type. Worth lining all three up before moving on:

Owner TeamAccess TeamMicrosoft Entra group team
Can own recordsYesNoYes
Can hold a Security RoleYesNoYes
Grants access viaRole privileges, evaluated with the team as the record ownerA direct share of a specific record, at the rights defined by a templateRole privileges, evaluated exactly like an Owner Team
ScopeEvery record the team owns or holds role-based access toOnly the records it’s been explicitly attached toEvery record the team owns or holds role-based access to
Membership managedManually, in DataverseManually (user-created) or automatically per record (template-driven)Automatically, from a Microsoft Entra ID group — not editable inside Dataverse at all
Best fitA stable department or function with a fixed roleAd hoc collaborators whose composition changes record by recordA department or function whose Dataverse membership should always mirror an Entra ID group, with zero manual syncing

Only Owner Teams and Microsoft Entra group teams can own records or hold Security Roles — access teams can do neither. That single fact is why HR Team from Part 2 had to be an Owner Team, and why the Employee Salary Reviewers pattern above had to be an Access Team rather than a stripped-down Owner Team — Owner Teams are simply the wrong tool for “an unpredictable number of per-record collaborators,” in the same way Access Teams would be the wrong tool for “HR’s core, stable membership.”

Finance is about to become the third type.


Microsoft Entra ID Group Teams — Automating Finance Team Membership

Finance Self-Service has been assigned directly to Sam since Part 2, and both Part 2 and Part 3 flagged this as unfinished business. The obvious fix — an Owner Team for Finance, built exactly like HR Team — works, but it still needs Alex to remember to click + Add members every time Finance hires or loses someone. This section replaces that manual step entirely.

Why a Group Team Instead of a Plain Owner Team

Dataverse’s Team Type field isn’t limited to Owner and Access — it also offers Microsoft Entra Security group and Microsoft Entra Office group. A Microsoft Entra group team behaves exactly like an Owner Team — it can own records and hold Security Roles — with one difference: its membership is dynamically derived from an existing Microsoft Entra ID group rather than maintained by hand, evaluated each time a member accesses the environment. Contoso’s IT department already maintains a security group called Contoso Finance Employees for licensing and Teams-channel access — Sam is already a member of it. Rather than creating a second, Dataverse-only Finance team to maintain in parallel, Alex points Dataverse at the group that already exists.

If your environment restricts sign-in to an environment security group, make sure Contoso Finance Employees is nested inside that broader group too — otherwise new Finance hires still won’t be able to sign in at all, regardless of anything configured below.

Create the Group Team

Go to Users + permissionsTeams+ Create team:

FieldValue
Team nameFinance Team (Entra ID)
Business UnitContoso - Finance
Team typeMicrosoft Entra Security group
Group nameContoso Finance Employees
Membership typeMembers

Save. Membership type is a filter on the Entra ID group, not a Dataverse setting on top of it — choosing Members means only the group’s Members flow into this Dataverse team; its Owners and any Guests are excluded. You can create separate group teams against the same Entra ID group for different membership facets — for example, a second team pointed at the same group’s Owners, carrying a more privileged role — but Contoso doesn’t need that split today.

Assign the Security Roles

Open Finance Team (Entra ID)Manage security roles → tick Finance Self-Service and Basic User → Save. Identical step to what Part 2 did for HR Team — only the team type is different.

Retire Sam’s Direct Assignment

Open Sam’s user record → Manage security roles → untick Finance Self-Service and Basic User. Sam’s access now flows entirely through group membership, following the same “don’t leave both direct and team assignments active” principle Part 2 established for Jordan.

Verify

Sign Sam out and back in — group membership is evaluated fresh each time a member accesses the environment, so this is the equivalent of the propagation waits used throughout this series for team and profile changes. Refresh the Employee Salary table as Sam: identical result to before the migration — Sam’s own row, full Create/Read/Write, via Finance Self-Service now sourced from Finance Team (Entra ID) instead of a direct assignment. The Read-only grant on Jordan’s row from the Access Team section earlier is untouched by any of this — it lives independently in Dataverse’s sharing records, not tied to how Sam’s baseline Finance role happens to be delivered.

What Changes Going Forward

Add a new hire to Contoso Finance Employees in the Microsoft Entra admin center — no Dataverse step at all. The next time that person signs in to the environment, they’re automatically a member of Finance Team (Entra ID) and therefore hold Finance Self-Service and Basic User. Compare that to HR Team: onboarding a new HR employee still means Alex manually clicking + Add members in Dataverse, every time.

Offboarding is the same story in reverse. Remove Sam from the Entra ID group — say, if he moves to a different department — and the next time he accesses the environment, his Finance Team (Entra ID) membership silently drops along with everything it carried. Forgetting to manually remove a leaver from an Owner Team is a common access-hygiene gap; a group team removes it by construction, provided whoever owns offboarding remembers to update the Entra ID group in the first place.

Diagram: Contoso Business Unit and team hierarchy with root Contoso at the top, Contoso HR containing HR Team with Jordan and Morgan and Contoso HR Trainees with Riley beneath it, and Contoso Finance containing Finance Team (Entra ID) synced from the Contoso Finance Employees Microsoft Entra group with Sam as a member Updated Contoso structure: Finance Team is now a Microsoft Entra group team, its membership mirroring an Entra ID security group instead of a manually maintained list


What the Access Structure Looks Like Now

UserBusiness UnitTeam(s)Security Role sourceColumn Profile sourcePer-record extrasCan see Salary?
AlexRootSystem Administrator (direct)Bypassed✓ Always
JordanContoso - HRHR TeamEmployee Self-Service (via team)HR Salary Access (via team)✓ Own + team row
MorganContoso - HRHR TeamEmployee Self-Service (via team) + HR Manager Self-Service (direct)HR Salary Access (via team)✓ Own + Jordan + Riley + team row
RileyContoso - HR TraineesHR Trainee Self-Service (direct)None✓ Own row only
SamContoso - FinanceFinance Team (Entra ID)Finance Self-Service (via group team)NoneRead-only on Jordan’s row (Access Team)✗ Row visible, Salary blank

The key additions in this post: Sam’s baseline Finance access now maintains itself through an Entra ID group instead of a direct role assignment, and Sam’s visibility into one specific HR record comes from a mechanism that is completely orthogonal to Business Unit, ownership, or role scope — a per-record Access Team grant that would still be there even if Sam’s Finance role changed entirely tomorrow. Column security holds independently: Sam can see Jordan’s row but not the Salary value on it, because sharing a record does not grant access to secured columns — the two layers from Part 1 remain fully independent.


Things Worth Knowing

Sharing and Access Teams both extend an existing privilege — neither creates one from nothing. A recipient needs at least User-level access to the relevant privilege on the table (Read, in this post’s case) before a share or an access team grant does anything at all. If that baseline is set to None, the record stays invisible regardless of what gets shared or who gets added to a reviewer list.

Sharing a record does not bypass column security. Even after a row is shared with (or an access team grants Read on) a specific record, secured columns are still governed entirely by Column Security Profiles. A user without the right profile sees those columns as blank — the row-level gate and the column-level gate are evaluated independently. This is the same Part 1 principle at work: both must pass for a value to be visible.

Only Owner Teams and Microsoft Entra group teams can own records or hold Security Roles. Access Teams can do neither — they exist purely to attach specific access rights to specific records via sharing. This is the cleanest way to decide which team type a given scenario needs: if the team should ever own something, it isn’t an Access Team.

You can convert an Owner Team into an Access Team, but never the reverse, and group teams and access teams can’t be converted into anything else. Worth treating team type as close to a one-way door at design time — see Teams in Dataverse for the conversion command and its restrictions.

Membership type on a Microsoft Entra group team is fixed at creation. Changing which Entra ID group facet (Members, Members and Guests, Owners, Guests) feeds a group team means deleting and recreating it — there’s no in-place edit.

A user added to an Entra ID group doesn’t fully “arrive” in Dataverse until they’ve signed in to the environment at least once. They won’t appear as a Dataverse user record or a visible team member purely from being added to the group; the moment they do sign in, their group-driven team membership and roles apply immediately.

Managing a group team’s membership can’t be done inside Dataverse at all. The Members tab that lets you manually add or remove people on an Owner Team isn’t available the same way here — membership changes have to happen in Microsoft Entra ID, by whoever administers that group, which may not be Alex.

Business Unit assignment and group-team membership are two separate axes. Pointing Finance Team (Entra ID) at an Entra ID group automates role and team membership; it does not automatically set a new Finance hire’s Dataverse Business Unit. A genuinely new user still needs to be added and placed in Contoso - Finance the way Part 2 described before any of this applies to them.

All sharing — manual or via an Access Team — lives in the PrincipalObjectAccess (POA) table. This is worth knowing purely for governance: POA rows accumulate with every share and every access-team addition, and an environment with heavy sharing usage should periodically review this table’s growth rather than assuming sharing is free.

Reassigning a record’s owner is a different operation from sharing it, with a separate setting governing what the previous owner keeps. By default, reassigning a record does not leave the previous owner with any access to it afterwards; an environment-level setting can change that default, but it’s independent of anything covered in this post about Sharing or Access Teams.

Check Access is the fastest way to debug any of this. Every record’s command bar has a Check Access option that reports exactly why a given user has (or doesn’t have) access — ownership, team membership, Business Unit, hierarchy, or a specific share — which is considerably faster than manually re-deriving it from the role, team, and BU configuration each time.


Where This Leaves Contoso

Four posts in, Contoso’s Employee Salary table is secured by every major mechanism Dataverse offers:

Access mechanismWhere it was introducedWhat it does in Contoso’s setup
Row-level security (Security Roles + access levels)Part 1Controls which rows each user can see, based on ownership and scope
Column-level security (Column Security Profiles)Part 1Restricts the Salary column to users/teams with the HR Salary Access profile
Business UnitsPart 2Draws the boundary between HR and Finance data
Owner TeamsPart 2HR Team carries Employee Self-Service and HR Salary Access — one team, automatic onboarding
Member’s Privilege InheritancePart 2Determines whether team members see their own records, team-owned records, or both
Security Role scoping (BU field vs access level)Part 3Proved the role’s BU field is governance, the access level is the actual control
Parent:Child BU access levelPart 3Gives Morgan Read into Contoso - HR Trainees without granting Organisation-level access
Manager HierarchyPart 3Morgan sees Jordan’s data via the reporting line, independent of BU
Record SharingThis postOne-off, per-record, per-user Read grant — surgical and revocable
Access TeamsThis postSame per-record grant, managed from the form via a template — scales to groups
Microsoft Entra ID group teamsThis postFinance’s Dataverse membership mirrors an Entra ID security group — zero manual syncing

Sam seeing exactly one HR row — Jordan’s, Read-only, Salary blank, this quarter only — and nothing else in HR is the sum of all four posts working correctly at once: the Business Unit boundary still holds everywhere it isn’t explicitly crossed, and the one place it is crossed is scoped to a single record, revocable independently of everything else. Column security holds on top of that: the row is visible but the secured column isn’t, because sharing doesn’t bypass field-level gates. That’s the model working as intended, not an exception to it.

For anything not covered hands-on across this series — auditing, custom code-driven security, Position Hierarchy setup steps, or the full six-layer model in one place — the Complete Guide is the reference to go back to.

Comments