If you are British and a keen Dynamics CRM/Dynamics 365 for Enterprise (CRM/D365E) fan, then May 4th, 2017 was a proud day to be both. This is because Microsoft announced the general availability of UK hosted D365E instances. UK-based Office 365 customers who configure a new D365E subscription will have their instance(s) hosted within the UK, using the brand new crm11 URL identifier. This is line with the launch of 2 Azure Data Centre regions within the UK last year and represents an important development in the evolution of Microsoft’s cloud services within the UK.

For the “old fogies” (like me!), previously all CRM/D365E tenants in the UK were hosted by default within the Europe, Middle East and Africa (EMEA) region. The data centres for these locations are hosted within Amsterdam and Dublin, areas that are within the European Union and somewhat local to the UK. Those with tenants within this region may now be asking whether it is possible to move their existing instances to the UK. The reasons for this may be straightforward, complex or oddly patriotic in nature – ranging from data residency requirements through to the desire of being a proud Brit with a wholly British D365E instance 🙂 In this week’s post, we’ll take a look at whether it is possible to currently migrate an existing non-UK based tenant into the UK via the various options at our disposal.

For those who do not wish to read ahead, the TL;DR version can be accessed by clicking the button below:

Spoiler Inside SelectShow

 

If you have decided to stick around, then let’s take a closer look at the two avenues potentially at our disposal for migrating a CRM/D365E instance: A Microsoft Support Request and the Backup/Restore Feature.

Asking Microsoft Directly: What did they say?

Microsoft supports the ability for businesses to a move their CRM/D365E instance to an entirely different region. This is all handily summarised as part of a TechNet article:

The Geo Migration feature for Dynamics 365 (online) will allow customers to move their instances in a single tenant from one region to another.

I was recently involved as part of a support request with Microsoft, in which we asked the question whether it is possible to migrate an EMEA D365E instance to the UK. We were told that it is not currently possible to do this, with the following response given:

The data residency option, and the availability to move customer data into the new region, is not a default for every new region we launch. As we expand into new regions in the future, we’ll evaluate the availability and the conditions of data moves on a region by region basis.

No specific timeframes on when (if ever) this type of Geo Migration would be made available when this was queried with Microsoft. However, I would posit its likeliness for the near future, given that you can currently request the very same for your Office 365 tenant. At the time of writing (June 2017), however, the Geo Migration option is not viable for migrating your CRM/D365E instance across to the UK.

Backup and Restore: The Saviour of the Hour?

The ability to backup and restore your CRM/D365E Online instance(s) was a much welcome feature when it was introduced last year. Microsoft frequently performs backups of your instance(s), to provide sufficient disaster recovery potential on their end. These backups are exposed to Administrators via the Administration Centre, as well as the ability to generate your own backups at any time. These can then be restored into a spare Sandbox instance for testing/development. The key thing to remember with this feature is that it is limited to Online backup/restore only. You cannot, for example, download a copy of the SQL Server backup file and then use this as part of an On-Premise install.

You may be thinking at this stage this feature would allow us to get around the above issue by taking a backup of your non-crm11 existing organisation and restoring to your crm11 instance. Unfortunately, this is not possible, either via the Administration Centre or through logging a ticket with Microsoft. This is very likely due to the fact that different regions have different Administration Centres, with all of the functionality within that (backup/restore, administrative settings and update management) contained for instances within that specific region.

This can be confirmed by taking a look at the URL. When you are within the EMEA region, for example, the URL looks like this:

https://port.crm4.dynamics.com/G/Instances/InstancePicker.aspx

Whereas for the Great Britain (GBR) region its:

https://port.crm11.dynamics.com/G/Instances/InstancePicker.aspx

Businesses that have multiple instances across different regions are classed as “multi-tenanted” by Microsoft, and you have the ability to switch your region and access desired functionality from within the Administration Centre:

Going back to the above point re. functionality being “containerised”, this can be confirmed by accessing the properties of a crm11 instance whilst within the crm4 Administration Centre:

Our options to Edit, Reset, Copy etc. the instance are non-existent; to make them appear, you have to open the Administration Centre for the GBR region.

So why is all of this so important?

When speaking with customers regarding new IT Projects, the question of data location is one that is almost always raised. Whereas in the past, organisations would choose to host their entire IT infrastructure on-premise, the rise of cloud computing has meant it is generally more cost-effective to migrate infrastructure into a data centre or a SaaS provider, such as Microsoft. Whilst these solutions generally tick all of the boxes from a resiliency, performance etc. standpoint, the awkward tick box – the actual, physical location of the data itself – is more difficult to extrapolate. An organisation such as Microsoft, for example, has data centres all over the globe, leading to the potential of data leaving particular jurisdictions and some potentially controversial realities, such as the implication of the US Patriot Act on data that Microsoft holds. As a business, you may be required by local law to ensure that data is stored within the current jurisdiction, within the European Economic Area (EEA) and even be required to literally identify the server rack on which a particular database/system is hosted on. With this in mind, one barrier for adoption of CRM/D365E in the UK could be the question over data residency. There are also other performance considerations that arise from the location of your CRM/D365E instance. It is entirely feasible that connections to a UK hosted tenant will be faster compared to connecting to a tenant based in Europe, the US or anywhere else in the world. Administrators who may be attempting to identify ways in which their instance can run optimally may, therefore, benefit from having their CRM/D365E instance hosted in the UK.

Finding an Interim Workaround

For businesses who have strict, data residency requirements that could have serious legal implications, the situation is currently not ideal if they currently use CRM/D365E. In terms of finding a workaround until Microsoft support geo-to-geo migrations for UK regions, customisation components can be straightforwardly migrated via solutions, but other instance-specific settings/data could take a significant amount of time to move across. There are tools out there that can help in this:

  • Use KingswaySoft’s Dynamics 365 SSIS Integration Toolkit to create a .dtsx package to migrate all of the required data to a newly provisioned instance.
  • Utilise Scribe Online to configure a D365E to D365E one-time replication job.
  • Migrate the data using the applications built-in tools and Configuration Migration Tool, available within the SDK.

There is, fortunately, a way forward for the desperate, but the steps involved need to be carefully planned out in advance to ensure that no issues are encountered. For example, if you have recurring Workflows in your old environment, how do you migrate these across and ensure they are restarted correctly? I would envision that Microsoft will very soon offer the ability to migrate into the UK region, so it may end up being more prudent to hold off until this is announced and generally available.

The rise in virtualisation within IT has profoundly altered the landscape of how servers and applications are deployed across the globe. Whereas in the past you would need to rely on multiple, physical hardware servers, you can now achieve similar levels of performance via the use of a single hardware server with virtualised versions of your operating systems deployed onto it. This is, in a nutshell, how “the cloud” effectively operates and even organisations who are not yet using a cloud computing environment may have virtualisation occurring somewhere within their infrastructure. The number of vendors who now offer solutions within this space grows every year, and more longstanding software providers have significantly adjusted their traditional offerings to take virtualisation into account.

Microsoft is one of these organisations, having moved more with the tide in recent years – to the extent that you can virtualise additional Windows operating systems on top of a physical hardware server at no additional cost. For those who are a bit shaky on terminology, like me, these are referred to as “Hyper-V Guest Operating Systems” or just “guests“. The situation as it stands currently means that the two editions of Windows Server 2016 (which can be upgraded to rather straightforwardly, you may be pleased to hear) offer very clear guest usage rights – up to 2 for Standard and unlimited for the Datacenter edition. This can offer numerous benefits for your business:

  • Facilitates the quick deployment of additional virtual machine instances for additional production workloads, testing or development.
  • Enables you to drive maximum benefit from your hardware investment by utilising as much virtual compute power as required.
  • Greatly simplifies the process of activating your copies of Windows, as guest OS’s will be activated based on your host machine license key.

As with anything, there is a small learning curve involved in deploying a solution of this nature, but those who are reasonably comfortable working with Windows Server should find the journey relatively smooth.

I had a strange issue recently when setting up a lab environment, where I could not activate any guest Windows Server Datacenter Edition servers via the standard way (i.e. through the Settings page). As a result, I was getting the following errors/messages displayed constantly when working on the machine:

 

Clicking on the Change product key option does nothing, and you have no apparent way of forcing Windows to activate or to modify the Product Key supplied at installation. So how do you go about activating your copy of Windows?

It turns out this error is due to the Product Key being entered incorrectly on initial setup. I (incorrectly) assumed that Hyper-V guest OS’s on a Windows Server 2016 Datacenter host did not require a Product Key and would automatically activate upon installation. This assumption was made on the basis that the Windows 2016 installation wizard now lets you skip adding a Product Key. So, instead of entering a key, I simply pressed Next and let the install proceed as normal. The correct course of action should have been to supply the appropriate Automatic Virtual Machine Activation (AVMA) key, which essentially “tells” Windows to look at the host operating system to confirm whether it is licensed accordingly. A full list of the AVMA codes for Windows Server 2012 R2 and Windows Server 2016 can be found on TechNet, with the appropriate license keys for Server 2016 reproduced below:

  • Datacenter: TMJ3Y-NTRTM-FJYXT-T22BY-CWG3J
  • Standard: C3RCX-M6NRP-6CXC9-TW2F2-4RHYD
  • Essentials: B4YNW-62DX9-W8V6M-82649-MHBKQ

So, to avoid having to completely re-install Windows, we need to find some way in which we can update the OS to use the correct the license key. Fortunately, there is a way, if you are prepared to “get dirty” with the command prompt 🙂

First of all, you will need to ensure that your Hyper-V Manager is configured for Guest services. This can be done straightforwardly enough by going into Settings… on your virtual machine and verifying the appropriate box is ticked on the Integration Services tab. This will need to be done for each virtual machine that requires activation:

Next, because we are prevented from modifying the Product Key via the GUI interface, we must resort to using the slmgr command to remove the current key and add the appropriate AVMA key. As an interesting aside, this is actually a Visual Basic script file and ranks for me as one of the most surprising instances I’ve found of Visual Basic being used within a Microsoft product!

Log onto the virtual machine in question and open an elevated command prompt, executing the following command to remove the current license key:

slmgr -upk

After a few seconds, a pop-up message box will confirm that this has completed successfully:

Then, run the following command to install your AVMA key. In the example below, we are using the Datacenter key to activate a Datacenter edition guest:

slmgr -ipk TMJ3Y-NTRTM-FJYXT-T22BY-CWG3J

As above, we will get confirmation back that the script has completed successfully:

Straight away, you should notice that the Activate Windows message vanishes from the screen and this is confirmed by going into settings – happy days! 🙂

 

Although it is a little bit frustrating that there is no way in which the product key can be modified from within the Settings page (I am assuming that this is a bug; let me know in the comments below if you have encountered the same problem), it is good that we have an alternative mechanism in place for ensuring that Windows can be activated correctly. The lesson is well learned: when deploying out a new guest Hyper-V Server instance, be sure to enter the correct AVMA key at setup to avoid any of the rigmarole illustrated above.

When working with applications day in, day out, you sometimes overlook something that is sitting there, staring at you in the face. It may be an important feature or an inconsequential piece of functionality, but you never really take the time to fully understand either way just what it is and whether it can offer any distinct benefits or assistance. I realised a great example of this when recently deploying some new Plug-ins into Dynamics CRM/Dynamics 365 for Enterprise (CRM/D365E). When you are setting up a new Step for your Plug-in, you are given the option of specifying an Unsecure Configuration and Secure Configuration via a multi-line text box to the right of the window:

1

I was curious about just what these are and why it is not something that you ever really come across when you are first learning about Plug-in development with the application. I took a closer look at what these text boxes do and, as part of this week’s blog post, I wanted to share my findings and provide a demonstration of how they work in practice.

The Theoretical Bit: Unsecure/Secure Configuration Overview

Typically, when we want to get some juicy information relating to a piece of CRM/D365E functionality, we would turn to our good friends TechNet or MSDN. In this instance, however, there is no dedicated page that covers this topic in-depth. We must instead navigate to the Write a Plug-in Constructor page to find dedicated information about how these work:

The Microsoft Dynamics 365 platform supports an optional plug-in constructor that accepts either one or two string parameters. If you write a constructor like this, you can pass any strings of information to the plug-in at run time.

These “one or two” parameters are the multi-line text boxes indicated above. Information is exposed as string objects within you C# code and you enable this feature within your code by specifying the following, SDK adapted constructor within your Plug-in class:

public MyPlugin(string unsecureString, string secureString)
    {
        if (String.IsNullOrWhiteSpace(unsecureString) ||
            String.IsNullOrWhiteSpace(secureString))
            {
                throw new InvalidPluginExecutionException("Unsecure and secure strings are required for this plugin to execute.");
            }

            _unsecureString = unsecureString;
            _secureString = secureString;
    }

As with anything, there are a number of important caveats to bear in mind with this feature. These can be gleaned via additional online sources:

In terms of use cases, the above articles highlight some potential scenarios that they are best utilised within. Perhaps the best example is for an ISV solution that requires integration with external web services to retrieve data that is then consumed by CRM/D365E. Credentials for these web services can be stored securely when the Plug-in is deployed via the use of Secure configuration parameters. Other than that, if you are developing a Plug-in for internal use, that is unlikely to be deployed/managed across multiple environments, then it is probably not worthwhile to look at utilising configuration parameters when you can just as easily specify these within your code.

Practice Makes (for) Perfect (Understanding)!

The best way to see how something works is by getting hands-on and seeing how it works in action. Let’s assume you wish to deploy a plugin that executes whenever a record is opened/viewed by any user across the platform. The plugin should update the First Name (firstname) and Last Name (lastname) fields to match the value(s) in the Unsecure and Secure Configuration properties accordingly. The below plugin code will achieve these requirements:

using System;
using Microsoft.Xrm.Sdk;

namespace D365.BlogDemoAssets.Plugins
{
    public class PostContactRetrieve_PluginConfigurationTest : IPlugin
    {
        private readonly string _unsecureString;
        private readonly string _secureString;
        public PostContactRetrieve_PluginConfigurationTest(string unsecureString, string secureString)
        {
            if (String.IsNullOrWhiteSpace(unsecureString) ||
                String.IsNullOrWhiteSpace(secureString))
            {
                throw new InvalidPluginExecutionException("Unsecure and secure strings are required for this plugin to execute.");
            }

            _unsecureString = unsecureString;
            _secureString = secureString;
        }
        public void Execute(IServiceProvider serviceProvider)
        {
            // Obtain the execution context from the service provider.

            IPluginExecutionContext context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));

            // Obtain the organization service reference.
            IOrganizationServiceFactory serviceFactory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
            IOrganizationService service = serviceFactory.CreateOrganizationService(context.UserId);

            // The InputParameters collection contains all the data passed in the message request.
            if (context.InputParameters.Contains("Target") &&
                context.InputParameters["Target"] is EntityReference)
            {
                Entity contact = new Entity("contact", ((EntityReference)context.InputParameters["Target"]).Id);
                
                contact["firstname"] = _unsecureString;
                contact["lastname"] = _secureString;
                service.Update(contact);

            }
        }
    }
}

When deploying the plugin using the Plugin Registration Tool, we specify the step to execute on the Retrieve message and to execute in the Pre-Operation Stage (otherwise the form will need to be refreshed to see the updated values!). We also need to specify our desired values for the First Name and Last Name fields in the appropriate Configuration fields. The Register New Step window should look similar to the below if configured correctly:

When we navigate into the Jim Glynn (sample) Contact record within CRM/D365E, we can see that the Plug-in has triggered successfully and updated the fields to match against the values specified on Step above:

We can also confirm that the appropriate error is thrown when one of the configuration properties is missing a value, by modifying our Plug-in step and attempting to reload our sample Contact record:

Can you spot what’s missing? 🙂

By clicking Download Log File, we can view the error message specified as part of the InvalidPluginExecutionException call. Below is a modified excerpt of the ErrorDetails XML that is generated:

  <InnerFault>
    <ActivityId>ed4a2021-9c87-4f06-a493-6d804676bf96</ActivityId>
    <ErrorCode>-2147220891</ErrorCode>
    <ErrorDetails xmlns:d3p1="http://schemas.datacontract.org/2004/07/System.Collections.Generic" />
    <Message>Unsecure and secure strings are required for this plugin to execute.</Message>
    <ExceptionSource i:nil="true" />
    <InnerFault i:nil="true" />
    <OriginalException i:nil="true" />
    <TraceText i:nil="true" />
  </InnerFault>

Conclusions or Wot I Think

It is impossible to become what I would like to term a “pub quiz champion” in CRM/D365E; what I mean by this is that I would defy anyone to rattle off every little detail and fact about the entire platform. As with any pub-quiz, those that do may more than likely end up cheating by having their phone out. With this metaphor in mind, I think Plug-in configuration properties would be an excellent topic for a quiz of this nature. As mentioned previously, it is not something that I was ever made aware of when starting to learn about Plug-in development and is not a feature touted regularly within the online community. Perhaps this is because of its very specific and limited application – although it is handy to have at our disposal, I think its usage is really only targeted towards those who are developing solutions that are deployed across multiple environments AND require the need to store configuration properties for external URL’s/web services in a compact and secure manner. Therefore, if you are currently having to use a custom entity within the application to store this type of information, it would make sense to reduce the footprint of your solution within the application itself and make the appropriate changes to use Secure configuration parameters instead. Using a bit of ingenuity (such as XML configuration parameters), you can achieve the same requirements without the need to customise the application unnecessarily.

Generally, when you are looking at adopting Dynamics CRM/Dynamics 365 for Enterprise (D365E) within your business, you can be reasonably satisfied that the majority of what is already configured within the system can be very quickly adapted to suit your business needs. Whether it’s the Lead to Opportunity sales process or the entire Case management module, the functionality at your disposal is suitable for many organisations across the globe. The great thing as well is that, should you wish to fine-tune things further, you have a broad range of options at your disposal that can help you achieve your objectives – sometimes in very specific and highly unique ways. I have previously looked at a good example of this on the blog – namely, how to override the systems built-in pricing engine in favour of your own – and, assuming you have a good understanding of C# and how to deploy plugins to the application, you can spin an important aspect of the systems functionality on its head to match how your business operates.

Having this ability is, undoubtedly, a real boon, but can present some odd behaviours. For example, you may start to notice that suddenly the Extended Amount field is no longer being populated with data after implementing your custom pricing engine. The example pictures below demonstrate a before and after example of adding a Product line item to the Quote entity, using the exact same sample Product:

Before…

…and after.

The odd thing about this is that, as soon as you click into the record, you will suddenly see a value appear in this field. Very strange!

It is difficult to pinpoint exactly what is causing the problem, but I can do a “stab in the dark”. CRM/D365E uses the CalculatePrice message to determine the points when either a) the default price engine or b) a custom one is triggered to perform all necessary calculations. Although there is no official documentation to back this up, I suspect that this message is only triggered when you Update or Retrieve an existing Product line item record (regardless of whether it is an Opportunity Product, Quote Product etc.). This is proven by the fact that, as soon as we click into our Product record, the Extended Amount field is suddenly populated – the platform has triggered the Retrieve message as a result of you opening the record and then, as a next step, forces the CalculatePrice message to also fire. The important thing to clarify with this point is that you must have a custom pricing implemented successfully within the application for this to work. Otherwise, don’t be too surprised if the Extended Amount value remains at 0.

Whilst the workaround for this is somewhat tolerable if you are working with a small subset of records and do not rely on the Extended Amount as part of any existing reporting within the application, this could really start to cause problems for your end users in the long term and give an impression that the application does not “work” as it should do. Fortunately, there is a solution that we can look at implementing that will hopefully lead to some happy fingers from not needing to click into records anymore 🙂 Be sure to have the CRM/D365E SDK handy before you begin the below!

  1. Open up the Plugin Registration Tool from within the SDK, and log into your CRM/D365E instance.
  2. Scroll down to your Assembly and Plugin that contains your custom pricing engine. If already configured correctly, it should have a step configured for the CalculatePrice message on any entity, as a Synchronous, Post-Operation step.
  3. Right click your plugin and click on Register New Step to open the window that lets you specify the required settings for your step. Populate the form as follows:
    • Message: Create
    • Primary Entity: Select one of the Product line item entities that your custom pricing engine uses. The list of accepted entities are invoicedetailopportunityproduct, salesorderdetail or quotedetail.
    • Event Pipeline Stage of Execution: Post-Operation
    • Execution Mode: Synchronous

All other settings can be left as default. Your window should look similar to the below if configured correctly for the quotedetail entity:

  1. Click on Register New Step to add the step to the application.
  2. Repeat steps 3-4 for any additional Product line item entities that are using with your custom pricing engine

Now, when you go back into CRM/D36E, the Extended Amount values will start to be populated automatically as soon as you add a new Product onto the Product line item subgrid.

Conclusions or Wot I Think

Whilst the ability to override an important piece of CRM’s/D365E’s functionality is welcome, you do need to bear in mind the additional overhead and responsibility this leaves your organisation in ensuring that your custom pricing engine is correct and that you have adequately tested the solution to properly identify actions which are out of the ordinary, such as the one discussed in this post. What is slightly frustrating about this quirk, in particular, is the lack of clear documentation regarding the CalculatePrice message from Microsoft. Granted, the message is only exposed for minimal interaction from an SDK point of view and is, for all intents and purposes, an internal application message that we shouldn’t really mess with or care about. Having said this, even just a brief summary of when the message is triggered on the platform would have made it instantly more understandable why any custom pricing calculation engine will fail to provide you with an instant amount within your Extended Amount field. In the end, however, I am pleased that there is a straightforward workaround that can be put into place to ensure that things work as expected; hopefully to the extent that it becomes virtually impossible to determine easily whether your organisation is using the default or a custom pricing engine in the first place.