During last 12 months I participated in several migration projects from ground to cloud. In this post I will share my experience migrating customizations and data.
First recommendation – if your instance is eligible for FastTrack – don’t even think regarding other options. There will be no need to develop migration packages, map users, original data audit logs will stay in-place, nothing will be accidentally lost e.t.c. But if you can’t use FastTrack then this post is written for you.
Making your Customizations compatible with latest version (9.1 ATM)
Before migration of data you have to make customizations compatible. Unfortunately there is no easy way (at least those that I’m aware of) to import customizations from 2015 (or lover) to instance with latest version of D365CE. The only supported way is to go through sequential upgrade of your solutions in real instances of DCRM/D365.
Let’s assume that I migrate 2011 instance to latest cloud. To get 9.1-compatible customizations it’s required to have working instances of 2013, 2015 and 2016. There are 2 ways of doing it – either import of solution file or import whole organization DB (that is easier as for me). During the import there is a high probability chance experiencing issues with both data and customizations. Once all the issues are sorted out and customizations reached 2016 environment it’s possible to export it and import to the latest cloud – 9.1
Importing Customizations to cloud
You can say – what’s the problem? Just export default solution from source instance and import it to the destination. Yes, it’s possible but I remember only several attempts I succeeded. After many try/fault attempts I came up with following approach – import of customizations divided into following big chunks:
- WebResources & OptionSets
- Custom Entities + Dependencies on Standard Entities (like custom view of standard entity used in the subgrid of custom entity form)
- Standard Entities
- Security Roles
- Dashboards & Reports
- Processes & Plugins & Custom Workflow Assemblies
- SiteMap & Application Ribbon
I know that I missed Connection Roles, Templates, Field Security Profiles e.t.c. but if it is possible to add those pieces to one of groups to avoid annoying “Missing dependencies found” window during import of customizations so use common sense and knowledge of solution during choosing of proper place for those pieces.
Data Migration Tools
I used different approaches to migration – standard OOB Import, custom .Net code, Scribe and SSIS with different adapters. My choice after years doing migrations – SSIS + Kingsway Soft adapters. Why? There are many reasons. Here are several:
- simplicity – there is no need to learn how to write code (but obviously it is good to have and in some cases required to have), migration is built using mouse;
- flexibility – using combination of SQL, SSDT and KingswaySoft adapters I can build migration/data transformation with any level of complexity;
- foundation – Kingsway Soft released “Starter Package” that contains migration flows for majority of OOB entities.
Mapping of users
It’s not a rare situation that I migrate instance that has inactive users and some records reference those users. It’s great that now it’s possible to create inactive users inside Dynamics 365 using API. Those users are editable, have security role (Salesperson only), can be associated with records and do not occupy any license. I used following table to store list of users to be created (FirstName, LastName, internalemailaddress, windowsliveid and BusinessUnit are fields required for a user record to be created):
CREATE TABLE [dbo].[AdditionalUsers](
[FirstName] [varchar](max) NOT NULL,
[MiddleName] [varchar](max) NULL,
[LastName] [varchar](max) NOT NULL,
[internalemailaddress] [varchar](max) NOT NULL,
[windowsliveid] [varchar](max) NOT NULL,
[BusinessUnit] [varchar](max) NOT NULL
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
To create users from this table I used simple SSIS package:
ATTENTION: user records can’t be deleted from the system, you can’t change, add or remove security roles of those users. During import security privileges checks work for those users like for regular so if you want to assign custom entities to those users – include correspond privileges to “Salesperson” security role because this is the only role that assigned to those users and you can’t change it. One more thing to remember – create those users in the proper business unit from the first attempt. If business unit of that user was changed users loses security role and it’s not revertible.
Once all the users are in place (both “real” – provisioned through Office365 portal and “fake” – created through API) it’s possible to work on mapping. There are different approaches to mapping of users between environments but the easiest (for me) is to use full name of user. I don’t remember any migration where I had users with exactly the same names so it’s almost unique combination.
I use KingswaySoft “Starter Package” as a foundation for my migration package. When entity is not used inside instance I migrate I just delete correspond dataflow. When I know that entity is used and it has custom fields to be migrated I open Data source, click “Refresh Metadata” button, save changes inside datasource, open destination, click “Refresh CRM Metadata” and “Map Unmapped Fields”. That does 95% of mapping-related tasks. There are 2 exceptions for fields:
- if you want to set “Created On” field you should set as a source for “Overridden Created On” field to “Created On”;
- for “Owner” field I use mapping based on the name so instead passing “Owner” field as it is pass “Owner Name” field instead and set “Text Lookup” for field to true, choose “Use Primary Field”:
For custom entities actions are similar – add “Dynamics CRM Source”, choose proper connection in “Connection Manager”, inside “Source Entity” choose proper entity and click “OK”. Add “Dynamics CRM Destination”, connect previously created “Source” to “Destination”, open “Destination” component, choose proper connection in “Connection Manager”. My recommendation is to use “Upsert” instead of “Insert” because you can repeatedly import data (if something fails or new data is added or changed in source). Choose proper entity in “Destination Entity” – columns are automatically mapped based on the schema name. Don’t forget to change mappings for “Overridden Created On” and “Owner” fields.
Building of sequence of entities to import will appear organically- it’s not possible to import child record without parent record to be imported into the system already. Of course there is a case of cycle dependency – example in OOB entities – accounts and contacts – contact can have parent company and company can have primary contact. To resolve that cycle dependency 3-steps import is executed:
- import accounts without “Primary Contact” field imported
- import contacts
- update imported accounts only with “Primary Contact” field
In one of next posts I plan to write what issues I experienced during migration of activities and specifically – what to do with broken links – records referenced in activities through “Activity Party” fields (like “from”, “to”, e.t.c.) that were deleted from system.