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
owneridfield 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
- Validate Team: Verify that the provided MROTeamId exists and is a valid team
- Retrieve Contacts: Query all contact records
- Retrieve Family Groups: Query all mag_familygroup records
- Create Service Client Pool: Initialise 50 ServiceClient instances for parallel processing
- Update Ownership:
- For each contact: Update
owneridto MROTeamId - For each family group: Update
owneridto MROTeamId
- For each contact: Update
- Batch Processing: Groups updates into ExecuteMultipleRequest batches (10 records/batch)
- 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
- Navigate to https://admin.powerplatform.microsoft.com
- Select your environment → Settings → Teams
- 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
- In Power Apps, open Advanced Find
- Look for: Teams
- 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:
- Verify the team exists:
SELECT teamid, name FROM team WHERE teamid = 'f1e2d3c4-b5a6-7890-1234-567890abcdef'
- Copy the correct team ID from Power Apps or Advanced Find
- 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:
Verify the app has a security role with Assign privileges:
- Organization-level Assign for Contact
- Organization-level Assign for Family Group
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:
- The tool includes automatic retry with exponential backoff
- Run during off-peak hours to reduce throttling
- Check throttling in logs:
ERROR: Request throttled. Retrying in 30 seconds... (Attempt 5/50)
- 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:
- Check the log for ERROR messages with specific record IDs
- Review failed records:
SELECT contactid, fullname, statecode, statuscode, ownerid
FROM contact
WHERE contactid IN ('<failed-id-1>', '<failed-id-2>')
- 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
- datamanipulation Overview - All datamanipulation operations
- Recreate Family Groups - Create family groups for individuals
- TDS Table Extraction - Export contact and family group data
- Microsoft Dataverse Security Roles - Understanding permissions
- Microsoft Dataverse Teams - Managing teams