Getting the CRM Service Client in PowerShell

Code Vanguard has built out several Dynamics-centered build and release pipelines for various projects in service to the federal government. A lot of our build and release process is around normalizing these environments. Since production data lives on these instances, its not so easy as to just reset them. Thus, we’ve built out a whole set of automated actions that we can use on release to bring them back into conformity.

The first steps in all of these scripts is to download the CRM Core Tools library and create a connection with the target CRM instance. This allows for us to push our configuration values down to our environments quickly and repeatably. To achieve this, we use the CRM service client class to build a connection to the CRM instance. Below, we will be outlining the PowerShell scripts we use to create this connection.

Getting the CRM Core Tools Library

The first step is to download the CRM Core Tools library. This library will contain the latest binaries that we will need to create the CRM service client. The goal is to always have the latest version and to not have to download these manually. Thus, rather than simply downloading the package and installing it on our build servier, we will be using nuget.exe to download them on each build.

The script below downloads the latest version of the CRM Core Tools library. It essentially downloads the Core Tools to a Tools folder one level above the script’s location. You can easily adapt this to your directory structure.

## Script saved as DownloadCrmTools.ps1
# Test whether tools are already downloaded
if ((Test-Path "$PSScriptRoot..Tools") -and (Test-Path "$PSScriptRoot..ToolsCoreTools")) 
{
    Write-Host "Tools already downloaded."
    exit;        
} 

Write-Host "Downloading CRM Tools";
cd $PSScriptRoot/..
mkdir .Tools

$sourceNugetExe = "https://dist.nuget.org/win-x86-commandline/latest/nuget.exe"
$targetNugetExe = ".nuget.exe"
Invoke-WebRequest $sourceNugetExe -OutFile $targetNugetExe
Set-Alias nuget $targetNugetExe -Scope Global -Verbose

# Remove NuGet.exe
Remove-Item nuget.exe    

This script is a modified version of the one created by Microsoft. Check out the original to see how to also include the Configuration Migration tool, the Package Deployer, and the Package Deployer PowerShell module.

Loading the SDK Assemblies

The next step is to create a script that loads the assemblies into memory. On line 11, it calls the script above to download the Core Tools folder. Then, it loads the assemblies into memory. Note that line 10 makes this call happen only once. If the SDK assemblies have already been loaded into memory, it will simply not execute.

## Script saved as AddCrmSdk.ps1
function LoadAssemblyFromToolsFolder($AssemblyName, $ToolSource)
{  
    $path = "$PSScriptRoot..Tools$ToolSource";
    $path = Join-Path -Path "$path" -ChildPath "$AssemblyName"
    Write-Host "Adding assembly at: $path.";
    Add-Type -Path "$path";
}

if($sdkLoaded -eq $null) {
	& $PSScriptRootDownloadCrmTools.ps1

	LoadAssemblyFromToolsFolder -AssemblyName "Microsoft.Xrm.Sdk.dll" -ToolSource "CoreTools"
	LoadAssemblyFromToolsFolder -AssemblyName "Microsoft.Xrm.Tooling.Connector.dll" -ToolSource "CoreTools"
	LoadAssemblyFromToolsFolder -AssemblyName "Microsoft.Crm.Sdk.Proxy.dll" -ToolSource "CoreTools"
	LoadAssemblyFromToolsFolder -AssemblyName "Microsoft.Xrm.Sdk.Deployment.dll" -ToolSource "CoreTools"

	$sdkLoaded = $true
}

Creating the CRM Service Client

Finally, it is time to connect to our CRM instance. To do this, we will be using the CRM service client class. The only parameter this method needs is a connection string.

param(
    [Parameter(Mandatory=$true)]
    [string] $ConnectionString
)

# Load the assemblies
. $PSScriptRootAddCrmSdk.ps1;

# Reuse existing connection if it is valid
if($crmService -ne $null -and $crmService.IsReady)
{
	Write-Host "Reusing existing service" 
	return $crmService;
}

Write-Host "Getting service" 

# Dynamics 365 requires TLS 1.2
Write-Host "Current Security Protocol: $([Net.ServicePointManager]::SecurityProtocol)";
if(-not [Net.ServicePointManager]::SecurityProtocol.HasFlag([Net.SecurityProtocolType]::Tls12)) 
{
    [Net.ServicePointManager]::SecurityProtocol = [Net.ServicePointManager]::SecurityProtocol -bor 'tls12';

    Write-Host "Updated Security Protocol: $([Net.ServicePointManager]::SecurityProtocol)";
}

# Connection string normalization
if($ConnectionString -notlike "*;") 
{
    $ConnectionString += ";";
}

if($ConnectionString -notcontains "RequireNewInstance=True")
{
    $ConnectionString = "$ConnectionString RequireNewInstance=True;";
}

# Create service
$crmService= New-Object -TypeName Microsoft.Xrm.Tooling.Connector.CrmServiceClient -ArgumentList $ConnectionString;

if(-Not ($crmService.IsReady)) {
    Write-Host $crmService.LastCrmError;

    if($service.LastCrmException -ne $null) {
        Write-Error -Exception $crmService.LastCrmException;
    }

	Write-Host "Unable to create service connection to CRM."
    exit;
}

return $crmService;

And there you go! Whenever you need to have access to a CRM instance, you can simply add a call to this script using the dot-sourcing. This will create the $crmService variable in your script’s scope. After that, you can use it for your purposes. In our next post, we’ll explore using it to enable and disable SDK message processing steps.

If you’d like Code Vanguard to help your organization with its DevOps process, feel free to reach out to us!


Check out some of our other posts about Dynamics CRM!

James Stephens About the author

James is the founder of Code Vanguard and one of its developers. He is an applied mathematician turned computer programming. His focuses are on security, DevOps, automation, and Microsoft Azure.

No Comments

Post a Comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.