Development Tools? You don't always need a UI!

One of the most underused tools in Dynamics and CDS development teams the myriad of those available is the Microsoft.Xrm.Data.PowerShell library by the ever helpful Sean McNellis. If you have to perform repetitive tasks then there is nothing easier but with the unfamiliar nature of PowerShell for those of us that write C# or JavaScript on a daily basis, it's often avoided.

This post is a call to action - consider it as an option for the following reasons:

  1. You can quickly convert Excel spreadsheets into a PowerShell script to perform repetitive tasks such as adding roles to users or entities to solutions.
  2. Easily create reusable scripts that are parameterized without the complexity of a user interface.
  3. Easily automate build tasks and run them over and over again with no chance of human error
  4. Creating scripts to give to other people to run as their user account when you don't have access to the target environment

Recently I needed to add a load of entities to a solution which can be quite cumbersome using the classic solution UI and the PowerApps solution manager doesn't allow you to add entities without their sub-components yet - PowerShell to the rescue.

# Shows how to add entities to a solution

Set-ExecutionPolicy –ExecutionPolicy RemoteSigned –Scope CurrentUser
Install-Module Microsoft.Xrm.Data.PowerShell -Scope CurrentUser
Import-Module Microsoft.Xrm.Data.Powershell
$conn = Connect-CrmOnlineDiscovery -InteractiveMode

Function Add-SolutionComponent
{
    param
    (
        [string]$solutionuniquename,
        [Int32]$componenttype,
        [Guid]$componentid
    )

    # See https://docs.microsoft.com/en-us/previous-versions/dynamicscrm-2016/developers-guide/gg327422(v%3Dcrm.8) 
    $addrequest = new-object Microsoft.Crm.Sdk.Messages.AddSolutionComponentRequest
    $addrequest.AddRequiredComponents = 0
    $addrequest.ComponentType = $componenttype #1=Entity
    $addrequest.DoNotIncludeSubcomponents = 1
    $addrequest.ComponentId = $componentid
    $addrequest.SolutionUniqueName = $solutionuniquename
    $response= $conn.ExecuteCrmOrganizationRequest($addrequest)

}

Function Add-EntitiesToSolution
{
    param
    (
        [string]$solutionuniquename,
        [string[]]$addentities
    )

    Write-Host "Checking that solution exists '$solutionuniquename'"
    $solution = Get-CrmRecords -conn $conn -EntityLogicalName solution -FilterAttribute uniquename -FilterOperator eq -FilterValue $solutionuniquename -Fields solutionid
    $solutionid =  $solution.CrmRecords[0].solutionid

    Write-Host "Querying metdata to get entity id"
    $entities = Get-CrmEntityAllMetadata -conn $conn -EntityFilters Entity -OnlyPublished $false

    # Filter by the entities to add
    foreach($entity in $entities | ? {$_.LogicalName -in $addentities})
    {
        $logicalName = $entity.LogicalName
        $count = (Get-CrmRecordsCount -conn $conn -EntityLogicalName $logicalName -WarningAction SilentlyContinue)
        Write-Host "Adding $logicalName"
        Add-SolutionComponent -solutionuniquename $solutionuniquename -componenttype 1 -componentid $entity.MetadataId
    }
}

# Add lead, account and contact to the solution TestSolution
Add-EntitiesToSolution -solutionuniquename "TestSolution" -addentities "lead","account","contact"

So there you have it! I've picked this scenario because it shows some common things you'll need to use regularly:

  1. Querying for records
    Get-CrmRecords
  2. Executing SDK Messages
    ExecuteCrmOrganizationRequest
  3. Iterating and filtering collections
    foreach($entity in $entities | ? {$_.LogicalName -in $addentities})

So there you have it. Hopefully, you'll consider using PowerShell if you've not already!

You can find lots more samples on Sean's git hub samples repo.

Comments (1) -

  • Can you touch on why someone who is familiar with C# should invest time in learning this over writing similar scripts in C# using the existing SDK assemblies? The only thing I can really pick out would be portability assuming everyone has access to run Powershell, but I'm curious to know if there are other reasons not mentioned. I often use Linqpad with the CRM SDK assemblies for tasks similar to the ones described above
Comments are closed