You can tell from my recent blog posts that I'm spending a good deal of time in my SCM role at work.  I've recently been looking at using powershell scripts to replace some binary hooks that have become dated, and to expand our repository's integration with our bug tracking system.  All in all it was pretty simple, but a few gotchas held me up:

First, SVN hooks have to be directly executable (e.g., .exe, .bat., .com, .cmd, or windows script files); powershell scripts are not directly executable for security reasons, so I had to use a batch script as a proxy.  

Second, SVN invokes the hooks with an empty environment (again for security purposes); without an active PATH variable specified, the batch and powershell scripts need to specify full paths to all files.

Finally, some hooks, such as the post-revprop-change hook, read data from STDIN, but the proxy batch file will not forward its STDIN to the powershell process without some intervention.  

Here is the batch proxy for the post-revprop-change hook:

rem   =====================================================================
rem    %  Argument     Description
rem   --- ------------ ----------------------------------------------------
rem   [1] REPOS-PATH   (the path to this repository)
rem   [2] REV          (the revision that was tweaked)
rem   [3] USER         (the username of the person tweaking the property)
rem   [4] PROPNAME     (the property that was changed)
rem   [5] ACTION       (the property was 'A'dded, 'M'odified, or 'D'eleted)
rem   [STDIN] PROPVAL  ** the old property value is passed via STDIN.
rem   ---------------------------------------------------------------------

c:\windows\system32\windowspowershell\v1.0\powershell.exe -command "$input | d:\repository\hooks\postrevprop.ps1" -args "%1" "%2" "%3" "%4" "%5"

A few things to note:

  • I'm using full paths to the powershell executable and the powershell script; this is necessary because the batch file will be run with an empty environment and no PATH to search.
  • I'm not really executing the powershell script, I'm executing a command string that passes the implicit $input variable to the powershell script.  This $input variable resolves to the STDIN for the batch proxy, and enables the powershell script to read it.
  • Because my command string invokes a script file, I need to make sure that the powershell execution policy is set to RemoteSigned or Unrestricted on the SVN server.    

Here is the powershell script invoked by the batch file proxy:

param( $repo, $rev, $user, $propname, $action );
@($repo, $rev, $user, $propname, $action) + $input
    | out-file "d:\repository\hooks\log.txt" -append

The script doesn't do much at the moment - just logs the hook parameters and input to a file so I can verify that the script is executing correctly.  Now that I have ironed out the major wrinkles, I can start porting our hooks to powershell!