Import Configuration Data to CRM using Microsoft.Xrm.Data.PowerShell

CRM Dynamics data can be exported using the data migration tool by first generating the data schema file and using the later to export selected entities and fields. The same data migration tool can be used to import data into other environments. However it is still a manual process.

I have written a script using Microsoft.Xrm.Data.PowerShell module in PowerShell  to automate the data import. The zip generated by the export needs to be unzipped so that the path of the files can be passed to the method called to import the data.unzippedconfigfile

The script can be downloaded from TechNet gallery. Please note that the script has been tested with limited data so might require changes depending on the data being imported.

Call the method Import-ConfigData as in the snippet below.

 Add-type -Path ".\Assemblies\Microsoft.Xrm.Tooling.CrmConnectControl.dll"
 Add-Type -Path ".\Assemblies\Microsoft.Xrm.Tooling.Connector.dll"

import-module ".\Microsoft.Xrm.Data.PowerShell\Microsof t.Xrm.Data.PowerShell.psm1"

$crmOrg = New-Object `         
   -TypeName Microsoft.Xrm.Tooling.Connector.CrmServiceClient `         
   -ArgumentList ([System.Net.CredentialCache]::DefaultNetworkCredentials),             ([Microsoft.Xrm.Tooling.Connector.AuthenticationType]::AD) 
,            $serverName 
,            $serverPort 
,             $organizationName 
,             $False 
,            $False 
,           ([Microsoft.Xrm.Sdk.Discovery.OrganizationDetail]$null$dataFilePath =  "\PkgFolder\Configuration Data\data.xml" 
$dataSchemaFilePath = "\PkgFolder\Configuration Data\data_schema.xml" 
Write-Output "Begin import of configuration data..." 
Import-ConfigData -dataFilePath $dataFilePath 
-dataSchemaFilePath $dataSchemaFilePath -crmOrg $crmOrg 
Write-Output "End import of configuration data..."

First initialise the crm connection object of type Microsoft.Xrm.Tooling.Connector.CrmServiceClient stored in the variable $crmOrg above.

Pass the following parameters to the method.

datafilePath: Path of the file data.xml

crmOrg  : crm connection object

dataschemafilepath: Path of the file dataschema.xml

 

 

CRM Dynamics 2015 “Error Uploading Report” caused by using Visual Studio 2015

When I was trying to upload a SSRS report to replace an existing report to CRM Dynamics 2015 solution, I got the error

Error Uploading Report

An error occurred while trying to add the report to Microsoft Dynamics CRM.

erroruploadingreport

The error message does not say much.

I decided to use Visual Studio 2015 to edit the CRM report which has caused the issue.

I compared the code behind of the previous report and new report and found that there are new XML elements in the report generated by visual studio 2015 (SQL Server Data Tools for Visual Studio 2015). For example, “reportsections” xml tag has been inserted.

 <ReportSections>
 <ReportSection>
 <Body>
 <ReportItems>
 <Tablix Name="Tablix4">
 <TablixBody>
 <TablixColumns>
 <TablixColumn>
 <Width>3in</Width>
 </TablixColumn>
 <TablixColumn>
 <Width>1.5in</Width>
 </TablixColumn>
 <TablixColumn>
 <Width>1.5in</Width>
 </TablixColumn>
 <TablixColumn>
 <Width>1.5in</Width>
 </TablixColumn>
 <TablixColumn>
 <Width>2.0455in</Width>
 </TablixColumn>
 </TablixColumns>
 <TablixRows>
 <TablixRow>

The only option for me was to rework the report in Visual Studio 2013 (SQL Server Data Tools for Visual Studio 2013) before uploading the report to CRM dynamics solution successfully.

Instantiate CRMServiceClient using current user’s login

The Get-CrmConnection method can be used to  return connection to a CRM instance. The syntax to call the method is

Parameter Set: OnLine
Get-CrmConnection [-OnLineType] <OnlineType> [[-Credential] <PSCredential> ] 
[-DeploymentRegion] <String> [[-ProfileName] <String> ] -OrganizationName <String> [ <CommonParameters>]

Parameter Set: OnPrem
Get-CrmConnection [-ServerUrl] <Uri> [[-Credential] <PSCredential> ] 
[-OrganizationName] <String> [[-HomeRealmUrl] <Uri> ] [[-ProfileName] <String> ] 
[ <CommonParameters>]

Parameter Set: UIOnly
Get-CrmConnection [[-InteractiveMode]] [ <CommonParameters>]

I wanted to get the crm connection with the current user’s credentials without any prompts. The first and second options required the object PSCredential which can’t be created using logged current user’s credentials. The third option with the switch InteractiveMode  displays a dialog box prompting to enter connection details. All three options were not appropriate for the requirement.

The method returns the object Microsoft.Xrm.Tooling.CrmServiceClient. From the msdn article, it can be constructed using the NetworkCredential object.

The constructor’s definition in C#

public CrmServiceClient(
	NetworkCredential credential,
	AuthenticationType authType,
	string hostName,
	string port,
	string orgName,
	bool useUniqueInstance = false,
	bool useSsl = false,
	OrganizationDetail orgDetail = null
)

 

In PowerShell, the current user’s credentials can be retrieved using [System.Net.CredentialCache]::DefaultNetworkCredentials.

There is no way the [System.Net.CredentialCache]::DefaultNetworkCredentials can be converted to the PSCredential object.

The below syntax can be used to create the Microsoft.Xrm.Tooling.Connector.CrmServiceClient using logged in user’s credentials. Replace the variables $serverName, $serverPort, $organizationName with the respective values.

 $crmConnection = New-Object `
 -TypeName Microsoft.Xrm.Tooling.Connector.CrmServiceClient `
 -ArgumentList ([System.Net.CredentialCache]::DefaultNetworkCredentials), 
 ([Microsoft.Xrm.Tooling.Connector.AuthenticationType]::AD),
 $serverName,
 $serverPort, 
 $organizationName, 
 $False,
 $False,
 ([Microsoft.Xrm.Sdk.Discovery.OrganizationDetail]$null)

Filter N-N Add existing Look Up Contact Custom View CRM 2015

I had a requirement to add contacts where the [Account Type] is “Lawyer” to entity “Case”.  I created a relationship N:N between contacts and cases.

Unfortunately the filter for N-N Add Existing button on a sub grid stopped working on from version CRM 2013. It does not work on CRM 2015 on Premises as well.

I stumbled upon the blog Filter N:N Add Existing Lookup Dynamics CRM 2013 how to resolve the issue using the CRM function LookupObjectsWithCallback.

I created a view in the contacts list named “Lawyers” and noted down the view ID. To find the view Id, open the CRM solution which has the entity, expand entities and “contact”, select the view “Lawyers”.  Click on Arrow down next to Actions and select “Copy a Link”.FindCustomViewId The URL is in the following format.

<[CRM server]/[Organisation]/tools/vieweditor/viewManager.aspx?appSolutionId=%7bFD140AAF-4DF4-11DD-BD17-0019B9312238%7d&id=%7b5F90BBF5-4409-E511-80CF-00155D580900%7d>

Decode the url encoded id parameter into a valid GUID.

{5F90BBF5-4409-E511-80CF-00155D580900}

I created a .js file on the file system and examined the different parameters the method “LookupObjectsWithCallback” accepts and reconstructed the method so as the pop up dialog

  1. Allows selection of contact(s) from  only  Lawyers view
  2. Hides the New Button
  3. Hides other contact views
  4. Allows search of  contacts from  only  Lawyers view

The method “LookupObjectsWithCallback” can accept up to 25 parameters which are optional and position of the relevant parameter needs to be determined to update behaviour of dialog to select contact.


//filters an add existing lookup view (N:N)
function addExistingFromSubGridCustom(gridTypeCode, gridControl, context) {
var viewId = "{5F90BBF5-4409-E511-80CF-00155D580900}";//Lawyers
var relName = gridControl.GetParameter("relName");
var roleOrd = gridControl.GetParameter("roleOrd");
/*
LookupObjectsWithCallback(callbackReference,
lookupField,
lookupStyle, // "single" or "multi"
lookupTypes,
lookupBrowse,
bindingColumns,
additionalParams,
showNew, // "0" or "1"
showProp,
bPopulateLookup,
defaultType
searchString,
dataProviderOverride,
defaultViewId,
customViews,
filterRelationshipId,
rId,
rType,
rDependAttr,
allowFilterOff,
disableQuickFind,
disableViewPicker,
viewsIds,
additionalFetchFilter,
additionalFetchFilterTypes
);
*/
//pops the lookup window with our view injected
var parent = GetParentObject(null, 0);
var parameters = [gridTypeCode, "", relName, roleOrd, parent];
var callbackRef = Mscrm.Utilities.createCallbackFunctionObject("locAssocObjAction", context, parameters, false);
//Hide New Button, display only one view to pick up records, keep showing search button
LookupObjectsWithCallback(callbackRef, null, "multi", gridTypeCode, null, null, "", "0", null, 0, null, null, null, viewId, null, null, null, null, null, null, null, null, viewId);
}
//filters the Contact N:N lookup view from Case to show only Lawyers!!
function filterAddExistingContact(gridTypeCode, gridControl, primaryEntity) {
if (primaryEntity != "case") {
Mscrm.GridRibbonActions.addExistingFromSubGridAssociated(gridTypeCode, gridControl); //default button click function
return;
}
addExistingFromSubGridCustom(gridTypeCode, gridControl, this );
}

I uploaded the js file to the web resources of the CRM solution having the entities (including contact) and application ribbon . I downloaded RibbonWorkbench2013 version 2.0.1.3 to update the  behaviour of “Add Existing” button on the Contact Entity Sub Grid.

  • Open the Ribbon Workbench and select the CRM solution(s) containing the .js file, application ribbon and entities. Ensure no one else is modifying the CRM solution as their changes will be  lost when the ribbon workbench updates the solution.
  • When the solution is loaded into RibbonWorkbench, select entity contact.
  • Take an unmanaged backup of the CRM solution in case roll back is required
  • Under the SubGrid section, there are two “Add Existing” buttons, one for N:N and one for 1:N. The N:N (Mscrm.SubGrid.contact.AddExistingAssoc) is the second one. Right-Click on the second “Add Exiting” button and click on “Customize Command”
  • Expand “Commands” in the “Solution Elements”.
  • Select command  ‘Mscrm.AddExistingRecordFromSubGridAssociated’. In the “Properties: Command Action”  , replace the current FunctionName with the new function from your web resource (in the example code above, it’s the second function: filterAddExistingContact), and change the Library to the web resource. The parameter ” PrimaryEntityTypeName” needs to be added to the list of Parameters.

AmendRibbonSubGrid

  • Click on Publish from the solution and solution will be reimported with the changes.

OnlyOneCustomViewForContact

Navigate to the case entity form having the contacts sub grid to check whether only lawyers are displayed with no “New” button. When contacts Add Existing button for N:N relationships is clicked, the custom function displays only the Lawyers view.

Note: Filtering the Add Existing view using the method LookupObjectsWithCallback is unspported. It might break in the next release.

 

Set TimeOut when importing large CRM Dynamics customisation file

Recently while trying to deploy a CRM package into system test  environment using the import-crmpackage command via PowerShell, time-out was occurring despite doubling the RAM memory as well as removing a lot of checkpoints from the machine.

On the DEV environment, the deployment was taking around 20 mins. The DEV machine has more resources allocated explaining why the time-out was not spotted.

To resolve the timeout issue, the lengthy instructions from Microsoft Knowledge Base Article can be followed. A simpler solution would be to set the timeout property during import.

From the Import-CrmPackage documentation the -timeout property is of type string and meant for internal purpose only. The format of data the -timeout property is not evident. We tried passing “3600” which would be 1 hour if the property was expecting seconds, however the import-crmpackage failed because of invalid data.

Import-CrmPackage -CrmConnection $CRMConn -PackageDirectory "$($filePath)" -PackageName CRMPackageDeploymentTest.dll -Verbose -Timeout "3600"; Import-

Using a .Net Reflector tool, we managed to find out the format the timeout property needs to be passed is a timespan object of format “g”. By default the timeout is set to 30 mins.

Import-CrmPackage -CrmConnection $CRMConn -PackageDirectory "$($filePath)" -PackageName CRMPackageDeploymentTest.dll -Verbose -Timeout "1:00:00";

The deployment process took 34 mins to finish and timeout error was not thrown.