Friday, 22 April 2016

CRM 2016 Update Profile Picture

Information on this seems to be fairly limited at the moment, but this is cool feature.

1. Double click your image at the top right of the CRM 2016 screen.

 2. Select Choose File
 3. Pick your picture and click open
4. Click OK

Your profile picture should now be updated!


Tuesday, 5 April 2016

Unable to add user to CRM 2016

Recently I encountered an issue where I couldn't add a user as CRM determined that the user ID already existed in the organisation, however I could see no evidence of this.

After a quick search I found this article

https://blogs.msdn.microsoft.com/ukdynsupport/2009/07/16/authentication-when-you-are-adding-a-new-user-to-crm-or-a-user-to-a-new-organization-in-crm/

So the key was the user record was in the MSCRM_CONFIG database still, as we had done a restore and org import on an earlier backup.

To identify this was actually the cause I had to find the SID for the user, without access to the AD tools, I found an article on using powershell, the following commands got me the SID

PS> $objUser = New-Object System.Security.Principal.NTAccount("{domain name}")
PS> $strSID = $objUser.Translate([System.Security.Principal.SecurityIdentifier])
PS> $strSID.Value
S-1-5-21-1004336348-1715567821-725345543-40705
With the returned SID I could identify the record
 SELECT * FROM SystemUserAuthentication WHERE AuthInfo LIKE '%S-1-5-21-1004336348-1715567821-725345543-40705'
I decided to update the record SID to one that will never exist rather than delete, as there could be a spider web of relationships that get really stuffed up.
 
UPDATE SystemUserAuthentication
SET AuthInfo = 'W:S-1-5-21-1004336348-1715567822-725345543-40705'
WHERE Id = 'CF775160-6BE6-E511-80CF-005056BD0631'
After this update I was able to create the user record.

Wednesday, 2 March 2016

Unable to distribute Campaign Activities, Error retrieving next number (currentbulkoperationnumber) ..

In a CRM system we were having trouble distributing campaign activities, we would always get the following error 'Error retrieving next number (currentbulkoperationnumber) for organization {e14513f2-5cdb-4194-9ca1-52d04cd0b077): return value is empty'.  No matter what entity was in the marketing list the distribute would fail after choosing the owner.  What was equally perplexing new organisatios wouldn't have this issue.

We started getting this error in CRM 2011, my hope was upgrading to CRM 2016 would resolve this error, unfortunately not.

After doing a SQL trace on the SQL server we managed to find 1 SQL query which looked suspect.

exec sp_executesql N'declare @currentval int
update OrganizationBase set @currentval = CurrentBulkOperationNumber, CurrentBulkOperationNumber = CurrentBulkOperationNumber + 1 where OrganizationId = @orgid
select @currentval',N'@orgid uniqueidentifier',@orgid='E14513F2-5CDB-4194-9CA1-52D04CD0B077'

The CurrentBulkOperationNumber field in our OrganizationBase table was currently set to NULL, updating this to 1000 resolved the issue.

 UPDATE OrganizationBase SET CurrentBulkOperationNumber = 1000

This does make me wonder what other data issues are lurking in our database, that we just haven't noticed yet.

Wednesday, 2 December 2015

CRM 2011 Plugin Assembly not updating with new code

With CRM 2011, recently had a really odd situation, deploying the CRM 2011 plugin assembly wasn't overwriting the old code in the CRM database.  Even after I tried de-registering the assembly and redeploying the old code was still used.
How I fixed this was incrementing the assembly version, it then updated the plugin assembly properly in the database.

CRM 2011 - Ghost Dependencies

Long time since the last post sorry, but figured I would post about something odd I found in our CRM 2011 environment here.

When we were trying to delete an entity we were getting a message that we couldn't delete the entity due to dependencies showing a blank list!

After a lot of searching we found the error to be related to some orphaned records in the ReportEntityBase table that were set as a managed solution component.

I first attempted to remove this the supported way to no avail so had to come up with a 'hack' to get them out of the database.  I have no idea how you would do this with Cloud CRM.

First step was to backup the data about to be removed, just in case we had some downstream impact.

--Back the Dependencies, nodes and offending records
SELECT db.* INTO DependencyBase_backup FROM DependencyBase db 
JOIN DependencyNodeBase dnb ON dnb.DependencyNodeId = db.DependentComponentNodeId
JOIN ReportEntity rpe ON rpe.ReportEntityId = dnb.ObjectId
WHERE ComponentType = 32 and rpe.ObjectTypeCode = 10001

SELECT dnb.* INTO DependencyNodeBase_backup FROM DependencyNodeBase dnb
JOIN ReportEntity rpe ON dnb.ObjectId = rpe.ReportEntityId
WHERE ComponentType = 32 and rpe.ObjectTypeCode = 10001 

SELECT * INTO ReportEntityBase_backup FROM ReportEntityBase WHERE ObjectTypeCode = 10001

Next delete out the dependency records pointing to the problem records
 
DELETE db FROM DependencyBase db 
JOIN DependencyNodeBase dnb ON dnb.DependencyNodeId = db.DependentComponentNodeId
JOIN ReportEntity rpe ON rpe.ReportEntityId = dnb.ObjectId
WHERE ComponentType = 32 and rpe.ObjectTypeCode = 10001

Now delete the joining node records
 
DELETE dnb FROM DependencyNodeBase dnb
JOIN ReportEntity rpe ON dnb.ObjectId = rpe.ReportEntityId
WHERE ComponentType = 32 and rpe.ObjectTypeCode = 10001 
Delete the Orphaned records
DELETE FROM ReportEntityBase WHERE ObjectTypeCode = 10001 

Friday, 7 June 2013

CRM 2011 HTTPS Endpoint with SSIS and ADFS

After quite a bit of work, I finally managed to get a connection working with the CRM 2011 Https endpoint, using no config file, below is the code I used to achieve this.

private static IOrganizationService GetHttpsCRMService(string serverUrl, string adfsUrl, string username, string password)
        {
            Uri organizationUriIFD = new Uri(serverUrl + "/XRMServices/2011/Organization.svc");
                        
            EndpointAddress endpointAddress = new EndpointAddress(organizationUriIFD);

            CustomBinding customBinding = new CustomBinding();
            customBinding.Name = "CustomBinding";
            
            var tsBE = new TransportSecurityBindingElement();
            tsBE.AllowInsecureTransport = false;
            tsBE.IncludeTimestamp = true;


            EndpointAddress usernameMixed = new EndpointAddress(adfsUrl + "/adfs/services/trust/13/usernamemixed");
            WS2007HttpBinding wsbinding = new WS2007HttpBinding(SecurityMode.TransportWithMessageCredential);
            wsbinding.MaxReceivedMessageSize = 65536;
            wsbinding.MaxBufferPoolSize = 524288;
            wsbinding.Security.Transport.ClientCredentialType = HttpClientCredentialType.None;
            wsbinding.Security.Message.ClientCredentialType = MessageCredentialType.UserName;
            wsbinding.Security.Message.EstablishSecurityContext = false;

            IssuedSecurityTokenParameters stP = new IssuedSecurityTokenParameters(null, usernameMixed, wsbinding);
            stP.IssuerMetadataAddress = new EndpointAddress(new Uri(adfsUrl + "/adfs/services/trust/mex"));

            var additionalRquestParameters =
                @"<trust:SecondaryParameters xmlns:trust='http://docs.oasis-open.org/ws-sx/ws-trust/200512'>" +
                @"    <trust:KeyType xmlns:trust='http://docs.oasis-open.org/ws-sx/ws-trust/200512'>http://docs.oasis-open.org/ws-sx/ws-trust/200512/SymmetricKey</trust:KeyType>" +
                @"    <trust:KeySize xmlns:trust='http://docs.oasis-open.org/ws-sx/ws-trust/200512'>256</trust:KeySize>" +
                @"    <trust:Claims Dialect='http://schemas.xmlsoap.org/ws/2005/05/identity' xmlns:trust='http://docs.oasis-open.org/ws-sx/ws-trust/200512'>" +
                @"        <wsid:ClaimType Uri='http://schemas.xmlsoap.org/ws/2005/05/identity/claims/upn' xmlns:wsid='http://schemas.xmlsoap.org/ws/2005/05/identity' />" +
                @"    </trust:Claims>" +
                @"    <trust:KeyWrapAlgorithm xmlns:trust='http://docs.oasis-open.org/ws-sx/ws-trust/200512'>http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p</trust:KeyWrapAlgorithm>" +
                @"    <trust:EncryptWith xmlns:trust='http://docs.oasis-open.org/ws-sx/ws-trust/200512'>http://www.w3.org/2001/04/xmlenc#aes256-cbc</trust:EncryptWith>" +
                @"    <trust:SignWith xmlns:trust='http://docs.oasis-open.org/ws-sx/ws-trust/200512'>http://www.w3.org/2000/09/xmldsig#hmac-sha1</trust:SignWith>" +
                @"    <trust:CanonicalizationAlgorithm xmlns:trust='http://docs.oasis-open.org/ws-sx/ws-trust/200512'>http://www.w3.org/2001/10/xml-exc-c14n#</trust:CanonicalizationAlgorithm>" +
                @"    <trust:EncryptionAlgorithm xmlns:trust='http://docs.oasis-open.org/ws-sx/ws-trust/200512'>http://www.w3.org/2001/04/xmlenc#aes256-cbc</trust:EncryptionAlgorithm>" +
                @"</trust:SecondaryParameters>";

            System.Xml.XmlDocument additionalParamDoc = new System.Xml.XmlDocument();
            additionalParamDoc.LoadXml(additionalRquestParameters);

            stP.AdditionalRequestParameters.Add(additionalParamDoc.DocumentElement);
            stP.RequireDerivedKeys = false;
            stP.KeySize = 256;
            stP.KeyType = System.IdentityModel.Tokens.SecurityKeyType.SymmetricKey;
            
            tsBE.LocalClientSettings.DetectReplays = false;
            tsBE.LocalServiceSettings.DetectReplays = false;
            tsBE.EndpointSupportingTokenParameters.Endorsing.Add(stP);



            customBinding.Elements.Add(tsBE);

            var textEncoding = new System.ServiceModel.Channels.TextMessageEncodingBindingElement();
            var httpsTransport = new System.ServiceModel.Channels.HttpsTransportBindingElement();

            customBinding.Elements.Add(textEncoding);

            customBinding.Elements.Add(httpsTransport);
            customBinding.ReceiveTimeout = new TimeSpan(0, 10, 0);
            customBinding.SendTimeout = new TimeSpan(0, 1, 0);
            customBinding.OpenTimeout = new TimeSpan(0, 1, 0);
            customBinding.CloseTimeout = new TimeSpan(0, 1, 0);

            var contract = new System.ServiceModel.Description.ContractDescription("IOraganizationService", "http://schemas.microsoft.com/xrm/2011/Contracts/Services");
            contract.ContractType = typeof(IOrganizationService);

            OrganizationServiceClient osClient = new OrganizationServiceClient(customBinding, endpointAddress);
            osClient.ClientCredentials.UserName.UserName = username;
            osClient.ClientCredentials.UserName.Password = password;
            
            return (IOrganizationService)osClient;
        }

Tuesday, 5 March 2013

CRM 2011 Date Only Issue Plugin

As explained quite well in Kelvin's blog, CRM 2011 handles Date Only fields in a strange way.  So I have developed a plugin that will get round this.

The code for this is below and it should be deployed pre validation for the entities you wish to use it with, create or update.


/// <summary>
/// Fix for getting round the timezone issues with date only fields
/// </summary>
public class TimeZoneFix : IPlugin
{
    public void Execute(IServiceProvider serviceProvider)
    {
        //Get an instance of the helper class.
        PluginHelper helper = new PluginHelper(serviceProvider);
        helper.tracer.Trace("Loaded Helper");
        if (helper.targetEntity.Attributes.Any(a => a.Value != null && a.Value.GetType() == typeof(DateTime)))
        {
            IOrganizationService service = helper.service;
            helper.tracer.Trace("Building Request");
            RetrieveEntityRequest request = new RetrieveEntityRequest();
            request.LogicalName = helper.context.PrimaryEntityName;
            request.EntityFilters = EntityFilters.Attributes;
            RetrieveEntityResponse response =  (RetrieveEntityResponse)service.Execute(request);
            if (response != null && response.EntityMetadata != null)
            {
                List<KeyValuePair<string, object>> attribs = helper.targetEntity.Attributes.Where(a => a.Value != null && a.Value.GetType() == typeof(DateTime)).ToList();
                foreach (var att in attribs)
                {
                    DateTime date = (DateTime)helper.targetEntity[att.Key];
                    DateTime localDate = date.ToLocalTime();
                    TimeSpan dateDiff = localDate - date;
                    //Get the attribute metadata
                    AttributeMetadata meta = response.EntityMetadata.Attributes.FirstOrDefault(am => am.LogicalName.ToLower().Equals(att.Key));
                    //Check in the attribute metadata if the attribute is a date only.
                    if (meta != null && meta.AttributeType != null &&
                        meta.AttributeType == AttributeTypeCode.DateTime &&
                        ((DateTimeAttributeMetadata)meta).Format == DateTimeFormat.DateOnly)
                    {
                        helper.targetEntity[att.Key] = localDate.AddHours(dateDiff.Hours + 10);
                    }
                }
            }
        }
    }
}