Showing posts with label CRM 2015. Show all posts
Showing posts with label CRM 2015. Show all posts

Wednesday, January 27, 2016

CRM Outlook Client: Emails Tracked to Inactive Records

The way the CRM Outlook client tracks emails and links them to CRM records is based on email address.  It will take the customer's address from the email and search the entire CRM system for any records with an exact match.  This search covers any entity with an email address field, including custom entities, regardless of record status or anything else, really.  This can sometimes create a couple issues:

Problem #1: Emails are tracked to entity types that you don't necessarily want them tracked to. 
Unfortunately, CRM does not let you dictate which record types the Outlook Client tracks emails to.  As long as there's an email address field on the entity, the Outlook Client will attempt to link to it.

The fix: There is no way to turn off individual entity types from Outlook tracking.  This is something to keep in my when designing your entities.  If you have an entity that must have an email address stored on it, consider creating the field as a simple, single line of text.  Unless it's configured as an email-type field, the Outlook client will ignore it.

It's important to note, too, that once you create an email field on an entity, Outlook will search that entity for matches, and CRM doesn't let you undo or disable that.  

Problem #2: Emails get tracked to inactive records.  
One thing we've noticed after several years of using the CRM Outlook client is that it does not discriminate between active or inactive records.  CRM will try to link emails to matching email addresses on records regardless of record status.  As a result, you may notice inactive records being linked to your emails.

The fix: As we already know, CRM take a blanket approach to linking emails.  The key in linking track an email against a record is the email address.  So, if you want inactive records to be ignored by the Outlook client you can create a workflow or plugin that deletes or changes the email address upon deactivation.  For one of my clients we just add "-inactive" to the end of the email address.  Adding this text will cause CRM to not recognize the email address and skip over it.

Tuesday, January 26, 2016

CRM Ellipses Missing from Subgrid Command Bar

This may be the simplest post I ever make.  Recently we had a remote user who had an issue where the ellipses (the '...' icon) would not appear in the command bar of a subgrid.  They were looking for the Export to Excel button.  We are running CRM 2015 on premise.  This is apparently an issue with CRM 2015 and happens when the labels in the command bar run too long (see here).  Usually CRM accounts for this by hiding the buttons and displaying the ellipses at the end.  After checking for Export to Excel permissions (on the Business Management tab of a Security Role), customizations, and every piece of functionality I could think of, I finally found the fix.  The fix is...

...(drum roll)...

Widen your browser window.  

Sometimes getting caught up in the complexities of the system can distract you from the most obvious and simple solutions.

Thursday, August 13, 2015

Dynamics CRM Performance Test with PowerShell

This is a little script I made as a sort of performance test for CRM.  Basically, how it works is it queries 1000 Contact records from CRM and tracks the time it takes to loop through them and make an update to each one.  It's designed to update a single field (in this case, 'fax') with a dummy value, then change it back.  So, to not overwrite valid data it queries only records where the field to be updated is null, makes the update, then it changes it back to null.

Furthermore, it writes the time it takes to make all the updates to a csv file of your choosing and then restarts itself to run after a certain amount of time (currently 1 hour).  Over time it creates a log of these durations which you can build charts and reports off of.

One thing to point out is that the list of 1000 contact records is queried through the SQL database, so as written this script only works for on premise deployments.  In order to make it work for CRM Online instances you'll need to change the SQL query to a CRM query call to the API.  A few of my other posts should show you how to accomplish this.

Please remember, this is a performance test.  Speedy, efficient code is not the goal here, but rather understanding the time it takes to run.  You may notice some unnecessary steps being performed.  I'm just trying to hit as many areas of the system as possible to get as much of a complete read as possible.

This script might be useful to measure differences in speed throughout the day, or to compare the system before and after large changes.  In my own case, I built this script to get some kind of measurement of the system prior to us enabling CRM Auditing.  There were concerns that this feature would slow down CRM.  And for those interested, there was no noticeable difference shown to us.

I hope this is useful to someone out there.

#Add SDK references
    Add-Type -Path "[mySDKPath]\Bin\Microsoft.Xrm.Sdk.dll";
    Add-Type -Path "[mySDKPath]\Bin\Microsoft.Xrm.Client.dll";
    Add-Type -Path "[mySDKPath]\Bin\Microsoft.Crm.Sdk.Proxy.dll";

#CRM Connection
    $CRMUrl = "https://[myCRMPath]";
    $CRMLogin = "[myCRMAccount]";
    $CRMPwd = Read-Host "Enter password for account $CRMLogin"
    $CRMConnection = [Microsoft.Xrm.Client.CrmConnection]::Parse("Url=$CRMUrl; Username=$CRMLogin; Password=$CRMPwd");
    $CRMService = New-Object -TypeName Microsoft.Xrm.Client.Services.OrganizationService -ArgumentList $CRMConnection;

#SQL Connections
    $sqlUser = "[mySQLAccount]"
    $sqlPwd = Read-Host "Enter password for SQL account $sqlUser" -AsSecureString
   
#Source datasource
    $sourceDatabaseServer = "[mySQLDatabaseServer]"
    $sourceDatabase = "[mySQLDatabase]"
    $sourceConnectionString = "Server=$sourceDatabaseServer;uid=$sqlUser; pwd=$sqlPwd;Database=$sourceDatabase;Integrated Security=true;"
    $sourceConnection = New-Object System.Data.SqlClient.SqlConnection
    $sourceConnection.ConnectionString = $sourceConnectionString

function PerformanceTest{
#SQL Query
    #Source Database Query
    $top = "1000"
    $sourceConnection.Open()
    $sourceQuery = “SELECT TOP $top contactid, fax
                    FROM [mySQLTable]
                    WHERE fax is null”
    $sourceCommand = $sourceConnection.CreateCommand()
    $sourceCommand.CommandText = $sourceQuery
    $sourceResult = $sourceCommand.ExecuteReader()
    $Global:sourceTable = New-Object “System.Data.DataTable”
    $sourceTable.Load($sourceResult)
    $sourceConnection.Close()

    #Looping Through Records
    $count = 0
    $startTime = Get-Date
    foreach($record in $sourceTable){
        $count ++;
        #Query Record
        $CRMQuery = New-Object -TypeName Microsoft.Xrm.Sdk.Query.QueryExpression -ArgumentList "contact";
        $CRMQuery.ColumnSet.AddColumn("firstname");
        $CRMQuery.ColumnSet.AddColumn("lastname");
        $CRMQuery.ColumnSet.AddColumn("telephone1");
        $CRMQuery.ColumnSet.AddColumn("telephone2");
        $CRMQuery.ColumnSet.AddColumn("gendercode");
        $CRMQuery.ColumnSet.AddColumn("address1_country");
        $CRMQuery.ColumnSet.AddColumn("ownerid");
        $CRMQuery.ColumnSet.AddColumn("address2_country");
        $CRMQuery.ColumnSet.AddColumn("address1_line1");
        $CRMQuery.ColumnSet.AddColumn("address2_line1");
        $CRMQuery.ColumnSet.AddColumn("emailaddress1");
        $CRMQuery.ColumnSet.AddColumn("emailaddress2");
        $CRMQuery.Criteria.AddCondition("contactid", [Microsoft.Xrm.Sdk.Query.ConditionOperator]::Equal, $record.contactid.Guid);
        $CRMQuery.Criteria.AddCondition("fax", [Microsoft.Xrm.Sdk.Query.ConditionOperator]::Null);
        $CRMQueryResults = $CRMService.RetrieveMultiple($CRMQuery);
        $CRMRecords = $CRMQueryResults.Entities

        #Create Entity Object and identify
        $targetRecord = New-Object -TypeName Microsoft.Xrm.Sdk.Entity -ArgumentList "contact";
        $targetRecord.Id = $CRMRecords[0].Id.Guid;
       
        $targetRecord["fax"] = "test data";
        $CRMService.Update($targetRecord);

        $targetRecord["fax"] = $null;
        $CRMService.Update($targetRecord);

        Write-Host "Record"$record.contactid": $count/$top"
    }
    $endTime = Get-Date
    Write-Host "`n`nStarted: "$startTime
    Write-Host "Ended:   "$endTime
    $duration = New-TimeSpan $startTime $endTime
    Write-Host "`nDuration: $duration"
    Add-Content -Path "[myPath]\PerformanceTest.csv" "$startTime,$duration,$top,PROD" -Force

    Write-Host "Timing out for 1 hours"
    Start-Sleep -Seconds 3600

    PerformanceTest
}
PerformanceTest