CRM Best Practice Webinar was a hit

by Bill Owens 2. September 2011 02:07

We held our first webinar on CRM Best Practices. Follow this link to sign up to be notified for the next events and to download the webinar and handouts.

Here is a quote from one of the attendees

“I attended today’s webinar and found it really useful.  It was clear, well organized and presented a lot of important information. Most webinars disappoint.  Yours delivered.”

Affiliated will be hosting a series of free CRM 2011 webinars just for you. The CRM Best Practices webinar series topics will include:
• Workflows
• Dialogs
• Advanced Find
• Reporting (online)
• Dashboards
• Goals

the webinar above was the 50,000 overview of these topics and best practices.

Tags: , , ,

CRM 2011 | CRM 4.0

CRM Best Practice Webinar coming up (Free)

by Bill Owens 18. August 2011 01:45

Great COMPLIMENTARY Training Opportunity: Webinar Series - Best Practices for CRM 2011

We like to invite you to join renowned CRM expert, Bill Owens, on August 31, as he presents an overview to the upcoming webinar series, Best Practices and Tips/Techniques for Microsoft Dynamics CRM 2011.
Over the next several weeks, Affiliated will be hosting a series of free CRM 2011 webinars just for you. The CRM Best Practices webinar series topics will include:
• Workflows
• Dialogs
• Advanced Find
• Reporting (online)
• Dashboards
• Goals
Join us as we kick-off of this exciting webinar-based training series designed specifically for CRM super-users like you.
Attendees will receive a CRM Workflow Best Practices Guide for joining us on August 31.
Register now to reserve your spot at this highly anticipated webinar kick-off event.
We look forward to seeing you on August 31!
For more information, call Jim Manning at (614) 889-6555, ext. 206, or jim.manning@aresgrp.com for additional details.

 

-----

There will be pdf handouts on all 6 areas

This is an example of one of the handouts

workflowbestpractice[6]

Tags:

CRM 2011

CRM 2011 Dialogs have added a new hidden feature that ROCKS!

by Bill Owens 13. July 2011 02:06

I have just stumbled upon a great new hidden feature that Dialogs inherited from workflows. You can look up records, and have the user select a record, then execute other workflows/dialogs against that record.

 

So here is an example of this. I want to create a Dialog that helps me verify that a lead should be qualified or if there are more than 1 leads with the same company name I want to choose if we want to qualify one of the other leads. If we do then the other lead will be qualified and the current lead will be lost. Otherwise, we will qualify the current lead.

A . Create a dialog called Lead-Qualify Lead

leadq1

 

1. Under steps add query CRM data call the step “Query-All Leads with This leads Company Name”

2. Paste in the fetchXML

<fetch version="1.0" output-format="xml-platform" mapping="logical" distinct="false">
  <entity name="lead">
    <attribute name="fullname" />
    <attribute name="createdon" />
    <attribute name="statuscode" />
    <attribute name="subject" />
    <attribute name="ownerid" />
    <attribute name="leadid" />
    <order attribute="createdon" descending="true" />
    <filter type="and">
      <condition attribute="statecode" operator="eq" value="Variable1" />
      <condition attribute="companyname" operator="eq" value="Variable2" />
      <condition attribute="leadid" operator="ne" uiname="Robert Ahlering (sample)" uitype="lead" value="Variable3" />
    </filter>
  </entity>
</fetch>

3. Add the Company Name from current lead

4. Add the Lead

This query will return all active leads with the same Company Name.

d3

B. Add a condition to check if the Query has more than 0 rows

d4

C. Add a Page called “P01-Do you want to use one of these instead”

D. Add a field called “P01-Show all of  the leads found”. this will show the other leads that we can select from.

d5

E. Add Field called “P01-Do you want to close the above lead instead” . We need to know if they want to use the selected lead.

d6

F. Add the check condition to see if we should use the selected lead

d7

G. Under this we can now execute a workflow that we have already created called Lead-Qualify that copies the Account, Opportunity, and Contact information from the lead and creates the entities described. We could also put logic in there to check for existing Accounts and Contacts so we do not get duplicates.

d8

But NOTICE how you select the P01- Show All of the Leads field that was chosen from the Page displayed.

d9

In workflows in the past we could create entities and act upon them later in the Workflow but I never found a way to lookup and execute against a different entity with the workflows because you had to CREATE them within the workflow. No the Page Prompts are considered created within the workflow and we can act upon them. Outstanding…

H. Add the Workflow execution to mark the current lead as lost. Again this workflow was already created.

d10

I. Now add in the Stop

d11

J. Finish off by Qualifying the current lead since if we made it this far it should be closed.

d12

 

Now activate the Dialog and test it.

This screen show this running against a lead and it is the only lead with that Company Name. No Prompts were given

d13

 

The Following Screens are when I run the dialog against a lead where there are multiple leads with the same Company Name.

a1

 

a3

As you can see the workflow executed against the other lead chosen.

a4

 

I hope that this provides you some value and fun times with Dialogs.

Tags: ,

CRM 2011

CRM 2011 and PowerShell

by Bill Owens 8. July 2011 00:40

CRM 2011 on premise versions now have a new tool to help with configuration and deployments.

I know that in my company we have many pages of documentation that shows step by step clicks and adding into CRM Deployment manager on creating Organizations, adding Administrative users, how to get license information, setting up IFD, etc.  Now with PowerShell intergration with CRM 2011 we can script these functions.

So what is PowerShell?

Wikipedia defines it as:


Windows PowerShell is Microsoft's task automation framework, consisting of a command-line shell and associated scripting language built on top of, and integrated with the .NET Framework. PowerShell provides full access to COM and WMI, enabling administrators to perform administrative tasks on both local and remote Windows systems.
In PowerShell, administrative tasks are generally performed by cmdlets (pronounced command-lets), specialized .NET classes implementing a particular operation. Sets of cmdlets may be combined together in scripts, executable (which are standalone applications), or by instantiating regular .NET classes (or WMI/COM Objects).[3][4] These work by accessing data in different data stores, like the filesystem or registry, which are made available to the PowerShell runtime via Windows PowerShell providers


I define it more like Windows Batch files on steroids. Many of us have created batch files in Windows and found it very limiting. With PowerShell you have programming logic capabilities that can access system functions as well as operations against system functions. Way too cool.

How do I get it?
First PowerShell comes with Windows Server 2008 which is advantageous because that is where we install the CRM

Server.

As part of the CRM Server install you can install the Deployment Tools role. After this role is installed you are able to add the Dynamics CRM PowerShell-Snap-In to your PowerShell session.
To use the cmdlets you have to enter following command into a PowerShell console, which adds the PowerShell-Snap-In to your active session.

Add-PSSnapin Microsoft.Crm.PowerShell


If you want to see all of the commands available you can type in

Get-Command -Module Microsoft.Crm.PowerShell 

As of 7/7/2011 here is the current lis

tPowershellcrm2011commands

If you search within the SDK you will find this list:

 

Supported PowerShell cmdlets

The following table lists the cmdlets available for use with Windows PowerShell.

Cmdlet

Description

Disable-CrmServer

Disables the specified Microsoft Dynamics CRM server.

Disable-CrmOrganization

Disables the specified Microsoft Dynamics CRM organization.

Edit-CrmOrganization

Edits properties of the specified Microsoft Dynamics CRM organization.

Enable-CrmServer

Enables the specified Microsoft Dynamics CRM server.

Enable-CrmOrganization

Enables the specified Microsoft Dynamics CRM organization.

Get-CrmOrganization

Retrieves one or all of the organizations in the deployment of Microsoft Dynamics CRM.

Get-CrmOperationStatus

Retrieves the status on asynchronous operations sitting in the deferred operation queue for Microsoft Dynamics CRM.

Get-CrmSetting

Retrieves a Microsoft Dynamics CRM deployment setting object. For a list of the settings objects, see Use Deployment Entities and Deployment Configuration Settings.

Get-CrmServer

Retrieves a server object for one or all Microsoft Dynamics CRM servers in a deployment.

Get-CrmLicenseProperty

Retrieves the license properties object for Microsoft Dynamics CRM.

Get-CrmAdvancedSetting

Gets an advanced setting value for Microsoft Dynamics CRM. The metadata specify that the setting is readable in order to retrieve the specified value.

Get-CrmAccessLicense

Retrieves the server licensing and CAL licensing information for the deployment of Microsoft Dynamics CRM.

Get-CrmDeploymentAdministrator

Retrieves the deployment administrators for the Microsoft Dynamics CRM deployment.

Get-CrmCertificate

Retrieves the certificate information for Microsoft Dynamics CRM. The certificate object contains the public key of the service bus signing certificate.

Import-CrmOrganization

Initiates the process to import a Microsoft Dynamics CRM organization database into the deployment.

New-CrmOrganization

Initiates the process to create a new organization in the Microsoft Dynamics CRM deployment.

New-CrmDeploymentAdministrator

Creates a new deployment administrator for the Microsoft Dynamics CRM deployment.

Remove-CrmOrganization

Deletes the specified organization from the Microsoft Dynamics CRM deployment.

Remove-CrmServer

Deletes the specified server from the Microsoft Dynamics CRM deployment.

Remove-CrmCertificate

Removes the specified certificate from Microsoft Dynamics CRM.

Remove-CrmDeploymentAdministrator

Removes the specified deployment administrator from the Microsoft Dynamics CRM deployment.

Set-CrmProductKey

Sets the product key for the Microsoft Dynamics CRM deployment.

Set-CrmSetting

Sets the specified Microsoft Dynamics CRM deployment wide settings. For a list of the settings objects, see Use Deployment Entities and Deployment Configuration Settings.

Set-CrmAdvancedSetting

Sets an advanced setting value for Microsoft Dynamics CRM. The metadata specify that the setting is writable in order to set the specified value.

Set-CrmCertificate

Creates a certificate record or sets the properties of an existing certificate record in the Microsoft Dynamics CRM configuration database.

Update-CrmOrganization

Updates the specified Microsoft Dynamics CRM organization with the latest patches or upgrades the organization from Microsoft Dynamics CRM 4.0 to Microsoft Dynamics CRM 2011.

So what can you do?

How about getting the licensed users on the CRM server

Get-CrmAccessLicense -LicenseName "Dynamics CRM 2011 Full CAL" -Period 0

 

userlist

 

You can deploy settings, configure IFD, claims forms, add administrative users, you pick.

the SDK offers this example

 

Example

The following shows how to use Windows PowerShell to enable tracing. This pattern can be used for all settings. For a list of the settings objects, see Use Deployment Entities and Deployment Configuration Settings.

Windows PowerShell

PS C:\Users\Administrator> Add-PSSnapin Microsoft.Crm.PowerShell

Windows PowerShell

PS C:\Users\Administrator> Get-CrmSetting TraceSettings

CallStack     : True
Categories    : *:Error
Directory     : c:\crmdrop\logs
Enabled       : False
FileSize      : 10
ExtensionData : System.Runtime.Serialization.ExtensionDataObject

Windows PowerShell 

PS C:\Users\Administrator> $setting = Get-CrmSetting TraceSettings

Windows PowerShell

PS C:\Users\Administrator> $setting.Enabled="True"

Windows PowerShell

PS C:\Users\Administrator> Set-CrmSetting $setting

Windows PowerShell

PS C:\Users\Administrator> Get-CrmSetting TraceSettings

CallStack     : True
Categories    : *:Error
Directory     : c:\crmdrop\logs
Enabled       : True
FileSize      : 10
ExtensionData : System.Runtime.Serialization.ExtensionDataObject

 

Within the SDK examples are PowerShell examples as well. Look under SDK\SampleCode\ps

 sdkexamples

How do I find out how to use these commands

You can ask for a descriptive help on each command within PowerShell. Example. I want to find out what I can do with the get-CRMSetting cmdlet.

get-help Get-CrmSetting -detailed
helpexample

 

You can also search within the SDK for PowerShell to find out more information. BTW the page “Use Deployment Entities and Deployment Configuration Settings” is a good page for the above command as well.

One Last Item

I recommend if you are using PowerShell to download PowerGUI from powergui.org

powergui

 

This has a nice editor as well as way to issue PowerShell commands as you want to see them.

Here is an Example where I added to the PowerGui the CRM PowerShell commands to show me the CRM license and All users

powerguiexample1

and here is a snapshot of the Script Editor in action

powerguiscripteditor

 

I hope that this is useful to you, I know that I have learned a lot just putting this together.

Tags: , ,

CRM 2011

CRM 2011 Tools Set that everyone should have

by Bill Owens 1. July 2011 17:36

Some people deserve accolades and Tanguy is one of those people. He has had many freely public tools that have helped implementers and CRM super users customize their systems. He has updated his tools for CRM 2011 and they now work for both Online and Onpremise. These are must have tools.

First about Tangy


My Photo

View his complete profile

Technical consultant on Microsoft Dynamics CRM since version 1.2.
He works for ALSY (Orange Business Service subsidiary), one of the French leader in Microsoft Dynamics CRM integration.

His blog can be found here 

------------------------------------

His tools

SiteMap Editor for Microsoft Dynamics CRM 2011

Features

  • Connections to OnPremise, Online and Claim based deployments
  • TreeView display of SiteMap
  • Add SiteMap component with mouse usage
  • Add default SiteMap component if you removed one
  • Cut/Copy/Paste of SiteMap component
  • Display Xml of SiteMap component
  • Add SiteMap component from Xml
  • Reset SiteMap to default system one
  • Import back the SiteMap to CRM server

Screenshot

SiteMapEditor

Download

As usual the application is available on codeplex

JavaScript Web Resource Manager for Microsoft Dynamics CRM 2011

this new tool allows you to update JavaScript web resources with the following features:

  • Export scripts web resources from CRM server
  • Save scripts web resources to disk
  • Load scripts files from disk
  • Edit scripts with default text editor or Visual Studio
  • Edit web resource properties
  • Save scripts to CRM server
  • Publish scripts to CRM server

Screenshot

jswebresourcemanager

Download

it is published on codeplex

Ribbon Browser

You will be able to:

  • Display system entity ribbon definition
  • Display custom entity ribbon definition
  • Display Ribbon control attributes
  • Display Ribbon control XML
  • Save ribbon in XML file

The tool is released on codeplex

Screenshot

Ribbon Browser

 

CrmDiagTool 2011

The features are the following:

  • Enable/Disable tracing
  • Zip content of Trace directory
  • Open Trace directory
  • Generate diagnostic file in text or html format with components selection
  • Enable/Disable DevErrors

Some screenshots:

crmdiagtool2011_1

crmdiagtool2011_2

crmdiagtool2011_3

crmdiagtool2011_4

Regarding source code: As the previous version had not its source code released, this version does not too.

Download link

Searchable Property Updater for Microsoft Dynamics CRM 2011

Searchable Property Updater1

I posted the tool, the source code and the documentation on codeplex. Use the link below to access to these files:

http://searchpropupdater.codeplex.com

Tags: ,

CRM 2011

On-Premise multi-organization SQL job

by Bill Owens 29. June 2011 22:33

I have a client with 20+ organizations on their CRM server and I just ran into an issue where we really needed to issue un update SQL command against all of the CRM’s currently installed on the server. In this case we needed to update the Case’s subjectid if it was not filled in and there is a kb article attached to the case. The KB Article has the subjectid we need to update into the case entity. I must also add this is CRM 4.0 On-Premise. I playing around I created the following script that reads the MSCRM_CONFIG DB for the organization databases and then dynamically executes an update to the databases

-- =============================================
-- Author:        Bill Owens    
-- Create date: 6/29/2011
-- Description:    Update all of the Case Subjects with the KB Article's Subject
-- =============================================
SET NOCOUNT ON;
DECLARE @DB as Varchar(100)
DECLARE @SQL AS nVarChar(4000)
DECLARE Org_Cursor CURSOR FOR
    SELECT     DatabaseName
    FROM         mscrm_config.dbo.Organization
    WHERE     (IsDeleted = 0)
OPEN Org_Cursor;
FETCH NEXT FROM Org_Cursor into @DB;
WHILE @@FETCH_STATUS = 0
   BEGIN
        SET @SQL = 'Select count(*) as cnt from ' + @DB +'.dbo.AccountBase'
        set @SQL = 'UPDATE IncidentBase SET SubjectId = KbArticleBase.SubjectId FROM '+@DB +'.dbo.IncidentBase INNER JOIN '+@DB +'.dbo.KbArticleBase ON IncidentBase.KbArticleId = KbArticleBase.KbArticleId WHERE('+@DB +'.dbo.IncidentBase.SubjectId IS NULL) AND (NOT ('+@DB +'.dbo.IncidentBase.KbArticleId IS NULL))'
        EXEC sp_executesql @SQL
      FETCH NEXT FROM Org_Cursor into @DB;
   END;
CLOSE Org_Cursor;
DEALLOCATE Org_Cursor;

. FYI, cross scripting needs to be turned on on the SQL server for this to work.

Tags: ,

CRM 4.0

CRM Ribbon Bar disappears after adding JavaScript to the page

by Bill Owens 2. June 2011 01:04

I’m at a client at the moment and I was teaching them how to add JavaScript to the forms within CRM 2011 and long and behold they stumbled across an odd issue. It appears that if you add the ()’s to the function name on the formload event the ribbonbar will disappear.

Here is what I’m talking about.

The Lead Page before the customization

leadgood

Now I add the simple JavaScript code.

1. Click on Form Properties

2. Add/create a JavaScript web resource

3. Simple JavaScript function
leadsaddcode

Now for the piece that messes it all up. Add the page onload event and put the ()’s on the function name. Example enter test() instead of what you should be entering test.

leadbadd1

you should now see this

Leaddonecust

Save and Publish. now open a lead and you will see this:

leadbad

Tags:

CRM 2011

CRM 2011 Workflow logs can be auto deleted

by Bill Owens 11. May 2011 20:56

Ahhh! Another slightly hidden pain relief valve in the new CRM 2011. If you are like me, you found that in CRM 4.0 the Workflow logs were wonderful, they showed you everything that happen and gave you links to items updated or created. It was wonderful…….UNTIL……. The database filled up. I still remember one of my clients that used a lot of workflows and they called me in a panic because they had 2.5 million workflow logs and it was taking up 70GB of space in their SQL database. OUCH! Needless to say that was fun. Then Microsoft came out with the roll up that allow you to delete all completed workflows (You needed to manually enable this and we did for all of our clients). This left another issue; sometimes you need those logs, especially when you are testing workflows. Now we had to stop the workflows in error to keep the logs..

Well, now in CRM 2011, when you create a workflow or dialog on the administration tab way down at the bottom of the page is a new check box that will purge the completed workflow logs automatically. YIPPIE!

Workflowautopurge

Tags: , ,

CRM 2011

Deleted Records hanging in there! Forcing the delete job

by Bill Owens 22. July 2010 23:46

Here is a scenario for you to ponder..

  1. You have a separate database with accounts in them that need to be uploaded to MSCRM.
  2. You use the DDM or write your own application to load the data into MSCRM
    • You use the key (a GUID) from the data being imported as the new key in CRM. Yes you can pass in the key GUID you want to create the record for.
  3. You realize you need to make some changes.
  4. You delete the records in MSCRM using the screens
  5. You try the import and it fails telling you you have a duplicate key.
  6. You search the screens thinking you did not delete them only to find out you did.

What happens when you delete a record in MSCRM is that the record is flagged with a 2 in the deletion State Code and a daily job runs that will clean up and perform all of the deletions.

So no the question, how do you force the deletion job to run NOW.

Well it is not hard.

Run the following SQL on your SQL Server

 

USE MSCRM_CONFIG 
 
UPDATE ScaleGroupOrganizationMaintenanceJobs 
SET NextRunTime = getdate()
WHERE OperationType = 14 

then restart the Microsoft CRM Asynchronous Service

 

 

I would suggest that after you are done you revisit this and set the next date/time to sometime in the evening well before backups so that the job runs normally after hours.

Tags:

CRM 4.0

Custom workflow action which renders and sends a report for Microsoft Dynamics CRM 4.0 with email

by Bill Owens 15. July 2010 22:50

I found this on Andriy Butenko’s blog and it looked like a very good article to share. Way to go Andriy. His post can be found here  .


Tuesday, August 04, 2009

Custom workflow action which renders and sends a report for Microsoft Dynamics CRM 4.0 with email

Idea of this custom workflow action is following:
1. Give user possibility to run and export report in one action.
2. Insert this exported report as attachment into email.
3. Sent this email to recipient.

I've created a new project. Type of project is 'Class Library', Framework - 3.0.
First step is to add all required references to reporting service, Workflow assemblies and CRM assemblies:
Reporting Services:


Workflow assemblies:

And Microsoft CRM SDK assemblies.
As a result I retrieved such project:

Second step - is to create a custom workflow action which does't have a required code but can be deployed to CRM. So the code of such class:

using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Crm.Workflow;
using System.Workflow.Activities;
using System.Workflow.ComponentModel;
 
namespace SendReportAction
{
    [CrmWorkflowActivity("Execute and send a report")]
    public class SendReport : SequenceActivity
    {
        protected override ActivityExecutionStatus Execute(ActivityExecutionContext executionContext)
        {
            return ActivityExecutionStatus.Closed;
        }
    }
}

Next step is to declare properties for worflow action (url of reporting services web service, report to run, recipient of email with report - in my case a systemuser):
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Crm.Workflow;
using System.Workflow.Activities;
using System.Workflow.ComponentModel;
using Microsoft.Crm.Sdk;
using Microsoft.Crm.SdkTypeProxy;
 
namespace SendReportAction
{
    [CrmWorkflowActivity("Execute and send a report")]
    public class SendReport : SequenceActivity
    {
        protected override ActivityExecutionStatus Execute(ActivityExecutionContext executionContext)
        {
            return ActivityExecutionStatus.Closed;
        }
 
        public static DependencyProperty ServiceURLProperty = DependencyProperty.Register("ServiceURL", typeof(string), typeof(SendReport));
 
        [CrmInput("ServiceURL")]
        public string ServiceURL
        {
            get
            {
                return (string)base.GetValue(ServiceURLProperty);
            }
            set
            {
                base.SetValue(ServiceURLProperty, value);
            }
        }
 
        public static DependencyProperty ReportNameProperty = DependencyProperty.Register("ReportName", typeof(string), typeof(SendReport));
 
        [CrmInput("ReportName")]
        public string ReportName
        {
            get
            {
                return (string)base.GetValue(ReportNameProperty);
            }
            set
            {
                base.SetValue(ReportNameProperty, value);
            }
        }
 
        public static DependencyProperty MailRecipientProperty = DependencyProperty.Register("MailRecipient", typeof(Lookup), typeof(SendReport));
 
        [CrmInput("MailRecipient")]
        [CrmReferenceTarget("systemuser")]
        public Lookup MailRecipient
        {
            get
            {
                return (Lookup)base.GetValue(MailRecipientProperty);
            }
            set
            {
                base.SetValue(MailRecipientProperty, value);
            }
        }
    }
}
 
Next step - is to write code which will create an email:
if (MailRecipient != null && !MailRecipient.IsNull && !MailRecipient.IsNullSpecified)
            {
                IContextService contextService = (IContextService)executionContext.GetService(typeof(IContextService));
                IWorkflowContext workflowContext = contextService.Context;
                ICrmService crmservice = workflowContext.CreateCrmService();
 
                email mail = new email();
 
                activityparty fromparty = new activityparty();
                fromparty.partyid = new Lookup();
                fromparty.partyid.type = EntityName.systemuser.ToString();
                fromparty.partyid.Value = workflowContext.UserId;
                mail.from = new activityparty[] { fromparty };
 
                activityparty toparty = new activityparty();
                toparty.partyid = new Lookup();
                toparty.partyid.type = EntityName.systemuser.ToString();
                toparty.partyid.Value = MailRecipient.Value;
                mail.to = new activityparty[] { toparty };
 
                mail.subject = "Report Subscription";
                mail.sender = "crm@example.com";
 
                mail.description = "Report Subscription";
 
                mail.ownerid = new Owner();
                mail.ownerid.type = EntityName.systemuser.ToString();
                mail.ownerid.Value = workflowContext.UserId;
                Guid createdEmailGuid = crmservice.Create(mail);
            }

Next step is to execute and export report:
Reporting.SessionHeader sessionheader = null;
                byte[] result;
                string encoding;
                string mimetype;
                Reporting.ParameterValue[] parametersUsed = null;
                Reporting.Warning[] warnings;
                string[] streamids;
 
                BasicHttpBinding binding = new BasicHttpBinding(BasicHttpSecurityMode.TransportCredentialOnly);
                binding.Security.Message.ClientCredentialType = BasicHttpMessageCredentialType.UserName;
                binding.Security.Mode = BasicHttpSecurityMode.TransportCredentialOnly;
                binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Windows;
                binding.Security.Transport.ProxyCredentialType = HttpProxyCredentialType.None;
                binding.Security.Transport.Realm = string.Empty;
                EndpointAddress endpoint = new EndpointAddress(ServiceURL);
            
                Reporting.ReportingServiceSoapClient client = new Reporting.ReportingServiceSoapClient(binding, endpoint);
                client.ClientCredentials.Windows.AllowedImpersonationLevel = TokenImpersonationLevel.Impersonation;
            
                client.Render(ref sessionheader, ReportName, "Excel", null,
                null, null, null, null, out result, out encoding, out mimetype,
                out parametersUsed, out warnings, out streamids);

Next step is to attach retrieved file to the email:
activitymimeattachment attach = new activitymimeattachment();
                attach.activityid = new Lookup(EntityName.email.ToString(), createdEmailGuid);
                attach.body = System.Convert.ToBase64String(result);
                attach.subject =
                attach.filename = "Report.xls";
                attach.filesize = new CrmNumber(result.Length);
                attach.mimetype = @"application/vnd.ms-excel";
 
                crmservice.Create(attach);
 
And sent the email:
SendEmailRequest sendrequest = new SendEmailRequest();
                sendrequest.EmailId = createdEmailGuid;
                sendrequest.TrackingToken = "";
                sendrequest.IssueSend = true;
 
                crmservice.Execute(sendrequest);
 


Full code of this custom workflow action:
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Crm.Workflow;
using System.Workflow.Activities;
using System.Workflow.ComponentModel;
using Microsoft.Crm.Sdk;
using Microsoft.Crm.SdkTypeProxy;
using System.ServiceModel;
using System.Security.Principal;
 
namespace SendReportAction
{
    [CrmWorkflowActivity("Execute and send a report")]
    public class SendReport : SequenceActivity
    {
        protected override ActivityExecutionStatus Execute(ActivityExecutionContext executionContext)
        {
            if (MailRecipient != null && !MailRecipient.IsNull && !MailRecipient.IsNullSpecified)
            {
                IContextService contextService = (IContextService)executionContext.GetService(typeof(IContextService));
                IWorkflowContext workflowContext = contextService.Context;
                ICrmService crmservice = workflowContext.CreateCrmService();
 
                email mail = new email();
 
                activityparty fromparty = new activityparty();
                fromparty.partyid = new Lookup();
                fromparty.partyid.type = EntityName.systemuser.ToString();
                fromparty.partyid.Value = workflowContext.UserId;
                mail.from = new activityparty[] { fromparty };
 
                activityparty toparty = new activityparty();
                toparty.partyid = new Lookup();
                toparty.partyid.type = EntityName.systemuser.ToString();
                toparty.partyid.Value = MailRecipient.Value;
                mail.to = new activityparty[] { toparty };
 
                mail.subject = "Report Subscription";
                mail.sender = "crm@example.com";
 
                mail.description = "Report Subscription";
 
                mail.ownerid = new Owner();
                mail.ownerid.type = EntityName.systemuser.ToString();
                mail.ownerid.Value = workflowContext.UserId;
                Guid createdEmailGuid = crmservice.Create(mail);
 
                Reporting.SessionHeader sessionheader = null;
                byte[] result;
                string encoding;
                string mimetype;
                Reporting.ParameterValue[] parametersUsed = null;
                Reporting.Warning[] warnings;
                string[] streamids;
 
                BasicHttpBinding binding = new BasicHttpBinding(BasicHttpSecurityMode.TransportCredentialOnly);
                binding.Security.Message.ClientCredentialType = BasicHttpMessageCredentialType.UserName;
                binding.Security.Mode = BasicHttpSecurityMode.TransportCredentialOnly;
                binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Windows;
                binding.Security.Transport.ProxyCredentialType = HttpProxyCredentialType.None;
                binding.Security.Transport.Realm = string.Empty;
                EndpointAddress endpoint = new EndpointAddress(ServiceURL);
            
                Reporting.ReportingServiceSoapClient client = new Reporting.ReportingServiceSoapClient(binding, endpoint);
                client.ClientCredentials.Windows.AllowedImpersonationLevel = TokenImpersonationLevel.Impersonation;
            
                client.Render(ref sessionheader, ReportName, "Excel", null,
                null, null, null, null, out result, out encoding, out mimetype,
                out parametersUsed, out warnings, out streamids);
 
                activitymimeattachment attach = new activitymimeattachment();
                attach.activityid = new Lookup(EntityName.email.ToString(), createdEmailGuid);
                attach.body = System.Convert.ToBase64String(result);
                attach.subject =
                attach.filename = "Report.xls";
                attach.filesize = new CrmNumber(result.Length);
                attach.mimetype = @"application/vnd.ms-excel";
 
                crmservice.Create(attach);
 
                SendEmailRequest sendrequest = new SendEmailRequest();
                sendrequest.EmailId = createdEmailGuid;
                sendrequest.TrackingToken = "";
                sendrequest.IssueSend = true;
 
                crmservice.Execute(sendrequest);
            }
 
            return ActivityExecutionStatus.Closed;
        }
 
        public static DependencyProperty ServiceURLProperty = DependencyProperty.Register("ServiceURL", typeof(string), typeof(SendReport));
 
        [CrmInput("ServiceURL")]
        public string ServiceURL
        {
            get
            {
                return (string)base.GetValue(ServiceURLProperty);
            }
            set
            {
                base.SetValue(ServiceURLProperty, value);
            }
        }
 
        public static DependencyProperty ReportNameProperty = DependencyProperty.Register("ReportName", typeof(string), typeof(SendReport));
 
        [CrmInput("ReportName")]
        public string ReportName
        {
            get
            {
                return (string)base.GetValue(ReportNameProperty);
            }
            set
            {
                base.SetValue(ReportNameProperty, value);
            }
        }
 
        public static DependencyProperty MailRecipientProperty = DependencyProperty.Register("MailRecipient", typeof(Lookup), typeof(SendReport));
 
        [CrmInput("MailRecipient")]
        [CrmReferenceTarget("systemuser")]
        public Lookup MailRecipient
        {
            get
            {
                return (Lookup)base.GetValue(MailRecipientProperty);
            }
            set
            {
                base.SetValue(MailRecipientProperty, value);
            }
        }
    }
}

Next step is to build and publish developed custom workflow action:

And now I can use this step in CRM. As an example I'll create on demand workflow which will send 'Contacts' report (this report have no parameters but my custom workflow action can be extended with parameters to be used in report).
This workflow:




Save and publish it and the result of work:






As you see - this works. But there is one trick. To make this workflow action work you have to run Microsoft CRM Asynchronous Service under account which have access to Reports used in the workflow.

Posted by Andriy a33ik Butenko

Tags: , ,

CRM 4.0

Page List

About the author

I work for a consulting firm in Dublin Ohio called Affiliated Resource Group. For the last five years I have been spearheading our Microsoft Dynamics CRM practice. I have a deep appreciation for the Microsoft CRM platform and I am very excited about it. You might even describe me as a Microsoft CRM Advocate. I have many battle scars from my experience with the product and I’m constantly being asked questions about CRM and how-to-do something in it. Hence, this BLOG is to help disseminate that knowledge and information to everyone. As of last year I was posting links to many other blogs to help spread the knowledge, but now with the community.dynamics.com doing that for me, I will be following that practice unless a really juicy article catches my eye. Many people have asked where my post are for the first half of 2010, my company had me posting to another blog and maintain two was near impossible. I am now down to just this blog. So good luck and I hope that this blog may help in some way. If you have suggestions or questions, please email me them.

Disclaimer
The opinions expressed herein are my own personal opinions and do not represent my employer's view in anyway.

© Copyright 2012 BillOnCRM