The specified module ‘MSAL.PS’ was not loaded because no valid module file was found in any module directory.

Recently when I used Dynamics 365 Finance and Operation tools plugin for Azure Devops I faced an issue with a missing Powershell module.

Error message:

##[error]The specified module 'MSAL.PS' was not loaded because no valid module file was found in any module directory.

In order to bypass this issue, add a PowerShell step with the below commands:

Set-PSRepository PSGallery -InstallationPolicy Trusted
Install-Module MSAL.PS
Import-Module MSAL.PS

Your final pipeline should look like the one below.

An additional issue you may face, could relate with the service connection authentication endpoint. The error indicates that the common endpoint cannot be used and the specific tenant-endpoint should be used instead.

##[error]AADSTS9001023: The grant type is not supported over the /common or /consumers endpoints. Please use the /organizations or tenant-specific endpoint.

Go and edit your service connection details

Endpoint URL:

https://login.microsoftonline.com/organizations

Be sure that your user has sufficient privileges and that prerequisites are met as documented from Microsoft.

LCS doesn’t support service-to-service authentication. Therefore, only regular user credentials (that is, a user name and password) can be used. Because the pipelines don’t run interactively, multifactor authentication must not be set up for the account that you use. We recommend that you set up a separate user account that has limited access and strong credentials that can regularly be rotated for security purposes.

Create an LCS connection in Azure Pipelines

https://docs.microsoft.com/en-us/dynamics365/fin-ops-core/dev-itpro/dev-tools/pipeline-lcs-connection

Trigger Azure Devops build pipelines using REST API

In some cases you may need to schedule pipelines execution on nights but the schedules yaml feature cannot accomplish your needs. This could could happen if you have to provide parameters as inputs on the pipelines for a specific project export/import. In this case you could trigger your pipelines with REST APIs using ansible or another scripting tool.

In this article I will explain how you could trigger pipelines execution using the REST API of Azure Devops.

First things first you should create a personal access Token (PAT) in order to get the access required to run the pipelines on your organization. You can accomplish that by pressing your profile icon and selecting the sub-menu shown below.

You can specify the expiration of the token along with the access permissions. For the simplicity of deployment I gave it full access. You will need to copy the token somewhere as it will not be accessible after the creation.

In order to trigger a new build we would have to use the POST HTTP verb. Along with that we will need the repository name, the project name and the build pipeline ID. The below URL uses build API of version 6.1-preview.6 with the parameters

Organization: GeralexGR
Project: test-project

https://dev.azure.com/GeralexGR/test-project/_apis/build/builds?api-version=6.1-preview.6

Using CURL we can get information of runs for a specific pipeline. For example in order to get the latest runs for pipeline with ID:11. In the below example you should replace PAT with your provisioned personal access token.

curl  --user '':'PAT' --header "Content-Type: application/json" --header "Accept:application/json" https://dev.azure.com/GeralexGR/test-project/_apis/pipelines/11/runs?api-version=6.1-preview.1

In order to implement a run of a build pipeline using REST APIs I will use Postman.

The selected verb is POST and the URL is the one mentioned above. By giving the URL on the input field, POSTMAN will automatically enumerate Query parameters.

In Authorization tab you should select Basic Auth. The username can be empty and the password will be your PAT.

On Headers tab, add Content-Type as application/json

In the body, you should specify the build pipeline ID in the JSON format that is shown in the picture. If you press Send, you will successful trigger your build pipeline with ID 11.

The next step is to edit the pipeline to include also input parameters.

In order to do that, I will use the latest version of the REST API that uses the runs URL instead of builds.

As shown in the picture the request URL will be pipelines/buildID/runs

https://dev.azure.com/GeralexGR/test-project/_apis/pipelines/11/runs?&api-version=6.1-preview.1

The logic of the pipeline will only print the parameters that has been provided as input on the REST API.

trigger:
- none

pr: none 

pool:
  vmImage: ubuntu-latest

parameters:
  - name: name
    displayName: Tell me your name.
    type: string
    
steps:
- script: echo ${{parameters.name}} "succesfully triggered this build from a REST API call"
  displayName: 'print message from automatically created pipeline'

You can see in the result that my name is printed.

Azure Devops Rest API documentation:

https://docs.microsoft.com/en-us/rest/api/azure/devops/pipelines/runs/run-pipeline?view=azure-devops-rest-6.0

Youtube video:

Pass parameters from build to release pipelines on Azure devops

When you need to pass parameters between your build and release pipelines it could be a real struggle if you do not want to use variable groups. Variable groups can accomplish the requested (to pass values between build and release pipelines) but this scenario is not useful for a parametric input which is a common case when deploying a project. You can accomplish that either by using a plugin from another publisher or by following the publish artifacts procedure that I will describe.

In order to pass variables between your build and release pipelines you can create/export a file containing your variable on your build agent. This file should be exported as build artifact and then downloaded on the release pipeline.

The below build pipeline implements the functionality I described. The exported file is named projectname.txt and will be located on artifacts folder on your build agent inside folder drop. For example C:\agent\1\a\drop

trigger:
- dev

pool:
  vmImage: windows-latest

parameters:
  - name: powerenvironment
    displayName: Where to deploy?
    type: string

steps:

- task: PowerShell@2
  inputs:
    targetType: 'inline'
    script: |
      $variable = '${{parameters.powerenvironment}}'
      $variable | Out-File $(Build.ArtifactStagingDirectory)\projectname.txt
      Get-Content $(Build.ArtifactStagingDirectory)\projectname.txt

- task: PublishBuildArtifacts@1
  inputs:
    PathtoPublish: '$(Build.ArtifactStagingDirectory)'
    ArtifactName: 'drop'
    publishLocation: 'Container'

When you run the pipeline you will be asked for a parameter. I gave this entry my name which will be passed on release.

My release pipeline will download the build artifacts and get the value of the file. The release pipeline includes two steps.

The first one downloads the folder drop from build artifacts. The projectname.txt is located there.

Then the powershell will print the contents of the projectname.txt

You can check the result and verify you get the parameter input value from the powershell script.

Bonus content:

You can also write your input parameter as a variable on the build agent and reference this value on a later step. This should be again a powershell step on your release pipeline.

$myVariable = "ProjectName";
$myValue = Get-Content $(System.ArtifactsDirectory)/drop/projectname.txt;

Write-Host "##vso[task.setvariable variable=ProjectName]($myValue)";

Lastly create a dump archive step to reference the input parameter from the build pipeline.

In order to test, use in the archive path the ProjectName variable.

Run the pipeline and verify that input parameter is correct (I used gerasimos).

Youtube video:

Connect to power platform – Azure Devops pipelines

In this article I will explain how to create a Power platform environment and connect on it through Azure Devops pipelines. Power platform is a low code environment provided by Microsoft that can implement services and functionality quickly with a GUI.

In order to follow the tutorial you will need an Azure subscription and a power platform subscription which will be connected.

First things first, you should create a power platform environment. You can do this, by logging in the Power Platform admin center and pressing the New button.

Then you should select the type and region and also the database connection. I chose a sample database so that I get automatically data to test.

By choosing the trial subscription the environment only works for 30 days. This is good enough for the purposes of this article but not for production environments. After the provision of the environment you will get the environment URL and also some sessions details that will be needed for Azure devops.

You can find the sessions details on the right upper corner.

The you will need to create an app registration on your Azure subscription.

Press New registration

Give a name and select which accounts could access this application.

After the provision of the application, you will have to set the API permissions. Select Dynamics CRM -> User impersonation

Then you will have to create a secret for the application. Go to certificates and secrets and create a new client secret. Copy the value, as it will be needed later.

On Azure Devops you should create a service connection. Go to project settings -> Service connections and add a new connection. Select power platform on the connection type.

You should then add the connection details gathered on previous steps. Client secret and application ID from the Azure application that you created. The server URL and tenant ID can be gathered from power platform admin center.

Then go and create a new Pipeline on Azure Devops and add the below two steps. The power platform tools installer is required any time you want to connect on power platform. This will instruct the build agent to download the necessary tools for the deployment. The WhoAmI task will authenticate with the instance and verify if the connection is working.

Edit the WhoAmI step and include the service connection

Check the result of the task, as it should be successful (Green)