Reusable Commands
One of the most important ideas in PowerShell is the Get/Update/Set pattern. A clear delineation between resources (nouns) and commands (verbs) helps to write code that is useful not only for scripting, but also in the interactive shell.
We only need a couple of new commands. First we need to Find
the working copies under some directory, then Update
each working copy. The list of approved verbs for PowerShell is a great resource for help with naming your commands. Let's use these names.
- Find-SvnWorkingCopy (
Find
looks for an object in a container)
- Update-SvnWorkingCopy (
Update
brings a resource up-to-date)
Functions and Modules
Now you're convinced that we should create reusable commands with these great new names. What next? PowerShell v2 introduced the concept of a module, which is just a file that contains functions. (Of course, you could just create a new script for each command but it helps to keep things tidy by bundling all of the functions together in one file.)
What should our functions look like? Yes they will need to take some parameters. But more importantly, they should return objects to the pipeline, even if they aren't a "getter" function! This makes it easier to review what impact a function had.
Some actual code
Luckily for us, somebody else already found a way to find all the svn working copies underneath a directory. We can reuse that.
SvnTools.psm1
function Find-SvnWorkingCopy
{
Param (
[Parameter(ValueFromPipeline=$true,Mandatory=$true)]
$BasePath
)
process
{
$prev = "^$"
Get-ChildItem -Recurse -Force -Include ".svn" -Path $BasePath |
Where-Object {
$_.PSIsContainer -and $_.Fullname.StartsWith($prev)-eq $false
} |
ForEach-Object {
$prev=$_.Fullname.TrimEnd(".svn")
$prev
}
}
}
I took some liberties with the command Update-SvnWorkingCopy
. In addition to calling "svn update" like your original script, it also calls "svn info" and parses the results to find the current revision number and include that in the object returned to the pipeline.
SvnTools.psm1 (continued)
function Update-SvnWorkingCopy
{
Param (
[Parameter(ValueFromPipeline=$true,Mandatory=$true)]
$WorkingCopy
)
process {
svn update $WorkingCopy > $null
[String[]] $result = svn info $WorkingCopy
[String] $revStr = $result -like "Revision:*"
[int] $revNumber = $revStr.Replace("Revision: ", "")
New-Object -TypeName PSObject -Prop @{
WorkingCopy=$WorkingCopy;
Revision=$revNumber;
} | Write-Output
}
}
Now we can reap the benefits from creating these commands. Here's your original script, rewritten to take advantage of our new module using just one line.
UpdateMyWorkingCopies.ps1
Import-Module C:\path\to\module\SvnTools.psm1
Find-SvnWorkingCopy -BasePath "C:\TRUNK\" | Update-SvnWorkingCopy
You could easily redirect the output to a file. If you don't, it will show up on screen looking something like this.
WorkingCopy Revision
----------- --------
C:\TRUNK\Alpha 31
C:\TRUNK\Bravo 42
C:\TRUNK\Charlie 16
References
The Scripting Guy! blog on TechNet has a really excellent series about building your own PowerShell cmdlet that I recommend reading.
Coding Style
Bonus Points
For bonus points, install the module into one of the module path folders ($env:PSModulePath
) so that you can import it from the shell more easily.
And if you want to get even more fancy, implement another command called Get-SvnWorkingCopy
which parses all of the results from svn info
. It should integrate nicely with the two commands we already created here.