Portal Records Mover Console updates (finally!)

It’s been a while since I released the Portal Records Mover Console application based on the invaluable Portal Records Mover XrmToolBox Tool by Tanguy Touzard. This console application is a port of the Tool code that would allow us to include this functionality to our DevOps pipelines.

Since the first post, Tanguy has released significant updates that address issues that he’d been tracking. After a bit of neglect, I finally finished integrating his changes into the console version, keeping the core logic in sync with his Tool. I also address a few issues of my own from my initial releases.

Update summary

Some of the updates improve processing of the file attachments to ensure that all are correctly moved. Tanguy gets all the credit for this update as it was part of his XrmToolBox Tool updates.

A fix that I made to my code was the inclusion of Inactive files. This was definitely a bug where the command line flag was not being honored, so Inactive files should be moved as part of the export. Thanks to Rakshit Rastogi for reporting the issue!

Command Line

The most notable changes were to the command line options. The README has been updated with more detail but I wanted to point out a few here.


The first updates impacts credentials. My initial release assumed moving from one environment to another under the same account, so I only captured one set of credentials and a simple environment name used to built connection strings. This is pretty limited, so the command line will now capture the following items:

  • "SourceEnvironment": Full URL of the environment from which records are retrieved. Ex. https://microsoft.crm.dynamics.com
  • "SourceUsername": Username for the Source environment
  • "SourcePassword": Password for the Source environment
  • "TargetEnvironment": Full URL of the environment to which records are imported. Ex. https://contoso.crm.dynamics.com
  • "TargetUsername": Username for the Target environment
  • "TargetPassword": Password for the Target environment

These are pretty self explanatory – you can now include the same credentials if source and target are part of the same instance or provide different credentials to move your Portal configuration between different environments.

Avoid those errors

I made updates to address a few things were just plain missed in the initial release. When the Portal Records Mover Tool begins an import, it prompts the user for a few things to avoid errors:

  • Disable the JavaScript restriction in the tenant: by default, CDS will not allow attaching JavaScript files to Notes as a security precaution. If this is not disabled, any Web Files with JavaScript attachments will fail.
  • Disable some Portal specific Plug-ins: some plug-ins apply restrictions when creating Portal records and you could see errors on import. For example, you might see an error creating a Web Page because of Language dependencies. Disabling these plug-ins during the import will allow the records to migrate without error.
  • Clean web files: option that will allow you to remove extraneous attachments on Web Files. This will ensure that the only item being moved will remain after the import.

So the following command line options account for these options:

  • "DeactivateWebPagePlugins": Deactivate plugins before import, reactivate on completion. Default: true
  • "RemoveJavaScriptFileRestriction": Remove JS restriction in system settings Default: true
  • "CleanWebFiles": Clean target organization annotation for web file so that only the annotation you import is kept in the web file. Default: true

If not specified in your command line, the default value is true for each of these parameters. Once the import is complete, the current settings are restored. I don’t really see much need to override these settings, but I wanted to keep in line with the XrmToolBox functionality.


You can place all settings in a configuration JSON file and not use the command line at all. The new command line params are now available via the JSON configuration, but I also fixed an issue that allows you to filter CDS Entities being exported. Early versions of this tool would take all Entities and export everything, ignoring the list of Entities.

This is not as flexible as the XrmToolBox Tool that allows selective export of individual records but it should offer similar functionality to selecting Entities in the left navigation. This configuration item is named SelectedEntities and is in the format of a JSON string array.

For example, if you do want to apply a filter and export all Entities, you can include: "SelectedEntities": [] . If you would like to filter to a specific list of Entities, you would include the following: "SelectedEntities": ["adx_autonumberingdefinition","adx_contentsnippet","adx_entityform"]

This can be useful if you have several Portal solutions deployed to an environment but do not want to deploy everything. For example, you may not want to deploy items related to Blogs. A full example is included in the ExportSettings.json file in the repository.

A side note… Community!

How this console app came about highlights the beauty of this community of professionals.

I was on a Portals project and we used the Portals Record Mover regularly as part of our deployment and we were looking to automate some steps. I did not personally know Tanguy, but I reached out and asked if I could port his code to a console and he agreed without question!

It took me a bit of work to complete the console application but it does not come close to the work already invested in the XrmToolBox version and it was shared it without hesitation. So we were not forced to reinvent the wheel and added automated steps effectively using the same tool with which we were already using with confidence.

This mindset of openness and sharing is a fantastic thing so I like to call it out when possible!

Up Next…

Authentication will be significantly changing for the SDK in the near future, so I will be updating the solution to handle these changes in a new release.

I also need to add full unit tests to this solution. This is a console application so I really have no excuse to include full unit tests!

NOTE: The normal disclaimer comes with using these kinds of tools: please be sure to have a back up of your environments before kicking these off!

As always, comments, questions, suggestions are all welcome! If you find issues with this release, please add an issue on the repository and I will take a look!

0 Points

One thought on “Portal Records Mover Console updates (finally!)”

  1. Rick Putnam says:

    Hi Jim. I downloaded the latest Portal Records Mover Console app but upon running it, ran into the following exception:
    Unhandled Exception: System.ArgumentNullException: Organization cannot be null or empty.
    The error is thrown on line 302 of the CrmServiceClient class. I have attempted to debug but am stumped at this point. I’m not sure what parameter I am missing as there is no Organization parameter in the json file. Can you give me any clue as to what I’m doing wrong?

    Below is the full output from the console (only the passwords have been deleted):
    C:\Users\rputnam\Documents\Atlas360\PortalRecordsMoverConsole\PortalRecordsMoverConsole\bin\Debug>portalrecordsmover /settings:ExportSettings.json
    2020-09-21 18.01.52: Initializing the ExportSettings
    2020-09-21 18.01.52: command line arg: Name: settings, Value: ExportSettings.json
    2020-09-21 18.01.52: ActiveItemsOnly: True
    ModifyFilter: 9/13/2020 12:00:00 AM
    DateFilterOptions: ModifyOnly
    WebsiteFilter: 21f8c343-d3d3-47ce-a326-57002ec70528
    ImportFilename: portal export 2020-09-21.xml
    ExportFilename: portal export 2020-09-21.xml
    PriorDaysToRetrieve: 8
    SourceUsername: richardputnam@cgiatlas.onmicrosoft.us
    TargetUsername: richardputnam@cgiatlas.onmicrosoft.us
    SourceEnvironment: https://rpdev.crm.microsoftdynamics.us
    SourceConnectionString: RequireNewInstance=True;AuthType=Office365;Username=richardputnam@cgiatlas.onmicrosoft.us; Password=@@@@@@@;Url=https://rpdev.crm.microsoftdynamics.us
    TargetEnvironment: https://atlasstaging.crm.microsoftdynamics.us
    TargetConnectionString: RequireNewInstance=True;AuthType=Office365;Username=richardputnam@cgiatlas.onmicrosoft.us; Password=@@@@@@@@@;Url=https://atlasstaging.crm.microsoftdynamics.us

    2020-09-21 18.01.52: Beginning the export – SourceEnvironment: https://rpdev.crm.microsoftdynamics.us, ExportFilename:portal export 2020-09-21.xml

    Unhandled Exception: System.ArgumentNullException: Organization cannot be null or empty.
    Parameter name: Organization Name
    at Microsoft.Xrm.Tooling.Connector.CrmServiceClient.ConnectToCrmWebService(String crmConnectionString)
    at Microsoft.Xrm.Tooling.Connector.CrmServiceClient..ctor(String crmConnectionString)
    at PortalRecordsMover.AppCode.Exporter..ctor(ExportSettings settings) in C:\Users\rputnam\Documents\Atlas360\PortalRecordsMoverConsole\PortalRecordsMoverConsole\AppCode\Exporter.cs:line 26
    at PortalRecordsMover.PortalMover.Main(String[] args) in C:\Users\rputnam\Documents\Atlas360\PortalRecordsMoverConsole\PortalRecordsMoverConsole\Program.cs:line 31


Leave a Reply

Your email address will not be published. Required fields are marked *