Deploy plugins / workflows assemblies with Powershell


 

Context

When you work on a new plugin, you need to deploy it multiple time to get the expected behavior regarding customer need.
But, using Registration Tool multiple time per day represent an optimisable workload considering manual operations and also the risk of human error.
So I have made a little script that scan the binaries folder in output of Visual Studio compilation and update the existing CRM assemblies.

Prerequisites

The script couldn’t run properly without the following criterias:

  1. CRM user specified in configuration file need to be system administrator (update assembly)
  2. You should provide an Assembliesfolder that contains
    1. CRM SDK assemblies :
      1. Microsoft.Xrm.Sdk.dll
      2. Microsoft.Xrm.Client.dll
      3. Microsoft.Crm.Sdk.Proxy.dll
  3. Script must be run with elevated privilèges

 

Process

  1. Scan assembly folder given in parameter
  2. Check if assembly need to be updated (regarding configuration : name and configuration)
  3. Update assembly
  4. Deploy debug symbols (pdb) to configured folder

Configuration

The script use a configuration.xml file that provide the following parameters :

 1: <Configuration>
 2:     <CrmConnectionString>Url=http://crm/dev</CrmConnectionString>
 3:     <Assemblies>
 4:         <Path>c:\MCS\Assemblies</Path>
 5:         <Configuration>debug</Configuration>
 6:         <Names>Plugins.dll;Workflows.dll;</Names>
 7:         <SymbolPath>\\crmsrv\C$\Program Files\Microsoft Dynamics CRM\Server\bin\assembly</SymbolPath>
 8:     </Assemblies>
 9: </Configuration>
  • CrmConnectionString : Connection to CRM organization (More info :https://msdn.microsoft.com/en-us/library/gg695810.aspx)
  • Assemblies
    • Path : Folder where assemblies are outputed
    • Configuration : Specify if assemblies are build in “debug” or “release”
    • Names : Names of the assemblies to update ‘'(separated with semi-colon ‘;’)
    • SymbolPath : Folder where to copy pdb files for debug purposes

Script

 1: clear;
 2:  
 3: function Add-Crm-Sdk
 4: {
 5:     # Load SDK assemblies
 6:     Add-Type -Path "$PSScriptRoot\Assemblies\Microsoft.Xrm.Sdk.dll";
 7:     Add-Type -Path "$PSScriptRoot\Assemblies\Microsoft.Xrm.Client.dll";
 8:     Add-Type -Path "$PSScriptRoot\Assemblies\Microsoft.Crm.Sdk.Proxy.dll";
 9: }
 10:  
 11: function Get-Configuration()
 12: {
 13:     $configFilePath = "$PSScriptRoot\Configuration.xml";
 14:     $content = Get-Content $configFilePath;
 15:     return $content;
 16: }
 17:  
 18:  
 19: function Get-Assembly
 20: {
 21:      PARAM
 22:     (
 23:         [parameter(Mandatory=$true)]$name,
 24:         [parameter(Mandatory=$true)]$orgService
 25:     )
 26:  
 27:     $query = New-Object -TypeName Microsoft.Xrm.Sdk.Query.QueryExpression -ArgumentList "pluginassembly";
 28:     $query.Criteria.AddCondition("name", [Microsoft.Xrm.Sdk.Query.ConditionOperator]::Equal, $name);
 29:     $query.ColumnSet =  New-Object -TypeName Microsoft.Xrm.Sdk.Query.ColumnSet -ArgumentList $true;
 30:     $results = $orgService.RetrieveMultiple($query);
 31:     $records = $results.Entities;
 32:  
 33:     if($records.Count -eq 1)
 34:     {
 35:         return $records[0];
 36:     }
 37:     return $null;
 38: }
 39:  
 40: function Get-Base64
 41: {
 42:     PARAM
 43:     (
 44:         [parameter(Mandatory=$true)]$path
 45:     )
 46:     
 47:     $content = [System.IO.File]::ReadAllBytes($path);
 48:     $content64 = [System.Convert]::ToBase64String($content);
 49:     return $content64;
 50: }
 51:  
 52: Add-Crm-Sdk;
 53: $config = Get-Configuration;
 54:  
 55: # =======================================================
 56: # Crm Connection
 57: # =======================================================
 58: $crmConnectionString = $config.Configuration.CrmConnectionString;
 59: $crmConnection = [Microsoft.Xrm.Client.CrmConnection]::Parse($crmConnectionString);
 60: $service = New-Object -TypeName Microsoft.Xrm.Client.Services.OrganizationService -ArgumentList $crmConnection;
 61:  
 62: $assembliesPath = $config.Configuration.Assemblies.Path;
 63: $assemblyConfiguration = $config.Configuration.Assemblies.Configuration.ToLower();
 64: $assembliesToDeploy = $config.Configuration.Assemblies.Names.Split(";", [StringSplitOptions]::RemoveEmptyEntries);
 65:  
 66:  
 67: # =======================================================
 68: # Process assemblies
 69: # =======================================================
 70: $d = Get-Date;
 71: Write-Host "$d - Deploy Assemblies ($assemblyConfiguration) start" -ForegroundColor Cyan;
 72:  
 73: $assemblies = Get-ChildItem $assembliesPath -recurse -include *.dll;
 74: $assemblies | ForEach-Object {        
 75:     $assemblyPath = $_.FullName.ToString();
 76:     $assemblyName = $_.Name.ToString();
 77:         
 78:     if($assemblyPath.Contains("bin") -and $assemblyPath.ToLower().Contains($assemblyConfiguration))
 79:     {
 80:         foreach($assemblyToDeploy in $assembliesToDeploy)
 81:         {
 82:             if($assemblyName -eq $assemblyToDeploy)
 83:             {        
 84:                 Write-Host " - Deploying assembly $assemblyPath ...";
 85:                 
 86:                 $assemblyFile = [System.Reflection.Assembly]::LoadFile($assemblyPath);
 87:                 $assemblyProperties = $assemblyFile.GetName().FullName.Split(",= ".ToCharArray(), [StringSplitOptions]::RemoveEmptyEntries);
 88:                 $assemblyShortName = $assemblyProperties[0];
 89:                 $assemblyFile = $null;
 90:  
 91:                 $assemblyContent = Get-Base64 $assemblyPath;
 92:  
 93:                 Write-Host " > Searching assembly $assemblyShortName ..." -NoNewline;
 94:                 $crmAssembly = Get-Assembly -name $assemblyShortName -orgService $service;
 95:                 if ($crmAssembly -eq $null)
 96:                 {
 97:                     Write-Host "not found!" -ForegroundColor Red; 
 98:                     continue;
 99:                 }
 100:                 else
 101:                 {    
 102:                     Write-Host "found!" -ForegroundColor Green; 
 103:                 }
 104:  
 105:                 $crmAssembly["version"] = $assemblyProperties[2];
 106:                 $crmAssembly["culture"] = $assemblyProperties[4];
 107:                 $crmAssembly["publickeytoken"] = $assemblyProperties[6];
 108:                 $crmAssembly["content"] = $assemblyContent;
 109:  
 110:                 Write-Host " > Updating assembly $assemblyShortName ..." -NoNewline;
 111:                 try
 112:                 {
 113:                     $service.Update($crmAssembly);
 114:                 }
 115:                 catch [Exception]
 116:                 {
 117:                     Write-Host "failed! [Error : $_.Exception]" -ForegroundColor Red;
 118:                     break;
 119:                 }
 120:                 $assemblyFile = $null;
 121:                 
 122:                 Write-Host "done!" -ForegroundColor Green; 
 123:                 break;
 124:             }
 125:         }
 126:     }
 127: }
 128:  
 129: # =======================================================
 130: # Deploy PDB
 131: # =======================================================
 132:  
 133: Write-Host "";
 134:  
 135: $debugFolder = $config.Configuration.Assemblies.SymbolPath;
 136:  
 137: if(![string]::IsNullOrEmpty($debugFolder))
 138: {
 139:     $debugFiles = Get-ChildItem $assembliesPath -recurse -include *.pdb;
 140:     $debugFiles | ForEach-Object {  
 141:         $debugFilePath = $_.FullName.ToString();
 142:         $debugFileName = $_.Name.ToString();
 143:         if($debugFilePath.Contains("bin") -and $debugFilePath.Contains("$assemblyConfiguration"))
 144:         {
 145:             Write-Host " - Deploying pdb $debugFilePath to $debugFolder ..." -NoNewLine;
 146:             Copy-Item $debugFilePath -Destination $debugFolder -Force;
 147:             Write-Host -ForegroundColor Green "Done!";
 148:         }
 149:     }
 150: }
 151: $d = Get-Date;
 152: Write-Host "$d - Deploy Assemblies ($assemblyConfiguration) stop" -ForegroundColor Cyan;
 153:  
 154: $d = Get-Date;
 155: Write-Host "$d - Deploy assemblies stop" -ForegroundColor Cyan;

Download full script

Comments (4)

  1. Anonymous says:

    Your "Download full script" button is pointing to the wrong script.

  2. Oups .. Thanks Nicolas, that should be ok now!

  3. Thanks a lot Aymeric :-) says:

    Great article as usual !!!

  4. Col says:

    Nice script that saves me having to do the laborious plugin deployment dance, thanks.

    I had to remove the ToLower() on the configuration as my configuration path is ‘Debug’ not ‘debug’.

Skip to main content