Enable additional language in CDS with Azure DevOps Pipelines

In this blog post, you will learn how to enable additional languages in your CDS environment with Azure DevOps pipelines.

This post can be considered the second post in a series of blog posts that talk about different approaches to solve challenges with Azure DevOps Pipelines that cannot be solved with the Power Platform Build Tools. The first blog post in that series explained how one could create its own application to solve a problem.


In one of my earlier blog-posts, I described how to set up a Basic ALM Process. This process uses a JIT (Just-In-Time) environment to build the managed solutions. The general idea is to create the environment whenever you would like to create your managed solutions (right before deployment to the first environment which is not development). This is done to get rid of old stuff and minimize dependencies. There are some issues with that approach. Just to mention some of them:

  • Generating an environment from scratch takes a lot of time.
  • Installing ISV solutions could be complicated. Especially when there are manual install steps.
  • The new Connection References in Power Automate flows require a manual step when they get installed the first time.
  • If you have Early Access installed in your other environments the JIT-Build environment needs that too.
  • If you have different languages in your solution you must enable them as well.

What we ended up within one of our projects is to recreate the JIT environment whenever we have deployed to prod. This means that we reuse the same environment between two releases. After that, we delete the JIT environment and recreate it, to get rid of leftovers (old stuff that was not cleaned up since the JIT environment is unmanaged) and minimize dependencies.

The goal is to automate the process of recreating the JIT environment as much as possible.


This blog post tackles the above-mentioned language problem.

Let’s assume your implementation is using more than one language. If you create a JIT environment automatically you have to enable all the needed languages. Otherwise, your translation will be lost in the process of creating managed solutions.

Let’s see how we can automate the process of installing/enabling an additional language in your environment.


Like always there several solutions that could fix that problem

  • One could execute this step manually
  • One could write a small application that does that
  • One could use a PowerShell Module

As mentioned earlier: One of my previous blog posts describes the solution of creating a small application.

In this post, we will look at the last option – A PowerShell Module. We will use the Module “Microsoft.Xrm.Data.PowerShell” by Sean McNellis.

A big thank you to David Rivard for showing me the Module and how to use it.

Let’s dive into the solution.

PowerShell script

First, we have to create a PowerShell script that will do all our work and will be stored in our repository.

To do so we create a file called “EnableLanguage.ps1” and save it somewhere in your repository there it makes sense. For me I choose to create a folder called “Tools\PowerShell” as the location.


The first part of the file will be the parameters we need.

The script will take the connection string as well as the Language Code ID (LCID)


Install Module

As the second step we have to install the mentioned PowerShell module.

Write-Output "Installing http://Microsoft.Xrm.Data.PowerShell"
Install-Module Microsoft.Xrm.Data.PowerShell -Scope CurrentUser -Force

Generate connection

Third step is to create a connection to our environment.

Write-Output "Connecting to CDS"
$conn = Get-CrmConnection -Verbose -ConnectionString "$($connectionstring)"

Enable Language

The final step is to enable the language.

Write-Output "Enable Language"
Enable-CrmLanguagePack -conn $conn -LCID $($languageId)

This step will get a timeout since the installation/enabling of a language is a long-running process. But after between 30 min and an hour, the language will be enabled anyway.

Complete file

Here is the complete file we created

Write-Output "Installing http://Microsoft.Xrm.Data.PowerShell"
Install-Module Microsoft.Xrm.Data.PowerShell -Scope CurrentUser -Force
Write-Output "Connecting to CDS"
$conn = Get-CrmConnection -Verbose -ConnectionString "$($connectionstring)"
Write-Output "Enable Language"
Enable-CrmLanguagePack -conn $conn -LCID $($languageId)


After we created the PowerShell script and stored it in our repository, we have to call this script in a pipeline.

For the ease of this article, I will use a blank pipeline that only will execute our needed step.


We need the following variables:


This variable contains the LCID of the language we would like to install. By checking the checkbox “Settable at release time” we are able to choose the solution for every release.


This variable will contain only the password of the user you are using. It is important to check the little lock so that DevOps knows that it contains a password. If this is checked DevOps will not show the content or write the content in logs.


This variable should contain the connection string to your org, with the password as an Azure DevOps parameter. It should look something like the following.

Url=https://<your org>.crm<region>.dynamics.com/;Username=<your Username>;AuthType=Office365;RequireNewInstance=True;Password=$(password)
Pipeline parameters
Pipeline parameters


The actual pipeline/tasks are quite easy. We only need one step to achieve our goal.

PowerShell Script

The only step, as mentioned, is a PowerShell Script step. First we chose the path to our PowerShell Script via the file chooser on the right side. In our demo the path looks like this:


For the argument we choose the string below (including the quotation marks)

-connectionstring "$(connection)" -languageId $(language)

If you have worked with pipelines earlier, you will notice that this syntax shows that we use the variables we configured earlier.

As mentioned we will get a timeout but don’t want the pipeline to fail because of that, we choose “Continue” as the “ErrorActionPreference” and “Continue on error” under “Control Options”

Adding PowerShell Scrpt step
Adding PowerShell Scrpt step
Complete pipeline
Complete pipeline


As you can see this is an easy solution to one of the problems one has with the JIT environment.

Since it takes time until a language is enabled it’s a good approach to automate this process and maybe run it in the night.

I hope this article helped you. Feel free to contact me if you have any questions. I am happy to help.

This is just 1 of 60 articles. You can browse through all of them by going to the main page. Another possibility is to view the categories page to find more related content.
You can also subscribe and get new blog posts emailed to you directly.
Enter your email address to receive notifications of new posts by email.


Add a Comment

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