Dynamics CRM/Dynamics 365 for Customer Engagement (CRM/D365CE) is an incredibly flexible application for the most part. Regardless of how your business operates, you can generally tailor the system to suit your requirements and extend it to your heart’s content; often to the point where it is completely unrecognisable from the base application. Notwithstanding this argument, you will come across aspects of the application that are (literally) hard-coded to behave a certain way and cannot be straightforwardly overridden via the application interface. The most recognisable example of this is the Lead Qualification process. You are heavily restricted in how this piece of functionality acts by default but, thankfully, there are ways in which it can be modified if you are comfortable working with C#, JScript and Ribbon development.

Before we can start to look at options for tailoring the Lead Qualification process, it is important to understand what occurs during the default action within the application. In developer-speak, this is generally referred to as the QualifyLead message and most typically executes when you click the button below on the Lead form:

When called by default, the following occurs:

  • The Status/Status Reason of the Lead is changed to Qualified, making the record inactive and read-only.
  • A new OpportunityContact and Account record is created and populated with (some) of the details entered on the Lead record. For example, the Contact record will have a First Name/Last Name value supplied on the preceding Lead record.
  • You are automatically redirected to the newly created Opportunity record.

This is all well and good if you are able to map your existing business processes to the application, but most organisations will typically differ from the applications B2B orientated focus. For example, if you are working within a B2C business process, creating an Account record may not make sense, given that this is typically used to represent a company/organisation. Or, conversely, you may want to jump straight from a Lead to a Quote record. Both of these scenarios would require bespoke development to accommodate currently within CRM/D365CE. This can be broadly categorised into two distinct pieces of work:

  1. Modify the QualifyLead message during its execution to force the desired record creation behaviour.
  2. Implement client-side logic to ensure that the user is redirected to the appropriate record after qualification.

The remaining sections of this post will demonstrate how you can go about achieving the above requirements in two different ways.

Our first step is to “intercept” the QualifyLead message at runtime and inject our own custom business logic instead

I have seen a few ways that this can be done. One way, demonstrated here by the always helpful Jason Lattimer, involves creating a custom JScript function and a button on the form to execute your desired logic. As part of this code, you can then specify your record creation preferences. A nice and effective solution, but one in its guise above will soon obsolete as a result of the SOAP endpoint deprecation. An alternative way is to instead deploy a simplistic C# plugin class that ensures your custom logic is obeyed across the application, and not just when you are working from within the Lead form (e.g. you could have a custom application that qualifies leads using the SDK). Heres how the code would look in practice:

public void Execute(IServiceProvider serviceProvider)
    {
        //Obtain the execution context from the service provider.

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

        if (context.MessageName != "QualifyLead")
            return;

        //Get a reference to the Organization service.

        IOrganizationServiceFactory factory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
        IOrganizationService service = factory.CreateOrganizationService(context.UserId);

        //Extract the tracing service for use in debugging sandboxed plug-ins

        ITracingService tracingService = (ITracingService)serviceProvider.GetService(typeof(ITracingService));

        tracingService.Trace("Input parameters before:");
        foreach (var item in context.InputParameters)
        {
            tracingService.Trace("{0}: {1}", item.Key, item.Value);
        }

        //Modify the below input parameters to suit your requirements.
        //In this example, only a Contact record will be created
        
        context.InputParameters["CreateContact"] = true;
        context.InputParameters["CreateAccount"] = false;
        context.InputParameters["CreateOpportunity"] = false;

        tracingService.Trace("Input parameters after:");
        foreach (var item in context.InputParameters)
        {
            tracingService.Trace("{0}: {1}", item.Key, item.Value);
        }
    }

To work correctly, you will need to ensure this is deployed out on the Pre-Operation stage, as by the time the message reaches the Post-Operation stage, you will be too late to modify the QualifyLead message.

The next challenge is to handle the redirect to your record of choice after Lead qualification

Jason’s code above handles this effectively, with a redirect after the QualifyLead request has completed successfully to the newly created Account (which can be tweaked to redirect to the Contact instead). The downside of the plugin approach is that this functionality is not supported. So, if you choose to disable the creation of an Opportunity record and then press the Qualify Lead button…nothing will happen. The record will qualify successfully (which you can confirm by refreshing the form) but you will then have to manually navigate to the record(s) that have been created.

The only way around this with the plugin approach is to look at implementing a similar solution to the above – a Web API request to retrieve your newly created Contact/Account record and then perform the necessary redirect to your chosen entity form:

function redirectOnQualify() {

    setTimeout(function(){
        
        var leadID = Xrm.Page.data.entity.getId();

        leadID = leadID.replace("{", "");
        leadID = leadID.replace("}", "");

        var req = new XMLHttpRequest();
        req.open("GET", Xrm.Page.context.getClientUrl() + "/api/data/v8.0/leads(" + leadID + ")?$select=_parentaccountid_value,_parentcontactid_value", true);
        req.setRequestHeader("OData-MaxVersion", "4.0");
        req.setRequestHeader("OData-Version", "4.0");
        req.setRequestHeader("Accept", "application/json");
        req.setRequestHeader("Content-Type", "application/json; charset=utf-8");
        req.setRequestHeader("Prefer", "odata.include-annotations=\"OData.Community.Display.V1.FormattedValue\"");
        req.onreadystatechange = function () {
            if (this.readyState === 4) {
                req.onreadystatechange = null;
                if (this.status === 200) {
                    var result = JSON.parse(this.response);
                    
                    //Uncomment based on which record you which to redirect to.
                    //Currently, this will redirect to the newly created Account record
                    var accountID = result["_parentaccountid_value"];
                    Xrm.Utility.openEntityForm('account', accountID);

                    //var contactID = result["_parentcontactid_value"];
                    //Xrm.Utility.openEntityForm('contact', contactID);

                }
                else {
                    alert(this.statusText);
                }
            }
        };
        req.send();
        
    }, 6000);     
}

The code is set to execute the Web API call 6 seconds after the function triggers. This is to ensure adequate time for the QualifyLead request to finish and make the fields we need available for accessing.

To deploy out, we use the eternally useful Ribbon Workbench to access the existing Qualify Lead button and add on a custom command that will fire alongside the default one:

As this post has hopefully demonstrated, overcoming challenges within CRM/D365CE can often result in different – but no less preferred – approaches to achieve your desired outcome. Let me know in the comments below if you have found any other ways of modifying the default Lead Qualification process within the application.

Perhaps one of the most useful features at your disposal when working with Azure SQL Databases is the ability to integrate your Azure Active Directory (Azure AD) login accountsa la Windows Authentication for on-premise SQL Server. There are numerous benefits in shifting away from SQL Server-only user accounts in favour of Azure AD:

  • Ensures consistent login identities across multiple services.
  • Can enforce password complexity and refresh rules more easily.
  • Once configured, they behave exactly the same as standard SQL Server only logins.
  • Supports advanced usage scenarios involving Azure AD, such as multi-factor authentication and Single Sign-On (SSO) via Active Directory Federation Services (ADFS).

Setup can be completed in a pinch, although you will need to allocate a single/group of user(s) as the Active Directory admin for the Azure SQL Server. You may also choose to take due care and precautions when choosing your Active Directory admin(s); one suggestion would be to use a unique service account for the Active Directory admin, with a strong password, instead of granting such extensive privileges to normal user accounts.

Regardless of how you go about configuring the feature, I would recommend using it where-ever you can, for both internal purposes and also for anyone who wishes to access your SQL Server from an external directory. This second scenario is, you may be surprised to hear, fully supported. It assumes, first off, that you have added this account to your directory as a Guest/External User account. Then, you just follow the normal steps to get the account created on your Azure SQL Server.

There is one major “gotcha” to bear in mind when doing this. Let’s assume that you have added john.smith@domain.co.uk to the Azure AD tenant test.onmicrosoft.com. You then go to setup this account to access a SQL Server instance on the tenant. You will more than likely receive the following error message when using the example syntax below to create the account:

CREATE USER [john.smith@domain.co.uk] FROM EXTERNAL PROVIDER

The issue is, thankfully, simple to understand and fix. When External user accounts are added onto your Active Directory, despite having the same login name that derives from their source directory, they are stored in the new directory with a different UserPrincipalName (UPN). Consider the above example – the UPN in the source directory would be as follows:

john.smith@domain.co.uk

Whereas, as the Azure AD tenant name in this example is test.onmicrosoft.com, the UPN for the object would be:

john.smith_domain.co.uk#EXT#@test.onmicrosoft.com

I assume that this is done to prevent any UPN duplication across Microsoft’s no-doubt dizzying array of cloud Active Directory tenants and forests. In any event, knowing this, we can adjust our code above to suit – and successfully create our Database user account:

CREATE USER [john.smith_domain.co.uk#EXT#@test.onmicrosoft.com] FROM EXTERNAL PROVIDER

I guess this is one of those things where having at least a casual awareness of how other technologies within the Microsoft “stack” work can assist you greatly in troubleshooting what turn out to be simplistic errors in your code. Frustrating all the same, but we can claim knowledge of an obscure piece of Azure AD trivia as our end result 🙂

I would not recommend setting up a Windows Server Domain Services role for the first time flying blind. Whilst not necessarily classing myself as a “newbie” in this respect, I have only run through this a few times in the past within lab environments. The process is always tricky – not just in deploying out the role in the first instance, but more via the many quirks that get thrown up as you try to accomplish what should be simple tasks, such as domain joining devices or getting DNS settings correctly mapped out. These and other tiresome rat races can leave you with a severely scratched head and distract you from your ultimate goal.

For this reason, you could argue that Azure Active Directory Domain Services (or AADDS) is the perfect solution for “newbies”. The thing I like the most about it is that a lot of the hassle I make reference to above is something you will never see a sight of, thanks to the fact that Microsoft manages most aspects of the deployment behind the scenes. In addition, the step-by-step guides available on the Microsoft Docs website provide a very clear and no-nonsense holding hand through every step of an Azure Domain Services rollout. What this ultimately means is that you can spend more time on achieving your end goal and reduce the need for extensive administration of the solution following its rollout. Having said that, it is always useful to ensure that you have thoroughly tested any solution as extensively as possible for your particular scenario, as this will always throw up some potential issues or useful tips to remember in future; AADDS is no exception to this rule.

Having recently worked closely with AADDS, in this weeks blog post, I wanted to share some of my detailed thoughts regarding the solution in practice and a few things to remember if you are checking it out for the first time.

Resetting AADDS User passwords could become the bane of your existence

If you are creating an AADDS resource in isolation to any existing identity providers you have in place (i.e. there is no requirement to use Azure AD Connect with an On-Premise Domain Server), then be aware that you will have to set up a users password twice before they will be able to login to the domain. Microsoft explains better than I can why this is:

To authenticate users on the managed domain, Azure Active Directory Domain Services needs credential hashes in a format that’s suitable for NTLM and Kerberos authentication. Azure AD does not generate or store credential hashes in the format that’s required for NTLM or Kerberos authentication, until you enable Azure Active Directory Domain Services for your tenant. For obvious security reasons, Azure AD also does not store any password credentials in clear-text form. Therefore, Azure AD does not have a way to automatically generate these NTLM or Kerberos credential hashes based on users’ existing credentials…If your organization has cloud-only user accounts, all users who need to use Azure Active Directory Domain Services must change their passwords

Source: https://docs.microsoft.com/en-us/azure/active-directory-domain-services/active-directory-ds-getting-started-password-sync

The above article goes into the required steps that need to be followed for each user account that is created and, at the time of writing, I do not believe there is any way of automating this process. Whether you choose to complete these steps yourself or get your end users to do so instead is up to you, but there is a good chance that if a user is experiencing login issues with an AADDS account, then the steps in the above article have not been followed correctly.

Make sure you’re happy with your chosen DNS Name

When first creating your Domain Services resource, you need to be pretty certain your desired DNS domain name will not be subject to change in the future. After some fruitless digging around on the portal and an escalated support request to Microsoft, I was able to confirm that there is no way this can be changed after the Domain Services resource is deployed; your only recourse is to recreate the resource from scratch with your newly desired DNS domain name. This could prove to be problematic if, say, you wish to change the domain name of your in-development domain services account from the default onmicrosoft.com domain to a bespoke one…after you have already joined Virtual Machines to your new domain : / Some efficient use of the Azure templates feature can save you some aggro here, but not if you have already expended considerable effort on bespoke customisation on each of your VM’s operating systems.

Be aware of what’s supported….and what isn’t

There are a few articles that Microsoft have published that can help you to determine whether AADDS is right for your particular scenario:

Whilst these are invaluable and, admittedly, demonstrate the wide-feature array contained with AADDS, there are still a few hidden “gotchas” to be aware of. The articles above hint towards some of these:

  • Only one AADDS resource is allowed per Azure tenant. You will need to configure a clean Active Directory tenant (and therefore a separate Azure portal) for any additional AADDS resource you wish to setup, which also requires an appropriate subscription for billing. This could result in ever-growing complexity to your Azure footprint.
  • AADDS is a continually billable service. Unlike VM’s, which can be set to Stopped (unallocated) status at any time and, therefore, not incur any usage charges, your Domain Services resource will incur fees as soon as you create it and only cease when the resource is deleted.

One unsupported feature that the above articles do not provide any hint towards is Managed Service Accounts. Introduced as part of Windows Server 2008 R2, they provide a more streamlined means of managing service accounts for applications running on Windows Server, reducing the requirement to maintain passwords for these accounts and allowing administrators to provide domain-level privileges to essential service account objects. I try to use them whenever I can in conjunction with SQL Server installations, particularly if the service accounts for SQL need to access network-level resources that are secured via a security group or similar and I would encourage you to read up on them further to see if they could be a help within your SQL Server deployments.

Back to the topic at hand – if you attempt to create a Managed Service Account via PowerShell, you will receive an error message saying that they are not supported within the domain. So, assuming that you are wanting to go ahead and deploy SQL Server on an AADDS joined VM, you would have to revert back to using standard Active Directory user accounts for your Service Accounts to achieve the same functionality. Not great if you also have to enforce password refresh policies, but it would be the only supported workaround in this situation.

Conclusion or Wot I Think

When reviewing potential new IT vendors or products, I always try and judge “how dirty handed” I would need to get with it. What I mean by this is the level of involvement myself, or a business, would need to invest in managing physical server hardware, backend elements of the infrastructure or any aspect of the solution that requires an inordinate amount of time poking around the innards of to troubleshoot basic problems. The great benefit of services such as Azure is that a lot of this pain is taken away by default – for example, there is no need to manage server, firewall and networking hardware at all, as Microsoft does this for you. AADDS goes a step further by removing the need to manage the server aspect of a Domain Services deployment, allowing you to focus more on building out your identities and integrating them within your chosen application. Whilst it does need some work to get it up to an acceptable level of parity with a “do-it-yourself” Domain Server (for example, extensive PowerShell support for the completion of common tasks), the service is still very much in a developed and user-friendly state to warrant further investigation – particularly if you have a simplified Active Directory Domain in place or are looking to migrate across to Active Directory from another vendor. £80 per month for a directory smaller than 25,000 objects is also not an exorbitant price to pay as well, so I would definitely recommend you check AADDS out to see if it could be a good fit for your organisation/application in the near future.

In the early days of Office 365, you would be accustomed to a certain kind of experience when purchasing licenses as a small/medium size business (SMB) customer. As these types of organisations are typically too small to warrant the cost for Enterprise Agreements or Volume Licensing, your only recourse to buying Office 365 services was via the portal itself. At this time, any involvement with a Microsoft Partner would be minimal or even non-existent. Partners would only enter the picture if a business opted to grant them Partner of Record status, thereby allowing them to manage aspects of your subscription behind the scenes. This process, while wholly sufficient, did have some notable gaps and, if you were an organisation focused on tightly managing all aspects of your customer journey, could be prone to change or interruption via interference from Microsoft

The Cloud Solutions Provider programme (or CSP for short) is Microsoft’s “next-generation” opportunity for partners to get directly involved as part of a customers journey onto Office 365, Dynamics 365 and/or Azure and aims to resolve some of the issues highlighted above. Instead of turning directly to Microsoft when you need a new license subscription or have an issue with a particular Office 365 opportunity, customers would instead deal directly with a CSP provider, who will be able to offer them all of this, and more. Everyone wins – the customer, CSP provider and Microsoft itself – and here’s just a few reasons why:

Moving to CSP can save you money

Perhaps the most important reason of all to consider CSP 🙂 The price you will pay for pretty much every single Office 365 Subscription offering available via Microsoft directly will be lower if purchased from a CSP partner. In most cases, this will typically result in a 10-15% reduction across the board guaranteed; a figure which, depending on the size of your organisation, could be a significant portion of your per annum IT spend. In addition, there is no need to wait for your subscription anniversary to switch – any early cancellation charges will be credited in full by Microsoft, should you cancel at any point in your subscription and migrate to the equivalent CSP subscription.

CSP users can benefit from special promotions, previews and other deals unavailable via Microsoft Direct

One example of this at the moment is the preview for Microsoft 365 Business – the next evolutionary step for Office 365 – which is accessible to those who are working with CSP providers currently. Other promotions may also appear from time to time, so you should be speaking to your CSP provider regularly to ensure that they are informing you of any potential discounts or offers available.

CSP enables your current Microsoft Partner to support you better

If you are working with a Microsoft Partner to help support your Office 365 services or Dynamics 365 deployments, there’s a good chance that they may have spoken to you about CSP or migrated you across already. The reasons for this will not be purely based on an altruistic desire to reduce your monthly running costs; by having their customers operating under CSP licensing, Partners are granted additional information regarding your subscriptions and their usage. They also become the de facto organisation that needs to be contacted in case any issues occur relating to the subscription. A customer who, for example, contacts Microsoft directly regarding an Exchange Online issue on their CSP subscription will instead be referred back to the CSP Partner in the first instance; they will then be responsible for escalating the case to Microsoft if required. In most circumstances, this can surely be seen as a plus and in helping Partners to work more closely with their customers.

The above example also goes some way towards explaining why CSP license prices are cheaper compared to going directly to Microsoft. By placing Partner organisations at the front-line of dealing with common 1st/2nd Line support issues, Microsoft can reduce the number of support professionals it allocates internally  and place the burden instead on Microsoft Partners to do the “heavy lifting”, particularly when it comes to dealing with easy to resolve issues (i.e. any support request that can be resolved via the Administration Centre).

It’s for Azure as well…with some caveats

Chances are if you are using Office 365 within your organisation, then you will also be consuming some additional Azure services on top of this – either Virtual Machine(s), storage, websites or even some database capacity. The good news is that you can also look at moving your Azure subscriptions across to CSP, with the same benefits available: reduced monthly costs and the ability for your partner of choice to support you better.

At the time of writing this post, the key “red flag” I would draw you towards when considering Azure CSP is what you lose compared to a Pay As You Go or other direct subscription. For example, ongoing and previous usage history will not be visible on the Azure portal and, chances are, you will only get full visibility of your Azure usage costs at the time when you are billed by your CSP partner. If you typically prefer to micro-manage your ongoing Azure usage costs, then a 10-15% saving may not be a fair trade-off for losing this visibility.

Finally, don’t be surprised if this becomes the de facto way of buying Office 365/Azure in the future if you are an SMB

I mentioned above one reason why CSP license costs are cheaper, and through this, you can begin to see the writing on the wall for SMB’s. This is not necessarily a bad thing. My own personal preference would be in dealing with a Microsoft Partner as opposed to Microsoft direct, as Partners will generally be a lot more flexible and reactive to work with. Having assumed that Microsoft can generate significant internal cost savings and also give eager Partner organisations the opportunity to fill the void, why would they not then turn round and say “We’re sorry, but if you are an organisation that employs 300 people or less, then please speak to a Microsoft Partner for further assistance.”? Certainly, the vibe and talk around CSP at the moment would seem to indicate that this is the long-term trajectory for the programme. Watch this space, but it will be interesting to see in the future whether the Microsoft Direct route is downplayed or removed completely if your potential license order per annum is in only in the hundreds of £’s.

When Server-Side Synchronization (Server-Side Sync) was first introduced in Dynamics CRM 2013, I imagine that lots of application and email server administrators breathed a huge sigh of relief. The feature greatly simplified the amount of effort involved in integrating On-Premise/Online CRM instances with their equivalent Exchange Server versions. Previously, the only way of achieving such an integration was via the E-mail Router, a cumbersome application that provided limited integration between email servers and CRM (i.e. no synchronization of items such as Tasks, Appointments, and Contacts). Granted, the E-mail Router was desirable if you were running a non-Exchange based Email Server, but having to provision a dedicated computer/server as the “intermediary” for all email messages to flow through could start to make a simple application deployment grow arms and legs very quickly.

Since the addition of Server-Side Sync, the feature has been continually updated to make it more versatile and the de facto choice for getting your emails tagged back into CRM & Dynamics 365 for Enterprise (D365E) – to the extent that the Email Router will shortly be extinct. Server-Side Sync now supports hybrid-deployments (e.g. D365E Online to Exchange On-Premise and vice-versa), has been expanded to include other Email protocol types and is now tailored to provide easier mechanisms for diagnosing mail flow issues from within the application itself. The last of these developments is best epitomised by the introduction of the Server-Side Synchronization Monitoring dashboard, introduced in CRM 2016 Update 1:

With this Dashboard, Administrators now have a simplified means of monitoring the health of their Server-Side Sync settings, facilitating the easy identification of problematic mailboxes, mailboxes that have failed a Test & Enable and those that have a recurring error being generated on them. Having all of this information at our fingertips enables CRM administrators to much more proactive in managing their health of their instance.

When recently working within some D365E organizations, which were originally provisioned as Dynamics CRM Online 2015 instances on the same Office 365 tenant, I noticed that the above Dashboard was missing:

Therefore, when clicking on the appropriate button in the sitemap area, an alternative Dashboard is loaded instead (either the user’s favorite Dashboard or a random one instead). So the question was – where has the Dashboard gone?

It turns out that the reason for its absence is down to an error as part of a previous major version upgrade, and is an issue that may be encountered by CRM Organisations provisioned a few years back. After escalating to Microsoft Support for further assistance, we were able to find a workaround to make the Dashboard available on the instances that were missing it. The steps involved are relatively straightforward, but in our case, we did have to resort to a spare trial/demo instance available that had the Dashboard installed successfully. The workaround steps are as follows:

  1. Log into an instance that contains the Dashboard. Go into Customizations and rename the Dashboard (doesn’t matter what you call it, as long as it’s not the same as the default name).
  2. Create a new unmanaged Solution and add in the renamed Dashboard. Export the solution as an Unmanaged Solution.
  3. Import the Solution into the instance that is missing it.
  4. Attempt to access the Dashboard and verify that it loads successfully.

You may be wondering why the Dashboard needs to be renamed before exporting. When attempting to import this Dashboard into any target instance with its default name, the component is automatically skipped during the import process. A Microsoft engineer advised that this is because an instance with the missing Dashboard actually thinks it is there and therefore does not try to import and overwrite a system component with the same name.

For the benefit of those who may also be experiencing the same issue and do not readily have access to another CRM/D365E instance, I have uploaded below two unmanaged solution files for the previous two versions of the application:

Version 8.1 (Dynamics CRM Online 2016 Service Pack 1)

Version 8.2 (December 2016 update for Dynamics 365)

The solution is a simple 1 component solution, containing a renamed version of the Server-Side Synchronization Monitoring Dashboard:

Once you have downloaded your Solution of choice above, follow steps 3-4 above and then go into Solution and the Dashboard to rename it from Copy of Server-Side Synchronization Monitoring -> Server Side Synchronization Monitoring. The application will accept the changes and it will be as if you always had the Dashboard there in the first place 🙂

It seems strange that this issue occurred in the first place, and I suspect I may not be the only one who has faced it recently. The Microsoft engineer I spoke to seemed to confirm that they’ve had this type of issue crop up several times previously, which makes it strange that this has not been acknowledged as a bug, either within the application itself as part of the twice-yearly upgrade processes. Notwithstanding this fact, it is good that an established workaround can be applied to fix the issue.