Saturday, February 23, 2013

How MSBuild could make a file inparseable

Problem: A text file that was being parsed from an assembly being part of a developing system. In the developer environment, this worked great. After having deployed the text file and the necessary assemblies to a different location using MSBuild, where MSBuild also replaced a couple of strings inside the text file, parsing would no longer work.
  • Looking at the file in a text editor (i use Notepad++) confirmed that the edited version looked fine.
  • Editing the file in the developer environment manually (not running MSBuild on it) worked fine - the file was parseable afterwards.
Obviously, MSBuild made the file inparseable So how could MSBuild make the text file inparseable? The command touching the file was
<MSBuild.ExtensionPack.FileSystem.File 
     TaskAction="Replace" 
     RegExPattern="Something" Replacement="SomethingElse"
     Files="%(filename)"/>
Only when tracing the code parsing the file it became clear to me that the file now contained some extra characters at the beginning of the file. Then it occurred to me:

Solution: MSBuild changed the file encoding. To make sure MSBuild used the right encoding, I had to add one more key/value pair to the MSBuild tag mentioned above:
TextEncoding="Windows-1252"
I found this by inspecting the file encoding on the source and destination text files. My source file was reported as ANSI, whileas my destination file was reported as UTF-8. It was however not as simple as putting "ANSI" as the TextEncoding, as described in this excellent StackOverflow article, which also lead me on the right path to "Windows-1252".

In my opinion, MSBuild should have retained the original encoding on the files it touches instead of  defaulting it into something unwanted. But then again, that's wat keeps bread on my table... Thanks, MS...

Monday, November 12, 2012

Failing Office automation when run from a service

Scenario: I needed to create a small script to automate the conversion of a Word document into PDF. There's plenty of help out there to script this by using the Microsoft.Office.Interop namespace, for example this simple one. I tried both writing a Powershell script and a compiled C# .exe with the same result: When running from the desktop, everything works fine, whileas running from a scheduled task or from CruiseControl running as a system service failed. If CruiseControl was running from its debug console window however, everything ran fine.

Problem: It seemed clear that the Office libraries required a logged on session to run in, as  also Microsoft confirms here in their Q257757 article.

Solution/workaround: I came across this hack - reposting it here for my own easy access to the knowledge:
  1. Browse to or create this folder: C:\Windows\SysWOW64\config\systemprofile\Desktop on 64 bits Win7/Win2008 - for 32-bits Windows, substitute SysWOW64 part of the path with System32. You might have to change some permissions to get there and you of course need to have administrative rights.
  2. Make sure the user credentials running the service or scheduled task you want to use has full control access permissions to the folder.
I have no idea how this trick can make it all work, but it does - at least in my case. Since Microsoft does not recommend or describe it however - use solely at your own risk. Not suitable for rocket launchers, weapon systems etc..

Friday, June 8, 2012

"Could not find a part of the path" from MSBuild/CruiseControl.NET

This case turned out to be a no-brainer, but for my own (and others who may need it) later reference, here it is:
Scenario: I had set up a test environment for testing MSBuild targets run from CruiseControl.NET. The target I wanted to run was supposed to do simple file operations like copying and unzipping files to a specific disk letter, which in my test environment happened to be a subst to a folder on my local hard drive. Windows 7 64-bits with UAC (User Account Control) on was used, running CruiseControl.NET elevated to give it necessary privileges.
Problem: When running the MSBuild target itself, things worked like a dream. However, when running the target from CruiseControl.NET, it always grinded to a halt at the first attempt to copy/unzip data to my disk
Cause: This is the no-brainer: Since CruiseControl.NET ran with elevated privileges (i.e. started with "run as an administrator"), it did not see the substed drive I had set up from a non-elevated cmd window.
Solution: Simply start a cmd window elevated (run as administrator) and do the same subst from there, and voilla! - it works.