Powershell is a Joke

Powershell is a joke, at least as far as build systems are concerned. The concepts behind it sound great, it's billed as the one true scripting language for everything windows, but it falls flat on it's face in the real world.

I've spent a couple of days trying to setup a rather simple build. The requirements for this build are about as simple as you could hope for, compile the app, prepare the deployment, twiddle the web config and finish with an xcopy deploy.

Should be simple right? The following is a chronicle of my exasperation, with the occasional nant snippet for comparison.

Clean and Init

Managing the build directory is the "hello world" of creating a build. Just creating the build directory lead to the first gotcha:

New-Item .\build -type directory

This works fine the first time, but subsequent builds will fail because the directory exists. The force parameter is needed:

New-Item .\build -type directory -force

Apparently you have to force powershell to not create a new directory. When I create a directory, I just want to make sure it's there. Failing on an existing directory is not a sensible default. How does nant do it:

<mkdir dir="build" />

Much less cryptic. Let's move onto clean, surely an advanced scripting language can delete a directory right?

Remove-Item -path .\build\

Nope this prompts the user, exactly the sort of interactivity I don't want. I have to tell it to delete all the files first:

Remove-Item -path .\build\  -Include * -Recurse

This is the best we can do and it still has a few caveats. It will fail if the directory doesn't exist. It will also fail if explorer is open in one of the directories. It will fail the first time anyway, it will delete all files and leave the directories. The second time it will work, the third time it will fail because the directory is missing. Not the sort of consistency you want in your build system. How does nant do it?

<delete dir="build" />

Always works, doesn't fail if the directory is missing.

Copying Files

So it's not great at directories, how does it handle the next common task, copying files?

Copy-Item .\Rtg.AssetManagement.Web\* .\build\web -recurse -force

So far so good, though defaulting to recursing and overwriting existing files would make more sense in a build system. What if I only want to exclude .html files?

Copy-Item .\src\* .\build\ -recurse -force -Include ".html"

Kind of, it only copies .html files in the base directory. Likewise, exclude will only filter on the base directory:

Copy-Item .\src\* .\build\ -recurse -force -Exclude ".html"

Anything "advanced" requires getting a bit complicated (not my code, one I found online):

$exclude = @("main.js")
$excludeMatch = @("app1", "app2", "app3")
[regex] $excludeMatchRegEx = ‘(?i)‘ + (($excludeMatch |foreach {[regex]::escape($_)}) –join “|”) + ‘’
Get-ChildItem -Path $from -Recurse -Exclude $exclude |
  where { $excludeMatch -eq $null -or $_.FullName.Replace($from, "") -notmatch $excludeMatchRegEx} |
      Copy-Item -Destination {
          if ($_.PSIsContainer) {
            Join-Path $to $_.Parent.FullName.Substring($from.length)
          } else {
            Join-Path $to $_.FullName.Substring($from.length)
          }
        } -Force -Exclude $exclude

Quite frankly, I don't understand powershell enough to tell you what this is doing. It is extremely obfuscated though, especially compared to the nant equivalent:

<copy todir="build">
  <fileset basedir="src">
    <include name="*.html" />
  </fileset>
</copy>

The real kicker is that the complexity of the nant script stays relatively flat as well, multiple base directories, complicated include/exclude functionality, It all stays simple and understandable. The powershell equivalent quickly ramps up in complexity.

Not Built for Purpose

Is powershell a dud? For build purposes I would say yes. It's overly complicated, even for simple tasks, and the default behavior just does not do what I want. Compared to nant it is downright cryptic.

I can see it's usefulness, I can see why the defaults are the way they are. I can see how sys admins might make good use of it. I can see how exposing powershell endpoints to my apps could make administration easier.

It is terrible for building software though.