Passing SolutionDir to NAnt For Post-Build Event in TeamCity

I just spent the better part of a day trying to solve this problem, so I’m posting the solution for any who may encounter it in the future. You’re welcome 😉

For a project I am currently working on, I needed to add a post-build event which invokes a PowerShell script. The script performs some minor tasks involving a database and is called PostBuild-DbSync.ps1. At the outset, this was a straightforward proposition. I created the script file, then referenced it in the Build Events section in Visual Studio.

Powershell.exe -ExecutionPolicy Unrestricted -file “$(SolutionDir)Build\PostBuild-DbSync.ps1”

The Problem

Running the build locally in Visual Studio was successful, and I ran it repeatedly while tweaking the script. Once the script was perfected, I checked it in to our SVN repo, and that triggered an automated build on our TeamCity server. That’s when the problems began. The first build failed with the following error:

Processing -File ‘UndefinedBuild\PostBuild-DbSync.ps1’ failed: Illegal characters in path. Specify a valid path for the -File parameter.

The value for “$(SolutionDir)” was not being passed to the Nant file which was being used to run the build.

Attempt #1

After some research, I learned that you can specify the Solution Directory as a parameter to MSBuild. However, because TeamCity is running the builds, I don’t have a specific directory to use as the value for that parameter. It may change from one build to the next. But TeamCity does expose several predefined build parameters, including the working directory and the checkout directory. So I decided to use one of these parameters in my NAnt file to set the appropriate solution directory.

<arg value=”/p:SolutionDir=${}” />

Unfortunately, this approach did not work. I got a new error:

The argument ‘C:\TeamCity\buildAgent\work\86ef71b243852ab1Build\PostBuild-DbSync.ps1’ to the -File parameter does not exist.

So the path was getting passed into the NAnt process correctly, and to the post-build event. However, I was missing a slash at the end of the solution directory, so its not finding the PowerShell file. I’m close, right? It just needs a little more tweaking…

Attempts #2, #3, #4

This part of the process was the most frustrating of them all. I went around and around trying to get that missing slash in the right place. First I tried adding it to the post-build event.

Powershell.exe -ExecutionPolicy Unrestricted -file “$(SolutionDir)****Build\PostBuild-DbSync.ps1″

For some reason, that brought me back to the “Undefined” error that I got at first. Next I tried adding it in the NAnt file.

<arg value=”/p:SolutionDir=${}\” />

Again,“Undefined”. I even tried a forward slash, but that didn’t resolve the issue. The next approach was to edit the project file manually and try to specify the solution directory as a relative path there.

<SolutionDir Condition=”‘$(SolutionDir)’” or ‘$(SolutionDir)’Undefined'”>..</SolutionDir>

This attempt also failed, since the PowerShell command requires the full path to the file, not a relative path.

The Solution

For a few other values used by the NAnt file, I had set up environment variables in TeamCity. So I decided to use that approach to solve this problem. I set up an environment variable in the build configuration with the name ‘SolutionDir’ and the value ‘\’. Notice that I’m using the predefined build parameter, and I can easily tack that extra slash on the end.

Now, I can go back to my NAnt file and set the SolutionDir parameter for MSBuild with the following line:

<arg value=”/p:SolutionDir=${environment::get-variable(‘SolutionDir’)}” />

With that, the build succeeds, and the post-build event processes flawlessly as well.

About Martin Witters