The CRM Grid – A Microsoft CRM Blog

Greg Owens’ rose-tinted MS-CRM mumblings

Which privilege failed?

A quick tip that might come in handy if you start editing roles and permissions in your CRM deployment. Often when I start to define completely custom roles, especially when using a brand new role with no existing values, I will encounter an error message when testing the role:

Error Description:
0x80040220 SecLib::CheckPrivilege failed. Returned hr = -2147220960, User: 00000000-0000-0000-0000-000000000000, PrivilegeId: a3311f47-2134-44ee-a258-6774018d4bc3 Platform

Error Details:
0x80040220
SecLib::CheckPrivilege failed. Returned hr = -2147220960, User: 00000000-0000-0000-0000-000000000000, PrivilegeId: a3311f47-2134-44ee-a258-6774018d4bc3
Platform

So what do I need to change to make this work? MSCRM isn’t being particularly helpful with this error message, so here’s how to make it make sense. Run the SQL script below against your [Organization]_MSCRM database. Replace the GUID in the query below with the PrivilegeId GUID in the error message:

select [Name] from dbo.PrivilegeBase where privilegeid = 'a3311f47-2134-44ee-a258-6774018d4bc3'

You should get a single result back, like ‘prvReadEntity’ (Read access required for “Entity” which is found on the Roles matrix under the Customization tab, Entity row, Read column) or ‘prvCreateUserSettings’ (Business Management tab, User Settings row, Create column). As you can see, the Name of the privilege should give you the pointer needed to set the required permissions.

You are not a Deployment Administrator

We’ve all seen this error at some point when trying to access the Microsoft Dynamics CRM Deployment Manager on the server:

Only the Deployment Administrators are able to use Deployment Manager. You are not a Deployment Administrator.

Most of the time this is not a problem at all – perhaps you’re logged in with the wrong account or you simply need to request that another administrator logs in and adds you to this list. Sometimes it can be trickier though – perhaps the only administrator is on holiday, has left (and had their account deleted rather than just disabled) or any other number of things that might just ruin your day. The only supported method at this point is a reinstall of CRM. Cripes…!

How about an unsupported method to get you by?

Try this little SQL script which should add you to the list of Deployment Administrators. It is ENTIRELY UNSUPPORTED and probably shouldn’t be used in a production environment etc etc. But needs must and this might just save your day (but don’t blame me if I make it worse, right?).

IMPORTANT NOTE: This script will get you into the Deployment Administrator, but if you were NOT already a CRM user, it won’t get you into the CRM front-end. Clearly something missing from my script at present – be very very careful if you use this in production…

USE MSCRM_CONFIG

DECLARE @username AS VARCHAR(MAX) ,
        @newuserguid AS uniqueidentifier ,
        @userguid AS uniqueidentifier ,
        @adminroleguid AS uniqueidentifier

-- *** TODO:  ADD THE USERNAME YOU WANT TO MAKE A DEPLOYMENT ADMINISTRATOR HERE
SET @username           = '<domain>\<username>' 
SET @newuserguid        = NEWID()

-- Get guid for the Deployment Admin role
SELECT @adminroleguid = id
FROM   dbo.securityrole
WHERE  Name = 'Administrator'

-- Add the user as a systemuser (unless they already exist...)
IF NOT EXISTS
    (SELECT ID
    FROM    SYSTEMUSER
    WHERE   NAME = @username
    )
    BEGIN
            INSERT
            INTO   SYSTEMUSER VALUES
                   (
                          '00000000-0000-0000-0000-000000000000',
                          @newuserguid                            ,
                          @username                               ,
                          0
                   )
    END

-- Get the user's guid
SELECT @userguid = ID
FROM   SYSTEMUSER
WHERE  NAME = @username

-- Add the user's guid and the admin role to the SystemUserRoles table
INSERT
INTO   dbo.SystemUserRoles VALUES
       (
              NEWID()       ,
              @adminroleguid,
              @userguid   ,
              NULL          ,
              0
       )

We also may need to add the record to the appropriate AD groups and CRM tables. I’m not going to show you how to add items to Active Directory Groups or which groups to use. Suffice to say, you would need to know the user’s Active Directory sid (Security ID). Try this command from the server prompt:

dsquery user -name Greg* | dsget user -sid

This should return a result similar to this:

sid
S-1-5-21-0123456789-0123456789-0123456789-1234
dsget succeeded

You’re on your own from this point… ;-)

Dates in FetchXml queries

Another quick post. A colleague was trying to execute a FetchXml statement that included a filter on a date field but couldn’t understand why he was not returning the expected results (indeed, wasn’t returning any results).

At first glance, the query looked fine:

<fetch mapping="logical">
	<entity name="new_entity">
		<attribute name="new_entityid"></attribute>
		<filter type="and">
			<condition attribute="new_linkentityid" operator="eq" value="f25f4cee-e851-df11-bebe-000c29a1faa8"></condition>
			<condition attribute="new_date" operator="eq" value="2010-04-30"></condition>
		</filter>
	</entity>
</fetch>

The link entity was definitely correct and the date field certainly read 30th April 2010. The date field was also defined as Date Only in the attribute definition.

It transpired that the problem was (predictably) linked to times. CRM stores all dates in UTC format () so even if the attribute is defined as “Date Only” in the entity definition, 30th April 2010 will actually be stored as 2010-04-30T00:00:00. For some reason, which I haven’t yet determined for certain (there are a couple of theories that i don’t have time to test), the record he was seeking was dated 2010-04-30T08:00:00. It may be due to his time zone, since he was working in the US at the time of the problem. It may be that this attribute was previously a Date AND Time attribute and then got changed. Either way, the simplest solution was to use a different FetchXml operator – replacing the “eq” operator in the “new_date” condition with the “on” operator thereby ignoring times:

<fetch mapping="logical">
	<entity name="new_entity">
		<attribute name="new_entityid"></attribute>
		<filter type="and">
			<condition attribute="new_linkentityid" operator="eq" value="f25f4cee-e851-df11-bebe-000c29a1faa8"></condition>
			<condition attribute="new_date" operator="on" value="2010-04-30"></condition>
		</filter>
	</entity>
</fetch>

A list of FetchXml operators can be found on MSDN

Checking the ExecuteFetchRequest message

Sorry no updates for so long – NDAs with my main client and 5 hours commuting a day is hammering my blog time!

Just a quick note: new version of the CRM SDK is out now – version 4.0.12.

One of the items I noted was a technique to improve the performance of plugins that operate on the Execute message. I have been developing various plugins for my client which change and/or calculate data that gets passed to the UI, by harnessing the Retrieve and RetrieveMultiple messages. When data is being displayed a CRMGrid control however, CRM uses the Execute message instead (specifically the ExecuteFetchRequest message, but this can’t be checked directly).

Given the pervasive nature of Execute message calls (tested thanks to David Jennaway’s work here), we’d already determined that checks were necessary to processing the majority of calls to the Execute message. After discovering that the Execute message’s InputParameters only contain a FetchXml property when a grid is being processed, we can exit the plugin code much quicker thereby improving system performance. It’s nice to know that this is actually the preferred method too!

Here’s a little sample:

    public class ExecuteHandler : IPlugin
    {
        public void Execute(IPluginExecutionContext context)
        {
            if (context.InputParameters.Contains("FetchXml"))
            {
                if (context.OutputParameters.Contains("FetchXmlResult"))
                {
                     // here I intercept and change some values in the FetchXmlResult fragment
                }
            }
        }

Windows Update killed my app pool!

Tried to access my client’s development server today to find that CRM 4.0 was down. First thing I did was to check IIS, to find that the CRMAppPool was stopped. I tried to restart it – it looked like it had worked, but alas a refresh showed that it had failed to start properly.

After first blaming the client’s visiting tech who was also working on the server (sorry ‘Cheung!), I checked the Event Viewer and the System Log showed a series of messages from my attempt to restart the Application Pool:

A process serving application pool ‘CRMAppPool’ terminated unexpectedly. The process id was ‘3432’. The process exit code was ‘0xffffffff’.

After a few attempts, W3SVC had given up:

Application pool ‘CRMAppPool’ is being automatically disabled due to a series of failures in the process(es) serving that application pool.

Scrolling down, it became clear that the new prime suspect was Windows Update. A number of updates had been installed early this morning. I checked the KB articles for each one until I came across KB973917 (Extended Protection for Authentication in Internet Information Services). I read the article and although some extra configuration was required, it didn’t seem to fit my scenario (aka, this is a development server and there was a lot of text in the article and I needed to get back to development, rather than poncing about with security updates). The solution for me was to simply uninstall KB973917 and reboot the server.

Microsoft Dynamics CRM 4.0 is now working just fine, though this probably needs some more investigation. I quick straw poll of some of my CRM buddies did not suggest a widespread issue (yet?) but maybe this was because of the particular setup we are using here?

I’m not about to fully troubleshoot now, but here is some information about the server that was stricken – maybe it will help you all to pinpoint any issue with your own servers:

    Microsoft Dynamics CRM 4.0 – Update Rollup 5
    Microsoft Windows 2003 SP2
    Internet Information Services 6.0
    Microsoft SQL Server 2005 SP3
    All running on one box
    Application pools running under default Network Service account

I believe this will not be limited to just CRM – at least one other report online of it affecting WSS.

Update 1:
Already a lot of hits today – if this solution works for you, please post and let everyone know. Also summarise your setup so we can work out when this is happening :)

Update 2:
Kudos to Richard (who has commented below) for discovering that Microsoft have now rushed out a KB article to explain the problem and propose a longer-term fix: http://support.microsoft.com/Default.aspx?kbid=2009746. In short, reinstall Windows 2003 SP2.

Restarting the CRM application pool

So you’re developing plug-ins and you need to redeploy your DLL periodically since it is otherwise “in use” or there is some other reason that is asking for a full iisreset. Since a full reset is a bit invasive and global (e.g. this is a production server which also runs SharePoint, website or goodness knows what else), why not recycle the application pool instead?

Of course, we can do this via IIS Manager with a bit of point and click – but this can’t be automated and it’s a bit fiddly. Instead, do it from the command line with this handy bit of text:

cscript c:\windows\system32\iisapp.vbs /a "CrmAppPool" /r

Recycling the application pool is distinctly quicker than doing a full iisreset (though admittedly there are some scenarios when recycling the application pool is insufficient – no idea on the specifics though! See here, perhaps). I find this especially useful in the post-build events of Visual Studio (Project > %ProjectName% Properties > Build Events) to ensure that copying my DLLs always works without manually intervention.

Event execution order with ‘onbeforeunload’

Recommended JavaScript Book!

I'd also like to highly recommend this JavaScript book by Douglas Crockford - it will definitely improve the quality of your JavaScript development experience!


Recently I had a requirement to conditionally add some dynamic script to the onClose event for a CRM form. Given the flexiblility demanded by the requirements, it was not practical to write script in the form’s onClose() event hander in the CRM Form Properties window. Instead, I used Internet Explorer’s attachEvent method

The problem with the attachEvent method is that the collection of functions that are appended to the event are executed in “random order”. “Random” is rarely a desirable sequence  in my experience and in this case one cannot guarantee that a custom dynamic “validation check” (for example) will be executed before the default event handler (i.e. the one that may ask “Are you sure you want to navigate away from this page?”).

Alas a simple solution is at hand, thanks to this post made by “Adios” over at CodingForums.com. The function below will effectively inject your function call before the default event handler.  Obviously this function can be easily amended to deal with any type of event but the example  below is hard-coded to deal with the “onbeforeunload” event handler.

Define this function in your form onLoad script (or somewhere in your global code, if you have adopted a custom solution for centralising your JavaScripts):

function addbeforeunloadEvent(func)
{
    var oldonbeforeunload = window.onbeforeunload;
    if (typeof window.onbeforeunload != 'function') {
        window.onbeforeunload = func;
    } else {
        window.onbeforeunload = function() {
            oldonbeforeunload();
            func();
        }
    }
}

Then use the following snippet to insert your function ahead of the default or existing event handler:

//TODO: replace myFunctionName and myParameter list to match your custom function signature
addbeforeunloadEvent(function(){myFunctionName(myParameterList);});

Follow

Get every new post delivered to your Inbox.