BM-Bloggers

The blogs of Black Marble staff

Going Postal–Can the Black Marble Brigade Save Xmas 2010?

Episode OneIt’s that time of year again … Santa has been kidnapped and the only team that can save him is the Black Marble Brigade!  And what BlechleyParkgreat tools do the team have at their disposal this year?!  Why Windows Phone 7 and Microsoft Surface! There is no limit to what use these can be put to to save Santa and Christmas in 2010.

Look out for episode 2 next week!

Plus, once again we are supporting The National Museum of Computing (TNMOC) and Bletchley Park with our Christmas Cards, and I encourage you all to do the same.

Installation of CRM 4.0; ASP.NET 2.0 not installed and the Asynchronous Service fails to start

The above two errors hit me recently while I was trying to get a CRM 4.0 development environment installed for some upcoming work.

The first error shows up when the CRM 4.0 installer is checking the server configuration of the computer on which it is being installed as one of the final steps before installation commences. I checked that .NET 2.0 was installed and patched (it was) and that I had run the correct aspnet_regiis command to install ASP.NET 2.0 and update the scriptmaps (I had). As I’d patched the server completely, the server now had .NET 4 installed and following a bit if research, it appears that for CRM 4.0 installation, this interferes with the detection of ASP.NET 2.0. There’s a good walkthrough of the workaround, which involves adding a new ISAPI filter at the root of the websites listed in IIS manager, at http://www.powerobjects.com/blog/2010/08/14/ms-dynamics-crm-installation-asp-net-2-0-is-not-installed/

For the record, in this instance I was using Windows Server 2003 R2 x86 for the CRM server and Windows Server 2003 R2 x64 for the SQL server.

Following the above error, I also saw an issue at the very end of the installation, whereby the CRM Asynchronous Service failed to start. The error shown in the dialogue was

“Action Microsoft.Crm.Setup.Common.RegisterAsyncServiceAction failed. An exception occurred during the Commit phase of the installation. This exception will be ignored and installation will continue. However, the application might not function correctly after installation is complete. Time out has expired and the operation has not been completed.”

In addition, the following was recorded in the crm40svrSetup.log file located at C:\Document and Settings\<user name>\Application Data\Microsoft\MSCRM\Logs

12:10:24|  Error| System.Exception: Action Microsoft.Crm.Setup.Common.RegisterAsyncServiceAction failed. ---> System.Configuration.Install.InstallException: An exception occurred during the Commit phase of the installation. This exception will be ignored and installation will continue. However, the application might not function correctly after installation is complete. ---> System.ServiceProcess.TimeoutException: Time out has expired and the operation has not been completed.
   at System.ServiceProcess.ServiceController.WaitForStatus(ServiceControllerStatus desiredStatus, TimeSpan timeout)
   at Microsoft.Crm.ExtendedServiceInstaller.StartService(Object sender, InstallEventArgs e)
   at System.Configuration.Install.InstallEventHandler.Invoke(Object sender, InstallEventArgs e)
   at System.Configuration.Install.Installer.OnCommitted(IDictionary savedState)
   at System.Configuration.Install.Installer.Commit(IDictionary savedState)
   --- End of inner exception stack trace ---
   at System.Configuration.Install.Installer.Commit(IDictionary savedState)
   at System.Configuration.Install.AssemblyInstaller.Commit(IDictionary savedState)
   at Microsoft.Crm.Setup.Common.RegisterAsyncServiceAction.Do(IDictionary parameters)
   at Microsoft.Crm.Setup.Common.Action.ExecuteAction(Action action, IDictionary parameters, Boolean undo)
   --- End of inner exception stack trace ---, Error, RetryCancel, Option1

I also noticed that on the SQL server, the following error was reported:

Login failed for user 'NT AUTHORITY\ANONYMOUS LOGON' on SQL server

This indicated a possible issue with Kerberos and following a bit of investigation, this turned out to be the case. Microsoft have very helpfully supplied a walkthrough for correcting the issue at http://support.microsoft.com/kb/921393 (although personally I find using ADSIEdit far easier than SetSPN; ADSIEdit can be installed on Windows Server 2003 R2 from the \Support\Tools folder of the installation media).

Once the correct SPNs were in place, the CRM Asynchronous Service started successfully.

Powershell to find missing features in SharePoint 2010

When migrating from SharePoint 2007 to 2010, no matter how hard you try there’s always the chance the the content database upgrade process will throw out errors about features being referenced that are not present in the farm. We have used Stefan Goßner’s WssAnalyzeFeatures and WSSRemoveFeatureFromSite (see his original article) to track down the references and exterminate them. It’s not the fastest thing on two legs though, and I have a fondness for having my SharePoint 2010 tooling in PowerShell because of the flexibility it gives me.

Here then, with a big hat-tip to Stefan, is the PowerShell to replicate his functionality. We differ slightly, in that I wanted one command to purge both site- and web-referenced features in one shot rather than calling a command with a scope switch. I have two functions – get-spmissingfeatures takes a Site Collection url as a parameter and scans through site and web feature collections, listing any features with a null definition property. The second function, remove-spmissingfeatures takes the same url and this time finds and removes the errant features in one pass.

Get-SpMissingFeatures:

function get-spmissingfeatures([string]$siteurl)
{
  $site = get-spsite $siteurl


  foreach ($feature in $site.features) {
    if ($feature.definition -eq $null) {
       write-host "Missing site feature:"
       write-host $feature.DefinitionId
       write-host $feature.parent
#      $site.features.remove($featureid)
    }
  }

  $webs = $site | get-spweb -limit all
  foreach ($web in $webs) {
  foreach ($feature in $web.features) {
    if ($feature.definition -eq $null) {
       write-host "Missing web feature:"
       write-host $web.url
       write-host $feature.DefinitionId
       write-host $feature.parent
#      $site.features.remove($featureid)
    }
  }

  }

}

Remove-SPMissingFeatures:

function remove-spmissingfeatures([string]$siteurl)
{
  $site = get-spsite $siteurl


  foreach ($feature in $site.features) {
    if ($feature.definition -eq $null) {
       write-host "Missing site feature:"
       write-host $feature.DefinitionId
       write-host $feature.parent
      $site.features.remove($feature.DefinitionId)
    }
  }

  $webs = $site | get-spweb -limit all
  foreach ($web in $webs) {
  foreach ($feature in $web.features) {
    if ($feature.definition -eq $null) {
       write-host "Missing web feature:"
       write-host $web.url
       write-host $feature.DefinitionId
       write-host $feature.parent
      $web.features.remove($feature.DefinitionId)
    }
  }

  }
}

Where can you learn more on Typemock after last night session at NEBytes?

Thanks to everyone who turned out from Rik’s and my session last night at NEBytes. I have not bothered uploading my slides as it was really a demo driven session, but there is a video of a similar session I did at NDC2010

However, if you want to learn more about using Typemock Isolator with legacy system why not attended Roy Osherove’s ‘Be a Legacy Code Unit Test Ninja with Typemock Isolator’ web session next week?

Also I will be doing another web session, similar to last nights, on Typemock and SharePoint on the 1st December.

Live Messenger behind TMG cannot log in (error 80072f7d)

We’ve seen some examples of users being unable to log into Windows Live Messenger (both 2009 and 2011) recently with the error 80072f7d being returned.

Users who are able to make a connection to the internet outside our TMG firewall have been successful in logging in, even when they returned to the office and were once again behind the TMG firewall, so it seems to be an initial connection to the Messenger service which is failing when behind the TMG firewall.

Our TMG implementation is using HTTPS inspection, which we have seen cause issues with a number of services and this also turned out to be the case with Live Messenger. Once the URLs listed in KB960820 were excluded from HTTPS inspection, logging into Live Messenger from inside our TMG firewall started working again.

0x80004004 when trying to upgrade Live Writer and Messenger

For ages now I have have been prompted when I loaded Live Writer that there was an upgrade available, and every time I tried it get it, at the end of the install it failed and rolled back. As I did not have time to dig into it I just used the older version.

Well today, due to upgrades in our LAN, I need to upgraded Live Messenger and as this is of part of the same Live Essentials 2011 package it not unsurprising I hit the same problem. A bit of experimentation showed the issues was that the upgrade was not able to remove the old version. If i tried to remove it via Control Panel it failed with a 0x80004004 error. In the error log I saw

Product: Windows Live Messenger -- Error 1402. Could not open key: UNKNOWN\Components\A49B6681220C2EA49826913B104EE03B\B55DF58AB1984134795AAE690CDB085B.  System error 5.  Verify that you have sufficient access to that key, or contact your support personnel.

A bit of web research show this seems to be related to 32/64bt issues and maybe debris from the beta version of Live Writer.

The answer was to use Windows Clean Up Utility (remember this is take no prisoners tool so use it with care) and remove all the package with the words ‘Microsoft’ and ‘Live’ in their names. Once this was done the Live Essentials 2011 installer was happy to do a new install, and it even remembered my blog settings!

Adding a Visual Basic 6 project to a TFS 2010 Build

Adding a Visual Basic 6 project to your TFS 2010 build process is not are hard as I had expected it to be. I had assumed I would have to write a custom build workflow template, but it turned out I was able to use the default template with just a few parameters changed from their defaults. This is the process I followed.

I created a basic ‘Hello world’ VB6 application. I had previously made sure that my copy of VB6 (SP6) could connect to my TFS 2010 server using the Team Foundation Server MSSCCI Provider so was able to check this project into source control.

Next I created a MSbuild script capable building the VB project, as follows

<Project ToolsVersion="4.0" DefaultTargets="Default" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  
  <PropertyGroup>
    <TPath>C:\Program Files\MSBuild\ExtensionPack\4.0\MSBuild.ExtensionPack.tasks</TPath>
    <TPath Condition="Exists('C:\Program Files (x86)\MSBuild\ExtensionPack\4.0\MSBuild.ExtensionPack.tasks')">C:\Program Files (x86)\MSBuild\ExtensionPack\4.0\MSBuild.ExtensionPack.tasks </TPath>
  </PropertyGroup>
  <Import Project="$(TPath)"/>
 
  <PropertyGroup>
    <VBPath>C:\Program Files\Microsoft Visual Studio\VB98\VB6.exe</VBPath>
    <VBPath Condition="Exists('C:\Program Files (x86)\Microsoft Visual Studio\VB98\VB6.exe')">C:\Program Files (x86)\Microsoft Visual Studio\VB98\VB6.exe</VBPath>
  </PropertyGroup>
 
  <ItemGroup>
    <ProjectsToBuild Include="Project1.vbp">
      <OutDir>$(OutDir)</OutDir>
      <!-- Note the special use of ChgPropVBP metadata to change project properties at Build Time -->
      <ChgPropVBP>RevisionVer=4;CompatibleMode="0"</ChgPropVBP>
    </ProjectsToBuild>
  </ItemGroup>
  <Target Name="Default">
    <!-- Build a collection of VB6 projects -->
    <MSBuild.ExtensionPack.VisualStudio.VB6 TaskAction="Build" Projects="@(ProjectsToBuild)" VB6Path="$(VBPath)"/>
  </Target>
 
  <Target Name="clean">
    <Message Text="Cleaning - this is where the deletes would go"/>
    
  </Target>
  
</Project>

This used the MSBuildExtensions task to call VB6 from MSBuild, this MSI needed to be installed on the PC being used for development. Points to note about this script are:

  • I wanted this build to work on both 32bit and 64bit machines so I had to check both the “Program Files” and “Program Files (x86)” directories, the Condition flag is useful for this (I could have used an environment variable as an alternative method).
  • The output directory is set to $(OutDir). This is a parameter that will be passed into the MSBuild process (and is in turn set to a Team Build variable by the workflow template so that the build system can find the built files and copy them to the TFS drop directory).

This MSBuild script file can be tested locally on a development PC using the MSBUILD.EXE from the .NET Framework directory. When I was happy with the build script, I stored it under source control in the same location as the VB project files (though any location in source control would have done)

The next step was to create a new Team Build using the default build template with a workspace containing my VB6 project.

The first thing to edit was the ‘Items to Build’. I deleted whatever was in the list (sorry can’t remember what was there by default). I then added the build.xml file I had just created and stored in source control

image

I then tried to run the build, this if course failed as I needed to install VB6 (SP6) and the MSBuildExtensions on the build server. Once this was done I tried the build again and it work. The only issue was I got a warning that there were no assemblies that Code Analysis could be run against. So I went into the build’s parameters and switched of code analysis and testing as these were not required on this build.

So the process of build ingVB6 on TFS 2010 turned out to much easier than I expect, it just goes to show how flexible the build system in TFS 2010 is. As long as you can express your build as an MSBUILD file it should just work.

Xml Validation error when inserting paragraphs in multi-line text box controls in Word 2007

Recently whilst developing a VSTO document template, I was presented with this error whilst attempting to re-open a saved document.

‘The Office Open XML File <documentname>.docx cannot be opened because there are problems with the contents.

Unspecified error. Location: Part: /word/document.xml, Line: 2, Column: 1054’

Word offered to recover the unreadable content; but subsequently saving and re-opening resulted in the same error. I unzipped the docx file and opened the contents into an editor to discover what was breaking it…

Word 2007 allows developers to use textbox controls to position/format specific text regions within a document template. The control provides a handy way of accessing this region from code behind.

The textbox control also provides multi-line capabilities; but in the form of new lines rather than ‘Paragraph’ breaks. You can see this by turning on symbols within word:

TextBoxControl

Notice, within the text box control, pressing return inserts a newline rather than a new paragraph. Outside the control it inserts a new paragraph.

However, this protection provided by the Word UI is not enforced when programmatically setting the text. It allows the following to happen:

image

This has no noticeable effect whilst in the document. However, once you save and re-open you’ll have stumbled onto a nasty bug with no obvious way of back-tracking to the cause. The representation of the paragraph in xml actually acts as the closing tags for the textbox xml block, causing the above error.

To avoid the error, I simply changed the text string; separating newlines with ‘\v’ [rather than StringBuilder.AppendLine()]. If I’d been unable to do that then I would have investigated the word API for a method to format the text.

To fix the broken document you can either

  1. Manually fix the broken xml file
  2. Allow Word to recover the document, remove the paragraph spacing and resave the document

This bug appears to be fixed in MS Word 2010.