User not found error

Word of warning: This change is unsupported as it involves editing the CRM database directly. Use it at your own risk.

I encountered a weird error in CRM, that basically said that the user cannot be found. When I checked the event log, this appeared to be the underlying exception:

Exception type: CrmException
Exception message: No Microsoft Dynamics CRM user exists with the specified domain name and user ID
at Microsoft.Crm.Authentication.Claims.AuthenticationProvider.GetOrganizationId(ClaimsPrincipal principal)
at Microsoft.Crm.Authentication.Claims.AuthenticationProvider.Authenticate(HttpApplication application)
at Microsoft.Crm.Authentication.AuthenticationStep.Authenticate(HttpApplication application)
at Microsoft.Crm.Authentication.AuthenticationPipeline.Authenticate(HttpApplication application)
at Microsoft.Crm.Authentication.AuthenticationEngine.Execute(Object sender, EventArgs e)
at System.Web.HttpApplication.SyncEventExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()
at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously)

But, the user was indeed there from before and all I did was reactivate a long dormant user. My initial suspicion was that this had something to do with AD. I ran the following query to check the SID of the user against the MSCRM_CONFIG database:

select c.FriendlyName,b.FullName,d.AuthInfo,b.DomainName
from SystemUserOrganizations a
inner join [ORG_MSCRM].dbo.SystemUser b on a.CrmUserId=b.SystemUserId
inner join Organization c on c.Id=a.OrganizationId
inner join SystemUserAuthentication d on d.UserId=a.UserId
where b.DomainName='CONTOSO\powerm'

This gave me the SID of the user when the user was first created in CRM. I next ran this command in to get the current SID of the user:

wmic useraccount where name='powerm' get sid

The SID did not match to the one already in CRM, so I had to update it in the MSCRM_CONFIG database:

update d
set d.AuthInfo='W:[SID OUTPUT FROM THE DOS COMMAND PROMPT]'
from SystemUserOrganizations a
inner join [ORG_MSCRM].dbo.SystemUser b on a.CrmUserId=b.SystemUserId
inner join Organization c on c.Id=a.OrganizationId
inner join SystemUserAuthentication d on d.UserId=a.UserId
where b.DomainName='CONTOSO\powerm'

Once I updated this, the user was able to login with the same AD account.

Server Side Sync: View for Synced and Not-Synced Appointments

If you decide not to use the CRM App for Outlook, syncing emails, contacts and appointments using just Server Side Sync and Forward Mailbox can be really painful sometimes, especially when you are troubleshooting why something is not being synced. The “Server-Side Synchronization Monitoring” Dashboard provides some assistance to the Administrator, but when you want to dig into the details, I often end up using “FetchXML Builder” or “LinqPad” to query the TraceLog entity. Below is the fetchxml I use

<fetch top="50" >
  <entity name="tracelog" >
    <attribute name="tracestatus" />
    <attribute name="tracedetailxml" />
    <attribute name="tracelogid" />
    <attribute name="machinename" />
    <attribute name="tracecode" />
    <attribute name="traceactionxml" />
    <attribute name="traceparameterxml" />
    <attribute name="traceparameterhash" />
    <attribute name="errortypedisplay" />
    <attribute name="modifiedon" />
    <attribute name="text" />
    <attribute name="level" />
    <attribute name="collationlevel" />
    <filter>
      <condition attribute="tracestatus" operator="eq" value="0" />
    </filter>
    <order attribute="createdon" descending="true" />
  </entity>
</fetch>

Another common scenario that I troubleshoot is, why an appointment is not synced to Outlook after it was created in CRM. The first thing to check in this case is the user’s sync filter. I use the XrmToolBox tool “Sync Filter Manager” to check what the user’s sync filter for appointment. After confirming that the fetchxml picks up the appointment that has to be synced, we can now proceed to stage 2 of troubleshooting.

The field that is key in this scenario is called “GlobalObjectId“. This field in the appointment entity will be set, after the appointment is synced to the user’s Outlook. Unfortunately, this field is marked as not searcheable, which means it cannot be used in Advanced Find.

Global ObjectId.png

But, we can still create view that shows the synced appointments and appointments that have not been synced, using FetchXML Builder. Below are the steps

  1. Install FetchXML Builder from XrmToolBox store, if you don’t have it already
  2. Save an existing view into a new view on appointment entity. Don’t worry about the filters yet as we will update this using FetchXML BuilderSave a new view.png
  3. Next step is to open this view in FetchXML BuilderOpen View.png
  4. Update the fetchxml and save the view. Confirm the user’s sync filter for appointment using the Sync Filter Manager and make sure the new fetchxml criteria match with the user’s sync filter criteriaSave View.png

Synced Appointments – FetchXML

<fetch version="1.0" output-format="xml-platform" mapping="logical" distinct="true" >
  <entity name="appointment" >
    <attribute name="subject" />
    <attribute name="scheduledstart" />
    <attribute name="scheduledend" />
    <attribute name="regardingobjectid" />
    <attribute name="prioritycode" />
    <attribute name="activityid" />
    <attribute name="instancetypecode" />
    <attribute name="location" />
    <order attribute="createdon" descending="true" />
    <filter type="and" >
      <condition attribute="scheduledstart" operator="not-null" />
      <condition attribute="instancetypecode" operator="neq" value="2" />
      <condition attribute="scheduledend" operator="not-null" />
      <condition attribute="globalobjectid" operator="not-null" />
    </filter>
    	<link-entity name="activityparty" from="activityid" to="activityid" alias="ad" >
      <filter type="and" >
        <condition attribute="participationtypemask" operator="ne" value="9" />
      </filter>
    </link-entity>
  </entity>
</fetch>

Not Synced Appointments – FetchXML

<fetch version="1.0" output-format="xml-platform" mapping="logical" distinct="true" >
  <entity name="appointment" >
    <attribute name="subject" />
    <attribute name="scheduledstart" />
    <attribute name="scheduledend" />
    <attribute name="regardingobjectid" />
    <attribute name="prioritycode" />
    <attribute name="activityid" />
    <attribute name="instancetypecode" />
    <attribute name="location" />
    <order attribute="createdon" descending="true" />
    <filter type="and" >
      <condition attribute="scheduledstart" operator="not-null" />
      <condition attribute="instancetypecode" operator="neq" value="2" />
      <condition attribute="scheduledend" operator="not-null" />
      <condition attribute="globalobjectid" operator="null" />
    </filter>
    	<link-entity name="activityparty" from="activityid" to="activityid" alias="ac" >
      <filter type="and" >
        <condition attribute="participationtypemask" operator="ne" value="9" />
      </filter>
    </link-entity>
  </entity>
</fetch>

You should now be able to use these new view from the grid area.

Synced Appointments.png

If you try to use the view from Advanced Find, you will get this error.Advanced Find.png

This means you have to use FetchXML Builder to update you fetchxml, if any changes are required in the future. If you want to add more columns to the view, you’ll have to use “View Designer” to do that, as you would not be able to use Advanced Find to do this, because of this error.

I hope this post will help you troubleshoot future appointment sync issues.

Tools used:

  1. LinqPad
  2. Dynamics CRM LinqPad Driver
  3. XrmToolBox
  4. FetchXML Builder
  5. View Designer
  6. Sync Filter Manager

CRM Upgrade – Network name cannot be found error

When you follow the “lift and shift” upgrade method i.e. backup the old CRM database, restore it in the target environment and run deployment manager to import the organisation database, upgrade should be relatively easy. But, recently I experienced an issue that was such a pain to troubleshoot, I thought I will share this experience so that it will be helpful to others.

Below is the error I got when I import the organisation database using Deployment Manager.

Deployment Manager Error

This is what is captured in the deployment manager log (%AppData%\Roaming\Microsoft\MSCRM\Logs)

14:36:39|   Info| CrmAction execution time; UpgradeDatabaseAction; 00:04:00.9426595
14:36:39|   Info| Executing Install action: Microsoft.Crm.Tools.Admin.InstallSqlClrHelperAction
14:36:39|  Error| System.Exception: Error.ActionFailed Microsoft.Crm.Tools.Admin.InstallSqlClrHelperAction —> System.IO.IOException: The network name cannot be found.

   at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)
   at System.IO.File.InternalCopy(String sourceFileName, String destFileName, Boolean overwrite, Boolean checkHost)
   at Microsoft.Crm.Setup.Database.Helpers.CopyDatabaseFile(String sourcePath, String sourceFileName, Boolean isBuildEnvironment, String sqlServerName, String destinationFilePath, String destinationFileName, String& copyDestinationPath)
   at Microsoft.Crm.Tools.Admin.InstallSqlClrHelperAction.Do(IDictionary parameters)
   at Microsoft.Crm.Setup.Shared.CrmAction.ExecuteAction(CrmAction action, IDictionary parameters, Boolean undo)
   — End of inner exception stack trace —, Error, AbortRetryIgnore, Option1
14:37:38|   Info| InputResult: Retry

It looks like the database server name is wrong. But it is not. I used “Process Monitor” to troubleshoot the error. Here is what “Process Monitor” picked up.

Process Monitor Error

As you can see, the underlying error is a caused to lack of permissions to copy a dll file to a UNC path pointing to the database server.

Cause: McAfee Antivirus was blocking copy of any dlls through UNC path.

Resolution: Turn off “On Access Scanner” and “Access Protection” features of McAfee Antivirus during the organisation import.

In my case the KB article for SqlServerPathOverrides caused me to waste more time. I still had the same issue even after creating the network share, as McAfee was blocking all dll copy operations to UNC paths.

Bug: Branched Business Process Flow

Branched Business Process Flow was introduced in CRM 2015. I encountered a bug in BPF today, which took a day and a half to figure out. I am posting the scenario so that it will be beneficial for others who experience the same error. The bug is this:

When a lead is qualified an exception is thrown when:

  1. BPF has branches AND
  2. BPF has condition stages AND
  3. Some condition stages have only one output i.e only Yes or No
  4. Data in the form could lead to a condition block that will result in a dead end

This is the BPF, I created to test this bug.

Test BPF.png

As you can see I have a condition called “Existing account is not null”, and a stage if is true, not no stage if it is false. With this BPF an exception is thrown when the lead is qualified and Existing account is null. Below is the full error in Dynamics 365 Online.

lead-qualify-error

<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
	<s:Body>
		<s:Fault>
			<faultcode>s:Client</faultcode>
			<faultstring xml:lang="en-US">An unexpected error occurred.</faultstring>
			<detail>
				<OrganizationServiceFault xmlns="http://schemas.microsoft.com/xrm/2011/Contracts" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
					<ActivityId>8cf5f7f2-d08f-4e2d-9374-daf02247e5d0</ActivityId>
					<ErrorCode>-2147220970</ErrorCode>
					<ErrorDetails xmlns:a="http://schemas.datacontract.org/2004/07/System.Collections.Generic"/>
					<Message>An unexpected error occurred.</Message>
					<Timestamp>2017-02-09T06:30:37.8410512Z</Timestamp>
					<ExceptionSource i:nil="true"/>
					<InnerFault>
						<ActivityId>8cf5f7f2-d08f-4e2d-9374-daf02247e5d0</ActivityId>
						<ErrorCode>-2147220970</ErrorCode>
						<ErrorDetails xmlns:a="http://schemas.datacontract.org/2004/07/System.Collections.Generic"/>
						<Message>System.ArgumentNullException: Value cannot be null.
Parameter name: g</Message>
						<Timestamp>2017-02-09T06:30:37.8410512Z</Timestamp>
						<ExceptionSource i:nil="true"/>
						<InnerFault i:nil="true"/>
						<OriginalException i:nil="true"/>
						<TraceText i:nil="true"/>
					</InnerFault>
					<OriginalException i:nil="true"/>
					<TraceText i:nil="true"/>
				</OrganizationServiceFault>
			</detail>
		</s:Fault>
	</s:Body>
</s:Envelope>

This is the exception detail in CRM 2015.

<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
	<s:Body>
		<s:Fault>
			<faultcode>s:Client</faultcode>
			<faultstring xml:lang="en-AU">An unexpected error occurred.</faultstring>
			<detail>
				<OrganizationServiceFault xmlns="http://schemas.microsoft.com/xrm/2011/Contracts" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
					<ErrorCode>-2147220970</ErrorCode>
					<ErrorDetails xmlns:a="http://schemas.datacontract.org/2004/07/System.Collections.Generic">
						<KeyValuePairOfstringanyType>
							<a:key>CallStack</a:key>
							<a:value i:type="b:string" xmlns:b="http://www.w3.org/2001/XMLSchema">   at Microsoft.Crm.Extensibility.VersionedPluginProxyStepBase.Execute(PipelineExecutionContext context)
   at Microsoft.Crm.Extensibility.PipelineInstrumentationHelper.Execute(Boolean instrumentationEnabled, String stopwatchName, ExecuteWithInstrumentation action)
   at Microsoft.Crm.Extensibility.Pipeline.Execute(PipelineExecutionContext context)
   at Microsoft.Crm.Extensibility.MessageProcessor.&lt;&gt;c__DisplayClass1.&lt;RunStage&gt;b__0()
   at Microsoft.Crm.Extensibility.PipelineInstrumentationHelper.Execute(Boolean instrumentationEnabled, String stopwatchName, ExecuteWithInstrumentation action)
   at Microsoft.Crm.Extensibility.MessageProcessor.RunStage(PipelineExecutionContext context, Int32 pipelineStage)
   at Microsoft.Crm.Extensibility.MessageProcessor.Execute(PipelineExecutionContext context)
   at Microsoft.Crm.Extensibility.InternalMessageDispatcher.Execute(PipelineExecutionContext context)
   at Microsoft.Crm.Extensibility.ExternalMessageDispatcher.ExecuteInternal(IInProcessOrganizationServiceFactory serviceFactory, IPlatformMessageDispatcherFactory dispatcherFactory, String messageName, String requestName, Int32 primaryObjectTypeCode, Int32 secondaryObjectTypeCode, ParameterCollection fields, CorrelationToken correlationToken, CallerOriginToken originToken, UserAuth userAuth, Guid callerId, Guid transactionContextId, Int32 invocationSource, Nullable`1 requestId, Version endpointVersion)
   at Microsoft.Crm.Extensibility.OrganizationSdkServiceInternal.ExecuteRequestRequestWithInstrumentation(OrganizationRequest request, CorrelationToken correlationToken, CallerOriginToken callerOriginToken, WebServiceType serviceType, UserAuth userAuth, Guid targetUserId, OrganizationContext context, Boolean returnResponse, Boolean checkAdminMode, Object operation)
   at Microsoft.Crm.Extensibility.OrganizationSdkServiceInternal.ExecuteRequest(OrganizationRequest request, CorrelationToken correlationToken, CallerOriginToken callerOriginToken, WebServiceType serviceType, UserAuth userAuth, Guid targetUserId, OrganizationContext context, Boolean returnResponse, Boolean checkAdminMode)
   at Microsoft.Crm.Extensibility.OrganizationSdkServiceInternal.ExecuteRequest(OrganizationRequest request, CorrelationToken correlationToken, CallerOriginToken callerOriginToken, WebServiceType serviceType, Boolean checkAdminMode)
   at Microsoft.Crm.Extensibility.OrganizationSdkServiceInternal.Execute(OrganizationRequest request, CorrelationToken correlationToken, CallerOriginToken callerOriginToken, WebServiceType serviceType, Boolean checkAdminMode)</a:value>
						</KeyValuePairOfstringanyType>
					</ErrorDetails>
					<Message>An unexpected error occurred.</Message>
					<Timestamp>2017-02-08T05:33:31.5174084Z</Timestamp>
					<InnerFault>
						<ErrorCode>-2147220970</ErrorCode>
						<ErrorDetails xmlns:a="http://schemas.datacontract.org/2004/07/System.Collections.Generic">
							<KeyValuePairOfstringanyType>
								<a:key>CallStack</a:key>
								<a:value i:type="b:string" xmlns:b="http://www.w3.org/2001/XMLSchema">   at System.Guid..ctor(String g)
   at Microsoft.Crm.ObjectModel.BusinessProcess.WorkflowConditionNextStageEvaluator.GetNextStage(StageStep stage)
   at Microsoft.Crm.ObjectModel.BusinessProcess.ActivePathEnumerator.MoveNext()
   at Microsoft.Crm.ObjectModel.BusinessProcess.ActivePathCalculator.Calculate(String targetEntityName)
   at Microsoft.Crm.Common.ObjectModel.NextProcessStageInformationFinder.CalculateGlobalStageAndTraversedInformation(String firstEntityName, String nextEntityName)
   at Microsoft.Crm.Common.ObjectModel.LeadService.QualifyLead(BusinessEntityMoniker leadId, Boolean createAccount, Boolean createContact, Boolean createOpportunity, BusinessEntityMoniker opportunityCurrencyId, BusinessEntityMoniker opportunityCustomerId, BusinessEntityMoniker sourceCampaignId, Int32 statusCode, ExecutionContext context)</a:value>
							</KeyValuePairOfstringanyType>
						</ErrorDetails>
						<Message>System.ArgumentNullException: Value cannot be null.
Parameter name: g</Message>
						<Timestamp>2017-02-08T05:33:31.5174084Z</Timestamp>
						<InnerFault i:nil="true"/>
						<TraceText i:nil="true"/>
					</InnerFault>
					<TraceText i:nil="true"/>
				</OrganizationServiceFault>
			</detail>
		</s:Fault>
	</s:Body>
</s:Envelope>

The root cause for this seems to be GetNextStage. It seems the method can’t figure out what the next stage should be, when the BPF ends with a condition with only one branch. I haven’t tested other scenarios where this error could be triggered, but I was able to consistently reproduce the error on lead qualify.

Unrelated Note:

It seems business process has a client side caching mechanism. I had to clear cache every time after I made change to the BPF to test this issue.

Executing large FetchXML with WebAPI

You can easily execute fetchxml in WebAPI using the “fetchXml” query parameter. But this “GET” method won’t work, if the fetchxml is too big. In this case, you have to use the “POST” method to execute the fetchxml.

Sample Request Header:

Accept: application/json
OData-MaxVersion: 4.0
OData-Version: 4.0
Content-Type: multipart/mixed;boundary=batch_contactfetch

Sample Request Body:

--batch_contactfetch
Content-Type: application/http
Content-Transfer-Encoding: binary

GET https://[CRM URL]/api/data/v8.2/contacts?fetchXml=<fetch count="10" ><entity name="contact" ><attribute name="fullname" /></entity></fetch> HTTP/1.1
Content-Type: application/json
OData-Version: 4.0
OData-MaxVersion: 4.0

--batch_contactfetch--

Sample Code:

var req = new XMLHttpRequest();
req.open("POST", Xrm.Page.context.getClientUrl() + "/api/data/v8.2/$batch", true);
req.setRequestHeader("OData-MaxVersion", "4.0");
req.setRequestHeader("OData-Version", "4.0");
req.setRequestHeader("Accept", "application/json");
req.setRequestHeader("Content-Type", "multipart/mixed;boundary=batch_contactfetch");
req.onreadystatechange = function() {
    if (this.readyState === 4) {
        req.onreadystatechange = null;
        if (this.status === 200) {
            var response = JSON.parse(this.response.substring(this.response.indexOf('{'),this.response.lastIndexOf('}')+1));
			console.log(response.value);
        } else {
            Xrm.Utility.alertDialog(this.statusText);
        }
    }
};

var body = '--batch_contactfetch\n'
body += 'Content-Type: application/http\n'
body += 'Content-Transfer-Encoding: binary\n'
body += '\n'
body += 'GET ' + Xrm.Page.context.getClientUrl()+'/api/data/v8.2/contacts?fetchXml=<fetch count="10" ><entity name="contact" ><attribute name="fullname" /></entity></fetch> HTTP/1.1\n'
body += 'Content-Type: application/json\n'
body += 'OData-Version: 4.0\n'
body += 'OData-MaxVersion: 4.0\n'
body += '\n'
body += '--batch_contactfetch--'

req.send(body);

Request Screenshot

Fetch Post Request.png

Response Screenshot

fetch-post-response

Gotcha: DateTimeKind and FetchXml

I was going through the FetchXML schema and found these two interesting attributes. The first one is “utc-offset” on the “fetch” node.

utcoffset

The other one is “usertimezone” on the “attribute” node.

usertimezone

Both these attributes give an impression, that it is possible to return datetime attributes in a different timezone instead of UTC, but in reality they don’t seem to do anything.

The only way to return datetime in the user’s local timezone, is by using the deprecated ExecuteFetchRequest. I will demonstrate this with XrmToolBox. This is my simple fetch query.

fetchxml-with-datetime

Below is the raw fetch result

fetch-xml-response-raw

Below is the table grid result

fetch-xml-response-retrievemultiple

I execute the FetchXML using the FetchXML Builder tool. As you can see, the datetime values are different. This is because when you use “RetrieveMultiple” to execute the fetch query, the datetime returned is always UTC and has to be converted to the local timezone. ExecuteFetchRequest is now deprecated and RetrieveMultiple is the recommended way to execute fetchxml. These two points really puzzle me:

  1. Why user-timezone and utc-offset don’t seem to do anything. Are they internally used?
  2. Why MS decided to change the datetime behaviour

So, this is a good point to remember when you are executing fetchxml using “FetchXML Tester” or have set the Result view to Raw fetch result in “FetchXML Builder” or using a mixture of ExecuteFetchRequest and RetrieveMultiple in your code.

References:

  1. ExecuteFetchRequest class
  2. XrmToolBox Issue #326

 

Convert Personal View to System View

When you design a query from the “Advanced Find” window, you can save the query for future use. I call this “Personal View”, but the official name for this is “Saved View”. This view is only visible to the person who saved the view (unless it is shared/reassigned).

As more personal views get created, it becomes an issue during migration, as these are not transported in the solution xml. You can of course use Solution Extender to copy this across, but I would like to do this right from the Advanced Find window. Apart from data migration, another scenario where you might find the need to create a system view from a personal view, is when you are constantly sharing views to a large number of people of group. When you are doing this, it is good time to actually make this a system view.

With these scenarios in mind, I have developed a solution that simplifies the process of creating a system view from a personal view. After installing the managed solution, you will see a new button called “Promote to System View” in the advanced find, when you switch to the “Saved Views” tab.

screenshot

To create a system view from the personal view, simply choose the views that need to be converted, and click the “Promote to System View” button. A message will be displayed after the conversion is complete. Once you refresh the window, you should be able to see the newly created system view(s).

Please log any issues/feedback/feature request in the github repo -> https://github.com/rajyraman/Personal-View-to-System-View/issues

You can download the managed solution from https://github.com/rajyraman/Personal-View-to-System-View/releases