Abhishek.DataMigrationTool
1.2026.10.1
dotnet add package Abhishek.DataMigrationTool --version 1.2026.10.1
NuGet\Install-Package Abhishek.DataMigrationTool -Version 1.2026.10.1
<PackageReference Include="Abhishek.DataMigrationTool" Version="1.2026.10.1" />
<PackageVersion Include="Abhishek.DataMigrationTool" Version="1.2026.10.1" />
<PackageReference Include="Abhishek.DataMigrationTool" />
paket add Abhishek.DataMigrationTool --version 1.2026.10.1
#r "nuget: Abhishek.DataMigrationTool, 1.2026.10.1"
#:package Abhishek.DataMigrationTool@1.2026.10.1
#addin nuget:?package=Abhishek.DataMigrationTool&version=1.2026.10.1
#tool nuget:?package=Abhishek.DataMigrationTool&version=1.2026.10.1
DataMigrationToolbyXTB
An XrmToolBox tool that migrates records from one Dataverse environment to another while preserving the record GUID. A record that does not exist on the target is created with the same Id; a record whose Id already exists on the target is updated.
This is ideal for moving configuration / reference data (and any GUID-sensitive records) between DEV → TEST → PROD without breaking the lookups and references that depend on those Ids.
The tool's display name in XrmToolBox is DataMigrationToolbyXTB; the compiled assembly is
DataMigrationToolbyXTB.dll.
Features
- Two-environment workflow – select a Source and a Target connection independently, using the standard XrmToolBox connection picker.
- Entity picker from the Default solution – loads the entities contained in the source environment's Default solution into a dropdown.
- FetchXML-driven selection – you supply the FetchXML that decides exactly which records are migrated. A starter template is generated automatically when you pick an entity.
- GUID preserved – records keep their primary key across environments (create-with-Id / update-by-Id).
- Schema-aware writes – read-only columns (calculated/rollup, audit, and other non-writable
system fields) and link-entity (
AliasedValue) columns are skipped automatically so writes don't fail. - Optional ownership – migrate
ownerid(off by default). - Optional status – migrate
statecode/statuscodeusingSetStateRequest(a proper, supported state transition), applied after the record is written (off by default). - Compare / preview before migrating – a Compare button reads the records selected by the FetchXML and opens a dashboard that shows, per record, a New / Update / Identical status and a field-by-field (line-by-line) source-vs-target diff (the target column is blank for records that don't exist on the target yet). Tick the records you want and click Migrate selected to migrate only those. The Migrate Data button still migrates everything directly, with no comparison needed.
- Related-record migration (N:N, N:1, 1:N) – a relationship picker lets you also migrate related
records. N:N replicates many-to-many links via
Associate. N:1 migrates the referenced parent records first (so the record's lookups, e.g. marketing area, resolve). 1:N migrates the child records after. You pick which relationships to include per entity (custom tables only). - N:N name/email matching (cross-environment users/teams) – optionally, when an N:N related
record's GUID is missing on the target, the tool matches it to a target record by a unique field:
the user's email (
internalemailaddress) forsystemuser, otherwise the entity's primary name (e.g. an Approver user/team whose Id differs across environments). Records that already exist on the target by GUID keep using that GUID; ambiguous or unmatched values are reported, never guessed. - Bulk performance – records are written in
ExecuteMultiplebatches (default 100, configurable 10–1000) withReturnResponses=falseand bulk existence checks. - Parallel writes – with Continue on error on, batches run concurrently on cloned target
connections (auto = server-recommended degree of parallelism, capped at 4; manual up to 8). Throttling
(service-protection 429s) is retried honouring
Retry-After. Continue on error off always runs sequentially. - Skip unchanged (fast re-runs) – the target snapshot is read once; identical fields are not re-sent, fully identical records are not written at all (reported as Unchanged), and status is only set when it differs.
- Metadata cache – entity metadata (writable columns, option sets, default status) is retrieved once per entity per run.
- Batched N:N – existing target links are pre-read and only missing links are sent, as batched
Associaterequests. - Self-referencing lookups – a lookup to a record in the same set that isn't created yet is deferred and set in a second pass (no more cleared parent lookups when order is unlucky).
- Suppress flow triggers (optional) – writes can skip queuing Dataverse-triggered Power Automate flows.
- Robust paging – source queries are paged automatically (handles > 5000 records).
- Resilient writes (transient-fault retry) – throttling / timeout / transport failures are retried
automatically with exponential backoff + jitter (honouring
Retry-After); a create whose record has already committed is treated as success, so a temporary throttle never fails a whole batch. (PR #17145) - Throughput & ETA – progress shows live records/second and an estimated time remaining, and each entity summary reports its throughput and any transient retries performed. (PR #17145)
- Migration profiles (save / load) – save the current entity, FetchXML, options and checked relationships to a portable JSON profile and reload it later for a repeatable migration (connection names only — never secrets). (PR #17145)
- Progress, cancel, and a full log – created / updated / failed counts plus per-record errors.
Requirements
- XrmToolBox (current release – runs on .NET Framework 4.8).
- Permissions on both environments: read on the source, create/update (and, for status migration, the relevant state-transition privileges) on the target.
Build
Open MigrateData.sln in Visual Studio 2022 and build, or from a developer prompt:
& "C:\Program Files\Microsoft Visual Studio\2022\Professional\MSBuild\Current\Bin\MSBuild.exe" `
MigrateData.sln /t:Build /p:Configuration=Debug /p:Platform="Any CPU"
A Debug build copies DataMigrationToolbyXTB.dll (+ .pdb) into
DataTransPorter\bin\Debug\Plugins\ via the post-build step.
The XrmToolBox host assemblies (
XrmToolBox.Extensibility,XrmToolBox.ToolLibrary,McTools.Xrm.Connection,McTools.Xrm.Connection.WinForms) are referenced withPrivate=False– they are provided by the host at runtime and are not copied to the output, which avoids version conflicts.
Install into XrmToolBox (manual / local)
Copy DataMigrationToolbyXTB.dll into your XrmToolBox Plugins folder, then restart XrmToolBox:
%APPDATA%\MscrmTools\XrmToolBox\Plugins
The tool appears in the tool list as DataMigrationToolbyXTB.
Publish to the XrmToolBox Tool Library (public)
XrmToolBox's in-app Tool Library (Configuration ▸ Tool Library) is fed from NuGet.org. A package is auto-discovered and installable for everyone when it:
- is tagged
XrmToolBox, - ships the tool assembly under
lib\<tfm>\Plugins\(third-party dependency DLLs, if any, go in a sub-folder named exactly like the tool DLL), and - declares a dependency on the
XrmToolBoxpackage (the host-version marker).
This repo already contains everything for that: DataMigrationToolbyXTB.nuspec
and pack-and-publish.ps1.
One-time setup
- Create a free NuGet.org account and an API key: https://www.nuget.org/account/apikeys (scope it to Push new packages and package versions).
- Edit
DataMigrationToolbyXTB.nuspecand set:<id>– must be globally unique on NuGet.org (currentlyDataMigrationToolbyXTB). It must not collide with another package, and the tool DLL name (DataMigrationToolbyXTB.dll) must not collide with another installed tool.<authors>,<projectUrl>,<iconUrl>,<license>– your details. (<iconUrl>must point at a publicly reachable copy ofimages\icon.png, e.g. the raw URL in your GitHub repo.)- The icon (
images\icon.png) and tool tile images are already wired in.
Build, pack and publish
# build + pack only (inspect artifacts\*.nupkg first)
.\pack-and-publish.ps1
# build + pack + publish to NuGet.org
.\pack-and-publish.ps1 -Push -ApiKey oy2xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
After NuGet finishes indexing (a few minutes) the tool shows up in the Tool Library; users click Install. There is no separate approval step, but the package must pass NuGet's validation and follow the three rules above.
Publishing requirements checklist
- ✅ Tagged
XrmToolBox(first tag). - ✅ Tool DLL in
lib\net48\Plugins\(the pack script + nuspec do this). - ✅ Dependency on
XrmToolBox(host-version marker). - ✅ Assembly is not strong-named (this project isn't).
- ✅ Unique NuGet
idand unique tool DLL name. - ✅ Host assemblies (
XrmToolBox.Extensibility,McTools.Xrm.Connection, Xrm SDK) are not bundled — they're referenced withPrivate=Falseand provided by the host at runtime.
Releasing updates
NuGet package versions are immutable — you cannot overwrite a published version. To update,
bump <version> in the nuspec and AssemblyVersion/AssemblyFileVersion in
Properties\AssemblyInfo.cs (keep them equal; date-based 1.YYYY.M.rev is the XrmToolBox
convention), re-run pack-and-publish.ps1 -Push -ApiKey …, and XrmToolBox offers the update
automatically.
XrmToolBox Tool Library validation checklist
How this package/tool satisfies the official Tool Library checklist:
| Checklist item | Status | How |
|---|---|---|
| NuGet package has an icon url | ✅ | <iconUrl> + embedded <icon> (images\icon.png) in the nuspec. Set <iconUrl> to your public raw URL. |
| NuGet package has a project url | ✅ | <projectUrl> in the nuspec (set it to your repo). |
Tool library under a Plugins folder |
✅ | DLL packed to lib\net48\Plugins\DataMigrationToolbyXTB.dll. |
| Tool version = NuGet package version | ✅ | AssemblyVersion/AssemblyFileVersion = 1.2026.6.12 = <version>. |
| Dedicated large tool image | ✅ | BigImageBase64 (80×80) in MyPlugin.cs. |
| Dedicated small tool image | ✅ | SmallImageBase64 (32×32) in MyPlugin.cs. |
| Controls resize with the main window | ✅ | Docked TableLayoutPanel with percentage rows; editors Dock=Fill; inputs anchored. |
| Tool opens without a connection | ✅ | OnLoad never requires Service; no connection is forced. |
| Without connection, controls work without error | ✅ | All handlers null-check the services and guide the user. |
| Connection-required controls open the connection dialog | ✅ | Select Source/Select Target raise the connection request; Load/Count/Migrate open it when no connection is set. |
| With a connection, controls work without error | ✅ | Standard ExecuteMethod/WorkAsync + IOrganizationService calls. |
| Long operations are async (UI not frozen) | ✅ | Every server operation runs in WorkAsync with progress + cancel. |
The images are stored as source PNGs under
images\(icon.png,tool-large.png,tool-small.png); the 80×80 and 32×32 are base64-embedded inMyPlugin.cs. Regenerate by replacing the PNGs and updating the two…ImageBase64strings.
Usage
- 1. Select Source – choose the environment to read records from. (The connection you are already on when you open the tool is used as the source by default.)
- 2. Select Target – choose the environment to write records to.
- 3. Load Entities – populates the dropdown with entities from the source Default solution.
- Pick an entity. A default FetchXML template is placed in the editor, and the entity's relationships load into the Relationships to also migrate list (N:N, N:1, 1:N).
- 4. FetchXML – edit the FetchXML to select exactly the records you want to migrate. Use Count source records to preview how many records match.
- (Optional) In the Relationships to also migrate list, check any relationships to also bring
across:
[N:N]replicates links,[N:1]migrates the referenced parent records first,[1:N]migrates the child records after. - 5. Migrate Data – confirm the prompt. Referenced parents are migrated first, then the selected records (same GUID), then child records, then N:N links. The log shows a per-entity summary.
Compare / preview (optional)
Instead of migrating straight away you can preview exactly what will change:
- Select Source and Target, Load Entities, pick an entity and set the FetchXML (steps 1–4 above).
- Click 4. Compare. The tool reads the records matched by the FetchXML and the matching target records (by GUID) and opens the comparison dashboard.
- The top grid lists one row per record with a Migrate tick-box and a status:
- New – the record does not exist on the target (the target side is blank).
- Update – the record exists and one or more migratable fields differ.
- Identical – the record exists and every migratable field already matches.
- Select a row to see the field-by-field comparison in the bottom grid: Field, Source value, Target value, and a per-field New / Changed / Same status (changed/new rows are highlighted).
- Tick the records to migrate (New and Update are ticked by default; Select all / none / new & changed help-buttons are provided), then click Migrate selected to migrate only those records. The same migration pipeline runs (GUID preserved, options and relationships honoured) against the chosen subset.
Copy GUID
- Copy GUID button (top bar) copies the GUID of the highlighted record.
- Right-click the records grid: Copy GUID, Copy name + GUID, Copy GUIDs of ticked records,
Copy GUIDs of all listed records (one per line — handy for a FetchXML
infilter). - Right-click a node in the related-records tree: Copy GUID / Copy name + GUID.
- Right-click the field grid: Copy value / Copy GUID from value (e.g. the GUID of a lookup).
Extra records on the target (clean-up)
When Compare runs, the same FetchXML is also executed on the target. Any target record it returns that the source FetchXML did not return is an extra record. The Extra on target (N)... button (red when N > 0) opens a list of them:
| Colour | Meaning |
|---|---|
| Red | Record does not exist on the source at all (typical clean-up candidate). |
| Yellow | Record exists on the source but falls outside the FetchXML filter there (e.g. different status). |
| Grey | Record is already inactive on the target (cannot be ticked). |
- Select a row to see all its target field values in the details grid; search and Hide records already inactive help filter; Copy GUID / right-click copy and Export CSV are available.
- Tick records (Select all not in source helps) and click Deactivate selected (N). After a
confirmation (default No), the tool sets them to the table's Inactive state via
SetStateRequestin batches. Records are not deleted. The Bypass custom plug-ins / Suppress flows options are honoured and every deactivated or failed GUID is written to the log. - Deactivation is offered only for tables with a plain Inactive state; tables such as
incident(Resolved/Cancelled) show the reason instead. Extras are not checked for aggregate FetchXML, FetchXML withtop, or when the FetchXML entity differs from the selected entity (a note explains why).
The comparison reflects the current option check-boxes: lookups are compared by referenced GUID; the Migrate owner option adds
ownerid; the Migrate status option addsstatecode/statuscoderows. Audit/system and non-writable columns are excluded (they are never migrated).
Options
| Option | Default | Behaviour |
|---|---|---|
| Migrate owner (ownerid) | off | When on, the source ownerid is written to the target. The referenced user/team must exist on the target. |
| Migrate status (state/status via SetState) | off | When on, after the record is written the source statecode/statuscode is applied via SetStateRequest. Failures are reported as warnings (the record itself still migrates). |
| Continue on error | on | When on, a failing record is logged and migration continues. When off, the batch runs with ContinueOnError=false, stops at the first failure, and later records are reported as Not attempted. |
| Skip missing lookup references | on | When on, a lookup pointing to a record that doesn't exist on the target is dropped so the record still migrates (the gap is reported in the summary). If a record still fails with an error that doesn't name the field (e.g. a target plug-in: ISV code reduced the open transaction count), it is re-written without its lookups, then each lookup is set on its own; a lookup that fails is skipped and listed with its error in the log and the Excel column Lookups skipped (write failed). |
| Bypass custom plug-ins (needs admin) | on | When on, custom synchronous plug-ins are skipped on create/update (requires prvBypassCustomBusinessLogic / System Administrator on the target). |
| Skip unchanged fields/records/status | on | Compares each record with the target copy and sends only changed fields; unchanged records are not written (reported as Unchanged) and SetState is skipped when the status already matches. Turn off to force a full re-write. |
| Don't trigger Power Automate flows | off | Adds SuppressCallbackRegistrationExpanderJob to every write so Dataverse-triggered cloud flows are not queued (needs System Administrator / prvBypassCustomBusinessLogic-level rights on the target). |
| Parallel batches (0 = auto) | 0 | Number of ExecuteMultiple batches in flight at once, each on a cloned connection. 0 = server recommendation capped at 4; 1 = sequential; max 8. Only used when Continue on error is on (fail-fast is sequential). |
| Batch size | 100 | Requests per ExecuteMultiple (10–1000). Lower it for tables with heavy plug-ins/flows (fewer timeouts); raise it for simple tables. |
| N:N: match related record by email/name if its GUID is missing on target | off | When on, an N:N related record whose GUID isn't on the target is matched to a target record by a unique field: the email (internalemailaddress) for systemuser, otherwise the entity's primary name. Records present by GUID are unaffected; a value with no match, or more than one match, is reported and skipped (never guessed). Self-referential N:N keeps the GUID path. |
| Notes & attachments | off | Also migrates the notes (annotation, incl. attachment body) of every migrated record, keeping the note GUID. |
| File & image columns | off | Also copies file columns and full-size images with the file-block messages (4 MB blocks). A file already on the target with the same name and size is skipped. |
| Business process flows | off | Also migrates BPF instances (active stage, traversed path). The instance the target auto-created for the record is matched by its parent lookup and updated (never duplicated). |
Advanced menu
| Menu item | What it does |
|---|---|
| Field rules (mapping / masking) | Per-entity (* = all) column rules applied to every record before it is written: Drop (don't send), Clear (send null), Constant, Rename (to another column), Regex replace, and PII masking — Hash, Redact, Fake e-mail (user.<token>@example.invalid), Fake phone (+1-555-01xx-xx00). Masks are deterministic (same input → same output). Target URL contains limits a rule to matching targets (e.g. mask only when the target contains dev). |
| Match keys (natural key identity) | When a record's GUID is not on the target, match it to one target record by a natural key (e.g. mash_code, or name,parentaccountid) and update that record instead of creating a duplicate. Lookups pointing at a key-matched record are remapped automatically (global lookup remap). Built-in keys: environmentvariabledefinition (schemaname), environmentvariablevalue (definition), connectionreference (logical name; connectionid is never copied), transactioncurrency (ISO code). Ambiguous / missing matches are reported, never guessed. |
| Jobs (multi-entity / multi-target) | Ordered list of profile steps (Auto-order sorts parents before children from lookup metadata; cycles are reported) run against one or more targets (Add target connects extra environments). Stop on step failure skips the remaining steps for that target; Confirm between targets asks before promoting to the next one (DEV → TEST → PROD). Save / load as *.job.json. |
| N:N link diff (current entity) | Compares the ticked N:N relationships of the current FetchXML result between source and target: links missing on the target can be associated, links only on the target can be disassociated (Yes/No confirmation). New associations are journaled for rollback; disassociations are not. |
| Run history / rollback | Every run writes a journal (%LOCALAPPDATA%\DataMigrationToolbyXTB\Runs\<runId>.json): created ids, pre-images of overwritten columns / states, created links, deactivated and deleted records. Roll back (current target must be the journal's target) removes created links, restores overwritten values and states, deletes created records, re-activates deactivated records and recreates deleted records (same GUID). An audit trail (ids + outcomes only, no field values) is written to ...\Audit\. |
| Resume | If a run with the same profile / source / target was interrupted, the next run offers to resume: records the journal already completed are skipped. |
| Export / Import data package | Export writes the current profile's records (N:1 parents, primary set, 1:N children, N:N pairs) to a gzip JSON *.dmtpkg. Import replays it against the current target without a source connection (air-gapped promotion, repeatable seeding). Packages contain record data — treat them as sensitive. |
In the compare dashboard, Extra on target now also offers Delete (typed confirmation). The ticked records are re-read right before the action, and each full record is journaled first so Run history → Roll back can recreate it (cascade-deleted children are not journaled).
Command line (CI / scheduled runs)
DataTransPorter.Cli builds dmt.exe, which runs a job (or a single profile) without XrmToolBox:
# Connection strings come ONLY from environment variables (never pass secrets as arguments).
$env:DMT_SOURCE = "AuthType=Certificate;Url=https://dev.crm.dynamics.com;ClientId=...;Thumbprint=..."
$env:DMT_TEST = "AuthType=Certificate;Url=https://test.crm.dynamics.com;ClientId=...;Thumbprint=..."
dmt --job .\seed.job.json --source-env DMT_SOURCE --target-env DMT_TEST [--target-env DMT_UAT ...]
dmt --job .\seed.job.json --check # validate the file and that the tool loads; no connection
Exit codes: 0 success, 1 failures (see the log, journal and audit trail), 2 usage error. Prefer
certificate or managed-identity auth; ConfirmBetweenTargets is ignored headless.
Build (after building MigrateData.sln in the same configuration):
dotnet build DataTransPorter.Cli -c Release → DataTransPorter.Cli\bin\Release\net48\dmt.exe.
The project's nuget.config restores through the Microsoft package feed proxy.
Tests
dotnet test DataTransPorter.Tests -c Release (after building the tool) runs unit tests for CSV
escaping, dependency ordering, field rules / masking, the value codec, journal hashing, data packages and
job loading, plus UI smoke tests that open and close every code-built dialog.
FetchXML examples
Migrate every record of the chosen entity:
<fetch>
<entity name="mash_service">
<all-attributes />
</entity>
</fetch>
Migrate a filtered subset:
<fetch>
<entity name="mash_service">
<all-attributes />
<filter type="and">
<condition attribute="statecode" operator="eq" value="0" />
<condition attribute="mash_category" operator="eq" value="100000001" />
</filter>
</entity>
</fetch>
Use
<all-attributes />(rather than naming columns) so every migratable field is carried over. Columns that cannot be written (calculated, rollup, audit, etc.) are filtered out automatically against the target schema.
How GUID preservation works
For each source record the tool:
- Builds a target
EntitywithId = source.Idand the migratable attributes. - Checks existence in bulk (
INquery by id, or the skip-unchanged snapshot read).- Not found →
Create(entity)– Dataverse honours the suppliedId, so the record is created with the same GUID. If a create is rejected as a duplicate, the exact id is re-checked: if it now exists (a create committed by a transport retry) it is re-sent as an update; otherwise it is a real alternate-key/duplicate collision and is reported as failed. - Found →
Update(entity)(only fields valid for update, and only changed fields when Skip unchanged is on).
- Not found →
Notes & limitations
- Reference order – references (lookups) resolve by GUID. Lookups to records in the same
migrated set are deferred and set after all records exist. Lookups to other tables must already be
on the target: migrate parent/lookup entities first (or tick the
[N:1]relationship). - Null values – a blank source value does not clear an existing target value (patch semantics).
- Parallel writes & throttling – parallel batches increase load on the target; if you see many "transient retries" in the summary, lower Parallel batches or Batch size. Test on a non-production target first.
- Related records (N:1 / 1:N) – checking a
[N:1]relationship migrates the referenced parent records before the main set (so the lookup resolves); checking[1:N]migrates the child records after. Only custom related tables are listed (system tables like team/user/currency are excluded). One level deep — it does not recurse into the related records' own relationships. - N:N associations – only links where the migrated record is one side are replicated, and the
other side must already exist on the target (otherwise that link is reported as failed). Links
that already exist on the target are detected and counted as "already linked" (idempotent).
Self-referential N:N is handled best-effort using the
Referencingrole. - Status –
statecode/statuscodeare never written as part of the create/update; they are applied separately viaSetStateRequest. A status reason of-1lets the platform pick the default status for the chosen state. - Owner / business unit – owning business unit/team/user are system-managed and are never
copied; only
owneridis migrated, and only when the option is enabled. - Counting loads the matching records to count them; for very large tables prefer a tight FetchXML filter.
Project layout
| File / folder | Purpose |
|---|---|
Release/ |
Ready-to-install build: copy DataMigrationToolbyXTB.dll into %APPDATA%\MscrmTools\XrmToolBox\Plugins and restart XrmToolBox. (Local convenience copy — not in source control.) |
MigrateData.sln |
Visual Studio solution — open this to build. |
DataTransPorter/MyPlugin.cs |
XrmToolBox tool export (name, description, tile images). |
DataTransPorter/MyPluginControl.cs |
All tool logic (connections, entity load, migration). |
DataTransPorter/MyPluginControl.designer.cs |
WinForms UI. |
DataTransPorter/ComparisonForm.cs |
Compare/preview dashboard (record selection + field-by-field diff). |
DataTransPorter/ComparisonForm.Designer.cs |
WinForms UI for the comparison dashboard. |
DataTransPorter/ExcelReportWriter.cs |
Dependency-free .xlsx writer used to export the multi-sheet comparison/migration report. |
DataTransPorter/MyPluginControl.*.cs |
Partial classes: Journal (journal, resume, rollback, safe delete), Identity (match keys, lookup remap, field rules, activity parties), SpecialData (notes, files, BPF), Ui (Advanced menu, link diff), Jobs (jobs, multi-target, packages, headless runner). |
DataTransPorter/Core/ |
UI-free helpers: ValueCodec, CsvUtil, DependencyOrder, RunJournal / JournalStore, FieldRules, DataPackage. |
DataTransPorter/*Form.cs, TypedConfirm.cs |
Code-built dialogs: jobs, field rules / match keys, run history, N:N link diff, extra records; typed confirmation. |
DataTransPorter.Cli/ |
dmt.exe headless runner (not part of MigrateData.sln). |
DataTransPorter.Tests/ |
xUnit tests (not part of MigrateData.sln). |
DataTransPorter/Settings.cs |
Persisted options / last selections. |
DataTransPorter/DataTransPorter.csproj |
Project + references (targets .NET 4.8; AssemblyName = DataMigrationToolbyXTB). |
DataTransPorter/packages.config |
NuGet dependencies — restored into packages/ on build (not checked in). |
DataMigrationToolByAbhishek.nuspec |
NuGet package manifest for the Tool Library. |
pack-and-publish.ps1 |
Build → pack → (optional) publish helper. |
deploy-to-xrmtoolbox.ps1 |
Copies the Release build into your local XrmToolBox Plugins folder (close XrmToolBox first). |
INSTALL.md |
End-user installation guide. |
Docs/CODE_DOCUMENTATION.md |
Detailed code walkthrough for developers. |
specs/ |
Feature specs (spec / plan / tasks) for enhancements. |
images/ |
icon.png (package icon) + tool-large.png / tool-small.png (tile sources). |
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET Framework | net48 is compatible. net481 was computed. |
-
.NETFramework 4.8
- XrmToolBox (>= 1.2025.10.74)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 1.2026.10.1 | 82 | 9/30/2026 |
| 1.2026.6.15 | 530 | 7/24/2026 |
| 1.2026.6.14 | 126 | 7/11/2026 |
| 1.2026.6.13 | 145 | 6/22/2026 |
| 1.2026.6.12 | 129 | 6/18/2026 |
| 1.2026.6.11 | 124 | 6/16/2026 |
| 1.2026.6.9 | 120 | 6/14/2026 |
| 1.2026.6.8 | 120 | 6/14/2026 |
| 1.2026.6.2 | 116 | 6/14/2026 |
1.2026.10.1 - New (Advanced menu): (1) Field rules - per-entity drop / clear / constant / rename / regex and deterministic PII masking (hash, redact, fake e-mail, fake phone), optionally only for matching targets. (2) Match keys - natural-key identity for records whose GUID differs across environments, with automatic lookup remap (built-in: environment variables, connection references, currencies). (3) Run journal - every run can be rolled back (created records, overwritten values and states, links, deactivations, deletes) and an interrupted run can be resumed; audit trail of ids and outcomes. (4) Notes and attachments, file and image columns, business process flows and activity parties migrate with the record. (5) N:N link diff with associate / disassociate, and Delete for extra target records (journaled, typed confirmation). (6) Jobs - ordered multi-entity steps with auto dependency order, run against several targets (DEV to TEST to PROD). (7) Offline data packages (export / import). (8) dmt.exe command-line runner for CI (connection strings from environment variables only) and unit tests. 1.2026.6.15 - New: (1) Resilient writes - transient failures (throttling / timeout / transport) are retried automatically with exponential backoff + jitter, honouring Retry-After; a create whose record has already committed is treated as success, so a temporary throttle no longer fails a whole batch. (2) Throughput and ETA - progress shows live records/second and an estimated time remaining, and each entity summary reports its throughput and any transient retries performed. (3) Migration profiles - save the current entity, FetchXML, options and checked relationships to a portable JSON profile and reload it later for a repeatable migration (connection NAMES only, never secrets). (4) Entity search - a Filter box next to the entity picker filters the list as you type by display name or logical name. 1.2026.6.14 - New: team LOOKUP fields are now resolved to the target the same way as systemuser - a team is matched on the target by its NAME and migrated with the record (systemuser is matched by email). Covers any team lookup, including a team-owned record's owner. Opt-in via the same "match related by name/email" option; unresolved/ambiguous teams are skipped, never guessed. 1.2026.6.13 - New: (1) systemuser LOOKUP fields on a record are now resolved to the target by EMAIL (internalemailaddress) and migrated with the record - the same cross-environment matching used for N:N related users - so user references (owner, approver/reviewer, any custom user lookup) are no longer dropped when the user's GUID differs across environments. Opt-in via the same "match related by name/email" option; unresolved/ambiguous users are skipped, never guessed. (2) Option-set values missing on the target are skipped per-value instead of failing the record: a multiselect keeps its valid values and drops only the missing one(s), and a single picklist with an out-of-range value has just that field skipped - the record still migrates. (3) Post-migration Excel (.xlsx) report: after a migration you can save a workbook listing Updated/Created records, Failed records (with error), records migrated with a missing (cleared) lookup GUID, and records with skipped option-set fields, plus a per-entity Summary. 1.2026.6.12 - New: N:N related-record matching by a unique field when the related record's GUID is missing on the target. systemuser is matched by EMAIL (internalemailaddress), every other entity by its primary NAME. Related records that already exist on the target by GUID are unaffected (GUID-first); values with no match or more than one match are reported and skipped (never guessed). Opt-in via the "N:N: match related record by email/name if its GUID is missing on target" option; ideal for Approver/user subgrids whose ids differ across environments. 1.2026.6.11 - New: Compare / preview dashboard. A "Compare" button reads the records selected by the FetchXML and opens a dashboard with a per-record New / Update / Identical status and a field-by-field (line-by-line) source-vs-target diff (the target column is blank for records that don't exist on the target yet). Tick the records you want and click "Migrate selected" to migrate only those; the "Migrate Data" button still migrates everything directly. 1.2026.6.10 - Reliability: the Dataverse channel timeout is raised to 20 minutes before reading/writing, so large ExecuteMultiple batches against a slow target no longer fail with "The request channel timed out ... after 00:02:00". 1.2026.6.9 - Package metadata corrected (author, project URL, icon). 1.2026.6.8 - Relationship migration now covers N:1 and 1:N in addition to N:N: checked N:1 relationships migrate the referenced parent records first (so lookups like marketing area resolve), checked 1:N relationships migrate child records after. 1.2026.6.7 - Summary lists which related table's records are missing per lookup field. 1.2026.6.6 - Bulk performance via ExecuteMultiple batching + bulk existence checks. 1.2026.6.5 - Proactive missing-lookup check. 1.2026.6.4 - Skip-missing-lookups and bypass-custom-plug-ins options; exclude SLA operational fields. 1.2026.6.3 - Fix Source/Target selection error on certain hosts. 1.2026.6.2 - GUID-preserving migration, default-solution entity picker, FetchXML paging, owner/status migration, N:N replication, images, icon, readme.