{Dynamic CRM Word templates} Setting word templates using workflow not working for custom entity in Dynamics CRM 2016? Check this out

Document template feature of Dynamics CRM 2016 came as a big relief to many consultants like us whose only option prior to that was to go to customer and speak about mail merge and many a times which was not liked by customers much. However the introduction of word and excel template features in Dynamics CRM 2016 never ceases to amaze the customers and has made the life of consultants like us much easier.

Now coming to word templates, one big disadvantage while accomplishing from the CRM UI is that it cannot be done for multiple records. You have to do for each individual record which is quite cumbersome right?

Well you have a quick fix for that. There is a new step introduced in the workflow called Perform Action Step and using that you can actually set the word template for an entity. So basically the idea is you can have an on-demand workflow which will use this step to set the word template to the target entity type and then coming back to the UI, you can select multiple records and run the workflow. And your very complex workflow will attach the word template to each of the records you selected the workflow to run. You could view the the attachment in the annotations section for each record.

image

 

image

 

image

The above pics are taken from Inogic blog on the same article. It is a wonderful article which has explained the same approach that I highlighted above.  Just like all their other articles, this one is also a treat to read. – http://www.inogic.com/blog/2016/02/set-word-template-through-workflow-in-dynamics-crm-2016/

Well so far so good. But wait, are we missing a link here. Hell yeah!

All the examples you find on this topic are all using OOB entities and indeed all the examples work great. But to be honest, in most of the cases we end up designing lot of custom entities for the customer. So what if we need to do something similar for the custom entities. Well then you have a problem. Let’s explore that.

I have created a custom entity called Template Test. I created a global word template for the custom entity. Now I create a workflow of on-demand type which will set the word template to the custom entity as the target.

As usual, I select the Perform Action –> Set word template –> Click on Set properties –> Select the appropriate word template for the entity

image

image

Oops! What happened here? The problem here is that while selecting the target, the entity is not showing up in the Form Assistant like the one it shows for OOB entities like Account and Contact.

 

Scratching your head here to identify the issue. Well I have two solutions for you as a workaround for this and I leave this up to you to identify which one fits best for you

 

Sol 1: Enable Business Process Flows for the custom entity:

As weird it may sound, enabling business process flow for the custom entity would indeed make your entity appear in the form assistant for the target field.

Go to your entity customization and check the checkbox for business process flow fields creation.

image

Save and publish the entity customizations. Now come back to the workflow created earlier and click on the target field. You should be able to set it to the custom entity.

image

You actually do not need to create the business process flows for the entity. Just enabling it to support business process flows would do the trick for you.

 

Sol 2: Programmatically set the word template for your target entity

If the above solution is not your cup of tea, then you can do something like below:

  • Create a on-demand workflow for your custom entity which would invoke a custom workflow assembly.
  • The custom workflow assembly would set the word template programmatically using the below code.

OrganizationRequest req = new OrganizationRequest("SetWordTemplate");
req["Target"] = new EntityReference("<custom entity schema name>", customentityguid);
req["SelectedTemplate"] = new EntityReference("documenttemplate", templateid);
orgService.ExecuteCrmOrganizationRequest(req);

A small stuff but enough to waste your days researching on the same.

 

Hope this helps!

Advertisements

{Dynamics CRM + SAML + ADFS} FParse SAML Assertion token generated from Dynamics CRM on-premise environment configured with Claims

This blog post is a continuation of my previous post in which I explained on how to get SAML Token programmatically for your Dynamics On-premise environment configured with claims. If you have not read the previous post, I strongly suggest to read it and come back to this.

https://debajmecrm.com/2016/06/05/utility-saml-token-generator-for-your-dynamics-crm-online-configured-with-claims/

 

In this blog post, I will show you how to read the SAML assertion token that was obtained in the previous step. This would be typically done by applications who are relying on your SAML token to authenticate the user and many cases would be handled by a separate. But knowing a bit more never really harms. So if you are interested, let’s proceed.

Our main intention here would be to parse the SAML token and get the user’s claims from that. But there is a problem here. The SAML assertion token would be encrypted by the certificate of your relying party. So the decrypting party would need to have the certificate to decrypt the SAML token. Just to give you an idea, the SAML assertion token would have the following format.

<samlp:Response ID=’_4172503e-7104-4382-8cda-6f93f65de530′ Version=’2.0′ IssueInstant=’2016-06-01T05:05:18.362Z’ Destination=https://SAMLAssertionendpoint” Consent=’urn:oasis:names:tc:SAML:2.0:consent:unspecified’ xmlns:samlp=’urn:oasis:names:tc:SAML:2.0:protocol’>
                              <Issuer xmlns=’urn:oasis:names:tc:SAML:2.0:assertion’>
/adfs/services/trust">http://<federation serverl url>/adfs/services/trust</Issuer>
                              <samlp:Status>
                                <samlp:StatusCode Value=’urn:oasis:names:tc:SAML:2.0:status:Success’ />
                              </samlp:Status>
                              <EncryptedAssertion xmlns=’urn:oasis:names:tc:SAML:2.0:assertion’>
                                <xenc:EncryptedData Type=’
http://www.w3.org/2001/04/xmlenc#Element’ xmlns:xenc=’http://www.w3.org/2001/04/xmlenc#’>
                                  <xenc:EncryptionMethod Algorithm=’
http://www.w3.org/2001/04/xmlenc#aes256-cbc’ />
                                  <KeyInfo xmlns=’
http://www.w3.org/2000/09/xmldsig#’>
                                    <e:EncryptedKey xmlns:e=’
http://www.w3.org/2001/04/xmlenc#’>
                                      <e:EncryptionMethod Algorithm=’
http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p’>
                                        <DigestMethod Algorithm=’
http://www.w3.org/2000/09/xmldsig#sha1′ />
                                      </e:EncryptionMethod>
                                      <KeyInfo>
                                        <ds:X509Data xmlns:ds=’
http://www.w3.org/2000/09/xmldsig#’>
                                          <ds:X509IssuerSerial>
                                            <ds:X509IssuerName><—Removed certificate details—-></ds:X509IssuerName>
                                            <ds:X509SerialNumber>2787593233934917942755289290276949976521129800</ds:X509SerialNumber>
                                          </ds:X509IssuerSerial>
                                        </ds:X509Data>
                                      </KeyInfo>
                                      <e:CipherData>
                                        <e:CipherValue>gj65thkZ4rB22ktgO6KdTsWLhyUy5gpvD2Jt94on4Z6ILT2VbpW/sMyFUVmdsY0dJ1nk8ijyhTt2w7T4HJf3Gl2OzB0LZm8S0KrjYtDGTUQetT08SI1puaXmN0JQMeiGWio/qyuJ8bUMGwMJnQbkZ6U/RMmICN8WQlErNI/ALux7n3SnI6kApA55UIP1OxnOglM6n8OzHwwnyCPBo6Je/impg3E5o1JtWC3tx6u2w2tOL3/kCWpZ9ELNMajcd8WeYXs8DAagHpoGVoqrmfL49dcnYhcWmEP+ROIRk6QerykmK1PVI3u0/mdCRAI6c+PlF4d2LPB9GZQyNGS78ch5UA==</e:CipherValue>
                                      </e:CipherData>
                                    </e:EncryptedKey>
                                  </KeyInfo>
                                  <xenc:CipherData>
                                    <xenc:CipherValue>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</xenc:CipherValue>
                                  </xenc:CipherData>
                                </xenc:EncryptedData>
                              </EncryptedAssertion>
                            </samlp:Response>

 

So let’s proceed with it.

  • Since Dynamics CRM is configured as your relying party, login to your Dynamics CRM server, open IIS –> Server Certificates –> Select the encryption certificate and right click – > select export option from the menu

image

  • Export it as .pfx file since you need the private key as well in the certificate to decrypt the SAML assertion. Since the certificate is exported as pfx file, you need to give a password here. Remember the password, this would be need later in code.

image

  • Click OK. The pfx file would be created in the location that you provided. Copy the .pfx file and store it in a location from  client application which consumes the SAML token, can access. The rest is very simple. Below is the sample code which would read the SAML assertion and get the claims back.

 

private static void SAMLParser()
                {
                        string samlFilePath = @"saml.xml";
                        string certificatePath = @"<certificate path>.pfx";
                        X509Certificate2 cert = new X509Certificate2(certificatePath, "<password when exported>");
                        var serviceTokens = new List<SecurityToken>();
                        serviceTokens.Add(new X509SecurityToken(cert));

                        var issuers = new ConfigurationBasedIssuerNameRegistry();
                        issuers.AddTrustedIssuer(cert.Thumbprint, cert.IssuerName.Name);

                        var configuration = new SecurityTokenHandlerConfiguration
                                    {
                                            AudienceRestriction = { AudienceMode = AudienceUriMode.Never },
                                            CertificateValidationMode = X509CertificateValidationMode.None,
                                            RevocationMode = X509RevocationMode.NoCheck,
                                            IssuerNameRegistry = issuers,
                                            MaxClockSkew = TimeSpan.FromMinutes(5),
                                            ServiceTokenResolver = SecurityTokenResolver.CreateDefaultSecurityTokenResolver(serviceTokens.AsReadOnly(), false)

                                    };

                        var tokenHandlers = SecurityTokenHandlerCollection.CreateDefaultSecurityTokenHandlerCollection(configuration);

                        using (StringReader sr = new StringReader(XDocument.Load(samlFilePath).ToString()))
                        {
                                using (XmlReader reader = XmlReader.Create(sr))
                                {
                                        if (!reader.ReadToFollowing("EncryptedAssertion", "urn:oasis:names:tc:SAML:2.0:assertion"))
                                        {
                                                throw new Exception("Assertion not found!");
                                        }
                                        SecurityToken token = tokenHandlers.ReadToken(reader.ReadSubtree());

                                        Saml2SecurityToken samlToken = token as Saml2SecurityToken; // Getting the SAML token here.

                                        // This is where you get the claims of the user from the SAML assertion token

                                        Dictionary<string, object> payload = new Dictionary<string, object>();
                                        foreach (Saml2Statement statement in samlToken.Assertion.Statements)
                                        {
                                                Saml2AttributeStatement attributeStatement = statement as Saml2AttributeStatement;
                                                if (null != attributeStatement)
                                                {
                                                        foreach (Saml2Attribute attribute in attributeStatement.Attributes)
                                                        {
                                                                Console.WriteLine("Name: {0}, Value: {1} ValueType: {2}", attribute.Name, attribute.Values[0], attribute.AttributeValueXsiType);
                                                                payload.Add(attribute.Name, attribute.Values[0]);

                                                        }
                                                }
                                        }

                                    // Use this to convert it into JWT token and pass on to the web-api.

                                }
                        }
                }

Since you are able to decrypt and find out the claims, you application assumes that it is being originated from your Dynamics CRM.

You can use these claims and then convert it into JWT token.

 

Hope this helps!

{Dynamics CRM + SAML + ADFS}–Get SAML Token programmatically for your Dynamics On-premise environment configured with claims

As a CRM Consultant we come across myriad of requirements. Of them some are our day-day stuffs. But the ones which puts us in a bit of head scratching and brainstorming are the ones which gives us the maximum satisfaction when completed. And this was one of them.

Our client had configured IFD for their Dynamics CRM 2015 on-premise environment. They had a WebAPI web service to which CRM needed to communicate. After initial discussions with the customer, the idea was to pass the SAML token from Dynamics CRM as one of header values in the web api call. The WebAPI would then parse the SAML token from the header of the request and then read the claims to authenticate the caller and send the response back to CRM.

So first things first. We have to pass the SAML token as one of the header values in the web-api call. How to approach this. Let’s understand the mechanism here. For people who already know this, it’s like a repeat but for readers who are unaware of this, I will try to put it in very simple terms.

  • CRM is configured as a relying party fro ADFS. So CRM will only trust only tokens generated from ADFS
  • User tries to login to Microsoft Dynamics CRM. Since user could not present a valid SAML token to CRM, CRM redirects the user to ADFS login page.
  • User enters the username and password. ADFS has active directory configured as trust store. It takes your userid and password and validates it against the identity provider which is your active directory.
  • IF the credentials are correct, Active directory issues a token which contains the claims for the user. ADFS then converts the claims and puts into the SAML token with the claims which are understood by your Dynamics CRM. The user now sends another request to Dynamics CRM and this time with a valid SAML token. CRM now allows the user login.

 

Believe me this is explained in a very simple way. However there are whole lot of stuffs that you need to configure for this to take place. If you are interested to know the gory details, you can visit the technet article – https://technet.microsoft.com/en-us/library/dn609803.aspx

Now coming back to our topic. Since our intention is to get the SAML token here, if we take an analogy, we have to replicate the whole process as above but without user intervention. Wait? What is the problem then? The problem the user’s credentials which needs to be passed to get the SAML token. How can we do this then?

The solution is to use execution users credentials and to do that we have to replicate the sign-in process. To do that the first thing make the user hit the SignOn page of ADFS.

The signon page has the url of https://<your adfs server url>/adfs/ls/idpinitiatedsignon.aspx

The next thing we need to do is create a SAML asserting endpoint for your relying party if that is already not present. To do this, follow the below steps

  • Open your ADFS server and then open ADFS Management window and click on relying parties.

image

  • Select the Relying Party trust for your CRM and then right click-> Properties  and go to EndPoints.

image

  • Check if you have SAML Assertion end-point showing up. If not then click on Add and enter a new SAML assertion end-point. Binding as POST and Assertion Endpoint with the same URL as your relying party.

 

image

  • Save and close out the Dialog.

Don’t worry. You ADFS configuration will not go wrong here. The Assertion end-point would work in conjunction with the WS-Federation end-points.

So that’s it you are all done. Now comes the coding part to get the SAML token. Well I have covered your back here. I have put the gory code into a managed solution and all you need to do is download the solution from the below codeplex link and then install it into your organization – https://crmsamlgenerator.codeplex.com/

Once installed, the following is the piece of code which you just need to write to get back your SAML assertion token.

OrganizationRequest samlInvoker = new OrganizationRequest();
samlInvoker.RequestName = "saml_SAMLInvoker";
samlInvoker.Parameters["IdpLoginPageUrl"] = “
/adfs/ls/idpinitiatedsignon.aspx";’>https://<federation server url>/adfs/ls/idpinitiatedsignon.aspx";
samlInvoker.Parameters["RelyingPartyUrl"] = "<Relying Party URL>";

var samlResponse = (OrganizationResponse)proxy.Execute(samlInvoker);

var samlParams = samlResponse.Results;

Console.WriteLine("SAML Token XML: {0}", samlParams["SamlTokenXml"]);

 

As you can see from the code above, all you need to do is invoke an action named “saml_SAMLInvoker” with the parameters I have mentioned before and you get the SAML token in XML format back. You call this from javascript too and get this token.

You can pass this to any any web-api call from javascript or server side call. A sample code for passing the SAML XML token in the header value is illustrated below.

_invokeWebAPI: function (samlToken) {
        var req = new XMLHttpRequest();
        req.open("GET", "<your web api query");
        req.setRequestHeader("Accept", "application/json");
        req.setRequestHeader("Content-Type", "application/json; charset=utf-8");
        req.setRequestHeader("OData-MaxVersion", "4.0");
        req.setRequestHeader("OData-Version", "4.0");
        req.setRequestHeader("SAML", samlToken);
        req.onreadystatechange = function () {
            if (this.readyState == 4 /* complete */) {
                req.onreadystatechange = null;
                if (this.status == 200) {
                    var discovery = JSON.parse(this.response);
                }
                else {
                    var error = JSON.parse(this.response).error;
                }
            }
        };
        req.send();

In my next article, I have explained how to parse the SAML Assertion token – https://debajmecrm.com/2016/06/06/parse-saml-assertion-token-generated-from-dynamics-crm-on-premise-environment-configured-with-claims/

Till then happy CRMing.

{Dynamics CRM + Powershell} Leverage Powershell to simplify your day to day CRM tasks

I have been using powershell for sometime now for my day to day job in my CRM project. And yes, whenever I use it, I simply love it. Just today another CRM consultant walked up to my desk and saw me running some CRM commands in PowerShell and he was simply amazed about quickly we can do stuffs without actually opening CRM. I showed him al the tricks and later I thought why not post it in my blog so that anybody who still does not know how to use it, can leverage the same. And yes you can do this everything from your desktop only.

So let’s start.

The first step is download the link – https://github.com/seanmcne/Microsoft.Xrm.Data.PowerShell and download the wonderful library which make all this possible. A zip file would be download Microsoft.Xrm.Data.PowerShell-master.zip. Unzip the file, you would see one folder – Microsoft.Xrm.Data.Powershell

image

 

Copy this folder and go to the location – c:\users\<username>\My Documents\

Create the folder in MyDocuments in the following hierarchy – WindowsPowerShell –> Modules and within modules paste the copied folder.

Launch Powershell ISE. You can launch just the default Powershell window but ISE will give you intellisense as well.

image

Once the window loads, type the below line

Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser

image

This line basically allows you to import the Microsoft.Xrm.Data.Powershell.dll which is unsigned. You would get a confirmation box once you execute the above code. Click on ‘Yes’

Once the above command is executed successfully, execute the below line.

Import-Module Microsoft.Xrm.Data.Powershell

Once done you are all set. But first lets see what we can do.

In the window type get-command *crm*  and you could see all the CRM related commands

 

image

There are 81 commands to use which will aid you greatly in your day-day tasks. I am not going to show all but I surely enough to make you curious and then out of the curiosity you would explore the rest Smile

First things first. People new to this might get overwhelmed about how to use these commands. No worries, PowerShell has your back here. To get detailed help for any of the commands just type the below line.

get-help Get-CrmOrganizations -detailed

 

image

Pretty detailed isn’t it.

Now the first thing you need to do is to connect to CRM organization and for that you would need credentials.

Type in the command window – get-credential. A window will pop-up to take the credential. In the below example I have take the credentials in a variable called $cred so that I can use it for later use.

Enter the credentials specific to the organization you want to connect to

image

 

The next step is to connect to the organization using the above credentials. And this what I do.

image

As you can see from the above screenshot, I just supplied the credentials and the Server Url. Just provide the server url not the entire organization service url. Once I press enter, system connects to CRM and determines I have access to two organizations. I select the first organization

And then my connection is set-up. Don’t worry if you are in online organization. Just like Connect-CrmOnPremDiscovery you have Connect-CrmOnlineDiscovery

Now coming to the interesting part – exploring the crm commands.

Get-CrmEntityName

What if you have the entitytypecode and need the logical name of a custom entity. No need to open CRM. Just a single line of code in the powershell

image

 

Get-CrmEntityTypeCode 

How many times we need this? I think lot of times. I have the entitylogicalname but I need the entitytypecode. No worries just one line.

image

 

Get-CrmEntityOptionSet  

Now here comes the big one. What if you are writing some jscript code and you have a picklist to refer to but as with everyone you cannot remember the picklist text and value (I wonder who can. Must be a genius). Just a couple of lines below and you get it. And yes intellisense is there to help you as you write this code.

image

Wonderful isn’t it. And did you observe one thing in the above code. It’s not case-sensitive as well unlike C#.

Similar to this, you have Get-CrmGlobalOptionSet  as well to explore the global option sets.

 

Get-CRMRecords

Yes you can query records as well just like you do in query expressions. However you are limited as power of Query Expression goes.

image

In the above example I just querying for all the accounts whose name begins with Test and then iterating and printing the names of the returned accounts.

 

Get-CrmRecordsCount

Say somebody would walk up to your desk and ask hey man, how many opportunities you have in your system. Say you do not have database access to run a SQL query on. And before you think of other ways, here is the code for you.

image

Easy isn’t it.

 

Export-CrmSolution

How many click when you export the solution? No need to open CRM even. Here is the one liner code for you.

image

In the above code, I am exporting a solution named ‘Sitemap’ as Managed solution and saving it in my location – c:\debajit as FromPowershell.zip.

 

Cool isn’t it. I would not show you all. By this time you have idea already. So start exploring. And yes you have 81 of the cool stuffs to explore. And all this from your desktop without even opening your CRM.

 

Hope this helps! Till you read one of my blog posts, happy CRMing.

{Dynamics CRM + Fetchxml + SQL} FetchXml to SQL converter for Dynamics CRM 2016/ 2015. Enjoy seeing your fetchxml queries getting converted to SQL without using profiler

First of all, I have been able to make this work for CRM 2015/ 2016 on-premise and IFD but does not work with online version. However I am still trying hard to make it work for online version as well. Hopefully I would be able to find a solution very soon.

Now coming to what the tool does.

  1. First of all, it is not a custom logic of string manipulation which is based on the format of FetchXml. So even if the fetch XML format changes in a rollup update, it would still work
  2. It would generate exactly the same SQL that would find if you check in your profiler, for your fetch calls.

Now coming to the requirement

How often does it happen that a view is taking significant amount of time to execute (both personal and system views) and you wish to view what is the SQL query generated behind the scenes. And sometimes you have constructed this fetchxml from advanced find and using it in your plugins and workflows and somehow that is taking a lot of time to execute. You wish if I could have the SQL for it to check what exactly is happening behind the scenes.

And below are the steps that you would normally do to view SQL query

  • Login to the database server (assuming you have access)
  • Launch the profiler
  • Run you view/ custom fetchxml
  • The profiler would generate lot of logs.
  • From the log list, find out the query for you trigger

 

We have all done it I guess. But you have two problems here

  • Assuming you have access to the database and launch the profiler, still it is a considerable effort to every time start a new session and take out your query from the list of logs  generated.
  • Second and perhaps the most important point here. You can use this tool even if you do not have login to the database server. Are you guessing that you still need to have System Administrator role in Dynamics CRM to use this tool? Well then I have to disappoint you here. Even if you are a sales user but still want to peek what’s going on behind the scenes, it will allow you to do so.

My team was having these repeated complaints about this and I thought why not give a weekend for this. 🙂

Download links

The tools is available for download at – FetchXml to SQL Converter

You would need to go to the Downloads section and download the version as per your CRM version

Capture

 

Documentation:

Once you download and unzip you would find two stuffs

  • Folder containing the executables
  • A managed solution.

I have using the 2016 version and this is what I see after I unzip.

image

 

The next step is to import the managed solution. Don’t worry. It is a very simple solution and it won’t even touch any of your existing entities any way.

Once the import is successful, open the executable folder and run the FetchXmlToSql.exe

image

The first thing it would ask for is your organization type. I have on-premise and hence I select the appropriate choices and it guides me to enter the details.

image

Once you enter your password and press enter, the system would search for all the organizations you have access to and show you.

image

I have only one. So I put ‘1’ as input in the console. If you have multiple organizations configured, all would be displayed here.

Once I select the appropriate organization and press enter, I am presented with the below choices

image

1 – Press 1 if you have any fetchxml saved in a file. Ideally you would use it in case you construct an advanced find query and download the fetchxml. In case you have some custom fetchxml, save it in a file. The moment you press enter, it would ask you to select a file.

2 – Using this option allows you to view the SQL query for your system views configured for an entity

3 – Using this option allows you to view the SQL query for your personal views you created for an entity.

 

FetchXml Input:

I enter 1 and then press Enter. It asks me to select a FetchXml file. I select a fetchxml that I downloaded from advanced find to view the enabled users for my organization.

image

After the file is selected, it takes some time to generate your SQL.

When done it will show a message like below screenshot.

image

The output file is generated in the same location as you executable. When I click open the file, I could see the same SQL being generated like the one you are familiar viewing in advanced find.

image

Liking it. Well then let’s explore the other options as well.

 

Saved Views:

I enter 2 this time and then you are prompted to enter the entity schema name. Please note you have to enter the entity logical name of the entity for which you want the system views to be displayed and not the display name. I enter opportunity.

image

When I press enter, I could see all the views configured in my system for opportunity.

image

As you can see that it displays all the system views configured for opportunity with a number for each. All you need to do is enter the number corresponding for the view you want to proceed with. I want to view ‘All Open Opportunities’. So I press 39 and then press enter

image

As it says, it saved to some file. I open the file and this is query generated below.

select  "opportunity0".sandisk_OpportunityID as "sandisk_opportunityid"
, "opportunity0".sandisk_opportunitytypeName as "sandisk_opportunitytypename"
, "opportunity0".CreatedOn as "createdon"
, "opportunity0".sandisk_OppCloseDateFiscalQuarterName as "sandisk_oppclosedatefiscalquartername"
, "opportunity0".sandisk_RSMName as "sandisk_rsmname"
, "opportunity0".sandisk_OpportunityValue as "sandisk_opportunityvalue"
, "opportunity0".sandisk_regionName as "sandisk_regionname"
, "opportunity0".OpportunityId as "opportunityid"
, "a_ef8066bb4eb040ba856b83c0ae259e29".StageName as "a_ef8066bb4eb040ba856b83c0ae259e29.stagename"  from  FilteredOpportunity as "opportunity0" left outer join FilteredProcessStage as "a_ef8066bb4eb040ba856b83c0ae259e29" on ("opportunity0".StageId  =  "a_ef8066bb4eb040ba856b83c0ae259e29".processstageid) order by  "opportunity0".name asc

 

Wow. isn’t that easy?

 

Personal Views:

Follow the same steps as Saved Views. Except you should chose 3 instead of 2 as input.

 

Now coming to another important part. The above would happen smoothly for a user who is a system administrator. However if you are a normal user, running it simply would throw an error. Don’t worry. I have you guys covered here.

The system administrator needs to open the security role you are having and then go to custom entities and then search for the entity named ‘Target Entity’

image

Provide access to this entity. And you are done.

The next time you run the same, you could see the the tool in action.

 

Leave me a comment if this tool really helped you.

If you wish to donate, you could do so at my paypal account debajit.prod@gmail.com. Your comments and support gives me the inspiration to keep me going.

{Dynamics 365 + Azure + Queues} Part4– Developing a queue listener to read messages from the queue

This is the final post in the series and if the you are directly in here, I strongly suggest to start from the link – https://debajmecrm.com/2016/05/12/blog-series-complete-in-depth-walkthrough-of-dynamics-crm-plugins-with-azure-service-bus-queues/

So we are almost at the end of our journey and we just have to build a client to read the message we have posted in the queue.

If you remember, in my third post, I have explained that are three sets of permissions for a queue

  • Send – If a client is provided with Send privileges for the queue, the client can post messages to the queue
  • Listen – If a client is provided with Listen privileges for the queue, the client can process incoming messages to the queue.
  • Manage – Manage is like the admin credentials for the queue. If you give manage, send and listen privileges are included by default

Since you are just building a listener here, you should provide only listen privileges to the queue to the client. It is very important to understand this. If you do not understand how the privileges work and simply follow the steps documented in the SDK, you might end up with using the Management credentials of the entire service bus in your code. Believe me I have seen real life examples where the queue listener is constructed with the service bus root credentials. Those are like super-admin credentials and a person gaining access to those credentials can end up modifying the entire service bus configuration and not just the queue.

So let’s see how we can set-up a Access Policy with just the listen privilege.

Go to your service bus  and then open the ‘testqueue’ that we created earlier.

Click on Configure. A screen like below will come up.

image

Go to ‘Shared Access Policies’ section and type in a new policy name called ListenerClient. Select Listen privilege only. After all, I just need the client to read messages right?

image

Click on Save at the bottom. Once saved in the ‘Shared Access Key generator’ section, select the ListenerClient Policy. You would see both the primary key and secondary key.

image

Now we need the connection string for the Queue for the ListenerClient policy. To find the connection string, click on the Dashboard of the queue and then click on View Connection String

image

Copy the connection string of the Listener client from the pop-up window and store it somewhere. You will need it very soon.

image

 

So you are all set. Now I create a console application called QueueListener. 

Using Nuget, install the azure service bus dlls. Also include reference to the Microsoft.Xrm.Sdk dll

image

Below is the code for reading data from the queue.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Configuration;
using System.ServiceModel;
using System.Runtime.Serialization;

using Microsoft.ServiceBus;
using Microsoft.ServiceBus.Messaging;
using Microsoft.Xrm.Sdk;

namespace QueueListener
{
    class Program
    {
        static void Main(string[] args)
        {
            var queueProcesssor = new QueueProcessor();
            queueProcesssor.CreateQueueClient();
            queueProcesssor.ProcessMessages();

            Console.Read();
        }
    }

    internal class QueueProcessor
    {
        private const string QueueName = "TestQueue";
        internal QueueClient _queueClient;

        public QueueProcessor()
        {
        }

        internal void CreateQueueClient()
        {
            _queueClient = QueueClient.CreateFromConnectionString(ConfigurationManager.AppSettings["Microsoft.ServiceBus.ConnectionString"]);
        }

        internal void ProcessMessages()
        {
            while(true)
            {
                var message = _queueClient.Receive();

                if(message != null)
                {
                    var context = message.GetBody<RemoteExecutionContext>();

                    Console.WriteLine("User Id: {0}", context.UserId);
                    Console.WriteLine("Organization Id: {0}", context.OrganizationId);

                    message.Complete();
                }
            }   
        }
    }
}

The code reads the connection string from configuration file from the Key – Microsoft.ServiceBus.ConnectionString. So add an app settings value like the one below

<appSettings>
        <!– Service Bus specific app setings for messaging connections –>
        <add key="Microsoft.ServiceBus.ConnectionString"
            value="<Paste the connection string copied for Listener client earlier>”/>

Just a few lines of code and you are done. And when I run the code, below is the screenshot from debugger.

image

 

I hope my series of blogs have not only helped you to show how you can configure dynamics crm with azure but also helped you to understand the inner workings as well.

Leave a comment on how you liked it. Till then happy CRMing

{Dynamics 365 + Azure + Queue} Part3 – ACS integration with Dynamics CRM and posting of messages to Queue

This is the third post in the series and if the you are directly in here, I strongly suggest to start from the link – https://debajmecrm.com/2016/05/12/blog-series-complete-in-depth-walkthrough-of-dynamics-crm-plugins-with-azure-service-bus-queues/

Open Plugin Registration Tool and click on Register –> New Service Endpoint

  • Name – Enter a suitable name.
  • Description -  Don’t leave this blank. It is mandatory otherwise you would get object reference error
  • Solution Namespace – This should be same as service bus namespace you created. I put the service bus namespace that we created in the previous step – crmdemo-ns
  • Path – This should be the name of the queue. In my last article, we created queue named ‘testqueue’. So I put testqueue here.
  • Contract – Since we are dealing with queues here, choose PersitentQueue from the list of values.

image

 

And you are done! Click on Save and Configure ACS button.

As soon as you click, you get a pop-up screen as shown in the screenshot below.

image

 

Management Key –

Open Azure Management Portal –> Service Bus –> Select your service bus –> Connection information (at the bottom of the screen). You should see a screen like below.

image

Copy the default key and paste in the management key box in plugin registration tool.

 

Certificate File –

The public certificate file that was used to configure Microsoft Dynamics CRM for integration with Microsoft Azure.

For Microsoft Dynamics CRM Online 2016 Update and Microsoft Dynamics CRM 2016 (on-premises), you can download this certificate file from the server. In the Microsoft Dynamics CRM web application click Settings > Customizations, and then click Developer Resources. Download and save the certificate file using the link provided below Microsoft Azure Service Bus Issuer Certificate.

 

Issuer Name –

The name of the issuer. This name must be the same name that was used to configure Microsoft Dynamics CRM for Microsoft Azure integration. You can obtain the issuer name from the Developer Resources webpage mentioned in the previous description.

image

 

Click “Configure ACS”. The system will create Rulegroups and relying party applications. Once done click on ‘Close’ and then click save on the main plugin registration window. So you have set-up Dynamics CRM to integrate with the queue to send messages. This steps you can even find in the SDK. Nothing new in that. But wouldn’t you like to know what happened inside. Come on – let’s explore it together.

Open Azure Management Portal –> Service Bus –> Select your service bus –> Connection information (at the bottom of the screen). In the pop-window click on ‘Open ACS Management Portal’ at the bottom of the screen.

image

Once the ACS management portal opens, go to ‘Relying Party applications’. Remember in the first post of this series, I explained that Queue would be set-up to trust the ACS for authentication. This is what CRM plugin registration tool has done. It has create an entry for the Relying Party.

image

Open the record. You would see a screen like below.

image

The field “Realm” is the path to the relying party. Any claims issued by ACS for realm would be valid.

In the ‘Authentication Settings’ section, the identity provider is selected as Windows Live Id. This is because Dynamics CRM online is based on the Office 365 credentials.

And then you have Rule Groups. Now these are the rules which dictates how the claims generated from Dynamics CRM identity provider are transformed into ACS token claims which is understood by the relying party. As you can as a part of the configuration process, Dynamics CRM has created a Rule group name ‘Rule group for testqueue’.

Let us open this rule group and check what rules are in there.

image

So as we can see, we have four rule groups. If you remember my first post in the series, the first thing that should happen is that when a user from Dynamics CRM posts a message to the Service Bus queue, CRM would validate the credentials and generate an IP token which will be passed to ACS in the next step. The rule which does that in the above screenshot is highlighted. If you see, the claim issuer is ‘crm.dyanmics.com’ which is the service identity that we set up in an earlier blog post in this series.

Unfortunately, ACS management portal does not support claim rules set-up from service identities. It supports claim rules set-up for only identity providers. So if you open this record you would see something like below. You can access this programatically however. If interested please explore it.

image

But as far we know what is going on here, we are good.

Now comes the other three rules. Before I explain the above rules, we should first know that a queue has three set of permissions ‘Send’, ‘Listen’ and ‘Manage’. For e.g if you have listen permissions, you can just connect to the queue and receive messages from the queue. You cannot however send a message to the queue.

Now coming to the rules, you can see that dynamics crm configuration process has create three separate claims rules for three permissions

  • sampleorgsendrule
  • sampleorglistenrule
  • sampleorgmanagerule

So now you understand why three claim transformation rules are set-up. I have been through many articles but in none I could find it properly explained regarding why these four claim rules. So I decided to pen it down.

Since we would be posting messages to the queue, I think you have already guessed it. We need to check the Send Rule. So let’s explore the ‘sampleorgsendrule’.

image

As you understand things, it becomes pretty obvious right. The first thing to notice here is the ‘Input claim Issuer’ section. As you can see Access Control service is selected. Remember I explained in the first post. The ACS converts the token from Identity Provider (IP) into claims which are understandable by the Relying party (queue).

However check for the value of the Input claim. It is specified as owner. Here we just want this rule to execute only if the input claims are from Dynamics CRM. For this I will substitute this value with the unique name of my CRM organization which you can find in Settings –> Customizations –> Developer resources.

One very important thing to remember here is for on-premises, you need to specify the Org Unique name. However for online it should be full host name. Since my organization name is sltraining, so for me the value would sltraining.crm.dynamics.com. Below is the screenshot after edit.

image

And finally the output claim value is set to ‘Send’. So basically ACS takes the name identifier claims and converts it into Send claim which is understood by the queue.

So now we are all set to send a message to this queue.

Open Plugin registration tool one more time. Right click on the service endpoint we created and click on register new step. Enter the below details.

image

What we are basically doing here is on-post create of an account we are posting the context information to the Queue. Remember to mark it asynchronous. CRM will not allow you to register Synchronous step here.

So all set and done. Let’s just go ahead and create a new account. Once account creation is completed, go to Settings-> System Jobs. If your configuration is correct, you would see that the post to queue is successful.

image

 

In my next article and which is the final article in the series, I will explain how to retrieve this message from the queue – https://debajmecrm.com/2016/05/12/azure-crm-integration-blog-series-part4-developing-a-queue-listener-to-read-messages-from-the-queue/