Dynamics 365 CE TLS Connectivity Issue from .NET and PowerShell

If you have been running recently into some strange unexplained connectivity issues to Dynamics 365 CE Online, then the chances are this might be due to TLS incompatibility between Dynamics and your client code.

What is the issue?

Microsoft has started to disable TLS 1.0 and TLS 1.1 support for Dynamics 365 online instances. That means only TLS 1.2 will be supported. Obviously this is for good reasons to improve security.

What is impacted?

Any of your clients or PowerShell Modules/Scripts that relies on the CRM SDK. This includes CRM development tools, CRM Package Deployment PowerShell Tools, Custom clients/portal/services and others.

Suggested Fixes?

You can find out more information about this change and potential fixes in this article. To cut a long story short, you either have to update your .NET client to 4.6.2 or provide implement a machine wide registry key to enforce highest security protocol (TLS 1.2).

How to see your current settings from code?

From .NET

Console.WriteLine(ServicePointManager.SecurityProtocol);

From PowerShell

$currentProtocol = [System.Net.ServicePointManager]::SecurityProtocol
Write-Verbose "Current Security Protocol: $currentProtocol"

This gets more complicated…

I noticed that even if you have PowerShell Cmdlets compiled in .NET 4.6.2, PowerShell will still sometimes run in its own run-time depending on the machine configuration.

So for example on my Windows 10 Machine with PS 5.1 by default I could only see SSL3 and TLS available. You will probably see the same on a .NET Client compiled using .NET 4.5.2 or earlier.

Alternative Solution…

So if you want to keep your .NET version or if you are facing the issues when running PowerShell you can try the solutions below.

If you are connecting to a known CRM instance/version. Then you force the connection to use TLS 1.2 using the code below.

From .NET

ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;

From PowerShell

[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls12;

However if you are building something that may need to connect using previous security protocol, for example a generic PowerShell Module that can be used for Online and On-premises. You probably want to keep your options open. The below code will check your current settings and add TLS 1.1 and TLS 1.2 support if not already configured.

From .NET

            WriteVerbose(string.Format("Current Security Protocol: {0}", ServicePointManager.SecurityProtocol));

            if (!ServicePointManager.SecurityProtocol.HasFlag(SecurityProtocolType.Tls11))
            {
                ServicePointManager.SecurityProtocol = ServicePointManager.SecurityProtocol ^ SecurityProtocolType.Tls11;
            }
            if (!ServicePointManager.SecurityProtocol.HasFlag(SecurityProtocolType.Tls12))
            {
                ServicePointManager.SecurityProtocol = ServicePointManager.SecurityProtocol ^ SecurityProtocolType.Tls12;
            }

            WriteVerbose(string.Format("Modified Security Protocol: {0}", ServicePointManager.SecurityProtocol));<span 				data-mce-type="bookmark" 				id="mce_SELREST_start" 				data-mce-style="overflow:hidden;line-height:0" 				style="overflow:hidden;line-height:0" 			></span>

From PowerShell

#Set Security Protocol
$currentProtocol = [System.Net.ServicePointManager]::SecurityProtocol
Write-Verbose "Current Security Protocol: $currentProtocol"
if (-not $currentProtocol.HasFlag([System.Net.SecurityProtocolType]::Tls11))
{
    [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol  -bor [System.Net.SecurityProtocolType]::Tls11;
}
if (-not $currentProtocol.HasFlag([System.Net.SecurityProtocolType]::Tls12))
{
    [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol  -bor [System.Net.SecurityProtocolType]::Tls12;
}
$currentProtocol = [System.Net.ServicePointManager]::SecurityProtocol
Write-Verbose "Modified Security Protocol: $currentProtocol"

Hope this was helpful. Let me know if you have others solutions and if the above solutions work for you.

Advertisements

UI Automation for Dynamics 365 CE – EasyRepro (Part 2)

In this post I will cover how to get started using EasyRepro framework for Dynamics 365 CE. If you are new to UI Automation, take a look at my previous Introduction post.

Note the framework consists of a single solution that contains a sample project. If you just want to take a look and get an idea, you can download the source code from the GitHub project and take a look at the sample test project.

Unless you want to contribute to the framework or debug the framework code you are more likely to just consume the framework libraries and focus on building your tests. This is the scenario I will cover in this post.

Scenario

Login to CRM
Navigate to Sales/Contacts/Active Contacts
Create a new Contact
Save

Create a Unit Test project

You can use any unit testing framework you like. I will use MSTest. For this just add a new unit testing project to your solution as per below. Note you need to select .NET 4.7 as the Nuget packages doesn’t seem to install correctly with lower versions.

UIAutomationProject

Add the required NuGet packages

Add the EasyRepro library from the Nuget Gallery . Not sure if this published by MS. As an alternative you can compile the sample project from GitHub and add the Microsoft.Dynamics365.UIAutomation.Api and Microsoft.Dynamics365.UIAutomation.Browser DLLs as a reference).

EasyReproNuget

Below are all the package syou need along with the versions.

<?xml version="1.0" encoding="utf-8"?>
<packages>
  <package id="Dynamics365.UIAutomation.Api" version="9.0.0" targetFramework="net47" />
  <package id="MSTest.TestAdapter" version="1.1.18" targetFramework="net461" />
  <package id="MSTest.TestFramework" version="1.1.18" targetFramework="net461" />
  <package id="Newtonsoft.Json" version="10.0.3" targetFramework="net47" />
  <package id="Selenium.Chrome.WebDriver" version="2.31" targetFramework="net47" />
  <package id="Selenium.Support" version="3.5.1" targetFramework="net47" />
  <package id="Selenium.WebDriver" version="3.5.1" targetFramework="net47" />
  <package id="System.Diagnostics.DiagnosticSource" version="4.4.1" targetFramework="net47" />
</packages><span 				data-mce-type="bookmark" 				id="mce_SELREST_start" 				data-mce-style="overflow:hidden;line-height:0" 				style="overflow:hidden;line-height:0" 			></span>

Add a Test

As a standard unit test to your project.
CreateContactTest

First you will need your CRM URL, Username and Password. Below I am retrieving these from Environment variables as I didn’t want to check-in credentials to into source control. You can use configuration files. I strongly recommend that credentials are encrypted and securely stored.

        private readonly SecureString _username = Environment.GetEnvironmentVariable("CRMUser", EnvironmentVariableTarget.User).ToSecureString();
        private readonly SecureString _password = Environment.GetEnvironmentVariable("CRMPassword", EnvironmentVariableTarget.User).ToSecureString();
        private readonly Uri _xrmUri = new Uri(Environment.GetEnvironmentVariable("CRMUrl", EnvironmentVariableTarget.User));

Next you will need to define your browser requirements. In this instance I will use Chrome in Private (Incognito mode).

        private readonly BrowserOptions _options = new BrowserOptions
        {
            BrowserType = BrowserType.Chrome,
            PrivateMode = true,
            FireEvents = true
        };

The first step is normally to open a new browser instance and login to CRM. As you can see the below API make this very simple to achieve.

            using (var xrmBrowser = new XrmBrowser(_options))
            {
                xrmBrowser.LoginPage.Login(_xrmUri, _username, _password);
                xrmBrowser.GuidedHelp.CloseGuidedHelp();

Once CRM is open. You can interact with CRM page using the XrmBrowser object. As you can see below, there are different components for Navigation, Grids and CommandBar. Note you will need to add some think time between different calls to allow the browser to do its work.


                xrmBrowser.Navigation.OpenSubArea("Sales", "Contacts");

                xrmBrowser.ThinkTime(2000);
                xrmBrowser.Grid.SwitchView("Active Contacts");

                xrmBrowser.ThinkTime(1000);
                xrmBrowser.CommandBar.ClickCommand("New");

                xrmBrowser.ThinkTime(5000);

Once you are on the new contact page, you can interact with the CRM entity form through the Entity component. This allows you to set values on the form. This can be simple texts fields or even composite controls and lookups.

                var fields = new List<Field>
                {
                    new Field() {Id = "firstname", Value = "Wael"},
                    new Field() {Id = "lastname", Value = "Test"}
                };
                xrmBrowser.Entity.SetValue(new CompositeControl() { Id = "fullname", Fields = fields });
                xrmBrowser.Entity.SetValue("emailaddress1", "test@contoso.com");
                xrmBrowser.Entity.SetValue("mobilephone", "555-555-5555");
                xrmBrowser.Entity.SetValue("birthdate", DateTime.Parse("11/1/1980"));
                xrmBrowser.Entity.SetValue(new OptionSet { Name = "preferredcontactmethodcode", Value = "Email" });

Now you can save the form.

                xrmBrowser.CommandBar.ClickCommand("Save");
                xrmBrowser.ThinkTime(5000);

Finally I will take a screen shot. You can take these at any point in time during the test or if the test fails. This can be used as test evidence, troubleshooting failed tests or for spot checks.

                string screenShot = string.Format("{0}\\CreateNewContact.jpeg", TestContext.TestResultsDirectory);
                xrmBrowser.TakeWindowScreenShot(screenShot, ScreenshotImageFormat.Jpeg);
                TestContext.AddResultFile(screenShot);

Run the Test

If you run the test now the browser should navigate to CRM and perform the actions described in the scenario. You will normally add some verification at the end of the test to ensure the expected outcome was achieved and fail the test otherwise.

CreateContactTestResults
CreateContactScreenShot

You can find this code including any future updates on GitHub

As you can see it very easy to setup an automated UI test using EasyRepro. In the following posts I will cover more advanced topics on UI Automation.

UI Automation for Dynamics 365 CE – Introduction (Part 1)

This post is an introduction to UI Automation Testing for Dynamics 365 CE. I will cover the basic concepts. The next post will show how to get started and provide a practical example.

What is UI Automation?

As the name suggests, UI Automation is the automated testing that happens at the UI layer. Where as unit and integration tests interact with assemblies and APIs, UI tests interact with the actual application UI.

What is involved?

Typically the automated test will open the application UI which in our case is the Dynamics 365 CE web interface and then execute a series of scenarios as if it was the actual user performing the actions.

How does it work?

UI Automation tests typically use frameworks that have the ability to create an instance of a browser. Frameworks also provide APIs or drivers/adaptors that provide you with the ability to interact with the browser instance to perform actions such as navigating to page, filling out forms and clicking on UI elements. Selenium is one of the most widely used frameworks for testing web applications. You can find out more on the Selenium home page.

What framework should you use for Dynamics 365 CE?

There are many UI automation frameworks out there. If you already have a framework being used in your organisation for other web applications there is a good chance it might work well with Dynamics too. For this series I will be using EasyRepro. This is an open source Framework based on Selenium that was released by Microsoft early in 2017 and has recently been updated to support V9. Take look at the GitHub project for more information on the Framework.

What else you need to know about EasyRepro?

  • Tests are created using .NET, something most CRM developers are already familiar with which can help with adoption and ensure testing practices as part of your development life cycle.
  • It provides you with XrmBrowser object which is a POM (Page Object Model) abstraction on top of the CRM Page. So it gives you API for some of the mostly used actions by the user such as logging in to CRM, interacting with forms and navigation.
  • Future updates may include the ability generate code by recording actions or using IDE.
  • The framework is easy to use and samples on the GitHub project give you a quick start.

What tests you should be automating?

Before you get going with writing tests I would strongly recommend that you think carefully about what tests it makes sense to automate at UI layer. For this the test pyramid always comes handy.

TestPyramid

UI Tests provide very good coverage as they cover the UI and all the layers below such as integrations and any plug-ins you may have. However note the below:

  • UI tests take long to run
  • UI tests normally run less frequently and are further up in your DevOps pipeline.
  • UI tests take longer to develop and maintain

You should have a good number of units tests and integration tests which should provide good coverage for your components and integrations. You can use UI tests to cover UI level features that are not possible to test using Unit and Integration Tests. UI tests can also be used to perform high level smoke testing of your functionality or regression packs. Try to write UI tests once the functionality gets more stable to avoid changes these frequently.

Whats next?

In the next post I will show you how to get started and provide you with a practical examples.

 

Summit EMEA Dublin 2018 – Call for Speakers

SummitEMEALogoRed

 

Summit EMEA is the User Group conference that brings Microsoft Dynamics 365, AX and CRM users, industry experts and software development vendors together to discuss important issues, to learn about product updates, and to find genuine solutions that suit your business needs.

The next event will take place in the Convention Centre Dublin between 24-26 April 2018.

This is a great opportunity to share your valuable knowledge and experience with the community. If you are not able to speak we also welcome your idea on what content you would be interested in seeing. You can submit your proposal to speak or ideas using our survey portal.

Please align your submission to one of the tracks below.

Please note deadline for submission is 30th Nov 2017.

Persona/Track Targeted Roles Track Intent
Power User CRM Administrator, CRM Project Owner, Business Analyst, IT Professional This track will help anyone new or responsible for their Dynamics 365/CRM deployment.  It will address topics featuring setup, security, relationships, data management, integration, workflow, optimization and overall best management practices to help those most responsible for managing their Dynamics 365/CRM environment.
Developer Developers, Application Engineers This track focuses on custom extensibility and code required modifications made to Dynamics 365/CRM.  Both beginner and advanced extensibility and developing concepts will be shared.
Customizer Experienced CRM Administrators, Project Owners, & IT Professional The track focuses on more intermediate to advanced topics to enable Dynamics 365/CRM to work for an organization.  Advanced configuration and no code customization topics will be shared, including the use of extended Microsoft cloud technologies that complement Dynamics 365/CRM.
Customer Engagement Service Leaders, Management, BDMs, CRM Project Owner, CRM Administrators, Business Analyst This track will exclusively focus on the role of all service use and customer engagement activities tied to customer, field, or project service within Microsoft Dynamics 365/CRM.  From case management, omni-channel support, or voice of the customer; this track will focus on everything customer care related.
Leadership BDMs, Sales, Service, Marketing Leaders & Management This track focuses on the promise of Dynamics 365/CRM for the business.  It will center around CRM buy-in, understanding the role of CRM for the organization, and collaboration with other departments & teams.  Content around change management, user adoption, and overall Dynamics 365/CRM customer success will be shared.
BI & Reporting Business Analyst, BDMs, CRM Administrator, Management, Business User The track features topics to view, dissect, & understand your CRM data.  Out of the box capabilities and other solutions (i.e. Power BI) will be shared to help companies get the most out of business intelligence when using Dynamics 365/CRM or related tools.

Finally registration is already open, would be great to see you at the event. You can register using this link.

Online Management PS Module for Dynamics 365 CE – Part 4 (Restore Instance)

In the previous post I have showed you how to delete an instance using the new Online Management PowerShell Module for Dynamics 365 Customer Engagement. In this post I will show how you can restore an instance from a previous backup.

Why would you want to restore a Dynamics 365 CE instance using PowerShell?

  1. You backup instances automatically as part of your automated release process. If the release fails you may want to automate the rollback procedure.
  2. You have a demo environment and you may want to automatically restore your environment to a previous state after the demo
  3. You want to automatically restore a backup of an environment to another environment. For example a backup of your stable development environment into a feature development environment or a backup or prod into a pre-prod testing environment.

Before you can restore an instance you will need the instance Id of the source and target instance. First the standard setup as per the first post where you will load the PS Module and define the ApiUrl and credentials. More details on this in my first post.

$ErrorActionPreference = "Stop"

Import-Module "C:\Dev\PowerShell\Microsoft.Xrm.OnlineManagementAPI\0.0.1.0\Microsoft.Xrm.OnlineManagementAPI.dll"

$Username = "user@domain.com"
$Password = "*****"
$ApiUrl = "https://admin.services.crm11.dynamics.com"

#Create Credentials
$SecPassword = ConvertTo-SecureString $Password -AsPlainText -Force
$Cred = New-Object System.Management.Automation.PSCredential ($Username, $SecPassword)

Next run this script to get a list of all instance along their details.

$instances = Get-CrmInstances -ApiUrl $ApiUrl -Credential $Cred
$instances

This should display all your instance as per below:

Id                        : ea30fded-8a7d-4891-a12a-58c16962dc46
UniqueName                : orgdb34d10e
Version                   : 9.0.0.2090
ApplicationUrl            : https://sourceinstance.crm11.dynamics.com/
ApiUrl                    : https://sourceinstance.api.crm11.dynamics.com
State                     : Ready
StateIsSupportedForDelete : True
AdminMode                 : False
Type                      : Production
Purpose                   : testingps
FriendlyName              : sourceinstance
DomainName                : sourceinstance
BaseLanguage              : 1033
InitialUserEmail          : ******
SecurityGroupId           : 27f6d70d-ca66-468f-bbf5-1959514bf597

Id                        : 273D535F-F341-4481-8C3D-72AC142B290C
UniqueName                : orgdb34d10e
Version                   : 9.0.0.2090
ApplicationUrl            : https://targetinstance.crm11.dynamics.com/
ApiUrl                    : https://targetinstance.api.crm11.dynamics.com
State                     : Ready
StateIsSupportedForDelete : True
AdminMode                 : False
Type                      : Production
Purpose                   : testingps
FriendlyName              : sourceinstance
DomainName                : sourceinstance
BaseLanguage              : 1033
InitialUserEmail          : ******
SecurityGroupId           : 27f6d70d-ca66-468f-bbf5-1959514bf597

Now you should have the Ids of both the source and target instance. Note in some cases these will be same if you are restoring to the same instance.

Next you will need the backup id of the source instance. To do this you can retrieve a list of backups using the script below.

$instanceBackups = Get-CrmInstanceBackups -ApiUrl $ApiUrl -Credential $Cred -InstanceId 'ea30fded-8a7d-4891-a12a-58c16962dc46'

$instanceBackups

This should output something like the below. Make note of the backup id.

Id                      : 4a810ecb-26ea-4fc9-bd97-27073d0c4153
Status                  : Available
CreatedBy               : Wael Hamze
CreatedOn               : 27/10/2017 20:47:01 +00:00
ExpiresOn               : 30/10/2017 20:47:01 +00:00
Version                 : 9.0.0.2090
Notes                   :
Label                   : PreRelease1
IsAzureBackup           : False
AzureStorageInformation : 

Now that you have all ids you are able to invoke the restore script.


$operation = Restore-CrmInstance -ApiUrl $ApiUrl -Credential $Cred -BackupId '4a810ecb-26ea-4fc9-bd97-27073d0c4153' -SourceInstanceId 'ea30fded-8a7d-4891-a12a-58c16962dc46' -TargetInstanceId '273D535F-F341-4481-8C3D-72AC142B290C'

As usual you can optionally wait for the restore operation to complete. I have uploaded a script to GitHub that will allow you restore an instance using the source and target instance name and also the backup label.

If you are using VSTS you can also use the Dynamics CRM Build Tools Extension to manage your Dynamics 365 CE instances.

Hope you found this series helpful.

Online Management PS Module for Dynamics 365 CE – Part 3 (Delete Instance)

In the previous post I have showed you how to provision a new instance using the new Online Management PowerShell Module for Dynamics 365 Customer Engagement. In this post I will show how you can query your instances and delete a specific instance.

Why would you want to delete a Dynamics 365 CE instance using PowerShell?

  1. You provision instances automatically as part of your automated build/release/test cycle. Once the testing is completed or before you start the next cycle you may want to delete the old instance
  2. You provision instances automatically for developers/teams to developer certain features and you may want to delete/refresh this instance when to starting to work on the next feature
  3. Your provision instance for any other reason and you want deleted automatically on a trigger or after a period of time

Before you can delete an instance you will need the instance Id. First the standard setup as per the first post where you will load the PS Module and define the ApiUrl and credentials. More details on this in my first post.

$ErrorActionPreference = "Stop"

Import-Module "C:\Dev\PowerShell\Microsoft.Xrm.OnlineManagementAPI\0.0.1.0\Microsoft.Xrm.OnlineManagementAPI.dll"

$Username = "user@domain.com"
$Password = "*****"
$ApiUrl = "https://admin.services.crm11.dynamics.com"

#Create Credentials
$SecPassword = ConvertTo-SecureString $Password -AsPlainText -Force
$Cred = New-Object System.Management.Automation.PSCredential ($Username, $SecPassword)

Next run this script to get a list of all instance along their details.

$instances = Get-CrmInstances -ApiUrl $ApiUrl -Credential $Cred
$instances

This should display all your instance as per below:

Id                        : 9dd50db3-8a9a-4c8b-94f7-50df38c50dc4
UniqueName                : org297aa972
Version                   : 9.0.0.2090
ApplicationUrl            : https://testingpowershell.crm11.dynamics.com/
ApiUrl                    : https://testingpowershell.api.crm11.dynamics.com
State                     : Ready
StateIsSupportedForDelete : True
AdminMode                 : False
Type                      : Sandbox
Purpose                   : Test PS...
FriendlyName              : testingpowershell
DomainName                : testingpowershell
BaseLanguage              : 1033
InitialUserEmail          : ******
SecurityGroupId           : 00000000-0000-0000-0000-000000000000

Now to delete an instance you can invoke the below script using the Id.

$operation = Remove-CrmInstance -ApiUrl $ApiUrl -Id '9dd50db3-8a9a-4c8b-94f7-50df38c50dc4' -Credential $Cred

$operation

This should return the operation status for the delete operation that will run in the background. You can optionally wait for this operation to complete.

OperationId       : af4a2672-6820-4ce4-a8e0-81c71da7b0b8
Status            : NotStarted
Errors            : {}
Information       : {}
OperationLocation : https://admin.services.crm11.dynamics.com/api/v1/Operation/af4a2672-6820-4ce4-a8e0-81c71da7b0b6
ResourceLocation  :
Context           : Microsoft.Xrm.Services.Admin.Client.Models.OperationContext

I have written a script that will allow you to delete an instance using its name and also give you the option to wait until the operation completes. You can find the script on GitHub.

Use this API with caution you you may not be able to recover the instance after if has been deleted.

If you are using VSTS you can also use the Dynamics CRM Build Tools Extension to manage your Dynamics 365 CE instances.

In the next post I will show you how you can restore an online instance from a previous backup.

Online Management PS Module for Dynamics 365 CE – Part 2 (Provision Instance)

In the previous post I have showed you how to get started with the new Online Management PowerShell Module for Dynamics 365 Customer Engagement. I covered how you can easily backup your instance.

In this post I will cover the provisioning new instances. One reason why you may want to do this is if you want to setup an automated process where you can automatically spin new a CRM instance as part of a build and deploy the latest configuration for functional, performance or load testing. You could also automate the process for provisioning instances for your users or developers. I am sure there are other reasons too.

Let’s get started, first the standard setup as per the previous post where you will load the PS Module and define the ApiUrl and credentials. More details on this in my previous post.

$ErrorActionPreference = "Stop"

Import-Module "C:\Dev\PowerShell\Microsoft.Xrm.OnlineManagementAPI\0.0.1.0\Microsoft.Xrm.OnlineManagementAPI.dll"

$Username = "user@domain.com"
$Password = "*****"
$ApiUrl = "https://admin.services.crm11.dynamics.com"

#Create Credentials
$SecPassword = ConvertTo-SecureString $Password -AsPlainText -Force
$Cred = New-Object System.Management.Automation.PSCredential ($Username, $SecPassword)

Next you will need define the currency of your new instance as per below. I am selecting GBP in this case.

$instanceCurrency = New-CrmInstanceInfo -CurrencyCode GBP -CurrencyName "Pound Sterling" -CurrencyPrecision 2 -CurrencySymbol "£"

If you are not sure which values you need or which values are supported, you can use the Cmdlet below to get a list of all currencies

$Currencies = Get-CrmCurrencys -ApiUrl $ApiUrl -Credential $Cred
Foreach($currencyList in $Currencies)
{
    Write-Host("RegionCode`t:" + $currencyList.RegionCode)
    Write-Host("Name`t:" + $currencyList.Name)
    Foreach($currency in $currencyList.Currencies)
    {
        $currency | Format-List
    }
}

You will get something similar to the below. As you can see there are lots of variations even for GBP.

RegionCode	:GB
Name	:United Kingdom

Code      : GBP
Precision : 2
Symbol    : £
Name      : Punt Sterling y DU

Code      : GBP
Precision : 2
Symbol    : £
Name      : Punnd Sasannach na RA

Code      : GBP
Precision : 2
Symbol    : £
Name      : Pound Sterling

Next you will need the serviceVersionId (Guid). This is Id of the Dynamics release that you want your instance to be based on. Again there is an Cmdlets which lists all of the available versions.

$serviceVersions = Get-CrmServiceVersions -ApiUrl $ApiUrl -Credential $Cred
$serviceVersions | Format-List

Depending on your tenant you may see more or less options listed. Below is a list from a .crm4 instance. I had only Dynamics 365 from a .crm11 instance.

LocalizedName : Dynamics 365
LCID          : 1033
Version       : 8.2
Id            : 31cafafe-c6b1-4c0a-bb53-73927841bc5c
Name          : Dynamics 365

LocalizedName : Microsoft Dynamics CRM Online 2016 Update 1
LCID          : 1033
Version       : 8.1
Id            : aaf5fa67-3f34-835d-85bb-6c8eb44aff8d
Name          : Microsoft Dynamics CRM Online 2016 Update 1

LocalizedName : Microsoft Dynamics CRM Online 2016
LCID          : 1033
Version       : 8.0
Id            : 015e6a5c-2fa5-e411-80ce-00155db07c21
Name          : Microsoft Dynamics CRM Online 2016

LocalizedName : Microsoft Dynamics CRM Online 2015 Update 1 (May 2015)
LCID          : 1033
Version       : 7.1
Id            : 9f2caf05-45b9-e411-80ec-6c3be5a88dd4
Name          : Microsoft Dynamics CRM Online 2015 Update 1 (May 2015)

In this case all we need is the (Guid) so lets go with “Dynamics 365” for now.

$releaseId = ’31cafafe-c6b1-4c0a-bb53-73927841bc5c’

Next you will need to set the language of your instance. For this you will need the integer language Id.

$languageId = 1033

If you are not sure on the language Id or the languages that are supported, again there is another Cmdlet for that.

$languages = Get-CrmLanguages -ApiUrl $ApiUrl -ServiceReleaseId $releaseId -Credential $Cred
$languages | Format-Table

Below is the list of languages available on my instance.

LCID Name                                LocalizedName
---- ----                                -------------
1033 English                             English (United States)
1025 Arabic                              العربية (المملكة العربية السعودية)
1069 euskara (euskara)                   euskara (euskara)
1026 български (България)                български (България)
1027 Català (Català)                     Català (Català)
3076 Chinese (Hong Kong S.A.R.)          中文(香港特別行政區)
2052 Chinese (PRC)                       中文(中华人民共和国)
1028 Chinese (Taiwan)                    中文(台灣)
1050 hrvatski (Hrvatska)                 hrvatski (Hrvatska)
1029 Czech                               čeština (Česká republika)
1030 Danish                              dansk (Danmark)
1043 Dutch                               Nederlands (Nederland)
1061 eesti (Eesti)                       eesti (Eesti)
1035 Finnish                             suomi (Suomi)
1036 French                              français (France)
1110 galego (galego)                     galego (galego)
1031 German                              Deutsch (Deutschland)
1032 Greek                               Ελληνικά (Ελλάδα)
1037 Hebrew                              עברית (ישראל)
1081 हिंदी (भारत)                        हिंदी (भारत)
1038 Hungarian                           magyar (Magyarország)
1040 Italian                             italiano (Italia)
1041 Japanese                            日本語 (日本)
1087 Қазақ (Қазақстан)                   Қазақ (Қазақстан)
1042 Korean                              한국어(대한민국)
1062 latviešu (Latvija)                  latviešu (Latvija)
1063 lietuvių (Lietuva)                  lietuvių (Lietuva)
1044 Norwegian (Bokmål)                  norsk, bokmål (Norge)
1045 Polish                              polski (Polska)
1046 Portuguese (Brazil)                 português (Brasil)
2070 Portuguese (Portugal)               português (Portugal)
1048 română (România)                    română (România)
1049 Russian                             русский (Россия)
2074 srpski (Srbija i Crna Gora (Bivša)) srpski (Srbija i Crna Gora (Bivša))
1051 slovenčina (Slovenská republika)    slovenčina (Slovenská republika)
1060 slovenščina (Slovenija)             slovenščina (Slovenija)
3082 Spanish                             español (España, alfabetización internacional)
1053 Swedish                             svenska (Sverige)
1054 Thai                                ไทย (ไทย)
1055 Turkish                             Türkçe (Türkiye)
1058 українська (Україна)                українська (Україна)
3098 Serbian (Cyrillic)                  српски (Србија и Црна Гора (Бивша))
1086 Malay                               Bahasa Melayu (Malaysia)

Now you will need to select the templates that you need to apply on your instance. These are the different modules that you can install on your instance such as Sales or Customer Service. In this case I will select the Sales and Customer Service.

$templateNames = "D365_Sales", "D365_CustomerService"

If you are not sure on what are the different values and what is supported on your tenant, you can use the Cmdlet below to get a list of supported templates.

$templates = Get-CrmTemplates -ApiUrl $ApiUrl -Credential $Cred
$templates | Format-List

Below is a list of templates currently available in my tenant which is the output from the script above.

Name                     : D365_Sales
LocalizedName            : Sales
LocalizedDescription     : Manage leads, close deals and accomplish more.
SupportedServiceVersions : {bce9abbf-90fd-42e7-b0e5-1ced6df22fa1, 31cafafe-c6b1-4c0a-bb53-73927841bc5c}

Name                     : D365_CustomerService
LocalizedName            : Customer service
LocalizedDescription     : Resolve cases quickly and deliver amazing customer service.
SupportedServiceVersions : {bce9abbf-90fd-42e7-b0e5-1ced6df22fa1, 31cafafe-c6b1-4c0a-bb53-73927841bc5c}

Name                     : D365_FieldService
LocalizedName            : Field service
LocalizedDescription     : Optimize onsite customer care.
SupportedServiceVersions : {bce9abbf-90fd-42e7-b0e5-1ced6df22fa1, 31cafafe-c6b1-4c0a-bb53-73927841bc5c}

Name                     : D365_ProjectServiceAutomation
LocalizedName            : Project service automation
LocalizedDescription     : Complete projects on time and within budget.
SupportedServiceVersions : {bce9abbf-90fd-42e7-b0e5-1ced6df22fa1, 31cafafe-c6b1-4c0a-bb53-73927841bc5c}

Now that we have all the different parameters we can create an instance, we need to create a new instance object with the values as per below. The domain name is the name that will appear in the url (i.e. https://%5Bdomainname%5D.crm4.dynamics.com). Instance type will be one of: Production, Sandbox, Support, Preview, Trial


$instanceInfo = New-CrmInstanceInfo -BaseLanguage $languageId -DomainName "<span 				data-mce-type="bookmark" 				id="mce_SELREST_start" 				data-mce-style="overflow:hidden;line-height:0" 				style="overflow:hidden;line-height:0" 			></span>testpowershell<span 				data-mce-type="bookmark" 				id="mce_SELREST_end" 				data-mce-style="overflow:hidden;line-height:0" 				style="overflow:hidden;line-height:0" 			></span>" -FriendlyName "Test PowerShell" -InitialUserEmail "user@domain.com" -InstanceType "Sandbox" -ServiceVersionId $releaseId -Purpose "Testing PowerShell" -TemplateList $templateNames

Finally You need to call the Cmdlet to create your new instance. You will get the OperationId back along with the status including errors if any. You can use the OperationId query the status of creation operation and possibly wait until it completes. This can be as quick as a few seconds. In most cases the operation seems to return immediately which status of “Succeeded”.

$operation = New-CrmInstance -ApiUrl $ApiUrl -NewInstanceInfo $instanceInfo -Credential $Cred

$OperationId = $operation.OperationId
$OperationStatus = $operation.Status

You should now be able to view the instance in the admin portal.

InstanceCreated

I have published a simple script on GitHub which encapsulates all of this functionality and you can view it here.

If you are using VSTS you can also use the Dynamics CRM Build Tools Extension to manage your Dynamics 365 CE instances.

If you need more information on creating instances you can visit the API documentation here. In the next post I will show you how to view your instance and also delete specific instances.