PowerShell scripting for Microsoft Dynamics CRM – Microsoft Tooling library

PowerShell scripting for Microsoft Dynamics CRM – Microsoft Tooling library
5 (100%) 2 votes

In the previous post, I described how to create a custom cmdlet to connect to the organization and deployment service of a Dynamics CRM organization.

However, Microsoft as released a new set of libraries in the Dynamics CRM SDK, providing more features and out-of-the-box capabilities for developers. In particular, the Microsoft.Xrm.Tooling.CrmConnector.Powershell library provides the following PowerShell cmdlets:

  • Get-CrmConnection, in order to connect to a Dynamics CRM organization and instantiate an appropriate service.
  • Get-CrmOrganizations, in order to retrieve organizations that the current user has access to.

This blog post aims to provide a few examples of how to use the high level methods provided by the Get-CrmConnection cmdlet in order to perform actions against a Dynamics CRM organization.

On the one hand, it is recommended – and more supported – to use the set of tools provided by Microsoft when interacting with Dynamics CRM. The process implemented will be more stable, supported in future release and for all deployment types. On the other hand, when the feature is not available and is required, a custom implementation is always an option.

For example, a custom cmdlet updating the display name of several fields may be required in case of a massive renaming campaign initiated by the business sponsors of the application. This action is not supported by the custom service delivered by the Get-CrmConnection cmdlet at the time of writing. I am glad that my planned example of custom cmdlet implementation is still relevant!

Requirements

Two requirements should be met according to the documentation:

  1. The version of PowerShell must be no earlier than version 3.0.
  2. The PowerShell execution policy must be permissive enough (AllSigned or Unrestricted).

Note: I used PowerShell 4.0 in order to test this library and I managed to use the Get-CrmConnection cmdlet. However, the Get-CrmOrganizations cmdlet did not behave according to the documentation, validating all expected parameters as mandatory.

Moreover, the Microsoft.Xrm.Tooling.Connector PowerShell snap-in must be installed on the client computer.

PowerShell 3.0 or less

The following script allows to check the version of PowerShell, and throws an exception if the requirement is not met:

# Get the major number of the PowerShell version
$PSVersionMajor = $Host.Version.Major

# Get the minor number of the PowerShell version
$PSVersionMinor = $Host.Version.Minor

# Check the version of PowerShell, should be no earlier than version 3.0.
if ($PSVersionMajor -gt 3 -or ($PSVersionMajor -eq 3 -and $PSVersionMinor -gt 0))
{
    throw "Requirement check failed: PowerShell version is greater than 3.0. Current version is $PSVersionMajor.$PSVersionMinor"
}

Permissive execution policy

The following script allows to check the PowerShell execution policy, and throws an exception if the requirement is not met:

$ExecutionPolicy = Get-ExecutionPolicy
if ($ExecutionPolicy -ne "AllSigned" -and $ExecutionPolicy -ne "Unrestricted")
{
    throw "Requirement check failed: Execution policy is restrictive. Current policy is $ExecutionPolicy"
}

Set-up required snap-in

The Microsoft Dynamics CRM SDK provide a script to set-up the required snap-in. This script is located in <SDK directory>/Bin.

Run the following command as Administrator to register the snap-in:

.\RegisterXRMTooling.ps1

Connect to the organization service

This paragraph present a simple example to use the Get-CrmConnection cmdlet.

# 1 - Import the required types
Add-PSSnapin -Name Microsoft.Xrm.Tooling.Connector

# 2 - Set the Server URL and the organization name
$ServerUrl = "https://crm.company.com"
$OrganizationName = "organization"

# 3 - Prompt user name and password to connect to the CRM instance in a graphical way
$Credentials = Get-Credential

# 3 bis - Or specify the service account to connect to the CRM instance
#$SecurePassword = [Microsoft.Xrm.Tooling.Connector.CrmServiceClient]::MakeSecureString("password")
#$Credentials = New-Object -TypeName 'System.Management.Automation.PSCredential' -ArgumentList "username", $SecurePassword

# Connect to the target On Premise organization
$CrmConnection = Get-CrmConnection –ServerUrl $ServerUrl -Credential $Credentials -OrganizationName $OrganizationName

# Or connect to a Microsoft hosted organization
# For the DeploymentRegion parameter, valid values are NorthAmerica, EMEA, and APAC.
# For the OnlineType parameter, valid values are Office365 and LiveID.
# $CrmOrganizations = Get-CrmOrganizations -Credential $Credentials -DeploymentRegion EMEA –OnlineType Office365

# Verify connection status
if ($CrmConnection.IsReady)
{
    # Access connected CRM organization Friendly Name and Version
    $message = $("Connected to CRM organization: {0} - {1}" -f $CrmConnection.ConnectedOrgFriendlyName, $CrmConnection.ConnectedOrgVersion)
    Write-Output -InputObject $message

    # Use the CrmConnection object's methods here!
    # See example below.
}
else
{
    # Write the last error
    Write-Error "An error occurred: " $CrmConnection.LastCrmError

    # Write the CRM exception details
    Write-Error $CrmConnection.LastCrmException.Message
    Write-Error $CrmConnection.LastCrmException.Source
    Write-Error $CrmConnection.LastCrmException.StackTrace
}

Use the CrmConnection object’s method

The documentation available presents example in C# code. Here are some example using the PowerShell syntax:

Note: the following functions should be defined before their call.

Retrieve the current user id

# Gets the user ID of the currently logged in user.
# Documentation: https://msdn.microsoft.com/fr-fr/library/microsoft.xrm.tooling.connector.crmserviceclient.getmycrmuserid.aspx
Function GetCurrentUserId
{
    $userId = $CrmConnection.GetMyCrmUserId()
    Write-Host "Current user id:" $userId
    return $userId
}

# Get current user id
$userId = GetCurrentUserId

Create a new account

# Create an account record
# Documentation: https://msdn.microsoft.com/fr-fr/library/microsoft.xrm.tooling.connector.crmserviceclient.createnewrecord.aspx
# Example C#: https://msdn.microsoft.com/en-us/library/dn688181.aspx
Function CreateNewAccount
{   
    # Possible CrmFieldType values are displayed using the following command:
    # [Enum]::GetNames([Microsoft.Xrm.Tooling.Connector.CrmFieldType])

    $namefield  = New-Object -TypeName 'Microsoft.Xrm.Tooling.Connector.CrmDataTypeWrapper' -ArgumentList "Sample Account Name", $([Microsoft.Xrm.Tooling.Connector.CrmFieldType]::String)
    $cityField  = New-Object -TypeName 'Microsoft.Xrm.Tooling.Connector.CrmDataTypeWrapper' -ArgumentList "Redmond", $([Microsoft.Xrm.Tooling.Connector.CrmFieldType]::String)
    $phoneField = New-Object -TypeName 'Microsoft.Xrm.Tooling.Connector.CrmDataTypeWrapper' -ArgumentList "555-0160", $([Microsoft.Xrm.Tooling.Connector.CrmFieldType]::String)

    $inData = New-Object -TypeName 'System.Collections.Generic.Dictionary[string, Microsoft.Xrm.Tooling.Connector.CrmDataTypeWrapper]'
    $inData.Add("name", $namefield);
    $inData.Add("address1_city", $cityField);
    $inData.Add("telephone1", $phoneField);

    $accountId = $CrmConnection.CreateNewRecord("account", $inData, $applyToSolution, $enabledDuplicateDetection, $batchId)

    # Verify if the account is created.
    if ($accountId -ne [guid]::empty)
    {
        Write-Host "Account created with id:" $accountId
    }
    else
    {
        # Write the last error
        Write-Error "An error occurred:" $CrmConnection.LastCrmError

        # Write the CRM exception details
        Write-Error $CrmConnection.LastCrmException.Message
        Write-Error $CrmConnection.LastCrmException.Source
        Write-Error $CrmConnection.LastCrmException.StackTrace
    }
    return $accountId
}

# Create a new account
$accountId = CreateNewAccount

Retrieve an account

# Retrieve an account
# Documentation: https://msdn.microsoft.com/fr-fr/library/microsoft.xrm.tooling.connector.crmserviceclient.getentitydatabyid.aspx
# Example C#: https://msdn.microsoft.com/en-us/library/dn688175.aspx
Function RetrieveAccount
{
    Param (
        [Parameter(Mandatory=$true)]
        [ValidateNotNullOrEmpty()]
        [guid]$accountId
    )

    # Specifies field list
    $fields = New-Object -TypeName 'System.Collections.Generic.List[string]'
    $fields.Add("name")

    $account = $CrmConnection.GetEntityDataById("account", $accountId, $fields, $batchId)
    foreach ($property in $account.GetEnumerator())
    {
        if ($property.Key -eq "name")
        {
            Write-Host "Name of the account is:" $property.Value
        }
    }
}

# Retrieve account
RetrieveAccount $accountId

Count all accounts

# Retrieve multiple accounts
# Documentation: https://msdn.microsoft.com/fr-fr/library/dn742115.aspx
# Example C#: https://msdn.microsoft.com/en-us/library/dn688175.aspx
Function CountAllAccounts
{
    # Define FetchXML query
    $fetchXML = 
        "&lt;fetch version='1.0' output-format='xml-platform' mapping='logical' distinct='false' returntotalrecordcount='true' &gt;
            &lt;entity name='account'&gt;
              &lt;attribute name='accountid' /&gt;
            &lt;/entity&gt;
        &lt;/fetch&gt;"

    $queryResult = $CrmConnection.GetEntityDataByFetchSearchEC($fetchXML, $batchId);
    if ($queryResult -ne $null)
    {
        Write-Host "Accounts records count:" $queryResult.TotalRecordCount
    }
}

# Count all accounts
CountAllAccount

Update an account

# Update an account
# Documentation: https://msdn.microsoft.com/fr-fr/library/microsoft.xrm.tooling.connector.crmserviceclient.updateentity.aspx
# Example C#: https://msdn.microsoft.com/en-us/library/dn688180.aspx
Function UpdateAccount
{
    Param (
        [Parameter(Mandatory=$true)]
        [ValidateNotNullOrEmpty()]
        [guid]$accountId
    )

    $namefield  = New-Object -TypeName 'Microsoft.Xrm.Tooling.Connector.CrmDataTypeWrapper' -ArgumentList "Sample Account Name - Updated!", $([Microsoft.Xrm.Tooling.Connector.CrmFieldType]::String)

    $updateData = New-Object -TypeName 'System.Collections.Generic.Dictionary[string, Microsoft.Xrm.Tooling.Connector.CrmDataTypeWrapper]'
    $updateData.Add("name", $namefield);

    $isUpdated = $CrmConnection.UpdateEntity("account", "accountid", $accountId, $updateData, $applyToSolution, $enabledDuplicateDetection, $batchId)
    if ($isUpdated)
    {
        Write-Host "Account updated!"
    }
}

# Update an account
UpdateAccount $accountId

Set an account state to inactive

# Deactivate an account
# Documentation: https://msdn.microsoft.com/fr-fr/library/microsoft.xrm.tooling.connector.crmserviceclient.updatestateandstatusforentity.aspx
# Example C#: https://msdn.microsoft.com/en-us/library/dn688180.aspx
Function DeactivateAccount
{
    Param (
        [Parameter(Mandatory=$true)]
        [ValidateNotNullOrEmpty()]
        [guid]$accountId
    )

    # Here are the state and status code values
    # statecode = 1 ( Inactive ) 
    # statuscode = 2 ( Inactive ) 
 
    $isUpdated = $CrmConnection.UpdateStateAndStatusForEntity("account", $accountId, 1, 2, $batchId)

    # the same command using the second form of the method
    #$isUpdated = $CrmConnection.UpdateStateAndStatusForEntity("account", $accountId, "Inactive", "Inactive", $batchId)
    
    if ($isUpdated)
    {
        Write-Host "Account deactivated!"
    }
}

# Set an account state to inactive
DeactivateAccount $accountId

Delete an account

# Delete an account
# Documentation: https://msdn.microsoft.com/fr-fr/library/microsoft.xrm.tooling.connector.crmserviceclient.deleteentity.aspx
# Example C#: https://msdn.microsoft.com/en-us/library/dn688178.aspx
Function DeleteAccount
{
    Param (
        [Parameter(Mandatory=$true)]
        [ValidateNotNullOrEmpty()]
        [guid]$accountId
    )

    $isDeleted = $CrmConnection.DeleteEntity("account", $accountId, $batchId);
    if ($isDeleted)
    {
        Write-Host "Account deleted!"
    }
}

# Delete an account
DeleteAccount $accountId

Retrieve multiple accounts

# Retrieve multiple accounts
# Documentation: https://msdn.microsoft.com/fr-fr/library/microsoft.xrm.tooling.connector.crmserviceclient.executecrmorganizationrequest.aspx
# Example C#: https://msdn.microsoft.com/en-us/library/dn688174.aspx
Function RetrieveMultipleAccount
{
    $accountsQuery = New-Object -TypeName 'Microsoft.Xrm.Sdk.Query.QueryExpression' -ArgumentList "account"
    $accountsQuery.ColumnSet.AllColumns = $true
    $retrieveRequest = New-Object -TypeName 'Microsoft.Xrm.Sdk.Messages.RetrieveMultipleRequest'
    $retrieveRequest.Query = $accountsQuery

    $response = $CrmConnection.ExecuteCrmOrganizationRequest($retrieveRequest)
    
    $entities = $response.EntityCollection.Entities
    Write-Host "First account name:" $entities[0].Attributes["name"]
}

# Retrieve multiple accounts
RetrieveMultipleAccount

Publish an entity

# Publishes an entity to the production system, used in conjunction with the Metadata services. 
# Documentation: https://msdn.microsoft.com/fr-fr/library/microsoft.xrm.tooling.connector.crmserviceclient.publishentity.aspx
Function PublishEntity
{
    Param (
        [Parameter(Mandatory=$true)]
        [ValidateNotNullOrEmpty()]
        [string]$entityLogicalName
    )

    $CrmConnection.PublishEntity($entityLogicalName)
    Write-Host "entity published:" $entityLogicalName
}

# Publish entity
PublishEntity "account"

Retrieve picklist elements

# Gets a PickList, Status List or StateList from the metadata of an attribute 
# Documentation: https://msdn.microsoft.com/fr-fr/library/microsoft.xrm.tooling.connector.crmserviceclient.getpicklistelementfrommetadataentity.aspx
Function GetPickListElements
{
    Param (
        [Parameter(Mandatory=$true)]
        [ValidateNotNullOrEmpty()]
        [string]$entityLogicalName,
        [Parameter(Mandatory=$true)]
        [ValidateNotNullOrEmpty()]
        [string]$attributeLogicalName
    )

    $picklist = $CrmConnection.GetPickListElementFromMetadataEntity($entityLogicalName, $attributeLogicalName)
    foreach($item in  $picklist.Items)
    {
        Write-Host "Item:" $item.DisplayLabel $item.PickListItemId
    }
}

# Get state values for account
GetPickListElements "account" "statecode

What’s next?

The following script displays all available methods for the CrmConnection object. There is a method for almost all common data manipulation actions.

# Displays all methods available
# https://msdn.microsoft.com/fr-fr/library/microsoft.xrm.tooling.connector.crmserviceclient_methods.aspx
$CrmConnection | Get-Member -MemberType Method

3 thoughts on “PowerShell scripting for Microsoft Dynamics CRM – Microsoft Tooling library

  1. Great Article,

    Do you know if its possible to create a new record using “CreateNewRecord” with a given Id? I tried to pass a Guid with type Key but no luck…

    Thanks
    Roman

Leave a Reply

Your email address will not be published.