Friday, December 19, 2008

Useful Out-of-the-Box SQL Functions for MSCRM

There are some very useful SQL functions that are built into the MSCRM database that are available to be used in the select queries to write reports, pull data into Excel, or just to check the data in your database. Some of the more notable functions, at least from what I think, are the following:

1. F_START_OF_WEEK (gets the first day of a week, and you can specify which day you want to be the start of your week, Monday, Tuesday, etc)
2. fn_LastXMonth (this is what Advanced Find uses, this is fairly easy to replicate with SQL but it gets even easier if there is a function to be used)
3. fn_FindUserGuid (this gets the logged in user's GUID, this is how Advanced Find figures out "Equals Current User")
4. fn_GetMaxUserPrivilege (tells you whether a user has sufficient rights to a specific privilege,)
5. fn_RptBracket (puts numbers in groups, for instance fn_RptBracket(75, 50) would return 50 - 99 . This translates to placing the number 75 into numbers 1-49, 50-99, 100-149, etc. Basically the first number is the number you want to group and the second is the interval at which you want your groupings. Play with it a bit to see how it works. It could be very useful for reporting)

To find all of the functions open up SQL Management Studio and expand the MSCRM database, then expand "Programmability", expand "Functions", and finally, expand "Scalar-valued Functions" to see the full list. Right click a function and choose "Script Function As", "Create To", "New Query Editor Window" to look at the code behind the function.

Some very cool things to find and use, hopefully this makes some report queries much more simple and other data check queries easier to write.

David Fronk
Dynamic Methods Inc.

Friday, December 12, 2008

Reassociating MSCRM Users with Active Directory Users

Back in the version 1.0 and 1.2 days fixing CRM user associations was a huge pain. Users would get deleted from Active Directory or CRM users would need to be reassociated with a different user in Active Directory. These tasks were either impossible to perform or nearly impossible to recover from. In these instances, MS Support had to get involved to reassociate records owned by that user through the back end with some of their utilities.

When version 3.0 came out finally users had the ability to use Deployment Manager to reassociate CRM users to Active Directory users. This helped a lot.

In version 4.0 the ability to reassociate CRM users with Active Directory users through Deployment Manager has gone away. When I discovered this I was very upset because I support numerous companies and inevitably, between all my clients, I will get a handful of these type of issues a year. So, having that utility was a reasonably big deal to me. After some poking around I found that reassociating users in MSCRM 4.0 is actually even easier than it was in 3.0. Since I was expecting some special command or utility I never even noticed it.

If you open up a user's card in CRM in all other versions the Username field has been locked down as soon as you save the record. In 4.0 this is not the case. All you have to do to reassociate the user record with a different Active Directory record is change the username. The autopopulate of the fields still occurs and everything gets reassociated.

Now you're ready to rock and roll and keep all of your users between MSCRM and Active Directory in sync.

David Fronk
Dynamic Methods Inc.

Friday, December 05, 2008

MSCRM 4.0 Rollup 1 is now available

This rollup fixes over some 80 issues with the server, client and email router (each a separate download and install). We've applied this in-house and had no issues as of yet, just improvement. To download click below:

http://www.microsoft.com/downloads/details.aspx?FamilyID=57c6267b-3b13-49dd-bfed-3cc83633aea7&displaylang=en

Also, please note that not all recent hotfixes made it into this rollup. I am aware of at least 2, a hotfix for the deletion service and one for issues with the Word Mail Merge connector. But each of those hotfixes are over 100MB.

I'm a fan of rollup 1 so far but if you're applying to fix specific issues just make sure that the appropriate hotfix is included so that you do actually fix the issue you are having.

David Fronk
Dynamic Methods Inc.

Friday, November 21, 2008

Disabling all fields on a form...dynamically

There have been a number of times where I have had clients request that when certain fields are set one way or another they would actually like to disable the entire form. Or they want to disable the entire form except for a status field, or something like that. For some clients this was a HUGE pain in the neck because every field would have to be done manually. And whenever a new field was added if the script wasn't updated then that new field would be updateable while everything else would stay locked down.

Well, I found this code posted by Michael Höhne from Stunnware and it was exactly what I've been trying to do.


for (var index in crmForm.all) {
var control = crmForm.all[index];
if (control.req && (control.Disabled != null)) {
control.Disabled = true;
}
}

That will disable them all. Pretty sweet. Then if they want to leave a status field or something enabled just manually enable them afterwards:

crmForm.all.new_status.Disabled = true;

And you're all set.

David Fronk
Dynamic Methods Inc.

Saturday, November 15, 2008

Sending Multiple Emails with Attachments

I've received multiple requests on how to add attachments to "canned" emails that you send out. Typically this is requested for the Quick Campaign. While you cannot add an attachment to Quick Campaign emails there is another way to accomplish our goal.

Workflow gives you the ability to send emails and it also allows you to send emails with attachments out of CRM. In workflow you can choose as a step the "Send Email" option and the "Set Properties". You'll see the "Attachment" tab and you can add multiple attachments to the email. Set the workflow to be triggered "On Demand" and you can then send out your emails with their attachments where you like. It is unfortunately only 250 at a time but that's better than none.

David Fronk
Dynamic Methods Inc.

Monday, November 10, 2008

Microsoft CRM Accelerators Released

Just announced Thursday during the CRMUG Workshop: Using the CRM Platform for Building Complex Business Applications - three new Accelerators have been released for users of Microsoft Dynamics CRM.
According to Reuben Krippner, Senior Product Manager - Microsoft Dynamics CRM, the "CRM Accelerators are a range of add-on solutions developed for Microsoft Dynamics CRM 4.0 customers and partners. Each accelerator is available at no cost and will showcase how the Microsoft Dynamics CRM 4.0 platform can be configured and extended to broaden marketing, sales and service capabilities."
Available now are accelerators for:• Notifications• Event Management• Enterprise Search
Five other accelerators are scheduled to be released prior to year-end.
Each accelerator available for download may consist of the following:• Customizations (entities, forms, views)• Workflow definitions• Business Intelligence elements such as custom reports (.RDL's)• Functional code samples (strictly adhering to SDK guidelines)• Documentation for installing, operating, localizing and extending the solution• An automated installerEach accelerator will be fully supported as per any other customization for Microsoft Dynamics CRM that follows SDK guidelines. Additionally, all samples are supplied with full source-code so they can be extended further to meet specific customer requirements. You can download the accelerators and supporting resources now here. Also available are discussion threads and feedback channels.

David Fronk
Dynamic Methods Inc.

Friday, November 07, 2008

CRM Accelerators Update

Events Management is now available for download. For those of you without a PartnerSource log in try the following link:

http://www.codeplex.com/crmaccelerators

I don't have any more dates for you, so we'll all just have to keep our eyes open to see when the rest get posted.

David Fronk
Dynamic Methods Inc.

Max size of an NTEXT field?

I actually have a client who wanted to test the limits of CRM NTEXT fields this week. Typically at about 5,000 characters most people think that's enough. However, this client had the need for more. All documentation from Microsoft states that 5,000 characters is the limit but my client wanted to see what would happen if he went over it. So, he attempted 100,000 and the system took it. We then tested putting in 100,000 characters of text and the field took them all and saved them to the database. We didn't feel like we needed to go higher than 100,000 characters, so I haven't found the "actual" limit of NTEXT fields, just know that they will take a lot.

Now, the downside to doing this is that your database now has to store a column that can handle 100,000 characters so it eats up the space in that table really fast. So, I don't recommend doing this on more than one field per CRM entity. Not that people really do duplicate checking on NTEXT fields, but there would be no way for you to duplicate check against this large NTEXT field. But since most NTEXT fields start at 1,000 characters you can't use out of the box duplicate checker on those fields anyway.

Anyway the point is that Microsoft built something that can handle some really big stuff, it's not recommended but still, pretty sweet if you really need it.

David Fronk
Dynamic Methods Inc.

Wednesday, October 29, 2008

MSCRM Accelerators Released!

Here it is straight from Microsoft:

The CRM 4.0 Accelerators have been released!
The following link will be used as the main Partner Accessible Index for all of the Accelerators for Microsoft Dynamics CRM content. It will contain links that direct Partners to the appropriate MSDN and CodePlex URLs for the Accelerator technical information as well as provide links to the Sales and Marketing collateral associated with the Accelerators for Microsoft Dynamics CRM. The page will be active starting October 29, 2008 and will be updated as new material is released.

https://mbs.microsoft.com/partnersource/newsevents/news/MD_CRM_Accelerators

The downloads for CRM Notifications and Extended Sales Forecasting are available on the site, and we expect the following will be available by the end of the week:

- eService
- Event Management
- Analytics

I'm excited to see how they turn out.

David Fronk
Dynamic Methods Inc.

Monday, October 27, 2008

CRM Accelerators

For anyone who is unaware of the CRM Accelerators for MSCRM 4.0 you may want to take a look into some of the things that the Microsoft CRM team has put together for partners to be able to access. There were a number of webinars on them last week and the Accelerators are supposed to be out very soon. I received word today that two are to be available today or tomorrow (10/27/08 or 10/28/08) and 3 others by the end of the week. As far as coding, everything is done, from what I understand, they just have to get everything through the PR and legal type stuff.

These are to be fully supported since they are built using the SDK. And source code will be available to partners as well so we can modify custom code to fit our clients needs if necessary. However, if you modify Microsoft's code and don't follow the SDK then you're on your own and not supported. If you stay within the SDK, it may not be as easy for Microsoft support to assist you but they will still support you.

The modules to be released this week are:

Today/Tomorrow:
Extended Sales Forecasting
CRM Notifications (RSS Feeds from CRM views)

Later this week:
eService (an external service portal)
Event Management
Analytics

Keep your eyes open inside of PartnerSource as that is where they will be posting the downloads. If you are not a Microsoft Partner then you will either need to become one, talk to your MSCRM partner, or wait until someone you know has gotten these from a Microsoft Partner and have him/her send them to you.

These are free but if you buy the external Accelerators (like eService) then you will need to purchase the external connector license, so be aware of that.

I'll keep you posted as I hear more.

David Fronk
Dynamic Methods Inc.

Friday, October 17, 2008

Hide Annoying Script Error Popups

While working on a server recently I noticed that any time I closed an Account form I would get prompted to send error data back to Microsoft. I couldn't figure out what was causing the script error and the annoying window to pop up at first but I wanted to get rid of the pop up. The one that looks like this:



Most people just get fed up with seeing this and either constently click Send or Don't Send. Well, there's an easier way around this. The last hyperlink on the message says "Change error notification settings."


By clicking on this a new window will open up to your CRM Personal Options page and take you right to your Privacy tab.


And your options here are to either always be prompted (default), always send automatically, or to never send error messages. If you choose to either always send or never send you will not see the annoying script error pop up box again. You will be free to go about using CRM without being interrupted by these windows again.

Evidently my script errors were related to the Presence Control. There is a Microsoft KB article on how to turn off the Presence Controls throughout the system, click here (you will need a PartnerSource log in to view the KB article) to see how to turn it off.

Happy script error window free CRM using!

David Fronk
Dynamic Methods Inc.

Friday, October 03, 2008

SQL 2008 and MSCRM 4.0

We successfully completed our internal upgrade to SQL 2008 and it is awesome. We did a complete revamp of our system and moved our CRM server and SQL server to a virtualized 64bit server then upgraded SQL to 2008 and it is great. The speed is fantastic and the move and upgrade were easy. The SQL 2008 upgrade was very easy and we're reaping the benefits. The enhancements to reports alone are worth it from a CRM perspective.

Check out some of the screenshots but if you are familiar with the slick looking reports that Excel 2007 has then you will be familiar with what SQL 2008 now has. There are gauges that Excel doesn't have (to my knowledge) that SQL 2008 has so that's one welcomed addtion.

Also, you can check out the Customer Effective Blog about this as Joel Lindstrom posted on this before SQL 2008 came out. My guess is that Joel has upgraded his system as well but you never know. We did and we're fans.

Here are some screenshots:





David Fronk
Dynamic Methods Inc.

Friday, September 26, 2008

Workflow "Increment by"




There is a lot of functionality to workflow in MSCRM 4.0 and I think the "Increment by" ability is one of those little known capabilities that can add a lot of value. One of my coworkers recently used the "Increment by" to update the number of devices an Account owned when an Opportunity was "Won." If the Opportunity that was won was for 4 devices then the Account "Total # of Devices" would increment by 4. This can be useful for Cases, Products, number of days open type calculation, etc. You can increment, decrement, multiply by or just set a field vaule all off of either a static value or a dynamic value from a field on a related form.



Great functionality that I don't see people using all that often. Hopefully this will be of use to someone out there.
David Fronk
Dynamic Methods Inc.

Friday, September 19, 2008

Mail Merge in CRM Online

This post comes from one of my co-workers who has been doing some extensive work with CRM Online. This was spurred by some data connection errors that we saw both from CRM Online as well as a couple of On Premise installations. The error only occurs through the web client, from what I am told, but basically the data connection stored in Word to pull all of the CRM data gets corrupted upon creation and isn't usable...making your CRM Mail Merge pretty lame. This is a work around for this issue. Microsoft is aware of the issue and is working on a hotfix.





Setting up Mail Merge in CRM Online. Here are some errors I got while setting up Mail Merge Documents in CRM Online, and what I did to fix it.

First I have to start with a blank Document. I choose my data fields and click ok. Here is the message I get.

"Opening the document will run the following SQK Command:
Data from your database will be placed in the document. Do you want to continue?"

I click Yes and then get this message:




From here, If I choose to "Find Data Source", I get stuck in an endless loop and can’t do anything. If I choose “Options”, then I can remove the data/header source.


Sorry for the small image, but the two buttons are "Remove Data/Header Source" or "Remove All Merge Info".

Then its regular mail merge. If I am using the web client, I have to go to Add-Ins, and click ‘CRM’. If I’m using the Outlook client, it opens the mail merge.

Once I create my xml template and upload it into CRM, I don’t have this problem with the data source anymore. I only have this problem when using a CRM Out of the Box template of doing a mail merge to a blank document.

Also, Outlook users don’t have to click Add-Ons> CRM one inside of word either, only web-users have to do that.

That should get you going and give your users some options if you ever run into this issue.

David Fronk and Team
Dynamic Methods Inc.

Friday, September 12, 2008

Managing Custom pages in IIS

I have recently been introduced to some new ways to manage custom webpages that I had no idea was readily available to me. I assume that everyone has seen those w3wp.exe processes in Task Manager, I knew that they were called Worker Processes but I didn’t realize that every Application Pool in IIS generates its own Worker Process (a w3wp.exe process in Task Manager). That being said simply by giving each page (CRM and custom pages) their own AppPool you can see any potential memory problem s, or where the largest load to IIS is among your pages. Secondly there are options on the AppPool that you can change to help as well. Here are some screenshots:




So, something like shutting down our Worker Processes on custom pages that are used as buttons after being idle for 5 minutes instead of 20 could make a big difference in a system that is already strapped for memory. Scheduling a recycle of a specific page (doing an IISRESET for just that one page) could also make a big difference. Some pretty cool features that make managing memory on our webpages that I had no idea were available to us. This may be something to put in your back pocket for a rainy day but hopefully this comes in handy for someone else later on.

David Fronk
Dynamic Methods Inc.

Friday, September 05, 2008

Methods for mass updating records in MSCRM

Working with MSCRM and from my background I have typically always been a web programmer as have my colleagues. This is essential in the MSCRM world if you want to be able to customize anything from form scripts to placing your own page that does crazy things right into the middle of the MSCRM GUI.

However, when presented with the task of needing to mass update data I have found that there are sometimes better ways than a web page. I have had minimal experience with application programming and programming an executable used to be a mystery to me.

A need presented itself for one of my clients where a procedure was needed to be rerun on a scheduled basis. Most of my previous procedures of this type were custom web pages with a "Go" button that ran all of my code. I quickly realized that I couldn't schedule a pressing of my "Go" button and I needed another solution. An executable was the solution.

I was scared that I was going to have to spend the better part of a week fighting and learning new calls and commands but amazingly enough, the majority of my code (the calls to the MSCRM API's) was all the same. For me, the learning curve into non-web programming came relatively quickly and there were a lot of benefits. There are benefits to both worlds so don't think that I've gone away from mass updating via web pages because that's not the case. Here are some pro's and con's that I have run into when developing a solution for a web based or console based solution.

Web Based Solution
Pro's: If you are already a web developer then you have all the skills required. Web pages can also be used externally very easily where console applications are a bit more difficult. One other advantage to web pages is that they are great to if you want your end users to access them and use them. Things like, update addresses for contacts related to a given account, or moving records from a sales rep's territory to a new territory owner are great for end user usage.
Con's: You have to set up the web page. If you don't build security around it everyone can see it and possibly use it. It cannot be scheduled, it must be run manually.

Console Based Solution
Pro's: Other than the coding, there is no additional set up, you just double click the executable or run it from a command prompt and away it goes. You can set up Scheduled Tasks that can run your code whenever you tell it to be run. Nightly, hourly, weekly, yearly, whatever. Also, if you build your code dynamically enough you can take your code from one installation to another and have it run just the same (authentication would have to be set up to be entered when run). Your code is compiled and no one can read your code unless you give it to them. Web pages have the ability to "View Source" and that might show off more than you want people to see.
Con's: Running externally requires that credentials be hard coded into your code. Most end users don't like running executables because they think it will install something on their machine and they don't understand what the code is doing. Black console screens (where you type in commands) scare end users. They have this mental block where if it's not in a GUI they don't understand it and would prefer not to have anything to do with it so that they don't break the system or their computer.

Well there you have it. Decide for yourself, each implementation is different so each usage can be very specific. I have a consultant's point of view where I have to be ready to do something for one client and then turn around and do something extremely similar but with minor differences for someone else and these differences between web based and console based applications can make all the difference.

Happy coding!

David Fronk
Dynamic Methods Inc.

Friday, August 29, 2008

Starter Execution Method

I have found that half of my trouble in writing a Plugin has been to figure out what message to use and how to pull the GUID from the record that the Plugin was triggered off of. Most of the messages are reasonably straight forward (Assign, Create, Update, or Delete) but finding what to use when an Opportunity closes took some digging. You'd think it was the SetState message but that's not right (nor is it the SetStateDynamicEntity).

In order to help out with this I have written myself a "Starter Execution Method" that has most of the common messages that I tend to use. I haven't coded against every message as there are now a ton of options but some of the new messages available to us are pretty cool.

Below the starter Execution Method I have also posted the possible MessageName's from the SDK. Hopefully this helps some people started.


Starter Execution Method:

public void Execute(IPluginExecutionContext context)
{
string opportunityid = "";

switch(context.MessageName)
{
case "Create":
if (context.OutputParameters.Properties.Contains("id"))
{
opportunityid = context.OutputParameters.Properties["id"].ToString();
}
break;
case "Update":
if (context.InputParameters.Properties.Contains(ParameterName.Target) && context.InputParameters.Properties[ParameterName.Target] is DynamicEntity)
{
DynamicEntity entity = (DynamicEntity)context.InputParameters.Properties[ParameterName.Target];
opportunityid = ((Key)entity.Properties["opportunityid"]).Value.ToString();
}
break;
case "SetState":
if (context.InputParameters.Properties.Contains("EntityMoniker"))
{
if (context.InputParameters.Properties.Contains("State"))
{
entity = (Moniker)context.InputParameters.Properties[ParameterName.EntityMoniker];
opportunityid = entity.Id.ToString();
}
}
break;
case "SetStateDynamicEntity":
if (context.InputParameters.Properties.Contains("EntityMoniker"))
{
if (context.InputParameters.Properties.Contains("State"))
{
entity = (Moniker)context.InputParameters.Properties[ParameterName.EntityMoniker];
opportunityid = entity.Id.ToString();
}
}
break;
case "Win":
opportunityClose = (DynamicEntity)context.InputParameters["OpportunityClose"];
Lookup WonLook = (Lookup)opportunityClose.Properties["opportunityid"];
opportunityid = WonLook.Value.ToString();
break;
case "Lose":
opportunityClose = (DynamicEntity)context.InputParameters["OpportunityClose"];
Lookup LostLook = (Lookup)opportunityClose.Properties["opportunityid"];
opportunityid = LostLook.Value.ToString();
break;
case "Assign":
if (context.InputParameters.Properties.Contains("Assignee") && context.InputParameters.Properties["Assignee"] is SecurityPrincipal)
{
Moniker assignEntity = (Moniker)context.InputParameters.Properties["Target"];
opportunityid = assignEntity.Id.ToString();
}
break;
case "Delete":
if (context.InputParameters.Properties.Contains("Target"))
{
Moniker monikerentity = null;
monikerentity = (Moniker)context.InputParameters.Properties[ParameterName.Target];
opportunityid = monikerentity.Id.ToString();
}
break;
}
}

MessageName Class (CrmHelpers)

AddItem
AddMember
AddMembers
AddMembersByFetchXml
Assign
Book
Clone
CompoundCreate
Create
Delete
DeliverIncoming
DeliverPromote
ExecuteWorkflow
ExecuteWorkflow
GrantAccess
Handle
Lose
Merge
ModifyAccess
RemoveItem
RemoveMember
RemoveMembers
RemoveMembersByFetchXml
Reschedule
Retrieve
RetrieveExchangeRate
RetrieveMultiple
RetrievePrincipalAccess
RetrieveSharedPrincipalsAndAccess
RevokeAccess
Route
Send
SetState
SetStateDynamicEntity
Update
Win

Happy Plug-in coding!

David Fronk
Dynamic Methods Inc.

Friday, August 22, 2008

MergeRequest/Response Limitations

This week one of my team members and I have been working through cleaning up duplicate data inside of CRM in such a way that we limit the amount of human interaction with the list of duplicates. When you have more than 150,000 records having someone manually merge even 10% of that is 15,000 records. Even if a list is provided of all of the duplicates that's a full time job for the better part of a year.

By coming up with acceptable matchcodes we figured out how to programmatically merge the records so that there doesn't have to be any human interaction. It works really well, except for one point. When you manually merge two records you get a little checkbox that selects any fields that the child record has data in but the parent record does not and then it populates the parent record with those values from the child record. That bit of code is only in the script on that form. It is NOT in the SDK. I'm working on the best way to go through and push all of the fields that the child has but the parent doesn't to make them populate the parent but unfortunately the project I'm on is a little time sensitive and I may just have to hack through it for an entity and go back later and come up with a reusable solution.

Anyway, just wanted to get that out there in case anyone else was wondering like I was until I saw my first record merge through the SDK.

David Fronk
Dynamic Methods Inc.

Friday, August 15, 2008

Integration with LaserApp

LaserApp is an application that assists in filling out forms. Typically these are forms that need information from a given person and he/she needs to sign the document. LaserApp helps save time by taking saved contact information and pushing it into their large repository of legal, financial, and other forms. Since LaserApp is keeping track of contacts and then pushing it's own contact data into the form wouldn't it be nice if you could use your CRM system to feed the forms provided by LaserApp.

We have bridged this gap at Dynamic Methods and will be participating in the LaserApp conference this upcoming week.


Basically from a high level standpoint, a button gets added to your contact form (or whatever form you would like) and when you press it, you are asked what form(s) you would like to push data to, click submit and you are then the system opens the new LaserApp file that gets created. Opening the file opens the LaserApp client which in turn loads the specified forms with the appropriate data.


Here are some screenshots:



David Fronk
Dynamic Methods Inc.

Friday, August 08, 2008

MSCRM Server Performance Counter Errors

In the last week or two I've gotten bombarded with Performance Counter information. Some was voluntary, some was forced due to errors on client's servers. I am by no means an expert but I do have to say that I have gleaned a fair amount of information that I bet the typical MSCRM admin or consultant doesn't know about. There just isn't much information out there specifically about Performance Counters within MSCRM.

My post last week talked about running the lodctr /R command. I found a post that stated that running just lodctr /R will rebuild all system Performance Counters and thinking this would clean things up I ran it on a server...not smart. At least not smart in the MSCRM world. Everything worked just fine, including CRM, until I ran an IISRESET later in the day and then CRM just died. I found articles on how to manually rebuild Performance Counters (http://support.microsoft.com/kb/300956) and that works just fine for Windows Server Performance Counters just fine. But not MSCRM. There is even a KB article in PartnerSource about Performance Counters but it says that running a repair would work just fine and resolve the problem. Well, I'd tried that before I'd even found the article and about 70% of the way through the repair it would error out with (the all too familiar error to me by now):

The requested Performance Counter is not a custom counter, it has to be initialized as ReadOnly.

Only this was on the server and what I did to fix the client was what caused the problem. So, running it again (which I tried) was zero help.

After many, many hours of deliberation I finally spoke with Adam in Australia from MS Support and he helped clear up everything and demistify Performance Counters for me. There are 4 important registry keys that need to be set up correctly in order for Performance Counters to work properly in MSCRM. Oh, and for whatever reason, if the Performance Counters fail then the whole application fails (as if I didn't realize that by now). But most other applications just allow them to fail and move on. They aren't system critical, they just track the performance of the application. Adam has submitted the request of Performance Counters not being a system requirement in future versions, hopefully they listen to his request and/or read this post.

Anyway, back to the fix. In the registry there are 3 keys that need to exist, all are under the following paths:

My Computer\HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Services (add the last two hives of each hive listed out below to get to the actual keys)

1. CRM Async Service
2. CRM Authentication\Performance
3. CRM Discovery\Performance
4. CRM LocatorService\Performance
5. CRM OutlookSync\Performance
6. CRM Platform\Performance
7. CRM Server\Performance
8. CRM Sql Governor\Performance
9. CRM Sql Governor Multi Instance

(Basically and hive under the Services hive that has CRM in it is what you need to check.)
Oh and one more for workflow performance

10. Windows Workflow Foundation 3.0.0.0

The keys that must be there and their values are:

Key--------------------------Value
Library----------------------netfxperf.dll
First Counter----------------(any value is fine, it just needs to exist)
Last Coutner----------------(any value is fine, it just needs to exist)

Running a repair on CRM will fix all of the Performance Counters for the CRM hives but it won't fix the Workflow hive. So, if you get the error regarding Performance Counters in the middle of your repair I can almost guarantee that your problem is that you are missing keys in your Workflow Performance hive. That's what I had to do and according to Adam (who has written the majority of the Performance Counter KB articles for the MSCRM Support team) only the Workflow Performance Counters would cause the repair to fail since the repair rebuilds them.

Now that we know what needs fixed, how do we fix it? If its CRM Performance Counters, just run a repair on the server. If you error during the repair with a Performance Counter error then you will need to reload the Library, First and Last Counter keys for Workflow Foundation. In order to do this you must use the lodctr command. DO NOT recreate these manually. I haven't tried it so I can't speak to what bad things could occur if you did I just know that you should rebuild them using the lodctr command.

You need to open a command prompt and go to the following directory:

%SystemRoot%:\WINDOWS\Microsoft.NET\Framework\v3.0\Windows Workflow Foundation

Then run the following command:

lodctr perfcounter.ini

That will rebuild the Workflow Foundation Performance Counters (which MSCRM is dependant on). If you look at the registry you should now see the keys there with correct values. Continue your repair, or try it again and you should be all set. I would recommend a reboot after the repair in this case to get everything reset and you should be back up and running.

For those of you who don't know what Performance Counters are used for, they can be very useful in showing the performance of the server and where the majority of the load is so that you can appropriately manage the server/network and correct the bottleneck of CRM. To view them open a run prompt and type "perfmon". This will open the Performance Monitor. By default it shows Pages/sec (if IIS is installed), Avg. Disk Queue Length, and % Processor Time. You can add other Counters to this list by right clicking in the list of counters at the bottom of the main section of Performance Monitor. Choose "Add Counters..." In the new window that comes up expand the "Performance object" dropdown and pick the application/object you want to monitor. Below that will be all of the counters you can monitor. Take a look at those and you'd be amazed at what you can track for CRM. There are also a lot of really good SQL ones for your SQL server. If you are looking for metrics to show companies the performance increase by going to MSCRM 4.0, or moving to a 64 bit SQL box, this will give you a great comparison and actually show the big wigs that their decision made a big difference.

I have learned a lot about Performance Counters and hopefully my lengthy post has helped someone else glean a little more information as well.

David Fronk
Dynamic Methods Inc.

Sunday, August 03, 2008

Outlook client Offline Performance Counter error when attempting to go Offline

When going offline users see the following message:

The requested Performance Counter is not a custom counter, it has to be initialized as ReadOnly.

Event Log Errors:

Event Type: Error
Event Source: LoadPerf
Event Category: None
Event ID: 3013
Date: 7/29/2008
Time: 11:38:09 AM
User: N/A
Computer: LFISKNBXP
Description:
Unable to update the performance counter strings of the 009 language ID. The Win32 status returned by the call is the first DWORD in Data section.

For more information, see Help and Support Center at http://go.microsoft.com/fwlink/events.asp.
Data:
0000: 43 02 00 c0 17 0d 00 00 C..À....

Event Type: Error
Event Source: LoadPerf
Event Category: None
Event ID: 3009
Date: 7/29/2008
Time: 11:38:09 AM
User: N/A
Computer: LFISKNBXP
Description:
Installing the performance counter strings for service CRM Client (%2) failed. The Error code is the first DWORD in Data section.

For more information, see Help and Support Center at http://go.microsoft.com/fwlink/events.asp.
Data:
0000: 43 02 00 c0 f6 13 00 00 C..Àö...

Event Type: Error
Event Source: MSCRMPerfCounters
Event Category: None
Event ID: 17188
Date: 7/29/2008
Time: 11:38:09 AM
User: N/A
Computer: LFISKNBXP
Description:
The description for Event ID ( 17188 ) in Source ( MSCRMPerfCounters ) cannot be found. The local computer may not have the necessary registry information or message DLL files to display messages from a remote computer. You may be able to use the /AUXSOURCE= flag to retrieve this description; see Help and Support for details. The following information is part of the event: Client.

Event Type: Error
Event Source: MSCRMOfflineSync
Event Category: None
Event ID: 6000
Date: 7/30/2008
Time: 10:30:28 AM
User: N/A
Computer: LFISKNBXP
Description:
An error occurred during Offline Synchronization. Try going offline again, or restart Microsoft Outlook. Exception happened The requested Performance Counter is not a custom counter, it has to be initialized as ReadOnly..
Stack Trace Info:
at System.Diagnostics.PerformanceCounter.Initialize()
at System.Diagnostics.PerformanceCounter..ctor(String categoryName, String counterName, String instanceName, Boolean readOnly)
at System.Diagnostics.PerformanceCounter..ctor(String categoryName, String counterName, Boolean readOnly)
at Microsoft.Crm.CrmPerformanceCounterFactory.LoadCounters(CounterContainer counterContainer, PerformanceCounterLoadSetting settings, String component)
at Microsoft.Crm.CrmPerformanceCounterFactory.LoadCounters(PerformanceCounterLoadSetting settings, String component)
at Microsoft.Crm.Performance.OutlookPerformanceCounterTracker.Initialize()
at Microsoft.Crm.Performance.OutlookPerformanceCounterTracker.Increment(OutlookPerformanceCounterType type)
at Microsoft.Crm.Application.Outlook.OfflineSync.SyncData.SyncInfoArray(String syncInfo)
at Microsoft.Crm.Application.Outlook.OfflineSync.SyncData.MoveData(String syncInfo, ITransferDataProvider transferDataProvider, Int32 progressSteps)
at Microsoft.Crm.Application.Outlook.OfflineSync.SyncData.Sync(ITransferDataProvider transferDataProvider, Int32 callPriority)
at Microsoft.Crm.Application.SMWrappers.OfflineSync.SyncThreadMethod() .

For more information, see Help and Support Center at http://go.microsoft.com/fwlink/events.asp.



Fix:

Uninstalled CRM client and then ran “lodctr /R:loadperf” on client machine from a command prompt. Reinstalled CRM client and went offline successfully.


Hope this helps someone else out as well.

David Fronk
Dynamic Methods Inc.

Friday, July 25, 2008

Hiding Fields and Labels on the fly via JScript

This is actually in reponse to a comment/question that was posted by Schnugie but I figured that this would benefit everyone so it became a post instead of a comment response.

So, how do you hide fields and then redisplay them based on the input of another field? Here's a code sample of how to do it:


var oField = crmForm.all.field;
var oLabel1 = crmForm.all.field_c;

switch(oField.SelectedText) {
case "0":
crmForm.all.field.style.visibility = 'hidden';
oLabel1.style.visibility = 'hidden';
break;
case "1":
crmForm.all.field.style.visibility = 'visible';
oLabel1.style.visibility = 'visible';
break;
default:
crmForm.all.field.style.visibility = 'hidden';
oLabel1.style.visibility = 'hidden';
break;
}

If crmForm.all.field is a picklist then the .SelectedText will work. But basically, this code looks at a picklist field, evaluates the value and depending on what the value is determines whether or not a field is displayed or hidden. You will also notice that I have some _c after my field name as a second variable, that is for the label. If you just hide the field it will not hide the label with it. So you will need to show/hide both.

Use this script on the onLoad, onChange, or where ever you see fit.

Happy scripting!

David Fronk
Dynamic Methods Inc.

Friday, July 11, 2008

Context.CallerOrigin

I have spent countless hours fighting infinite loops for numerous projects. Each loop has it's own logic and checks to avoid looping forever. I was writing some code that was updating another object which in turn would update the originating object and I really only needed either code to run once and only once. So, I set up all kinds of logic and was still getting loops. I then came across the CallerOrigin within the Context of the Plugin. The CallerOrigin tells you where the call came from:

1. Application (someone took action on a form)
2. AsyncService (workflow or an asynchronous plugin)
3. WebServiceApi (webpage or synchronous plugin or callout)

I could then check my code and say that unless the call came from the application to not perform any update. That killed my infinite loop real fast.

This also can be very useful for code that you want to fire when someone is taking an action or the system is taking action on something. I can't say that I've come across this scenario all that often but it's nice flexibility.

I will note that my check looked like this:


if (context.CallerOrigin.ToString() == "Microsoft.Crm.Sdk.ApplicationOrigin")

Maybe not as clean as some of us might like but it works. As I just found this I'm looking for more strongly typed means to run my checks but for this one issue this works just fine for me.

Happy coding!

David Fronk
Dynamic Methods Inc.

Tuesday, July 01, 2008

Email Router Hotfix

I received word from Microsoft that they have an update available to fix an issue that occurs with the email router. For whatever reason the email router will poll for an hour and then lock for an hour. If it unlocks itself after that second hour it will work for another hour and then lock itself again. The hour comes from the default polling time that is set up in the email router config file. So, if you were to modify that polling time then you would extend the life of your email router from locking up but also extend the amount of time to get the email router back up once it is locked.

I used a work around to get by until this hotfix became available by restarting the email router service each hour via a bat script.

However the hotfix you want to check out is KB article 952019. You will need to contact Microsoft via PartnerSource or CustomerSource in order to obtain the hotfix, but you will not be charged for the ticket if you are requesting the hotfix.

Hope this comes in handy for someone else as well.

David Fronk
Dynamic Methods Inc.

Updating Records in Mass via the SDK

For some time I've been updating (or importing) records in mass via the SDK (when I say mass I mean some where in the hundred's of thousands). However, whenever I have tried to do this I have run into an issue with my processes over taking all of the socket connections. Whether via webpage or windows app, either way the SDK would overrun the connections that IIS would allow. So, I would have to plan out my imports or updates through the SDK accordingly with the most records I could run before the connections get all used. Then once I had run that maximum number I would stop, run an IISRESET and then start again. Needless to say it made these kinds of jobs even longer and more tedious.

So, after quite a bit of searching and testing I have found what I believe to be the best way to mass update records in CRM via the SDK without locking up sockets or connections. I have seen people who like to update the registry by changing the following values:

HKLM\System\CurrentControlSet\Services\Tcpip\Parameters\MaxUserPort to be 65534
And
HKLM\System\CurrentControlSet\Services\Tcpip\Parameters\TCPTimedWaitDelay to be 30

And that works most of the time but I personally don't think that it's 100% reliable. Even after making these changes I have run into the same problem of locking up the sockets and connections. Here's the reference I found on this:

http://blogs.msdn.com/dgorti/archive/2005/09/18/470766.aspx

The best solution I found however is something that is to be implemented in your code. I have to give credit to AndrewN23 who posted his code in the groups. But the code is as follows:


int RETRY_ITERATIONS = 50;
int p = 0;
do
{
try
{
crmService.Update(entity);
p = RETRY_ITERATIONS;
}
catch (Exception e)
{
p++;
if (p >= RETRY_ITERATIONS)
{
throw (e);
//WriteToFile("updateContact error: " + e.Message + " " + e.InnerException);
}
System.Threading.Thread.Sleep(500);
}
} while (p < RETRY_ITERATIONS);

Basically the code goes and catches the connection error and waits for a connection to be freed up. Once a connection is freed up it continues on. I ran this against a group of more than 4,000 records as my first test and then ran it against more than 50,000 records without any issue.

One comment I will make on this however, is that if your update code triggers any other callout or plug-in code that will affect your update code and by using up connections that are already limited. I had to go through and add this block of code to ALL methods of my custom code that was triggered by my update code. When I only applied this code to my mass update code I would get the socket connection error showing up in the event log from my other custom code (callout or plug-in). Once I updated the rest of my custom code everything worked like a dream.

Hope this helps someone else out.

David Fronk
Dynamic Methods Inc.

Friday, June 13, 2008

Dynamically changing the name of a tab

This comes from one of my coworkers, great hack. This works not only in the onLoad but also on the onChange of any field on the form. This is a great, simple script that might help users out a bit more.

Code:
var title = crmForm.all.primarycontactid.DataValue;

if(title != null)
{
document.all.tab4Tab.innerText = title[0].name;
}


You will need to change your tab4Tab to whatever tab you have on the form (remember, tabs start at 0 for the first position so make sure you get your numbering correct).

Simple as that. Now your tab will show the text of the name of the Primary Contact. Oh, one stipulation, the size of the tab will not regrow using this code, only the text. So, if your tab is named "Test" and I were to replace it with "David Fronk" then my name would get "wordwrapped" and it could look pretty funny. So, make your initial name something longer. If I come across how to dynamically grow the tab so as to fit the name being placed in it I'll definitely post that up here as well.

Enjoy!

David Fronk
Dynamic Methods Inc.

Friday, June 06, 2008

Unable to send email template to all contacts

We recently found that attempts to email a list of users or contacts (pretty much any list) using an email template did not work. When attempting to send an email to a list we would get the following error:

"The requested record was not found or you do not have sufficient permissions to view it."

We brought this up with Microsoft and it ended up in being a bug and Microsoft has just released a bug fix for this issue. You must submit a ticket with Microsoft for the hotfix but there will be no charge for the ticket. The KB article is 951477.

The list of bug fixes is growing and I think that's a big help to CRM 4.0.

Hopefully this helps someone else out there.

David Fronk
Dynamic Methods Inc.

Friday, May 30, 2008

Private Views no longer exist in CRM 4.0/Hiding System Views in CRM 4.0

A simple customization that I would do for clients was remove some of the system views that come out of the box but aren't used. You used to be able to accomplish this by creating a team and then sharing a Public View with that team. Sharing of System Views is no longer available. You can have this functionality with views created in Advanced Find, just share the view with a team or individual users. But not the System Views.

The only ways that I've seen to get around this are to either modify the EntityXML or update SQL. Either way you update the IsPrivate attribute from 0 to 1. If you do this in the EntityXML you will make the change and then upload the XML. If you do it through the database then the change will occur as soon as you update the database...or so I'm told. Please remember that UPDATES to the CRM databases are NOT SUPPORTED. If you go this route you are on your own and Microsoft will wipe their hands clean of you and your system. So, please, do yourself a favor and backup your databases before you attempt anything like this, and do this in a development environment first, not on a live server!

Here's the SQL script that I've used:

update SavedQuery
set IsPrivate = 1
where SavedQueryId = '00000000-0000-0000-00AA-000010001002'
--replace the SavedQueryId with the ID of the SavedQuery to be hidden

Once you make this change the views will drop from site completely. Meaning you won't even see them in the Customizations of the Entity area. That's because they've been marked as being private but no rights were given to anyone to be able to see that private view so it completely "disappears."

If anyone else has any other solution for this issue, I'd love to hear it. Typically I have clients who don't want to see the "Accounts with no Orders in the Last 6 months" and creating new views is not a problem.

Good luck out there!

David Fronk
Dynamic Methods Inc.

Plugins triggered off the SetState Message

I was writing a plugin that needed to be triggered off of the SetState event, or message and I was having issues getting it to actually fire. I wrote out the plugin, registered it and set it all up but when I would change the state of the record I registered the plugin against nothing would happen. Nothing in the logs, nothing in the system logs, nothing anywhere.

After some hunting I found out that in order to get plugins to work off of the SetState message you must also register the plugin against the SetStateDynamicEntity message as well. I had to completely unregister my plugin and then register it. That piece may have been because I forgot to make my class public in my assembly but that was an unfortunate oversight on my part.

Any way, I hunted and fought this for a fair number of hours before I found my problem. Hopefully this will help someone else avoid the spending the same amount of time I spent looking for a solution to their problem.

David Fronk
Dynamic Methods Inc.

Friday, May 23, 2008

Virtualization supported in production environments for CRM 4.0

MSCRM 4.0 has joined the ranks of Microsoft supported software to be run in a virtual environment. MSCRM 4.0 is now supported to be run on Virtual Server 2005 in a production environment. Here's Microsoft's official statement on it:

Support policy for Microsoft Dynamics CRM 4.0 on a computer that is running Virtual Server 2005
loadTOCNode(2, 'summary');
Microsoft Dynamics CRM 4.0 is officially supported to run on a computer that is running Microsoft Virtual Server 2005 in production systems. In addition, the Microsoft Dynamics CRM team is committed to the following:

Continuing support for virtualized environments in future releases of Microsoft Dynamics CRM.

Testing Microsoft Dynamics CRM running on upcoming Microsoft virtualization technologies and publishing updated support policies as these technologies become available.

Reference: http://support.microsoft.com/kb/946600

I fully expect to be hearing about support being available for virtualization on Windows Server 2008 soon, I'm sure they're just finishing their testing. So, keep your eyes open for that.

David Fronk
Dynamic Methods Inc.

Sunday, May 18, 2008

Generating the CrmService over an IFD Connection

I've been working on an application that needs to connect using the Internet Connector license over an IFD connection. I have users who need to submit data into CRM that are not CRM users and thus have no login credentials. So I started researching using the GUID of a CRM user to authenticate. This is possible with plgins and is utilized for impersonation. However, after a few days of fighting code, authentication errors and discussing options with the MS Support SDK team, we found that authentication tghrough the IFD is not possible by using just a users GUID. There still has to be some level of authentication with Active Directory that must occur and a CRM user's GUID does not contain sufficient information to pass the credential challenge AD requires. IFD requires a username and password in order to instantiate the CRM service.

From what MS Support said, either not many are doing this yet, or I'm one of the few who hadn't figured this out yet.

Either way, I thought I'd share my CRM Service generation code that is used for connecting over an IFD connection Hopefully this helps someone else out, enjoy.


public CrmService IFDConnection(string organization, string server, string domain, string username, string password)
{
// A CrmService reference.
CrmService CrmService = null;
// URL of the Web application.
string WebApplicationUrl = String.Empty;
// GUID of the user's organization.
Guid OrganizationId = Guid.Empty;
//Remove any trailing forward slash from the end of the server URL.
server = server.TrimEnd(new char[] { '/' });
// Initialize an instance of the CrmDiscoveryService Web service proxy.
CrmDiscoveryService disco = new CrmDiscoveryService();
disco.Url = "http://" + server + "/MSCRMServices/2007/SPLA/CrmDiscoveryService.asmx";
//Retrieve a list of available organizations.
RetrieveOrganizationsRequest orgRequest = new RetrieveOrganizationsRequest();
orgRequest.UserId = domain + "\\" + username;
orgRequest.Password = password;
RetrieveOrganizationsResponse orgResponse = (RetrieveOrganizationsResponse)disco.Execute(orgRequest);
//Find the desired organization.
foreach (OrganizationDetail orgdetail in orgResponse.OrganizationDetails)
{
if (orgdetail.OrganizationName.ToLower() == organization.ToLower())
{
//Retrieve the ticket.
RetrieveCrmTicketRequest ticketRequest = new RetrieveCrmTicketRequest();
ticketRequest.OrganizationName = organization;
ticketRequest.UserId = domain + "\\" + username;
ticketRequest.Password = password;
RetrieveCrmTicketResponse ticketResponse = (RetrieveCrmTicketResponse)disco.Execute(ticketRequest);
//Create the CrmService Web service proxy.
CrmAuthenticationToken sdktoken = new CrmAuthenticationToken();
sdktoken.AuthenticationType = 2;
sdktoken.OrganizationName = organization;
sdktoken.CrmTicket = ticketResponse.CrmTicket;
CrmService = new CrmService();
CrmService.CrmAuthenticationTokenValue = sdktoken;
CrmService.Url = orgdetail.CrmServiceUrl;
WebApplicationUrl = orgdetail.WebApplicationUrl;
OrganizationId = orgdetail.OrganizationId;
break;
}
}
return CrmService;
}

David Fronk
Dynamic Methods Inc.

Friday, May 09, 2008

Plugins, Cached Memory and Global Variables

In the recent past I came across an issue where callouts that had been written for MSCRM 3.0 were behaving strangely in MSCRM 4.0. Whenever I would test the code it would work just as I expected it to. However, when users would test it values were not coming out as expected. Among different callouts I saw a number of different issues. Some being, the doubling of calculated fields, doubling of record creation (though one would get the data passed to it and the other wouldn't), among others. The trend that I noticed however was that things were doubling. I thought this was strange as other than the system being upgraded, nothing had changed.

After some testing I came to the conclusion that the new architecture was caching data. In a number of callouts I had used global (or class) variables, whether it was due to necessity or lack of time and a need to just get the piece done, and in every callout that I had written where I did not manage my global variables correctly I was getting strange results.

With that in mind I started changing how I coded and modified all code that was upgraded and used global variables. After discovering this I ran into a completely separate issue where the w3wp.exe process was running extremely high. It got past 1.5GB and was causing users to see an error stating "Out of memory exception." Only an IISRESET, or a reboot would remedy the problem, and that would only last a certain amount of time. I had not yet modified all of my code to not use global variables, I was under the assumption that if it wasn't broken, don't fix it. Well, it was broken users just weren't able to adequately inform me of the issues they were having because the errors were so sporatic. Needless to say the problem ended up in being the global variables. Once I removed them and/or managed them in my code the sporadic errors went away and the w3wp.exe process went down to about 400MB. That's a substantial change. Now, I will say that the client I was working on had about 35+ callouts running so they all helped to add to the problem.

So, all that being said, what point am I trying to make? The new plugin architecture that is used in MSCRM 4.0 utilizes caching to try to make the use of custom code more efficient by having it stored and more readily accessible to the application for when it is needed. What this caching means to those of us who use global variables is that global variables also get cached. So, if two instances of the same callout are running at the same time the values of the global variable are shared between the two instances. Let's assume we have a calculation running in a callout that is stored in a global variable. If two people were to trigger the callout at about the same time (within a few seconds of each other) the first callout would finish, cache the calculated value and pass that value into the next callout, starting it not at 0, or where one might expect it to be, but with the final result of the first callout. Get enough users clicking triggering the callout at the same time and you can imagine how quickly this issue will escalate.

I asked MS Support about this and here is what they said:

"Note For improved performance, Microsoft Dynamics CRM caches plug-in instances. The plug-in's Execute method should be written to be stateless as the constructor is not called for every invocation of the plug-in. All per invocation state information is stored in the context.

They will be adding a note that states we cannot use global variables with plug-ins for CRM 4.0. At this point, the code would need to be modified in either CRM 3.0 prior to the upgrade or the callout would need to be rewritten as a plug-in."

My suspicions now confirmed I made a stronger resolve to avoid using global variables. I thought I was the only one using global variables since I was the first one to bring this up (to my knowledge), either that or I was slow on the uptake and everyone else already knew about it. But MS Support also mentioned that they see code come in all the time with global variables and that this could be an issue that a lot of people bring to them in the near future. So, I know there are others like me out there, my hope is that I save you some of the time that I spent beating my head into the wall trying to figure this all out.

So, the moral of this story is, try to avoid global variables because they get cached. Use them is necessary but when you do be sure to manage them appropriately. And you might want to consider having two people trigger your custom code at the same time while you are still developing the solution that way you can make sure no reuse of values occurs where you don't want it to.

Hope this helps someone else out there.

David Fronk
Dynamic Methods Inc.

Sunday, May 04, 2008

MSCRM 4.0 Current Hotifx List

Here is a list of current hotfixes that are out and available for MSCRM 4.0:


Updates for General Distribution
948041
An update to the Help files for Microsoft Dynamics CRM 4.0 was released March 7, 2008
March 7, 2008
948917
How to obtain the setup updates for Microsoft Dynamics CRM 4.0
February 28, 2008
948593
Error message when you install the Microsoft Dynamics CRM 4.0 server: "Microsoft.Crm.CrmArgumentException: Invalid domain name. Domain name is either invalid or unreachable"
February 28, 2008

Hotfixes that have Limited Distribution

946649
Error message when you retrieve CRM schemas from a CRM 4.0 Web Service: "401 Unauthorized"
February 14, 2008
948045
Outlook stops responding when you track an Outlook contact in the Microsoft Dynamics CRM 4.0 client for Outlook
March 5, 2008
948035
FIX: The "New Record" button and the "Add Existing Record" button are missing in Microsoft Dynamics CRM 4.0
March 12, 2008
948876
Internet Explorer stops responding when you use the Microsoft Dynamics CRM 4.0 Web client to save or to send an e-mail message that has a large body
March 12, 2008
948002
The started time and the completed time are incorrect in workflows on an entity record in Microsoft Dynamics CRM 4.0
March 17, 2008
948155
A date or a time may not be converted to UTC time in the database for some time zones in Microsoft Dynamics CRM 4.0
March 13, 2008
947860
FIX: Error message when you use the Response messages of the SetStateEmailRequest object to set e-mail messages to Completed in Microsoft Dynamics CRM 4.0: "Crm Exception: Message: The specified sender type is not supported"
March 13, 2008
948157
Error message when you create a new record or open an existing record in Microsoft Dynamics CRM 4.0: "Invalid Argument"
March 16, 2008
948008
A new follow-up activity is still owned by the original user after you change the user in Microsoft Dynamics CRM 4.0
March 13, 2008
949141
Error message when you click "View in CRM" after you create an appointment in the Microsoft Dynamics CRM 4.0 client for Outlook: "At least one recipient could not be resolved to a record in the system"
March 12, 2008
948122
The collection of installed localized labels is incomplete when you use the Microsoft Dynamics CRM 4.0 metadata Web service to retrieve the collection
March 19, 2008
947401
Error message when you import customizations to another Microsoft Dynamics CRM 4.0 organization: "Identifiers cannot be more than 50 characters long"
March 19, 2008
948005
The OnSave event code or the OnLoad event code is not triggered after you modify a step in a workflow rule in Microsoft Dynamics CRM 4.0
March 12, 2008
949086
You receive Outlook sync messages when you view a shared calendar or a shared contacts folder in Microsoft Dynamics CRM 4.0 client for Outlook
April 1, 2008
949569
The Duplicate Detection function cannot detect duplicate records when you use a pre-update plug-in assembly in the update process in Microsoft Dynamics CRM 4.0
April 17, 2008
948121
Outlook may stop responding when you exit Outlook, go offline in the Microsoft Dynamics CRM 4.0 client for Outlook, or go online in the Microsoft Dynamics CRM 4.0 client for Outlook
April 17, 2008

To see this entire list from Microsoft's homepage follow the following link:

Click Here

David Fronk
Dynamic Methods Inc.

Friday, April 25, 2008

Dynamic Methods Convergence 2008

Wednesday we had a great event in the Irvine Microsoft office, Dynamic Methods Convergence 2008. We found that a fair number of our clients were interested in going to Convergence but were unable to take a full week off to attend or couldn't justify the trip for any period of time, but all were very interested in seeing what Microsoft had to present and see the new features and road maps for the products that they owned and worked with everyday. So, this year we decided to try something new and see what our clients thought.

Dynamic Methods Convergence 2008 was our solution to that problem. We had a day where we presented to our clients and potential customers what Microsoft had to say about Microsoft Dynamics CRM and Microsoft Dynamics GP as well as some break out sessions where we could show/train on some of the new features of the latest software and answer any questions people had about, well, anything.

Our thanks goes out to all who attended. In total we had 36 attendees (not bad for our first event like this) that were either existsing clients or potential customers, so a special thanks goes to each of them for taking a day out of their work week to join us at this event. A special thanks goes to all of our presenters/speakers from Microsoft; Lisa Hopkins, Randy Pack and Claire Saddington. We also had Gene Kaplan from Performance Operations (another Microsoft Partner) do one of our break out sessions for us on Warehouse management, so our thanks to Gene as well.

We also had a fantastic guest speaker, Peter Vidmar, the 1984 US Men's Gymnastics Team Captain and Olympic Gold Medalist start us off with "Risk, Originality & Virtuosity". Here is a picture of one of our CRM consultants (Nate Goodrich with Peter at the event):




In the afternoon we had break out sessions covering:

Microsoft Dynamics GP
GP 10.0 Overview and Enhancements
Microsoft Office SharePoint Server (MOSS) and Dynamics GP
Warehouse Management System (WMS)
FRx Tips and Tricks

Microsoft Dynamics CRM
Working with Microsoft Outlook and Word
Working with Microsoft Excel and Report Wizard
Workflow
Data Management with Duplicates and Import Tools

We got some great feedback from all of our attendees and we will do our best to improve where fell short next time around. The suggestion I think we received the most was to have more and longer break out sessions. We thought an hour would be just enough to not lose people's attention but apparently it was only just enough to wet their appetites. So, for next Dynamic Methods Convergence we expect to make changes to meet those requests from our attendees.

All in all, especially as it was the first year we've put this on, we felt it was a huge success. Jeff Arbuckle, though not a presenter, was in attendance and commented on how impressed he was to see the high percentage turn out of all who registered for the event. As most events go, you get people who register but don't show up. We had a very high percentage of registrants show up which from our point of view shows the loyalty of our customers as well as the great relationships that have been built between our consultants and our clients. And really at the end of the day, that's what my job is all about, making sure my customers are successful and happy.

So, once again, thanks to all who presented, prepared, or even just showed up for making Dynamic Methods Convergence 2008 a huge success.

David Fronk
Dynamic Methods Inc.

Friday, April 18, 2008

Many to Many Relationships

With the ability to create Many to Many (MtoM as I will reference them in this post) in CRM 4.0 people are so excited to use it they sometimes use it just to use it, even when it's not necessary or it's the wrong type of MtoM. Let me clarify.

Out of the box MtoM relationship just link one record to another. Nothing more. There is no additional data that gets tracked, only a link. This type of relationship is fantastic for things like seeing Associations that a Contact is affiliated with. You don't need to know when the affiliation started or anything else, just that the Contact is affiliated with that Association. NOTE: Association would be a custom object in a given CRM system.

However, the moment someone says that data needs to be tracked in that relationship you should NOT use the out of the box MtoM relationship. For example, Seminars, Events or Tradeshows are a great example of this. A Seminar (custom object) would contain data about the date and location of the event. However, the most important thing to track from a Seminar is who attended. This typically links to the Contact object. With the out of the box relationship you won't know if the person actually attended or not. If you enter the attendees after the fact, then sure that would work. But most of the implementations that I've done want to track who has registered and who actually attended. This way they can see how effective their registration process is and how effective they are at winning a deal when someone actually attends. This scenario requires what is typically referred to as a "linker" table. Seminar links to Seminar Attendee, which links to Contact. The Seminar Attendee is the link to both and it has a look up to both Seminar and Contact. It's actually a Mto1 relationship with a 1toM...if that makes any sense to anyone else. A Seminar will have many attendees, but a given attendee can only attend one seminar. An attendee can only be one person (Contact) but a Contact can attend multiple events.

Both options are great solutions to any given situation just be wary to use something new just because it's there. Just because the other method is older doesn't mean it's not as functional. The capabilities are there, let's just make sure our users get the systems setup correctly.

Good luck out there,

David Fronk
Dynamic Methods Inc.

Friday, April 11, 2008

Cannot "Track in CRM" Insufficient Privileges

I have been a part of over 10 upgrade or fresh installs of MSCRM 4.0 and every so often I get a complaint from the client that they cannot promote items from Outlook to CRM because they are told they do not have sufficient privileges to do so. After checking the security role everything looks good but still they cannot promote. I have even modified the role such that it has full access to EVERYTHING and still users with that role cannot promote. However, the system administrator can promote. So, the next step I tried was to create a copy of the system administrator role and have it replace the non-working role. The users who have the copy of the role as thier role, with no privileges modified, can now promote items from Outlook to CRM. I then tried removing the privileges such that they macthed the original role. Now the users could promote with not problem. All privileges were the same the last time through, so what was the difference? The only difference was that the second role was a copy of the System Administrator role.

I guess this means that there is some hidden attribute or something that CRM checks for that none of the other roles have (maybe the system customizer role).

The good news is that I haven't seen this issue with new installs of CRM 4.0, only in upgrades from 3.0 to 4.0. And in all honesty I've seen this issue in probably 20-30% of the upgrades I've been a part of. Not a ton but enough to cause a headache if you don't know the answer.

Good luck out there!

David Fronk
Dynamic Methods Inc.

Saturday, April 05, 2008

Word Mail Merge - Part 2: Getting Line items to work the way you want them to

I have been getting a lot of comments/question on how to set up a custom Word Mail Merge Quote so that the line items appear on one page and look nice and professional so that clients (or your own organization) can send out respectable Quotes (or whatever entity you may be running the merge from).

I have tried to explain it but unless you see the code and know how crazy coding in Word can be (at least it seems kind of crazy to me), explaining it in words doesn't do it justice.



So I have tried to do the next best thing and post a screenshot of the code I wrote for the Word Mail Merge Quote that I posted about previously. Please note that I have moved some of the fields around but that was only to help keep everything on one page so that it was easier to see in this screenshot. Also, I made the top table visible instead of hiding all of the table lines so that you can see how the nice straight formatting was accomplished.

I realize that you cannot read anything from the screenshot on the webpage. Please be sure to right click the image and do a Save As onto you desktop. It will look much better.

I hope this helps answer some of the questions I have not been able to fully answer.





Take note that the table with the fields from the quote line items is inside an IF statement. That IF statement is the key to keeping your line items together.
The last bit of advice I can give is to download the out of the box Mail Merge Quote template and reverse engineer it yourself. Microsoft puts those templates up there not just to show the capabilities or give you a quote that you'll never use, but to see how they did it so you can reproduce it. It doesn't help Microsoft in the least to hold onto that code and not let people figure out how to do what they did. So, check it out and learn all you can from it.

Happy Merging!


David Fronk
Dynamic Methods Inc.

Friday, March 28, 2008

Removing the Price List field from an Opportunity

The Price List field is an interesting field in that it is a field has script that fires from it but you cannot see it from the form editor where you place your own scripts. I recently tried removing this field from an Opportunity and the Account form. The Account didn't show any repercussions but the Opportunity wouldn't allow me to add an Opportunity Product to the Opportunity.

With the Price List field missing I just got this random non-descript scripting error. When I added the field back and tried to add an Opportunity Product I received the error I expected of having no Price List set. The problem now became that when I tried to select a Price List for the Opportunity I couldn't see any Price Lists to choose from. Basically the script that was running and populating the filtered list of Price Lists had been removed when I removed the field from the form and it doesn't come back when I put it back onto the form.

The question now became how do I fix it? How do I get that script back. I have to give credit to Nahi for his post in the Microsoft.Crm.Public group who ran into this issue and posted the solution he found. He didn't go into the details, he just went over the process. I'm going to try and give you a little bit more.

Basically the idea was, grab the script from another entity or another system where the Price List had not been removed. The way to do that is to export the Opportunity and look through the entity XML for the missing script. Then copy and paste the script XML into the entity XML of the entity that had the Price List field removed from it. Save changes and reimport it back into CRM, publish and you're set. It worked great for me and I now no longer have any issues with the Opportunity, Price List or adding Opportunity Products.

The best way to find the script from the clean entity XML is to search for "Price List" and then look through to where you see the script next to one of your finds for "Price List". Here's the XML block that I found and added (it should go between the LABEL and CONTROL tags):

<events>
<event name="setadditionalparams" application="true" active="true">
<script>
<![CDATA[
var oLookup = event.srcElement;
AddTransactionCurrencyParam(oLookup);]]>
</script>
<dependencies>
<dependency id="transactioncurrencyid" />
</dependencies>
</event>
</events>

Hope this helps someone else out.

David Fronk
Dynamic Methods Inc.

Friday, March 21, 2008

CRM Document Management...the low budget way

For those of you who work in the small to medium business industry, keeping tabs on budget is key, and typically (though not always) you are asked to do deliver a hot rod on a moped budget, and/or you have to deliver in half the time you would like to spend to make the solution really solid.

When this is the case for my clients I do my best to give them something usable that may or may not do 100% of everything they requested but will get them by until they are ready to spend the time and money on the complete solution.

When implementing MSCRM, document management is one of the topics where "baby steps" are necessary. I am a fan of SharePoint for document management, most of my clients are as well. However, as soon as they see that rolling out SharePoint is a whole other implementation, with software, licenses, server, installation, design, training, etc, I find out that they aren't as big of fans as was originally thought. From a solution implementators' perspective, that's totally fine. The goal that I then have is to help get them ready for the complete solution, just when they as a company feel ready to make the jump.

In the mean time, the company still needs to have some kind of document management and of course they want it either directly inside of MSCRM or to integrate with it. Here are my "low budget solutions" for document management.

1. Use and FTP site
2. Use a file server, or a shared folder on a server with a sufficient amount of disc space

Now, remember this is "low budget" so that means that there will be a number of manual steps but keeping those to a minimum will go a long way. Also, these are work-arounds, not full solutions, so there will be limitations to each solution. These solutions are very similar upon implementation, it's just a matter of where the data is stored.

Using an FTP site will allow users to store files while local or remote to the network, whether the FTP site is hosted by the company or someone else will dependent on the needs are desires of the company you are implementing the solution for. You can then embed the FTP site in an IFRAME on a specific form or put a link on the left NavBar, or give them a button that will open it in a new window. However, opening to the main page of an FTP site (whether they have to log in or not is entirely up to you) then makes the users have to click more in order to drill down to the level at which he/she wants to store a given document. Here's the customization that can go a long way.

I did this as a button but the concept is the same for a NavBar item as well. Using an IFRAME is a bit different, but I'll go over an IFRAME solution shortly.

In the isv.config.xml document on the CRM server add a button to the desired form similar to the following XML:

<Button Title="FTP" ToolTip="View product images stored on FTP site" Icon="/_imgs/ico_18_debug.gif" JavaScript="window.open('ftp://fptserver/Clients/' + crmForm.all.name.DataValue + '/')" PassParams="0" WinParams="" WinMode="0" />

Using this code will require that the folder structure on the FTP site is maintained so that there is a folder for each client under a Client folder but users are now able to get to shared documents for a given client (or opportunity, product, project, etc) with a single click. For the end users, this is fantastic. For the admin to administrate this may not be as fun however. But through custom code one could maintain the folder structure if necessary. Again it depends on budget and timing.

Also, take note that you will need to use the JavaScript attribute because the Url attribute expects an HTTP link. Lastly, note that it will be absolutely necessary for you to put the "ftp://" full URL in the code, otherwise the link will be assumed to be HTTP.

Now, for a shared directory. The limitation here is that users have to be local, or on a VPN in order to access it. If that isn't that big of a deal to the client then this can be great solution for end users.

First, on the entity you are using, add an plain text attribute called "Shared Folder". Place it where you want on the form (I suggest a tab solely dedicated to file sharing, but to each his own). Then create an IFRAME. Name it FileShare (or whatever you want), allow for cross frame scripting, hide the display name, etc. Set the URL to be "about:blank".

Now add script to the onLoad of the form. Add the following:

if(crmForm.all.new_sharedfolder.DataValue != null && crmForm.all.new_sharedfolder.DataValue != "")
{
document.all.IFRAME_FileShare.src = crmForm.all.new_sharedfolder.DataValue;
}
else
{
document.all.IFRAME_FileShare.src = "about:blank";
}

Then all users have to do is type in the UNC path, or directory path to the directory desired. This could be scripted upon the creation of a form for a static path with a dynamic name at the end, much like the FTP example from above, but again remember that the folder structure will need to be maintained one way or another.

Examples:
UNC: \\fileservername\Clients
Directory path: Z:\Clients

If you use the directory path option then you will have to make sure that the drive is mapped correctly on the user's machine, otherwise it will break. Otherwise UNC works every time (as long as the computer is on the network).

There isn't any auto version control but it gives the users a place to store documents "inside" MSCRM in a form that they are used to and comfortable with. Once they out grow this then it's time to move onto a real document management solution. But until then, happy "low budget" coding!

David Fronk
Dynamic Methods Inc.

Saturday, March 15, 2008

Allowing QuickFind to search Inactive records

In Microsoft CRM v3.0 there were certain entities that were allowed to search inactive records through the QuickFind/QuickSearch feature (the "Look For" query at the top of each main entity listing). Rollup 2 changed some of those entities that were capable of searching inactive records and now CRM v4.0 has made is so that the QuickFind/QuickSearch does not look for inactive records at all in any entities (at least in my testing, this is what I have found, if someone has found otherwise please let me know). Now, I won't say that I want this capability for every entity in the system but sometimes it might be nice. For instance, Cases has been an entity that has been requested that be allowed to search both active and inactive records.

What would be nice would be if there were some option that users could choose or set in their preferences, or even at the entity level, to allow or disallow the ability to search both active and inactive records. Something ask for in v5.0.

But until then there is hope. Depending on what version of CRM you are on depends on the solution you can implement.

CRM v3.0 involves modifying entity XML. CRM v4.0 requires a Plugin be written on the PreRetrieve method.

Today I'm going to talk about the CRM v3.0 modification. Technically this customization will work in CRM v4.0 as well, but let me be very clear when I state, THIS IS AN UNSUPPORTED CUSTOMIZATION. I cannot gaurantee that this will will break your upgrade or not, though I am very inclined to say that it will. Also, any repair or update could potentially undo your change as this customization requires you to modify the actual entity XML. So, if a patch or rollup doesn't include the entity XML then you should be pretty safe.

Steps:
1. Export the entity XML of the entity you wish to modify.
2. Copy your XML export file so that you have a backup to roll back to in case something goes wrong.
3. Open the XML file in your editor of choice and search for "Quick Find".
a. NOTE - don't let the XML fool you, it puts the name at the bottom of the "SavedQuery" XML chain, what you will be modifying should be above the name tag.
4. Remove the following filter from the Quick Find saved query:

<filter type="and">
<condition attribute="statecode" operator="eq" value="0" />
</filter>

5. Locate the "iscustomizable" tag and change the "name" attribute to say "Yes" instead of "No".
6. Save your modified XML file
7. Upload your modified XML file into CRM
8. Publish Customizations
9. Refresh your page and test

That's it. Personally I think is a pretty safe "unsupported" customization because the worst that will happen in a repair or upgrade is the entity XML will get replaced. The customization is pretty localized to the Quick Find. If you modify other pieces of the entity XML you're on your own.

Good luck!

David Fronk
Dynamic Methods Inc.

Friday, March 07, 2008

Hiding a Section

Hiding a section has been an interesting customization to figure out. I definitely got help by reading through posts and groups, but then again, who doesn't? When hiding things in CRM typically it's done by referencing a specific control name, something like the tab number or the field name. Sections are strange in that they don't have any of the normal "English" identifiers that one would expect. It's actually reference directly through a GUID. Each section gets assigned a GUID upon creation, so writing code that is dynamic for hiding sections directly really wasn't pretty...or possible.

However, if you reference a section indirectly things actually get much easier. For example, everything in the CRM forms are contained within something larger. Fields are contained by Sections, which are contained by Tabs, which are contained by the web form itself. That means that there is a direct parent/child relationship between objects on the form. JScript has thought about this and allows you to reference ParentNode's through code.

With this new knowledge referencing sections actually becomes very easy. All that has to be done is make a reference to a field on the form and then get it's parent node and do what you need to do to it.

Here's the code:

document.getElementById("ownerid").parentNode.parentNode.style.display = "none";

You'll notice that I have to parentNode references, that's not a mistake, this is the progression on how to get to the section. Fields are actually contained by Labels and Labels are contained by Sections on a form. I didn't realize this until I tried using only the first parentNode reference. Play with it a bit and you'll see what I mean.

Then to make the section visible again just use empty quotes:

document.getElementById("ownerid").parentNode.parentNode.style.display = "";

And now you have full control over what to make visible to users upon any condition you want.

Happy coding!

David Fronk
Dynamic Methods Inc.