Argos
Phil's CRM Blog | All posts tagged 'mscrm'

Windows7, IE 8 and CRM: popups being blocked

by Phil Adams 13. August 2010 13:36

One of our clients is having a really frustrating problem: on a new Windows 7 pc with IE 8 installed, popups from CRM are always being blocked with the usual "A Microsoft Dynamics CRM window was unable to open, and may have been blocked by a pop-up blocker." error message.
The Outlook CRM client isn't installed. 
When we get the above error message, it also causes additional iexplorer.exe processes to appear in task manager that won't dissapear after closing IE.

What we have already tried:

  • adding the site to the popup blocker exception list
  • disabling the popup blocker altogether
  • adding the site to the trusted zone
  • enabling/disabling protected mode
  • disabling all IE plugins
  • resetting security zone settings
  • enable protected mode for all zones
  • resetting all IE 8 parameters
  • checked if IE 8 is the default browser
  • cleared IE cache

I will update when we have found a resolution.

Tags: , , , , ,

CRM | IE8 | Javascript | mscrm4

Using Unresolved Email Recipients in CRM 4.0

by Phil Adams 11. August 2010 11:00
Unresolved emails are useful in that you can send an email to someone without having them setup as a system record (contact, account, lead, queue, user, ect).  Unresolved email addresses are turned off by default.  They should be used with caution.  If you send an email to an unresolved address it will not track the email to that lead/contact since one does not exist.  It also does not leverage the email "Do not allow" flags to allow people to opt out of emails.  With those considerations, there are still cases where it is very useful to send an email to someone without having to create a contact record.

I will show two example of sending emails to unresolved recipients.  The first will be sent from the email form using JavaScript.  The second will be done in a plugin.  We will add two unresolved email addresses as CC addresses on emails sent from a contact record.

Before we begin.  You must flip the setting to allow unresolved recipients.  Go to Settings --> Administration --> System Settings --> Email Tab.  Set Allow messages with unresolved e-mail recipients to be sent to yes.

 Second, we will add a couple of fields to the contact for secondary contacts email addresses.  These fields will contain our unresolved email addresses.


JavaScript Implementation
When the user clicks "Send Email" from the contact form we want the CC field to default with the two unresolved email addresses.  To do this we add the following Jscript to the onload of the email form.  The code will check to see if the regarding object is of type contact since this form is used for all emails.  Then it adds each email address to an email object that follows the activityparty schema for unresolved email addresses.  It has a type of 9206 and the email is set in the data property.

if (crmForm.FormType == 1 &&
    crmForm.all.regardingobjectid.DataValue != null &&
    crmForm.all.regardingobjectid.DataValue[0].typename == "contact" &&
    window.opener != null &&
    window.opener.document != null) {

    var ar = new Array();
    var emailObj = new Object();

    if (window.opener.document.crmForm.all.new_secondarycontactemail1 != null &&
            window.opener.document.crmForm.all.new_secondarycontactemail1.DataValue != null) {
        emailObj = new Object();
        emailObj['type'] = '9206';
        emailObj['category'] = '3';
        emailObj['data'] = window.opener.document.crmForm.all.new_secondarycontactemail1.DataValue;
        emailObj['name'] = window.opener.document.crmForm.all.new_secondarycontactemail1.DataValue;
        ar.push(emailObj);
    }

    if (window.opener.document.crmForm.all.new_secondarycontactemail2 != null &&
            window.opener.document.crmForm.all.new_secondarycontactemail2.DataValue != null) {
        emailObj = new Object();
        emailObj['type'] = '9206';
        emailObj['category'] = '3';
        emailObj['data'] = window.opener.document.crmForm.all.new_secondarycontactemail2.DataValue;
        emailObj['name'] = window.opener.document.crmForm.all.new_secondarycontactemail2.DataValue;
        ar.push(emailObj);
    }

    crmForm.all.cc.DataValue = ar;

}

Lastly, publish the customization.  When you click "Send Email" from the contact form your addresses will be added to the CC. 

 

 

Plugin Implementation

The same functionality can be added using a plugin.  The benefits of using a plugin versus a client side implementation is that you can implement consistent functionality regardless of whether the email send is triggered from a client portal, another plugin, or through the CRM UI.  The JavaScript implemenation is useful in that the user can see who the email is being sent to before they click Send. 

Install the plugin using the registration tool as a pre-create step for email save.  This will add the CC on the initial save of the email.  It is triggered regardless of whether the user clicks save or send from the email form.  The code also includes duplicate checking logic. So, if the user adds the email address to the CC from the form it will not duplicate the same address in the plugin.

using System.Web;
using System.Net;

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Crm.Sdk;
using Microsoft.Crm.SdkTypeProxy;
using Microsoft.Crm.Sdk.Query;
using System.Reflection;
using System.Web.Services.Protocols;
using Microsoft.Crm.SdkTypeProxy.Metadata;
using Microsoft.Crm.Sdk.Metadata;
using Inetium.CrmPlugins;
using System.Collections;

namespace Inetium.CrmPlugins.Plugins
{
    public class CaseUnresolvedEmailPlugin : IPlugin
    {
        public void Execute(IPluginExecutionContext context)
        {
            ICrmService service = null;
            try
            {
                if (context.InputParameters.Properties.Contains("Target") &&
                    context.InputParameters.Properties["Target"] is DynamicEntity)
                {
                    DynamicEntity entityInput = context.InputParameters.Properties["Target"] as DynamicEntity;
                    if (entityInput.Properties.Contains("regardingobjectid"))
                    {
                        Lookup regardingObjectLookup = entityInput.Properties["regardingobjectid"] as Lookup;
                        service = context.CreateCrmService(true);
                       
                        // Only using this for contacts
                        if (regardingObjectLookup.type == EntityName.contact.ToString())
                        {
                            // Pull parent contact - using helper method
                            DynamicEntity ctn = CRMUtilities.RetrieveById(service, EntityName.contact.ToString(), "contactid", regardingObjectLookup.Value, new ColumnSet(new string[]{"new_secondarycontactemail1", "new_secondarycontactemail2"}));
                            if (!ctn.Properties.Contains("new_secondarycontactemail1") && !ctn.Properties.Contains("new_secondarycontactemail2"))
                                return;

                            string email1 = ctn.Properties.Contains("new_secondarycontactemail1") ? ctn.Properties["new_secondarycontactemail1"].ToString() : "";
                            string email2 = ctn.Properties.Contains("new_secondarycontactemail2") ? ctn.Properties["new_secondarycontactemail2"].ToString() : "";

                            DynamicEntity[] partyArrayExisting = entityInput.Properties.Contains("cc") ? entityInput.Properties["cc"] as DynamicEntity[] : new DynamicEntity[] { };
                            List<DynamicEntity> partyList = new List<DynamicEntity>(partyArrayExisting);

                            if (email1 != "" && !IsEmailAlreadyInCC(email1, partyList))
                            {
                                DynamicEntity party = new DynamicEntity();
                                party.Name = EntityName.activityparty.ToString();
                                party.Properties["addressused"] = email1;
                                partyList.Add(party);
                            }

                            if (email2 != "" && !IsEmailAlreadyInCC(email2, partyList))
                            {
                                DynamicEntity party = new DynamicEntity();
                                party.Name = EntityName.activityparty.ToString();
                                party.Properties["addressused"] = email2;
                                partyList.Add(party);
                            }

                            // Generate CC's list by adding in those from contacts
                            if (partyList.Count > 0)
                                entityInput.Properties["cc"] = partyList.ToArray();

                        }

                    }
                }
            }
            catch (SoapException se)
            {
                throw new Exception(se.Detail.InnerText);
            }
            catch (Exception ex)
            {
                throw new Exception(ex.Message);
            }
            finally
            {
                if (service != null)
                {
                    service.Dispose();
                    service = null;
                }
            }
        }

        private bool IsEmailAlreadyInCC(string email, List<DynamicEntity> activityPartyList)
        {
            bool bAlreadyExists = false;
            foreach (DynamicEntity existingParty in activityPartyList)
            {
                // compare to existing CCs
                if (existingParty.Properties.Contains("addressused") &&
                    (existingParty.Properties["addressused"].ToString() == email))
                {
                    bAlreadyExists = true;
                    break;
                }
            }
            return bAlreadyExists;
        }
    }
}

Source: Andrew Zimmer

Tags: , , , ,

ASP.Net | CRM | MSCRM | mscrm4

CRM 4 Install and SQL Error 15401

by Phil Adams 4. May 2010 13:09

Last week i have had an issue where during the install of CRM 4, this is a fresh install the setup as follows:

SQL Box - Windows 2008 R2 + SQL2008 SP1
CRM Box - Windows 2008 R2

now both boxes have been freshly prepped and joined to the domain, all with out errors.
for added installation proof both servers had their windows firewalls turned off.

upon the Installation of CRM i encountered this error:

14:41:37|  Error| System.Exception: Action Microsoft.Crm.Setup.Server.GrantConfigDBDatabaseAccessAction failed. ---> System.Data.SqlClient.SqlException: Windows NT user or group 'Domain\SQLAccessGroup {9e798758-54f6-44a6-93a6-51b6faf49928}' not found. Check the name again.

   at Microsoft.Crm.Setup.Database.SharedDatabaseUtility.GrantDBAccess(String sqlServerName, String databaseName, String groupName, CrmDBConnectionType connectionType)

   at Microsoft.Crm.Setup.Server.GrantConfigDBDatabaseAccessAction.Do(IDictionary parameters)

   at Microsoft.Crm.Setup.Common.Action.ExecuteAction(Action action, IDictionary parameters, Boolean undo)

   --- End of inner exception stack trace ---, Error, RetryCancel, Option1

Now its quite obvious at this stage that it is failing to Gannt Access to an account to the MSCRM_CONFIG Database on the SQL server.

so i tried to add the SQLAccessGroup manually in the SQL Management Tools and the Error 15401: Windows NT user or group 'SCDC2003\SQLAccessGroup {9e798758-54f6-44a6-93a6-51b6faf49928}' not found. Check the name again.

now this is strange as i could not add the account manually, So i thought is this just Group Related and tried add a domain user and the same problem reared it's ugly head.

so a call to the Microsoft Support Team and some tests later, after running:

name2sid.zip (13.04 kb)

via the command line:
name2sid.exe domain\anyuser

the real error appeared:
LookupAccountName failed with error: The trust relationship between this workstation and the primary domain failed. (0x6fd/1789)

Now this helps the Microsoft Guys a lot so they asked me run:
netdom resetpwd /server:<DomainControllerName> /userd:<domain\domainadminuser> /passwordd:<password>

This Command Replied with:
The machine account password for the local machine has been successfully reset.

The command completed successfully.

now the next thing to do is to put this new command into action by restarting the netlogon service:
net stop netlogon
net start netlogon

and clear the kerberos Tickets on the sql server:
klist purge

then i tried adding the group manually again and hey presto and shazzam, it was working.

i hope this helps others having similar problems.

Phil

Tags: , , ,

ASP.Net | CRM | CRM Plugin | Group Policy | MSCRM | mscrm4

Debugging Workflows and Plugins in Microsoft Dynamics CRM 4.0

by Phil Adams 30. April 2010 00:21

The concept of debugging plugins and workflows has been blogged about in the past.  There is a lot of great information out there.  One thing I have noticed about debugging is that it involves a lot of steps.  These steps take time.  You end up waiting forever from the time you make a code change to the time that you are debugging again.  I wanted to share a couple things I have learned about debugging that have saved me a great deal of time.

Time Wasters:

  • Starting and stopping IIS and the async service
  • Deploying your new assembly
  • Attaching to processes
  • Getting back to debugging after making a small code change

Let’s get started… …

Project Setup
I like to start with a vanilla system on a virtual PC (VPC) that has CRM installed.  I import the customizations into my environment and set up some quick test data.

Note:  I stay away from remote debugging when possible as it requires specific security privileges on the CRM server and you will affect users that are trying to access the system.

From my VPC I open the project that includes my workflow or plugin.  Be sure to set the build path to the bin/assembly folder of your CRM instance.  On my machine it is C:\Program Files\Microsoft Dynamics CRM\server\bin\assembly\.  It varies from installation to installation.   Building to this location allows us to register the plugin to disk and make code changes quickly without having to move files around or re-register anything.

Register Plugin
Open the registration tool and register your plugin or workflow.  Be sure to register the plugin to disk.

Note:  When you move to production I recommend registering to the database, but registering to disk works great for debugging.

Attaching to Processes
Now that you have the plugin registered, you are ready to start debugging.  You need to attach to W3WP.exe to attach to plugins since they run within IIS.  To attach to workflows you need to attach to the CRM async service which is Crmasyncservice.exe.

 
Select w3wp.exe and Crmasyncservice.exe and click “Attach.”

To expedite the process I used a trick from Janne Mattila.  You leverage VS macros to attach to the processes by using a shortcut key. I have Ctrl+Shift+V tied to a script that attaches to both w3wp and crmasyncservice.   See my script below.

Courtesy of Janne Mattila:  http://blogs.msdn.com/jannemattila/archive/2008/10/30/attaching-debugger-to-w3wp-exe-using-nice-and-easy-keyboard-shortcut.aspx

Imports System
Imports EnvDTE
Imports EnvDTE80
Imports EnvDTE90
Imports System.Diagnostics

Public Module AttachHelper
    ' This subroutine attaches to w3wp.exe:
    Sub Attach()
        Dim attached As Boolean = False
        Dim proc As EnvDTE.Process

        For Each proc In DTE.Debugger.LocalProcesses
            If (Right(proc.Name, 8) = "w3wp.exe") Then
                proc.Attach()
                attached = True
            End If
        Next

        If attached = False Then
            MsgBox("Couldn't find w3wp.exe")
        End If

        attached = False
        For Each proc In DTE.Debugger.LocalProcesses
            If (Right(proc.Name, 19) = "CrmAsyncService.exe") Then
                proc.Attach()
                attached = True
            End If
        Next
        If attached = False Then
            MsgBox("Couldn't find crmasyncservice.exe")
        End If
    End Sub
End Module

So we are now able to quickly attach to processes.  We can debug.  Awesome!!!

 

But wait!  Next, you discover you need to make a code change.  We don’t have edit-and-continue available in plugins yet.  So, you stop the your session, make your code change and you get the following error when you try to build.

 

This is because you are trying to build to a file location that is already locked by the async service and/or IIS.  To get around this I have a bat file on my desktop and I run it every time I want to rebuild.  It includes the following:
iisreset
net stop MSCRMAsyncService
net start MSCRMAsyncService
"C:\Program Files\Internet Explorer\iexplore.exe" http://andrewvpc:5555

This script restarts IIS to unlock w3wp.exe.  Second, it restarts the async service.  Lastly, I reopen the CRM website in IE, so IIS will re-spawn itself (replace andrewvpc with your servername).  Otherwise, when you try to attach to processes it won’t be able to find w3wp.exe.

 

Now that you have ran the script, try to rebuild.  You will be rid of your error message and it will build successfully.  Now re-run your macro using Ctrl+Shift+V.  You are back to debugging again. Enjoy!!!

Source: Andrew Zimmer

Tags: , ,

CRM | CRM Plugin | MSCRM | mscrm4

Date field lookup cut off in IE8

by Phil Adams 29. April 2010 12:25

This seemed strange to me, as I knew that I had used right hand date fields in CRM 4 previously, and it had worked.  I tested on another machine, this time with IE 7, and the calendar lookup was not cut off.

IE 7    IE 8

Internet Explorer 7                                          Internet Explorer 8

Turns out that it’s not really a bug in CRM, but rather a side effect from some changes in Internet Explorer 8.  The CRM team worked with the IE team and came back with a fix for this issue.  The fix is to install IE update 974455 and make the following registry change on the client:

HKEY_LOCAL_MACHINE\Software\Microsoft\Internet Explorer\Main\FeatureControl
Create a new Key, and name it as follows:
FEATURE_FORCE_POPUPS_ONTO_MONITOR_KB974537
Within this key, point to New , and then click DWORD Value
Type iexplore.exe for the name of the key
Right-click iexplore.exe , click Modify and then type 1 in the Value data field

Read more about this fix at the UK MSCRM Support Blog.

Tags: , , , , ,

CRM | IE8 | Javascript | MSCRM | mscrm4

Determining CRM 4 ServicePack Level

by Phil Adams 30. March 2010 11:39

Since Microsoft first released Microsoft CRM 4.0 (in early 2008) they have released several hotfix roll ups.  Each hotfix rollup fixes several problems that have been identified since the initial release.  It is generally recommended that you keep your CRM patched with the latest release.  However, it can often be difficult to know which hotfix has been applied to an installation of Microsoft CRM. 

To determine which hotfix has been applied to your installation look at Help About (found on the top right hand side of the Internet Explorer window if using CRM via the browser or CRM > Help > About if using CRM via Outlook.  The Help About window will look similar to the following:

Help About in Microsoft Dynamics CRM 4

The hotfix that has been applied to your installation is indicated by the number in brackets after the CRM 4.0, and in particular the final four digits. An explanation of the numbers and their corresponding release numbers is given below:

RTM: 4.0.7333.3

Rollup 1: 4.0.7333.1213

Rollup 2: 4.0.7333.1312

Rollup 3: 4.0.7333.1408

Rollup 4: 4.0.7333.1551

Rollup 5: 4.0.7333.1644

Rollup 6: 4.0.7333.1750

Rollup 7: 4.0.7333.2138

Rollup 8: 4.0.7333.2542

Rollup 9: 4.0.7333.2644

Rollup 10: 4.0.7333.2741

Rollup 11: 4.0.7333.2861

Rollup 12: 4.0.7333.2935


One reason that it is important to be able to determine the hotfix version of an installation is when you want to import customisations from one version to another.  This is not always possible if the two installations are running different hotfixes.

Another reason to upgrade your installation is to benefit from the latest security patches and optimisation improvements.  In particular, hotfix rollup 5 introduced a number of speed improvements.

Tags: , ,

CRM | MSCRM | mscrm4

Creating A Group Policy Administrative Template For Deploying The CRM Client AutoUpdate Registry Keys

by Phil Adams 21. August 2009 16:26

In my Article CRM v4 Client AutoUpdate Procedure, I talked about deploying the required registry keys:

HKEY_LOCAL_MACHINE\Software\Microsoft\MSCRMClient\AutoUpdateDownloadUrl (for 32bit)
HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\MSCRMClient\AutoUpdateDownloadUrl (for 64bit)

This can either be done by tediously going to each PC and manually creating them or executing a .reg Merge file.
But that would not be time constructive, im sure you have more pressing things to do.

SO, im going to show you haw to create a Group Policy Administrative Template so you can deploy the registry entries the next time the pc reboots or refreshes it domain policy., right here goes:

;------------------------------- Start Of FILE --------------------------------------------

CLASS MACHINE
CATEGORY CRM_Client_AutoUpdate
  POLICY Update_Share_32Bit
  EXPLAIN !!ClientHelp
  KEYNAME Software\Microsoft\MSCRMClient
    PART "Set the File Share to :" EDITTEXT REQUIRED
    DEFAULT !!DefaultServer
    VALUENAME "AutoUpdateDownloadUrl"
    END PART
  END POLICY

  POLICY Update_Share_64Bit
  EXPLAIN !!ClientHelp
  KEYNAME SOFTWARE\Wow6432Node\Microsoft\MSCRMClient
    PART "Set the File Share to :" EDITTEXT REQUIRED
    DEFAULT !!DefaultServer
    VALUENAME "AutoUpdateDownloadUrl"
    END PART
  END POLICY
END CATEGORY

[strings]
dummy="dummy"
DefaultServer="http://mscrm/crmpatches/"

;explains
ClientHelp="Set The File Share That The CRM Client For Outlook Checks To See If There Is An Update., NOTE: MAKE SURE YOU FINISH URL WITH '/' E.g. 'http://[servername]/crmpatches/'  By Phil Adams(Cambridge Online)"

;------------------------- End of File -------------------------------------------------

Save the Above to a file called “CRM AutoUpdate.adm”

Then load up GPMC, then create and link the new policy to the OU required.
open the new policy and under User Configuration , right-click Administrative Templates and select Add/Remove Administrative Templates.

find the new ADM file and highlight it, then select Add. It will be copied into the policy in SYSVOL automagically. 
Now we highlight Administrative Templates and select View | Filtering.
Uncheck "Only show policy settings that can be fully managed" (i.e. any custom policy). It will look like this:
img3Now if you navigate to your policy, you get this (see the cool explanation too? No one can say they don’t know what this policy is about!
img4

Tags: , , ,

CRM | MSCRM | mscrm4 | Group Policy

CRM v4 Client Auto Update Procedure

by Phil Adams 21. August 2009 15:21

A new feature in CRM 4.0 is the administrative ability to prompt clients to install patches on their CRM For Outlook client. This feature is called AutoUpdate and it applies to any client where the user has administrative rights on his/her machine.

When you install the CRM 4.0 client, one of the new components is a tool called Update. This is the client component of the AutoUpdate process. You can launch the Update tool directly, run it as a scheduled task quietly, launch it from Outlook under the CRM toolbar – Check for Updates or it will run each time you launch Outlook. Also, by default, the AutoUpdate check is performed on all CRM 4.0 clients* every 4 hours*.
* These options can be turned off or adjusted via registry keys.

In order to make updates available to clients, you need to post the updates to the server. The CRM Server installation comes with a new tool called the Client Patch Configurator. The tool is installed by default at [Program Files]\MSCRM\Tools\Microsoft.Crm.Tools.ClientPatchConfigurator.exe. You need to run a DOS command to call the XML file in which you define the patches that will be provided to the client. The patch configurator process will add the patches to the MSCRM_Config database. You can use the tool to create, update or delete patch information, so if you add a patch you didn’t intend to add, you can remove it from being pushed to clients.

With that background information, here are the steps I give to customers asking how to set up AutoUpdate in their environment:

1. The first time you run autoupdate, go to your [ServerInstallDir]\Server\CRMWeb and create a new folder named crmpatches. Create this same folder on each subsequent web server in your deployment.

2. On each client, go to the registry and add a value in the HKEY_LOCAL_MACHINE\Software\Microsoft\MSCRMClient key called AutoUpdateDownloadUrl (String) for 32bit Machines and HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\MSCRMClient for 64bit machines. Give it a value of http://[servername]/crmpatches/ (remember the closing /). If you don't set this value, the clients will look to http://go.microsoft.com/fwlink/?LinkId= then the value in the LinkId XML parameter.
OR you can deploy the registry keys needed via Group Policy by Adding my “Group Policy Administrative Template” which there is a separate article: Creating A Group Policy Administrative Template For Deploying The CRM Client AutoUpdate Registry Keys

Troubleshooting Note: if when prompted to update the client you click install and crm responds “UntrustedUpdate” then please check the registry keys.

3. Download the hotfix to your server (or each web server) and extract the contents to the [ServerInstallDir]\Server\CRMWeb\crmpatches folder as set out below.

Extracting the contents of the client patch on your server to determine the PatchId value which is required for the XML file configuration.:

b. Open a command prompt, and type [DownloadLocation]\CRMv4.0-KB[KB#here]-i386-Client-ENU.exe /x

c. You will be prompted for a location to which the files will be extracted

d. Once extracted, find the config.xml file at the root of the directory

e. Within the XML file, copy the value of the <patchid> element and paste it into your configuration file you will create in Step 5

5. Creating your configuration XML file

Here's a sample configuration XML for Update Rollup 5:

<ClientPatches>
<Create>
    <ClientPatchInfo>
        <PatchId>{592DDF5E-D0D7-46FE-81C3-A3BCAC5E8F22}</PatchId>
        <Title>CRM v4 Update Rollup 5</Title>
        <Description>CRM v4 Update Rollup 5</Description>
        <IsMandatory>true</IsMandatory>
        <IsEnabled>true</IsEnabled>
        <ClientType>OutlookDesktop,OutlookLaptop</ClientType>
        <LinkId>CRMv4.0-KB970141-i386-Client-ENU.exe</LinkId>
    </ClientPatchInfo>
</Create>
</ClientPatches>

Note: You can add multiple <ClientPatchInfo> and container elements to post multiple hotfixes at one time. The title and description are up to the administrator to complete. The IsMandatory option dictates whether a user has to install this hotfix in order to continue using CRM functionality within CRM. The ClientType can be either OutlookDesktop or OutlookLaptop or OutlookDesktop,OutlookLaptop depending on which clients should receive the updates. There are several more options available, so please see the Implementation Guide for further details.

6. In a command prompt, go to the directory where the ClientPatchConfigurator.exe is located ([ServerInstallDir]\Tools and type microsoft.crm.tools.clientpatchconfigurator.exe [configfile].xml

7. Once the patch has been uploaded, launch the Outlook client

When Outlook launches, the following screen will pop up:
img1

When complete, you'll see this screen:
img2

8. You can then proceed to use CRM with the hotfixes applied. The hotfix installs will show in the Installed Updates area within Programs and Features in the Windows Vista Control Panel or in Add/Remove Programs on Windows XP.

This feature provides administrators with the assurance that their clients will be on the most updated hotfix. Therefore, CRM client troubleshooting doesn’t have to begin with the question “Did you apply these patches?”

Thanks to Eric Newell of the CRM Team for his original article :Here

Tags: , ,

CRM | MSCRM | mscrm4

CRMScape - Mark Kovalcson's MS CRM Development Blog

by Phil Adams 16. August 2009 20:39

 

The email templates in MS CRM can be leveraged as a powerful building block when generating emails programmatically.

Tips:

  • Generate your HTML in another editor and then paste it into the template editor to add data slugs.
  • Associate your template with the entity that you want the most information from.
  • Use Template Naming conventions that organize things and make programmatic template selection easier.

For an example lets say that we have product specific Quote Letters.

Using my helper method from a previous blog article, grab an email template matching a specific name based on the product.

// Get appropriate Template
BusinessEntityCollection templates = 
   h.GetAllEntitieswithFilter(EntityName.template.ToString(), new[] { "templateid" }, new[]{"title"}, new[]{emailTemplateTitle});

Then create a new InstantiateTemplateRequest using the template id and point it at an entity with the information that you want merged in. This must be the same type that you associated your template with when you created it.

var instTemplate = new InstantiateTemplateRequest
     {
         TemplateId = thisTemplate.templateid.Value,
         ObjectId = quoteId,
         ObjectType = EntityName.quote.ToString()
     };


// Execute the request to create an email message from the template.
var instTemplateResponse = (InstantiateTemplateResponse)h.service.Execute(instTemplate);

var newEmail = (email)instTemplateResponse.BusinessEntityCollection.BusinessEntities[0];

The result of the InstantiateTemplateResponse is an email entity collection. For this example we just have one email.

From here you can regard the email to a completely different entity if you want. It is only important that the ObjectId and ObjectType be set for the merge process. After that is complete this is just another email with a bunch of fields pre-filled. Now you can have your way with it like any other email that you created from scratch. This is critical to making the best use of email templates.

Additional Merging
If you are calculating other numbers or pulling information from another data source outside of CRM, there is no reason to limit merging to what can be represented as data slugs.

In this example I am using putting additional information into the email body with a simple string replace using an agreed upon naming convention to represent additional merge fields.

// If template had #EmbedLicense# in body replace it with the license information
newEmail.description = newEmail.description.Replace("#EmbedLicense#", embedFile);

From here you can add attachments as shown here.

Proofing before Email is Sent
Another useful thing to do if you are doing this in a web application or a client Winform application is save the email and then open it in a new window for final review before it is sent. To do that generate a URL like the following with your orgname and email id passed in. You can get the CRM server base URL from the registry as shown here which you need for your web service reference, and then use the following: CrmServerBaseUrl = CrmServiceUrl.Substring(0, CrmServiceUrl.ToLower().IndexOf("mscrmservices"));

 // Open newly created email activity at this Url.
var emailUrl = h.CrmServerBaseUrl + "/"+orgname+"/activities/email/edit.aspx?id={" + emailId + "}";

From a WinForm application you can pop a CRM screen up like this.

For a web application register some JavaScript in the code behind that sets the value of the new email's URL.

 // Sets Javascript variables to envoke Window Open to new Explorer Window with body onload event
const string SETQUERYSTRING_SCRIPT = "Email_String";

if (!Page.ClientScript.IsClientScriptBlockRegistered(SETQUERYSTRING_SCRIPT))
{
   Page.ClientScript.RegisterClientScriptBlock(GetType(), SETQUERYSTRING_SCRIPT, string.Format(@"<script language=""javascript"">emailRecordUrl = '{0}';</script>", emailUrl));
}

Then in the aspx file use the following JavaScript code to open the new window. Call the script from the onload of the body.

<script type="text/javascript"> var emailRecordUrl = ""; function UpdateCRMFormGenerateEmail() { if (emailRecordUrl != "") { window.open( emailRecordUrl,
"_blank", "toolbar=no,scrollbars=yes,resizable=yes"); emailRecordUrl = ""; } } </script> </head> <body onload="UpdateCRMFormGenerateEmail();">

CRMScape - Mark Kovalcson's MS CRM Development Blog

Tags: , , ,

CRM | Javascript | mscrm4 | MSCRM

CRMScape - Mark Kovalcson's MS CRM Development Blog

by Phil Adams 16. August 2009 20:37

 

If you write custom web applications in iframes that depend on the data in the parent form, it is important to run on up to date information to avoid user confusion.

Important! This requires that the Restrict cross-frame scripting box for your iframe is NOT checked.

image

Accessing attribute values on the Parent Form can be done simply by adding a parent.document in front of your normal attribute names. This gets you the values currently on the form, but doesn't guarantee those values have been saved.

var myAttributeValue = parent.document.crmForm.all.new_attribute.DataValue;

Parent Form Save "if modified" This is a nice method to call because if there are no modified values on the form it won't do anything and your application can continue on it's merry way.

parent.document.crmForm.Save();

Force a Parent Save Sometimes you want to force a save so that a Plug-in is called to do some additional calculations even though no attributes have been modified on your current form. The recalculate on the Opportunity, Quote, Order, and Invoice forms is a good example.

Note: The SubmitCrmForm method is not a MS supported method, but it hasn't changed in the last couple CRM revisions.

SubmitCRMForm( Mode, Validate, ForceSubmit, closeWindow)

Modes:
1 = Save, 2 = SaveAndClose, 7 = Send,
58 = SaveAsCompleted, 59 = SaveAndNew

Example: In this example I am forcing a save so that a plug-in is called on the Pre Update for the quote to create a new total value from the quote details that were filled in when the Quote was created from an Opportunity. These new fields were  mapped between the detail products see Mapping Note below. The iframe contains a button to do something that requires all of the data on the quote be up to date.

function RecalculateQuote() 
{ 
   if ( parent.document.crmForm.all.new_totalamount.DataValue == null)
   {    
    parent.document.crmForm.SubmitCrmForm(1, true, true, false);   
    return false;      
    } 
    
    parent.document.crmForm.Save();
}

The above JavaScript is made to work with an OnClientClick so that a return false will not generate a postback.

Why do we need a return false option?  If the validation fails, a message is generated for the user, the save is not performed, and you do not want your action to run.

The data has already been filled in, then the crmFrom.Save() will check to make sure that any modified fields on the form have been saved.

<asp:Button ID="RunMyNeatFeature" CssClass="button" runat="server" Text="Go" OnClick="RunMyNeatFeature_Click"
OnClientClick="javascript:return RecalculateQuote();"/>

For the button the OnClick will PostBack and run the functionality I care about only if the RecalculateQuote() is not false.

This safeguards the user from running the functionality with different data than what is on the screen when they press the "Go" button.

Mapping Note: For mapping details open SQL Management Studio and look at the EntityMapBase table to find the EntityMapId that has the SourceEntityName and TargetEntityName that you are interested in. Add your guid to the end of the URL below and it will bring up a form to map attributes between the Source and Target Entities.

http://yourcrmservername:5555//tools/systemcustomization/relationships/mappings/mappinglist.aspx?mappingId=

CRMScape - Mark Kovalcson's MS CRM Development Blog

Tags: , ,

CRM | Javascript | MSCRM | mscrm4

About Phil

Phil has been working with CRM since the BETA of CRM v1.0 and has seen a lot of the problems arising from installation, maintenance and Development.

Phil specializes in the ISV area of CRM; Creating Add-Ons and Plugins for various clients.

Phil currently works as a Microsoft Dynamics CRM Consultant and Developer for Cambridge Online Systems Ltd In the UK.

Phil also has several Microsoft Certifications in .NET and CRM