Ayende @ Rahien

My name is Oren Eini
Founder of Hibernating Rhinos LTD and RavenDB.
You can reach me by phone or email:


+972 52-548-6969

, @ Q c

Posts: 6,128 | Comments: 45,550

filter by tags archive

On PSake

time to read 7 min | 1212 words

James Kovacks introduced psake ( a power shell based build system )over a year ago, and at the time, I gave it a glance and decided that it was interesting, but not worth further investigation.

This weekend, as I was restructuring my Rhino Tools project, I realized that I need to touch the build system as well. The Rhino Tools build system has been through several projects, and was originally ported from Hibernate. It is NAnt based, complex, and can do just about everything that you want expect be easily understandable.

It became clear to me very quickly that it ain’t going to be easy to change the way it works, nor would it be easy to modify that to reflect the new structure. There are other issues with complex build systems, they tend to create zones of “there be dragons”, where only the initiated go, and even they go with trepidation. I decided to take advantage of the changes that I am already making to get a simpler build system.

I had a couple of options open to me: Rake and Bake.

Bake seemed natural, until I remember that no one touched it in a year or two. Beside, I can only stretch NIH so far :-). And while I know that people rave about rake, I did not want to introduce a Ruby dependency on my build system. I know that it was an annoyance when I had to build Fluent NHibernate.

One thing that I knew that I am not willing to go back to was editing XML, so I started looking at other build systems, ending up running into PSake.

There are a few interesting things that reading about it brought to mind. First, NAnt doesn’t cut it anymore. It can’t build WPF applications nor handle multi targeting well. Second, I am already managing the compilation part of the build using MSBuild, thanks to Visual Studio.

That leave the build system with executing msbuild, setting up directories, executing tests, running post build tools, etc.

PSake handles those well, since the execution environment is the command line. The syntax is nice, just enough to specify tasks and dependencies, but everything else is just pure command line. The following is Rhino Mocks build script, using PSake:

properties { 
  $base_dir  = resolve-path .
  $lib_dir = "$base_dir\SharedLibs"
  $build_dir = "$base_dir\build" 
  $buildartifacts_dir = "$build_dir\" 
  $sln_file = "$base_dir\Rhino.Mocks-vs2008.sln" 
  $version = ""
  $tools_dir = "$base_dir\Tools"
  $release_dir = "$base_dir\Release"

task default -depends Release

task Clean { 
  remove-item -force -recurse $buildartifacts_dir -ErrorAction SilentlyContinue 
  remove-item -force -recurse $release_dir -ErrorAction SilentlyContinue 

task Init -depends Clean { 
    . .\psake_ext.ps1
    Generate-Assembly-Info `
        -file "$base_dir\Rhino.Mocks\Properties\AssemblyInfo.cs" `
        -title "Rhino Mocks $version" `
        -description "Mocking Framework for .NET" `
        -company "Hibernating Rhinos" `
        -product "Rhino Mocks $version" `
        -version $version `
        -copyright "Hibernating Rhinos & Ayende Rahien 2004 - 2009"
    Generate-Assembly-Info `
        -file "$base_dir\Rhino.Mocks.Tests\Properties\AssemblyInfo.cs" `
        -title "Rhino Mocks Tests $version" `
        -description "Mocking Framework for .NET" `
        -company "Hibernating Rhinos" `
        -product "Rhino Mocks Tests $version" `
        -version $version `
        -clsCompliant "false" `
        -copyright "Hibernating Rhinos & Ayende Rahien 2004 - 2009"
    Generate-Assembly-Info `
        -file "$base_dir\Rhino.Mocks.Tests.Model\Properties\AssemblyInfo.cs" `
        -title "Rhino Mocks Tests Model $version" `
        -description "Mocking Framework for .NET" `
        -company "Hibernating Rhinos" `
        -product "Rhino Mocks Tests Model $version" `
        -version $version `
        -clsCompliant "false" `
        -copyright "Hibernating Rhinos & Ayende Rahien 2004 - 2009"
    new-item $release_dir -itemType directory 
    new-item $buildartifacts_dir -itemType directory 
    cp $tools_dir\MbUnit\*.* $build_dir

task Compile -depends Init { 
  exec msbuild "/p:OutDir=""$buildartifacts_dir "" $sln_file"

task Test -depends Compile {
  $old = pwd
  cd $build_dir
  exec ".\MbUnit.Cons.exe" "$build_dir\Rhino.Mocks.Tests.dll"
  cd $old        

task Merge {
    $old = pwd
    cd $build_dir
    Remove-Item Rhino.Mocks.Partial.dll -ErrorAction SilentlyContinue 
    Rename-Item $build_dir\Rhino.Mocks.dll Rhino.Mocks.Partial.dll
    & $tools_dir\ILMerge.exe Rhino.Mocks.Partial.dll `
        Castle.DynamicProxy2.dll `
        Castle.Core.dll `
        /out:Rhino.Mocks.dll `
        /t:library `
        "/keyfile:$base_dir\ayende-open-source.snk" `
    if ($lastExitCode -ne 0) {
        throw "Error: Failed to merge assemblies!"
    cd $old

task Release -depends Test, Merge {
    & $tools_dir\zip.exe -9 -A -j `
        $release_dir\Rhino.Mocks.zip `
        $build_dir\Rhino.Mocks.dll `
        $build_dir\Rhino.Mocks.xml `
        license.txt `
    if ($lastExitCode -ne 0) {
        throw "Error: Failed to execute ZIP command"

It is about 50 lines, all told, with a lot of spaces and is quite readable.

This handles the same tasks as the old set of scripts did, and it does this without undue complexity. I like it.



And there goes your ability to build on mono. Of course, if they'd fix xbuild so that it actully worked...



There is a cross-platform powershell implementation based on the 1.0 release available:


I have not used it (caveat emptor); however it is reported to support the entire 1.0 language and syntax set. The items that are not supported are the windoze-specific items, like WMI.

John Teague

you can use ruby + rake without requiring Ruby to be installed. AllInOneRuby packages Ruby and your Gems into an executable. Ruby+Rake is about 3mb.

Jeremy B

Out of curiousity -- how many lines would that have been in C#?

Going through reworking our current build system at work, I keep wondering if it wouldn't be more straightforward to write the majority of the build in C# and have a very small script that built that project and ran it...

Added benefit is people don't have to grok a different language like Ruby, msbuild, nant, powershell to use it.

Ayende Rahien


Compiling on Mono is not a priority for me.

When it does, I'll take care of it.


Psake is actually smaller & easier, I find.

Ayende Rahien


Probably not that much longer, but using the shell is much easier than a programming language. Most of the tools already have command line interface

Sean Scally

I think I still prefer the rake solution because it includes everything you need. When you need shell constructs, they're available in rake. When you need programming constructs, they're also there right in the buildfile, instead of having to use one language to sew up a patchwork quilt of shell scripts in a 2nd language and 3rd party tools in yet a 3rd language.

Mike Brown

I've been intrigued by powershell for some time now. From what I read ,the pipe structure is very powerful because you're piping .NET objects instead of just strings.

I'd imagine that the PSake tasks are defined as commandlets allowing you to define new tasks in C#.

Tobin Harris

I'm currently having some success with IronRuby + Rake (click my link to see recent blog post about that).

I like the fact that you easily can write Rake tasks that manipulate your own .NET business or utility objects. The downside of IronRuby is the extra dependency and it's still a touch slow.


@Ayende If/when compiling on Mono becomes a priority for you and you go to take care of it, what will you do? Do you reckon it will be easy enough to add Mono as a psake target, or do you expect you might have to change build systems?

(I have no interest in powershell, but after a cursory look at psake.ps1 it seems to me that adding Mono support might not be too difficult.)

Ayende Rahien


PowerSheel is a programing language

Ayende Rahien


I have absolutely no idea, it wasn't necessary so far

Ayende Rahien


No idea, I apply YAGNI here.

There is small enough infrastructure that I don't really worry about this


I like psake and have used it, but I already had some "owie" moments where psake did something unexpected. The next time I need a build script, I'll just do raw PowerShell--the only thing I'm losing is the task dependency management, which isn't a loss to me--tasks can be reformulated as function calls (or maybe cmdlets, I haven't thought this through much). Instead of making tasks dependent on each other, you'd just call the function.

I haven't totally thought through this, but it seems like dependency management for tasks isn't necessary for build scripts.


Also Sean, PowerShell is a great dynamic language, and you're only going to miss Ruby's OO-ness. If you're writing scripts, I'd say all the little touches done for PowerShell make it superior to Ruby.

As for the OO-ness, PowerShell has the ability in PowerShell V1 to add members and methods to an object at runtime via the add-member cmdlet, but it's verbose and all an object's members are public, so I acknowledge this isn't ideal. I've abused the add-member cmdlet here: www.pseale.com/.../...terScriptingGamesEvent5.aspx

PowerShell V2 lets you write C# classes inline in your PowerShell scripts that can be compiled and instantiated like any other .NET object. I haven't used this feature so I won't vouch for it.

Ayende Rahien

If I need to write OO code to handle my build, I already lost

Chris Bilson

You can still build using the mono tools on windows, and guess what: mono can even use assemblies not built using the mono tools. Even if you cared about building Rhino Tools for mono, whether or not to use powershell in your build is the least of your concerns.

Any idea when/if you are going to put this in Rhino-Tools? I recently started using psake and would like to take a look at your psake_ext.ps1. How come you dot-sourced it and didn't just "include" it?

Chris Bilson

You can just:

include psake_ext.ps1

But then you need to put all your functions in global:, which kind of sucks. See groups.google.com/.../7fc875b5dca3502b7

Not that there are any advantages to include, I guess, other than it seems a little more readable.


What problem do you have building WPF apps with NAnt? I'm using VS2008, MSBuild and NAnt to build a WPF ClickOnce app quite successfully at the moment. Perhaps I'm missing something.

Ayende Rahien


You said it, you are using MSBuild & Nant to build it.

Ayende Rahien


Just tried include, and it didn't work, I guess it isn't bringing it to the local scope or something like that.

Ayende Rahien

Okay, figured it out, it depends where you put it.

When I put it in a task, it didn't work


Re Nant & MSBuild, you are also using psake and msbuild right now, I don't see a difference. It's now like you had to create another xml file to configure msbuild.

Comment preview

Comments have been closed on this topic.


  1. The worker pattern - about one day from now

There are posts all the way to May 30, 2016


  1. The design of RavenDB 4.0 (14):
    26 May 2016 - The client side
  2. RavenDB 3.5 whirl wind tour (14):
    25 May 2016 - Got anything to declare, ya smuggler?
  3. Tasks for the new comer (2):
    15 Apr 2016 - Quartz.NET with RavenDB
  4. Code through the looking glass (5):
    18 Mar 2016 - And a linear search to rule them
  5. Find the bug (8):
    29 Feb 2016 - When you can't rely on your own identity
View all series


Main feed Feed Stats
Comments feed   Comments Feed Stats