PowerShell scripting for Microsoft Dynamics CRM – A cmdlet to connect

PowerShell scripting for Microsoft Dynamics CRM – A cmdlet to connect
5 (100%) 1 vote

Sending requests using a Dynamics CRM organization or deployment service requires both user authentication and instantiation of a service object ready to send requests. This article presents a simple way to connect to a Dynamics CRM organization and deployment through PowerShell using a custom cmdlet.

Before completing the following steps, please set-up your development environment according to my previous blog post: PowerShell scripting for Microsoft Dynamics CRM – Requirements.

Cmdlets interactions with the pipeline

Cmdlets

A cmdlet is a lightweight command available in a Windows PowerShell environment. A cmdlet may process one or many input objects from the pipeline and returns a single object to the next command in the pipeline.

Moreover, cmdlets do not generally do their own parsing, error presentation, or output formatting. These feature should be handled by the PowerShell runtime. I will deliver some insights regarding configuration management, error handling and log formatting in next blog posts.

For more information about the guidelines for writing cmdlets, see Cmdlet Development Guidelines

Pipeline

The concept of pipeline is important to keep in mind while implementing cmdlet. By working with objects in the pipeline, PowerShell allows to easily perform actions, filter or collect data on a collection of object.

For example, the following command illustrate that a cmdlet should process a single object at a time.

$users | Where-Object { $_.Role -eq "Administrator" } | ForEach-Object { Write-Output $_.Name }

Explanation:

  1. The first member delivers the $users collection of objects to the Where-Object command.
  2. Filters objects from the $users collection using an equality comparer based on the Role property.
  3. Delivers the filtered collection to the ForEach-Object command.
  4. Iterate through each object in the filtered collection and call the Write-Output command using the Name property as a parameter.

Note: PowerShell relies on the .NET CLR, so all object are Microsoft .NET Framework objects.

Source: Writing a Windows PowerShell Cmdlet

A first example: organization service

Most cmdlets are implemented as .NET Framework classes that derive from the Cmdlet base class. This base class provides the minimum set of dependencies on the PowerShell runtime. As a result, the cmdlet object is smaller and, more important, less subject to be affected by PowerShell runtime changes.

Implement a cmdlet to connect the organization

Here is the step required to implement a cmdlet to connect the organization service.

Tips: you can use NuGet in order to reference the project dependencies.

  1. Open Visual Studio
  2. Create a class library targeting Framework .NET 4.0. I named the project Hiyoko.Crm.PowerShell.
  3. Reference the System.Management.Automation assembly for declaring cmdlet object. The associated file should be located in C:\Program Files (x86)\Reference Assemblies\Microsoft\Windows\PowerShell\3.0\System.Management.Automation.dll
  4. Reference the Microsoft.Xrm.Client assembly in order to parse the Dynamics CRM connection string using the CrmConnection object.
  5. Reference the Microsoft.Xrm.Sdk assembly in order to instantiate the OrganizationService object.
  6. Create a class named Get_OrganizationService.cs,  and write the following code:
// PowerShell Cmdlet base class namespace 
using System.Management.Automation;

// Dynamics CRM client namespace 
using Microsoft.Xrm.Client;
using Microsoft.Xrm.Client.Services;

namespace Hiyoko.Crm.PowerShell
{
    // Windows PowerShell uses a verb-and-noun name pair to name cmdlets. The couple defined here is used by PowerShell runtime. 
    [Cmdlet(VerbsCommon.Get, "OrganizationService")]

    // Derive from the Cmdlet base class. 
    public class Get_OrganizationService : Cmdlet
    {
        // Define parameter as mandatory. This check is performed by the PowerShell runtime. 
        [Parameter(Mandatory = true)]

        // Validate that the parameter is not null or empty. This check is performed by the PowerShell runtime. 
        [ValidateNotNullOrEmpty]
        public string CrmConnectionString { get; set; }

        ///  
        /// Impelment the ProcessRecord method to provide record-by-record processing functionality for the cmdlet. 
        ///  
        protected override void ProcessRecord()
        {
            // Parse CRM connection string. 
            var connection = CrmConnection.Parse(CrmConnectionString);

            // Instanciate Organization service. 
            var service = new OrganizationService(connection);

            // Deliver the Organization service object to the pipeline. 
            WriteObject(service);
        }
    }
}

For more information about the simplified connection to Dynamics CRM, see Simplified connection to Microsoft Dynamics CRM.

Calling the Get-OrganizationService command

Once the Hiyoko.Crm.PowerShell project compiled, create a PowerShell script in the same directory as the DLL output file using PowerShell ISE:

# Get the current script directory path
$ScriptPath = $(Split-Path -Path $script:MyInvocation.MyCommand.Path)

# Add the definition of the objects contained in the Microsoft.Xrm.Client namespace.
Add-Type -Path $($ScriptPath + "\microsoft.xrm.sdk.dll")

# Import the Get_OrganizationService class.
Import-Module -Name $($ScriptPath + "\Hiyoko.Crm.PowerShell.dll")

# Define the CRM connection string
$CrmConnectionString = "Url=https://crm.company.org/organization;"

# Retrieve the corresponding OrganizationService object.
$organizationService = Get-OrganizationService -CrmConnectionString $CrmConnectionString

# Test connection
if($organizationService.InnerService.IsAuthenticated)
{
    Write-Host "User is authenticated!"
}

Click on Execute script button or F5 to test the script.

Another example: deployment service

The implementation process is similar to the previous example. The objects required are different and therefore the required references and namespace declarations change. You will need to reference the following assemblies:

  • System.ServiceModel
  • Microsoft.Xrm.Sdk.Deployment

Implement a cmdlet to connect to the deployment

Here is the step required to implement a cmdlet to connect the deployment service:

using System;
using System.Net;

// PowerShell Cmdlet base class namespace 
using System.Management.Automation;

// Dynamics CRM deployment namespace 
using Microsoft.Xrm.Sdk.Deployment.Proxy;

namespace Hiyoko.Crm.PowerShell
{
    // Windows PowerShell uses a verb-and-noun name pair to name cmdlets. 
    [Cmdlet(VerbsCommon.Get, "DeploymentService")]

    // Derive from the Cmdlet base class. 
    public class Get_DeploymentService : Cmdlet
    {
        // Define parameter as mandatory. This check is performed by the PowerShell runtime. 
        [Parameter(Mandatory = true)]

        // Validate that the parameter is not null or empty. This check is performed by the PowerShell runtime. 
        [ValidateNotNullOrEmpty]
        public Uri DeploymentUri { get; set; }

        ///  
        /// Impelment the method used to provide record-by-record processing functionality for the cmdlet. 
        ///  
        protected override void ProcessRecord()
        {
            // Create the deployment service from the deployment URI. 
            var service = ProxyClientHelper.CreateClient(DeploymentUri);

            // Use default network credentials if necessary. 
            if (service.ClientCredentials != null)
            {
                service.ClientCredentials.Windows.ClientCredential = CredentialCache.DefaultNetworkCredentials;
            }

            // Deliver the Deployment service object to the pipeline. 
            WriteObject(service);
        }
    }
}

Calling the Get-DeploymentService command

The following script should call the Get-DeploymentService command and return the associated DeploymentServiceClient object.

# Get the current script directory path
$ScriptPath = $(Split-Path -Path $script:MyInvocation.MyCommand.Path)

# Add the definition of the objects ontained in the Microsoft.Xrm.Sdk.Deployment namespace.
Add-Type -Path $($ScriptPath + "\microsoft.xrm.sdk.deployment.dll")

# Import the Get_DeploymentService class.
Import-Module -Name $($ScriptPath + "\Hiyoko.Crm.PowerShell.dll")

# Define the Deployment URI
$DeploymentUri = "https://crm.company.org/XRMDeployment/2011/Deployment.svc"

# Intanciate and retrieve the DeploymentServiceClient object.
$deploymentService = Get-DeploymentService -DeploymentUri $DeploymentUri

# Test connection
if($deploymentService.State -eq "Created")
{
    Write-Host "Deployment service created!"
}

What’s next?

Next time, I will show you how to use the OrganizationService in a cmdlet in order to update the display name of an attribute.

Please do not hesitate to share your thoughts about this first step toward a complete and industrialized delivery process!

Leave a Reply

Your email address will not be published.