Update Plugin Assembly dll iin Power Platform using Powershell

Keeping plugin assemblies updated in Dynamics CRM or Power Platform is crucial for maintaining constant functionality. Often Developers update the plugin assembly using the plugin registration tool individually. But we should need to mechanism that should buy the plugin and update it in Dynamics based on the source code in the Remote Repository. This blog post presents a PowerShell script that fetches a plugin assembly from a local or remote repository and updates it in Dynamics CRM using Powershell. This Powershell can be integrated with the DevOps Pipeline as well.

Prerequisites

Before running the script, ensure you have,

  1. PowerShell installed on your machine or pipeline agent.
  2. The Microsoft.Xrm.Data.Powershell module.
  3. Proper permissions to access and update the Dynamics CRM environment.
  4. Azure DevOps setup for running the pipeline.

Current Difficulties with Using the Plugin Registration Tool

  1. Manual Process: Time-consuming and prone to human error with repetitive tasks.
  2. Lack of Automation: No native CI/CD integration, requiring manual testing and deployment.
  3. Version Control Issues: Difficult to track and manage plugin versions, complicating rollbacks.
  4. Environment Consistency: Challenging to maintain consistency across multiple environments manually.

PowerShell Script for Updating the Plugin Assembly

Below is the PowerShell script that will be used in the DevOps pipeline to update the plugin assembly.

param(
  [Parameter(Mandatory = $true)]
  [String]$URL,
  [Parameter(Mandatory = $true)]
  [String]$ClientId,
  [Parameter(Mandatory = $true)]
  [String]$ClientSecret,
  [Parameter(Mandatory = $true)]
  [String]$TenantId,
  [Parameter(Mandatory = $true)]
  [String]$Assembly
)

# Install Modules
function InstallModules {
  Set-ExecutionPolicy -ExecutionPolicy Unrestricted -Force -Scope CurrentUser
  $module = Get-InstalledModule -Name "Microsoft.Xrm.Data.Powershell" -ErrorAction SilentlyContinue -WarningAction SilentlyContinue
  if ($module -ne $null) {
    Write-Host "Module - Microsoft.Xrm.Data.Powershell is Already Installed"
    $Details = $module | Format-Table -Wrap
    Write-Host $Details
  } else {
    Write-Host "Module is not installed, Installing Module 'Microsoft.Xrm.Data.Powershell'..."
    Install-Module -Name Microsoft.Xrm.Data.Powershell -Force -Scope CurrentUser 
    Write-Host "Module Installed"
  }
}

# Get Connection
function CRMConnection {
  Write-Host "Getting CRM Connection"
  $conn = Get-CrmConnection -ConnectionString "Url=$URL;AuthType=ClientSecret;ClientId=$ClientId;ClientSecret=$ClientSecret"
  return $conn
}

# Install Modules
InstallModules
$conn = CRMConnection

if ($conn -eq $null) {
  Write-Host "Connection Failed"
  break
} else {
  Write-Host "Connection Successful"
}

# Assembly Location
Write-Host "Assembly: $Assembly"

# Get the File Info of Assembly dll
$fileInfo = ([System.IO.FileInfo]$Assembly)
Write-Host "File Info: $fileInfo"

if (!$fileInfo.Exists) {
  Write-Error "Cannot find the plugin assembly on disk: $Assembly"
}

# Get Plugin Assembly in bytes
$bytes = [System.IO.File]::ReadAllBytes($fileInfo.FullName)

# Get File name without Extension
$filenameWithoutExt = [System.IO.Path]::GetFileNameWithoutExtension($fileInfo.Name)
Write-Host "File Name without Extension: $filenameWithoutExt"

# Fetch the Plugin Assembly
$fetch = "<fetch><entity name='pluginassembly'><filter><condition attribute='name' operator='eq' value='$filenameWithoutExt'/></filter></entity></fetch>"

$result = Get-CrmRecordsByFetch -conn $conn -Fetch $fetch -TopCount 1
$entity = $result.CrmRecords[0]

if (!$entity) {
  Write-Host "Cannot find the plugin assembly in D365..."
} else {
  Write-Host "Plugin Assembly Already Registered in D365"
  # Update the plugin assembly in D365
  $entity.content = [Convert]::ToBase64String($bytes)
  Write-Host "Updating the plugin assembly..."
  Set-CrmRecord -conn $conn -CrmRecord $entity
  Write-Host "Updated the plugin assembly!"
}

Explanation of the Script

Parameters

  • URL: The URL of your Dynamics CRM environment.
  • ClientId: The Client ID used for authentication.
  • ClientSecret: The Client Secret is used for authentication.
  • TenantId: The Tenant ID of your Azure Active Directory.
  • Assembly: The file path to the plugin assembly DLL.

InstallModules Function

  • Sets the execution policy to unrestricted for the current user to ensure the script can run.
  • Checks if the Microsoft.Xrm.Data.The Powershell module is already installed.
  • Installs the module if not already present.

CRMConnection Function

  • Establishes a connection to the Dynamics CRM environment using the provided connection parameters.

Main Script

  • Calls the InstallModules function to ensure the necessary PowerShell module is installed.
  • Establishes a connection to Dynamics CRM using the CRMConnection function.
  • Validates the connection and stops the script if the connection fails.
  • Check if the specified plugin assembly file exists on disk.
  • Reads the plugin assembly file into a byte array.
  • Extracts the file name without its extension.
  • Fetches the existing plugin assembly record from Dynamics CRM using the file name.
  • Updates the content with the new byte array and commits the changes to Dynamics CRM if the plugin assembly is found.

This PowerShell Script will output.

Powershell script

Integrating with Azure DevOps Pipeline

You can integrate this script into an Azure DevOps pipeline to automate the process of updating the plugin assembly. Here’s an example of YAML configuration for the pipeline.

trigger:
- main

pool:
  vmImage: 'windows-latest'

variables:
  D365URL: '<https://your-crm-url>'
  D365ClientId: '<your-client-id>'
  D365ClientSecret: '<your-client-secret>'
  TenantId: '<your-tenant-id>'
  Plugindll: '<path-to-your-assembly-dll>'

steps:
- task: PowerShell@2
  displayName: 'PowerShell - Update Plugin Assembly'
  inputs:
      filePath: 'scripts/Update-PluginAssembly.ps1'
      arguments: '-URL ''$(D365DevUrl)'' -ClientId ''$(D365ClientId)'' -ClientSecret ''$(D365ClientSecret)''  -TenantId ''$(TenantId)''-Assembly ''$(Build.BinariesDirectory)\$(buildConfiguration)\$(BuildFolder)\$(Plugindll)'''

Advantages

  1. Automation: Automates the process of updating plugin assemblies, reducing manual effort and potential errors.
  2. Reusability: The script can be reused across different environments and assemblies by changing the parameter values.
  3. Scalability: This can be integrated into CI/CD pipelines for continuous deployment, ensuring that plugin assemblies are always current.

By following this guide and using the provided script, you can efficiently update your plugin assemblies in Dynamics CRM or Power Platform, ensuring your customizations are always up to date and functioning correctly.