Monthly Archives: November 2007

Installing MS System Center Essentials 2007 fails at Reporting item

I’ve been trying to play around with System Center to see how we can use it to monitor our web application solution (DB utilisation, bandwidth, web server CPU/RAM etc).

Having eventually got through all the issues regarding the pre-existing WSUS 3.0 setup, existing SSRS install etc I got to the ‘installing’ section. This section took an absolute age to run (20mins approx on a Xeon 3050 (2×2.13Ghz) with 2Gb RAM). It would run through “Software Distribution and Update Management”, then “Server and Client Monitoring”, and finally “Reporting”. However on Reporting it would just put a red X next to it, then appear to roll-back a bit and reboot the PC without prompting – NICE!

System Center Essentials 2007 install error at Reporting

I looked for a while and couldn’t find any information about it until I stumbled across KB937831 which basically describes a problem which applies to our environment. Basically our domain is setup as follows:

Our company is called Xyz Ltd
Our public facing domain name is xyz.com
Our NETBIOS domain name is XYZ
Our Active Directory FQDN is internal.xyz.com

The issue appears to be that the installer makes an assumption that the first part of the FQDN is the NETBIOS name, which for us it isn’t. In this case it’s authenticating with the username INTERNAL\Administrator rather than XYZ\Administrator. The relevant part from the %TEMP%\ SCEReporting0.log file is:

UnableToGetUserNameFromManagementServerActionAccount = SetPropertiesToManagementServerActionAndSDKAccountCA error: Microsoft.EnterpriseManagement.Common.UnauthorizedAccessMonitoringException : The specified domain does not exist or cannot be contacted.
UnableToGetUserNameFromManagementServerSDKAccount = SetPropertiesToManagementServerActionAndSDKAccountCA error: Microsoft.EnterpriseManagement.Common.UnauthorizedAccessMonitoringException : The specified domain does not exist or cannot be contacted.

The KB937831 says that the patch is only available via product support, however this isn’t true as it’s included in the roll-up available in KB943111.

UPDATE: it seems I was a bit premature, that roll-up doesn’t resolve the issue. There appear to be two relevant blog posts which point to how to get the HotFix via a web request form, I’m waiting my 8hours now…
http://blogs.technet.com/cliveeastwood/rss_tag_Bugs+or+Features_3F00_.xml
http://blogs.technet.com/smsandmom/archive/2007/09/13/sce2007-install-fails-with-the-specified-domain-does-not-exist-or-cannot-be-contacted.aspx

Advertisements

Closing an MS CRM 3.0 Activity via SDK doesn’t set the ActualEndTime

I’m finding the activities in MS CRM very frustrating to work with, especially the way the states are dealt with.

We just did our first mass-mailing from MS CRM and for the life of me couldn’t work out how to get it to record the activities as closed. Basically we setup a campaign, a marketing list, a campaign activity and then hit “Distribute Campaign Activity”.

However, this just creates me thousands of open activities which effectively show us “to-do” items for the owners of each account (or worse…me!). I googled for ages for a solution to this and only found some piss-poor excuses about it’s up to each Sales person to ‘own’ and deploy the items – ridiculous ! We just sent postal mailers to 1500 people and over 5,000 e-mails!! Sales people are here to sell, not stuff envelopes!

Anyway, having used the MS CRM UI to create the activities I need the activities closed so if a sales guy goes in to the account they can say with confidence “did you receive the mailer we sent you on 15th November?”. My first stab at this basically consisted of:

  1. Creating a dataset and retrieving all of the activities that need altering by querying the filtered views, something like (alter to your needs !!!):
    SELECT     FilteredActivityPointer.activityid, 
    [FilteredActivityPointer].[statecodename] 
    FROM         FilteredCampaignActivity 
    INNER JOIN FilteredCampaignActivityItem 
              ON FilteredCampaignActivity.activityid = FilteredCampaignActivityItem.campaignactivityid 
    INNER JOIN FilteredActivityPointer 
              ON FilteredActivityPointer.regardingobjectid = FilteredCampaignActivity.activityid 
                  AND FilteredCampaignActivity.channeltypecodename = FilteredActivityPointer.activitytypecodename 
    WHERE FilteredActivityPointer.[statecodename]='Open'  -- Only open account/contact activities 
         AND [FilteredCampaignActivity].[subject] LIKE 'Mailer%' -- Name of the Campaign activity (ideally use a Guid instead)
  2. This gives us a list of ActivityIds that need to be ‘closed’, I simply call the GetData method on my dataset to give me a list I can foreach through.
  3. Thus for each open Activity I must iterate through, set the actualendtime and then set the state to close (some helper snippets by David Padbury):
    public static DoClose() 
    { 
    	// Have a datatable called activitiesToBeChanged already populated with rows of type ActivitiesFromCampaignRow 
        foreach (ActivitiesFromCampaignRow row in activitiesToBeChanged.Rows) 
         { 
             activitypointer thisActivity = CrmHelper.RetrieveSingleEntity<activitypointer>(row.activityid, 
                     CreateColumnSet("activityid", "activitytypecode", "statecode")); 
             CloseLetter(thisActivity, ActualEndTime); 
         } 
    } 
    public static ColumnSet CreateColumnSet(params string[] columns) 
    { 
        #region Argument Validation 
        if (columns == null) 
             throw new ArgumentNullException("columns"); 
        if (columns.Length == 0) 
             throw new ArgumentException("There should be at least one column specified.", "columns"); 
        #endregion 
        ColumnSet columnSet = new ColumnSet(); 
        columnSet.Attributes = columns; 
        return columnSet; 
    } 
    public static T RetrieveSingleEntity<T>(Guid id, ColumnSetBase columnSet) 
         where T: BusinessEntity 
    { 
        EntityName entityName = GetEntityNameFromEntityType<T>(); 
        CrmService service = CrmServiceFactory.CreateService(); 
        BusinessEntity entity = service.Retrieve(entityName.ToString(), id, columnSet); 
        return (T)entity; 
    } 
    private static void CloseLetter(activitypointer activity, DateTime ActualEndTime) 
    { 
         CrmService service = CrmServiceFactory.CreateService(); 
        letter thisLetter = RetrieveSingleEntity<letter>(activity.activityid.Value, 
             CreateColumnSet("activityid", "actualend", "subject", "to"));
    
        SetStateLetterRequest setStateRequest = new SetStateLetterRequest() 
        SetStateRequest.EntityId = activity.activityid.Value; 
        TargetUpdateLetter target = new TargetUpdateLetter(); 
        target.Letter = thisLetter;     // Closing the activity doesn't set the end time, so we must do this first 
        if (target.Letter.actualend == null) 
        { 
             target.Letter.actualend = new CrmDateTime();          if (ActualEndTime.Ticks == 0 || ActualEndTime == null) 
                 ActualEndTime = DateTime.Now; 	 target.Letter.actualend.Value = ActualEndTime.ToString("yyyy/MM/ddTHH:mm:ss"); 
    	// Beware SDK is wrong on the formatting here!     } 	UpdateRequest update = new UpdateRequest(); 
    	update.Target = target; 
    	// Now set the time. 
    	UpdateResponse updated = (UpdateResponse)service.Execute(update); 
    
    	public static DoClose() 
    	{ 
    		// Have a datatable called activitiesToBeChanged already populated with rows of type ActivitiesFromCampaignRow 
        	     foreach (ActivitiesFromCampaignRow row in activitiesToBeChanged.Rows) 
    		{ 
    		         activitypointer thisActivity = CrmHelper.RetrieveSingleEntity<activitypointer>(row.activityid,                 CreateColumnSet("activityid", "activitytypecode", "statecode")); 
    			CloseLetter(thisActivity, ActualEndTime); 
    		} 
    	} 
    
    	public static ColumnSet CreateColumnSet(params string[] columns) 
    	{ 
    		#region Argument Validation 
        		if (columns == null) 
    			 throw new ArgumentNullException("columns"); 
    	        if (columns.Length == 0) 
    		throw new ArgumentException("There should be at least one column specified.", "columns"); 
    	    #endregion 
        		ColumnSet columnSet = new ColumnSet(); 
    		    columnSet.Attributes = columns; 
    	    return columnSet; 
    		} 
    public static T RetrieveSingleEntity<T>(Guid id, ColumnSetBase columnSet)
         where T: BusinessEntity 
    {
         EntityName entityName = GetEntityNameFromEntityType<T>(); 
        CrmService service = CrmServiceFactory.CreateService(); 
        BusinessEntity entity = service.Retrieve(entityName.ToString(), id, columnSet); 
        return (T)entity;
     } 
     private static void CloseLetter(activitypointer activity, DateTime ActualEndTime) 
    {
         CrmService service = CrmServiceFactory.CreateService(); 
        letter thisLetter = RetrieveSingleEntity<letter>(activity.activityid.Value,
             CreateColumnSet("activityid", "actualend", "subject", "to")); 
        SetStateLetterRequest setStateRequest = new SetStateLetterRequest();
         setStateRequest.EntityId = activity.activityid.Value;
        TargetUpdateLetter target = new TargetUpdateLetter();
         target.Letter = thisLetter; 
         // Closing the activity doesn't set the end time, so we must do this first
         if (target.Letter.actualend == null)
         {
             target.Letter.actualend = new CrmDateTime(); 
            if (ActualEndTime.Ticks == 0 || ActualEndTime == null)
                 ActualEndTime = DateTime.Now; 
            target.Letter.actualend.Value = ActualEndTime.ToString("yyyy/MM/ddTHH:mm:ss"); // Beware SDK is wrong on the formatting here!
         } 
        UpdateRequest update = new UpdateRequest();
         update.Target = target; 
        // Now set the time.     
        UpdateResponse updated = (UpdateResponse)service.Execute(update); 
        // Now close the activity
         setStateRequest.LetterState = LetterState.Completed;                                // Have to flag as Sent etc.     
    	// from the SDK " Set this field to -1 to have the platform set the appropriate value for the Microsoft CRM application. "
             // Alternatively do something like SELECT * FROM [FilteredStatusMap] WHERE [FilteredViewName] = 'FilteredLetter' to see valid statuses to states
         setStateRequest.LetterStatus = -1; 
        service.Execute(setStateRequest); 
    }

This isn’t meant to be a complete solution, but hopefully will give you enough pointers to be useful, especially with regard to other entity types. I have to say the MS CRM SDK is pretty useless, and the classes are pretty poorly documented