Table of Contents

Change Owner to MRO Team

Bulk transfer ownership of contacts and family groups to a specific team

Overview

The Change Owner to MRO Team operation performs a bulk ownership transfer for contact and mag_familygroup records. This is essential when restructuring teams, redistributing workloads, or ensuring consistent ownership across records during organisational changes.

The operation:

  • Retrieves all contact and mag_familygroup records
  • Updates the ownerid field to the specified team
  • Processes in parallel (50 threads) for performance
  • Handles both entity types in a single execution
  • Supports preview mode to verify changes before execution
Important

This operation requires the --MROTeamId parameter with the GUID of the target team.

When to Use This Operation

Use This Operation When:

✅ Restructuring teams and need to transfer ownership
✅ Deactivating a team and need to reassign their records
✅ Centralising ownership to a specific team for consistency
✅ After data migration to assign correct ownership
✅ Redistributing workload across teams
✅ Ensuring all records have a valid owner

Don't Use This Operation When:

❌ Ownership is already correct
❌ You need to transfer to individual users (not teams)
❌ You want to preserve existing ownership distribution
❌ Records should have different owners based on criteria
❌ Testing in production without preview mode first

Quick Start

Example 1: Preview Ownership Changes

.\WhanauTahi.Xpm.Tooling.CLI.exe datamanipulation `
  --ChangeOwnerToMROTeam `
  --MROTeamId f1e2d3c4-b5a6-7890-1234-567890abcdef `
  --EnvironmentUrl https://myorg.crm6.dynamics.com `
  --ClientId a1b2c3d4-e5f6-7890-1234-567890abcdef `
  --Secret YourClientSecretHere `
  --PreviewMode

Expected Output:

[2024-11-17 19:00:15.123] Starting ownership transfer (PREVIEW MODE)...
[2024-11-17 19:00:15.456] Target team: MRO Operations Team (f1e2d3c4-b5a6-7890-1234-567890abcdef)
[2024-11-17 19:00:15.789] Retrieving contact records...
[2024-11-17 19:00:18.012] Found 12,450 contact records
[2024-11-17 19:00:18.345] Retrieving mag_familygroup records...
[2024-11-17 19:00:20.678] Found 8,320 mag_familygroup records
[2024-11-17 19:00:20.901] PREVIEW: Would update 20,770 total records
[2024-11-17 19:00:20.234]   - 12,450 contacts
[2024-11-17 19:00:20.567]   - 8,320 family groups
[2024-11-17 19:00:20.890] No changes made (preview mode)

Example 2: Transfer Ownership for Real

.\WhanauTahi.Xpm.Tooling.CLI.exe datamanipulation `
  --ChangeOwnerToMROTeam `
  --MROTeamId f1e2d3c4-b5a6-7890-1234-567890abcdef `
  --EnvironmentUrl https://myorg.crm6.dynamics.com `
  --ClientId a1b2c3d4-e5f6-7890-1234-567890abcdef `
  --Secret YourClientSecretHere

Expected Output:

[2024-11-17 19:15:25.123] Starting ownership transfer...
[2024-11-17 19:15:25.456] Target team: MRO Operations Team (f1e2d3c4-b5a6-7890-1234-567890abcdef)
[2024-11-17 19:15:25.789] Retrieving contact records...
[2024-11-17 19:15:28.012] Found 12,450 contact records
[2024-11-17 19:15:28.345] Retrieving mag_familygroup records...
[2024-11-17 19:15:30.678] Found 8,320 mag_familygroup records
[2024-11-17 19:15:30.901] Total records to update: 20,770
[2024-11-17 19:15:31.234] Creating service client pool (50 threads)...
[2024-11-17 19:15:33.567] Processing records in parallel...
[2024-11-17 19:15:40.890] Progress: 2,000/20,770 (9.6%) - 180 records/sec
[2024-11-17 19:15:50.123] Progress: 5,000/20,770 (24.1%) - 195 records/sec
[2024-11-17 19:16:05.456] Progress: 10,000/20,770 (48.1%) - 200 records/sec
[2024-11-17 19:16:20.789] Progress: 15,000/20,770 (72.2%) - 205 records/sec
[2024-11-17 19:16:30.012] Progress: 20,000/20,770 (96.3%) - 210 records/sec
[2024-11-17 19:16:34.345] Ownership transfer completed
[2024-11-17 19:16:34.678] Total records processed: 20,770
[2024-11-17 19:16:34.901]   - Contacts: 12,450
[2024-11-17 19:16:34.234]   - Family Groups: 8,320
[2024-11-17 19:16:34.567] Total time: 68.7 seconds (1 min 9 sec)
[2024-11-17 19:16:34.890] Average throughput: 302 records/sec
[2024-11-17 19:16:34.123] Success rate: 100%

How It Works

Processing Steps

  1. Validate Team: Verify that the provided MROTeamId exists and is a valid team
  2. Retrieve Contacts: Query all contact records
  3. Retrieve Family Groups: Query all mag_familygroup records
  4. Create Service Client Pool: Initialise 50 ServiceClient instances for parallel processing
  5. Update Ownership:
    • For each contact: Update ownerid to MROTeamId
    • For each family group: Update ownerid to MROTeamId
  6. Batch Processing: Groups updates into ExecuteMultipleRequest batches (10 records/batch)
  7. Progress Reporting: Shows percentage complete and throughput

Ownership Update

Contact Record Before:

contact:
  contactid: 12345678-1234-1234-1234-123456789012
  fullname: "John Smith"
  ownerid: a1b2c3d4-a1b2-a1b2-a1b2-a1b2c3d4e5f6 (Original Owner)

Contact Record After:

contact:
  contactid: 12345678-1234-1234-1234-123456789012
  fullname: "John Smith"
  ownerid: f1e2d3c4-b5a6-7890-1234-567890abcdef (MRO Team)

Family Group Record Before:

mag_familygroup:
  mag_familygroupid: 23456789-2345-2345-2345-234567890123
  mag_name: "Smith Family"
  ownerid: b2c3d4e5-b2c3-b2c3-b2c3-b2c3d4e5f6a7 (Original Owner)

Family Group Record After:

mag_familygroup:
  mag_familygroupid: 23456789-2345-2345-2345-234567890123
  mag_name: "Smith Family"
  ownerid: f1e2d3c4-b5a6-7890-1234-567890abcdef (MRO Team)

Finding the Team ID

To get the MROTeamId for the --MROTeamId parameter:

Option 1: Power Apps Admin Center

  1. Navigate to https://admin.powerplatform.microsoft.com
  2. Select your environment → Settings → Teams
  3. Find your team → Copy the Team ID (GUID)

Option 2: SQL Query

SELECT teamid, name 
FROM team 
WHERE name LIKE '%MRO%' OR name LIKE '%Operations%'

Option 3: Advanced Find

  1. In Power Apps, open Advanced Find
  2. Look for: Teams
  3. Find your team → Copy URL parameter id=<team-guid>

Parameters

Required Parameters

--ChangeOwnerToMROTeam

Flag to enable the operation.

Example:

--ChangeOwnerToMROTeam

--MROTeamId

The GUID of the team to assign as owner.

Example:

--MROTeamId f1e2d3c4-b5a6-7890-1234-567890abcdef
Caution

Verify this is the correct team ID before running. All records will be assigned to this team.

--EnvironmentUrl (-e)

The URL of your Dataverse environment.

Example:

--EnvironmentUrl https://myorg.crm6.dynamics.com

--ClientId (-c)

The Azure AD application (client) ID for authentication.

Example:

--ClientId a1b2c3d4-e5f6-7890-1234-567890abcdef

Optional Parameters

--Secret (-s)

The client secret for authentication. If omitted, uses the default secret.

Example:

--Secret YourClientSecretHere
Caution

Never commit secrets to source control.

--PreviewMode

Preview what will be updated without making any changes. Limits to first 100 records.

Example:

--PreviewMode

Real-World Scenarios

Scenario 1: Team Restructuring

Situation: Your organisation is consolidating three regional teams into one centralized MRO Operations Team. You need to transfer ownership of all 20,000+ contact and family group records to the new team.

Solution:

# Step 1: Get the new team ID
$teamQuery = @"
SELECT teamid, name 
FROM team 
WHERE name = 'MRO Operations Team'
"@
# Result: f1e2d3c4-b5a6-7890-1234-567890abcdef

# Step 2: Preview the ownership transfer
.\WhanauTahi.Xpm.Tooling.CLI.exe datamanipulation `
  --ChangeOwnerToMROTeam `
  --MROTeamId f1e2d3c4-b5a6-7890-1234-567890abcdef `
  -e https://prod.crm6.dynamics.com `
  -c a1b2c3d4-e5f6-7890-1234-567890abcdef `
  -s $env:DATAVERSE_SECRET `
  --PreviewMode

# Review the preview output - confirm counts look correct

# Step 3: Transfer ownership for real
.\WhanauTahi.Xpm.Tooling.CLI.exe datamanipulation `
  --ChangeOwnerToMROTeam `
  --MROTeamId f1e2d3c4-b5a6-7890-1234-567890abcdef `
  -e https://prod.crm6.dynamics.com `
  -c a1b2c3d4-e5f6-7890-1234-567890abcdef `
  -s $env:DATAVERSE_SECRET

# Step 4: Verify ownership
$verifyQuery = @"
SELECT 
    (SELECT COUNT(*) FROM contact WHERE ownerid = 'f1e2d3c4-b5a6-7890-1234-567890abcdef') AS ContactsOwned,
    (SELECT COUNT(*) FROM mag_familygroup WHERE ownerid = 'f1e2d3c4-b5a6-7890-1234-567890abcdef') AS FamilyGroupsOwned
"@

Expected Outcome:

  • All contacts owned by MRO Operations Team
  • All family groups owned by MRO Operations Team
  • Regional teams can be deactivated
  • Centralised ownership for consistent management

Scenario 2: Post-Migration Ownership Assignment

Situation: You migrated 15,000 records from a legacy system. All records have default ownership (system administrator). You need to assign proper ownership to the MRO team.

Solution:

# Check current ownership distribution
$ownerQuery = @"
SELECT o.name AS OwnerName, COUNT(*) AS RecordCount
FROM contact c
INNER JOIN systemuser o ON c.ownerid = o.systemuserid
GROUP BY o.name
ORDER BY COUNT(*) DESC
"@
# Result shows most records owned by "System Administrator"

# Transfer ownership to MRO team
.\WhanauTahi.Xpm.Tooling.CLI.exe datamanipulation `
  --ChangeOwnerToMROTeam `
  --MROTeamId f1e2d3c4-b5a6-7890-1234-567890abcdef `
  -e https://prod.crm6.dynamics.com `
  -c a1b2c3d4-e5f6-7890-1234-567890abcdef `
  -s $env:DATAVERSE_SECRET

# Verify ownership distribution again
# Should now show all records owned by "MRO Operations Team"

Expected Outcome:

  • 15,000 contacts assigned to MRO team
  • Family groups assigned to MRO team
  • Proper ownership for reporting and security
  • System administrator no longer owns operational records

Scenario 3: Scheduled Monthly Ownership Cleanup

Situation: Your organisation has various automated processes that sometimes create records with incorrect ownership. You want to ensure all records are owned by the MRO team by running a monthly cleanup.

Solution:

# monthly-ownership-cleanup.ps1
$ErrorActionPreference = "Stop"

$env:CLIENT_SECRET = Get-Secret -Name "DataverseClientSecret"
$MROTeamId = "f1e2d3c4-b5a6-7890-1234-567890abcdef"

# Check if there are records with incorrect ownership
$checkQuery = @"
SELECT COUNT(*) AS IncorrectOwnership
FROM (
    SELECT ownerid FROM contact WHERE ownerid != '$MROTeamId'
    UNION ALL
    SELECT ownerid FROM mag_familygroup WHERE ownerid != '$MROTeamId'
) AS combined
"@

$incorrectCount = Get-IncorrectOwnershipCount -EnvironmentUrl "https://prod.crm6.dynamics.com"

if ($incorrectCount -gt 0) {
    Write-Host "Found $incorrectCount records with incorrect ownership. Correcting..."
    
    & "C:\Tools\WhanauTahi.Xpm.Tooling.CLI.exe" datamanipulation `
      --ChangeOwnerToMROTeam `
      --MROTeamId $MROTeamId `
      -e https://prod.crm6.dynamics.com `
      -c a1b2c3d4-e5f6-7890-1234-567890abcdef `
      -s $env:CLIENT_SECRET
    
    # Archive log
    $logFile = Get-ChildItem ".\Logs\DataManipulation_*" | Sort-Object LastWriteTime -Descending | Select-Object -First 1
    Copy-Item $logFile "\\fileserver\logs\ownership-cleanup-$(Get-Date -Format 'yyyy-MM-dd').log"
    
    # Send notification
    Send-MailMessage -To "admin@example.com" `
                     -Subject "Ownership Cleanup: $incorrectCount Corrected" `
                     -Body "Corrected ownership for $incorrectCount records."
} else {
    Write-Host "All records have correct ownership. Skipping cleanup."
}

Schedule via Windows Task Scheduler:

  • Trigger: Monthly on the 1st at 2:00 AM
  • Action: Run PowerShell script
  • Run whether user is logged on or not

Performance & Scalability

Processing Characteristics

  • Parallel Execution: 50 threads processing records simultaneously
  • Batch Processing: Groups updates into ExecuteMultipleRequest batches (10 records/batch)
  • Retry Logic: Exponential backoff for throttling errors (max 50 retries)
  • Two-Phase Processing: Processes contacts first, then family groups

Typical Performance

Total Records (Contact + Family Group) Estimated Time Throughput
1,000 5-10 seconds 100-200 records/sec
5,000 20-40 seconds 125-250 records/sec
10,000 40-80 seconds 125-250 records/sec
20,000 1-3 minutes 150-330 records/sec
50,000 3-7 minutes 120-280 records/sec
100,000 6-15 minutes 110-280 records/sec
Note

Performance depends on Dataverse API limits, network latency, and concurrent user load.

Optimisation Tips

1. Run during off-peak hours to avoid Dataverse throttling:

# Schedule for evenings or weekends when user load is low

2. Monitor progress in real-time:

# In another PowerShell window
Get-Content ".\Logs\DataManipulation_*" -Wait -Tail 20

3. Use preview mode for large datasets to verify scope:

--PreviewMode

Troubleshooting

Issue: "Team not found"

Cause: The provided MROTeamId doesn't exist or is incorrect.

Solution:

  1. Verify the team exists:
SELECT teamid, name FROM team WHERE teamid = 'f1e2d3c4-b5a6-7890-1234-567890abcdef'
  1. Copy the correct team ID from Power Apps or Advanced Find
  2. Ensure you're using the team GUID, not a user GUID

Issue: "Insufficient privileges to assign records"

Cause: The Azure AD app or authenticating user doesn't have Assign privilege.

Solution:

  1. Verify the app has a security role with Assign privileges:

    • Organization-level Assign for Contact
    • Organization-level Assign for Family Group
  2. Grant necessary privileges in Power Platform Admin Center

Issue: "Operation slow or timing out"

Cause: Dataverse throttling due to API limits or large dataset.

Solution:

  1. The tool includes automatic retry with exponential backoff
  2. Run during off-peak hours to reduce throttling
  3. Check throttling in logs:
ERROR: Request throttled. Retrying in 30 seconds... (Attempt 5/50)
  1. For very large datasets (100K+), consider processing in batches over multiple nights

Issue: "Some records not updated"

Cause: Records may be locked or in a state that prevents ownership change.

Solution:

  1. Check the log for ERROR messages with specific record IDs
  2. Review failed records:
SELECT contactid, fullname, statecode, statuscode, ownerid
FROM contact
WHERE contactid IN ('<failed-id-1>', '<failed-id-2>')
  1. Manually investigate and update failed records

Output & Logs

Log File Location

Logs\DataManipulation_2024-11-17_19-15-25-123.log

Log File Contents

Startup Phase:

[2024-11-17 19:15:25.123] Starting ownership transfer...
[2024-11-17 19:15:25.456] Target team: MRO Operations Team (f1e2d3c4-b5a6-7890-1234-567890abcdef)
[2024-11-17 19:15:25.789] Validating team exists...
[2024-11-17 19:15:26.012] Team validated successfully
[2024-11-17 19:15:26.345] Retrieving contact records...
[2024-11-17 19:15:28.678] Found 12,450 contact records
[2024-11-17 19:15:28.901] Retrieving mag_familygroup records...
[2024-11-17 19:15:30.234] Found 8,320 mag_familygroup records
[2024-11-17 19:15:30.567] Total records to update: 20,770
[2024-11-17 19:15:30.890] Creating service client pool (50 threads)...
[2024-11-17 19:15:33.123] Service client pool created successfully

Processing Phase:

[2024-11-17 19:15:34.456] Processing contact: John Smith (12345678-1234-1234-1234-123456789012)
[2024-11-17 19:15:34.789] Current owner: a1b2c3d4-a1b2-a1b2-a1b2-a1b2c3d4e5f6
[2024-11-17 19:15:34.012] Updating ownerid to: f1e2d3c4-b5a6-7890-1234-567890abcdef
[2024-11-17 19:15:34.345] Contact ownership updated successfully
[2024-11-17 19:15:34.678] Processing family group: Smith Family (23456789-2345-2345-2345-234567890123)
[2024-11-17 19:15:34.901] Current owner: b2c3d4e5-b2c3-b2c3-b2c3-b2c3d4e5f6a7
[2024-11-17 19:15:34.234] Updating ownerid to: f1e2d3c4-b5a6-7890-1234-567890abcdef
[2024-11-17 19:15:34.567] Family group ownership updated successfully
[2024-11-17 19:15:40.890] Progress: 2,000/20,770 (9.6%) - 180 records/sec
... (continues)
[2024-11-17 19:16:05.123] Progress: 10,000/20,770 (48.1%) - 200 records/sec
[2024-11-17 19:16:20.456] Progress: 15,000/20,770 (72.2%) - 205 records/sec

Completion Phase:

[2024-11-17 19:16:34.345] Ownership transfer completed
[2024-11-17 19:16:34.678] Total records processed: 20,770
[2024-11-17 19:16:34.901]   - Contacts: 12,450
[2024-11-17 19:16:34.234]   - Family Groups: 8,320
[2024-11-17 19:16:34.567] Records successfully updated: 20,770
[2024-11-17 19:16:34.890] Records failed: 0
[2024-11-17 19:16:34.123] Total time: 68.7 seconds (1 min 9 sec)
[2024-11-17 19:16:34.456] Average throughput: 302 records/sec
[2024-11-17 19:16:34.789] Success rate: 100%

Understanding the Results

Success Indicators:

  • ✅ "Success rate: 100%"
  • ✅ "Records failed: 0"
  • ✅ "Total records processed" matches expected count
  • ✅ No ERROR lines in log

Warning Signs:

  • ⚠️ "Records failed" > 0 - Review errors and retry failed records
  • ⚠️ Multiple throttling retries - Run during off-peak hours
  • ⚠️ ERROR messages - Check permissions or team ID validity
  • ⚠️ Success rate < 100% - Investigate failed records

See Also