Browsing Posts in Miscellaneous

I spent some time troubleshooting a Subversion failure. I created a new repository using CreateSvnRepo.ps1 and successfully fetched the contents using TortoiseSVN. I added some files and then tried to commit the changes, but I got this highly cryptic error message:

Error: Commit failed (details follow): 
Error: Authorization failed 

The causes of this generic error are many and varied. So googling did not pinpoint the problem. I tried turning authorization off in the conf\svnserve.conf. Same result.

Now that was really odd. I turned off authorization, but authorization was still failing for writes. After a bit of head scratching, I noticed this:


Thank you Notepad2! The character encoding was set to Unicode and svnserve.exe was choking silently on the encoding. Without a readable svnserve.conf, it was using defaults, which allow anonymous reads, but not writes. That’s why I was able to fetch the repository, but not write to it. Switching the character encoding to ASCII solved the problem. Here is the offending line in the PowerShell script:

“[general]`r`nanon-access=none`r`npassword-db=../../passwd`r`nrealm=Default`r`n” > $repoConfigFile

Once I updated the command to specify the character encoding, everything was good for creating new repositories too.

“[general]`r`nanon-access=none`r`npassword-db=../../passwd`r`nrealm=Default`r`n” | Out-File -filePath $repoConfigFile -encoding ASCII

You can grab the updated version of CreateSvnRepo.ps1 here.

Let me wrap up by saying that I like Subversion, but its failure modes leave something to be desired. It would have been more helpful to fail with an unreadable svnserve.conf than ignoring the file and using defaults. Even better would be if it understood Unicode configuration files.

Having done this a few times before and always ending up scouring the documentation regarding exactly how to enable the options I need, I’m hereby committing it to long-term memory…

Subversion 1.4.0 and later support running Subversion directly as a Windows Service. This allows you to access your repository via TortoiseSVN, svn.exe, etc. using:


You can find information in the Subversion FAQ as well as a link to a document describing exactly how to set it up. There is no tool provided to configure the Windows Service. So you’re stuck using sc.exe, the Service Control command line tool, which ships with various versions of Windows. It is rather quirky, even for command line tools. Note that the name/value pairs are “Name=” followed by a space followed by “Value”. The equals sign is part of the name and won’t work if the equals sign is omitted or if you insert a space before the equals sign.*

Here’s how I typically configure Subversion to run as a service:

sc create <ServiceName> binPath= “\”<PathToSvnBin>\svnserve.exe\” –service -r <SrcRepoRoot>” DisplayName= “Subversion Service” depend= Tcpip start= auto obj= <Computer or Domain\ServiceAccount> password= <Password>


<ServiceName> is the name of the service (as used in commands such as net stop <ServiceName>).

<PathToSvnBin> is the fully-qualified path to svnservce.exe. N.B. You have to surround it with \” to escape the path if it contains spaces.

<SrcRepoRoot> is the fully-qualified path to the directory that contains all your repositories.

<ComputerOrDomain\ServiceAccount> is the user account under which you want to run the service. You need to include the computer or domain name (depending on if it’s a local or domain account, respectively).

For my environment, it ends up looking like this:

sc create svnserve binPath= “\”C:\Program Files\Subversion\bin\svnserve.exe\” –service -r c:\SrcRepos” DisplayName= “Subversion Service” depend= Tcpip start= auto obj= Server\SvnDaemon password= P@ssw0rd

I usually use a local computer account, SvnDaemon, for running my repositories. After creating the account, I remove it from the Users group. By removing the account from Users, no one can log in using that account and it also removes it from the main log-in screen in Windows XP and Vista. In Local Security Policy… Local Policies… User Rights Assignment…, grant SvnDaemon the “Log on as a service” privilege. Explicitly grant Full Control to c:\SrcRepos.

Last thing you need to do is punch a hole in your firewall to allow connections on the standard svn port, which is TCP 3690.

Now you can start the service via “net start svnserve”. Your firewall might prompt you to grant permission for svnserve.exe to listen on the Subversion port.

Time to test. Launch the TortoiseSVN RepoBrowser and enter “svn://server/RepoName”. You should be able to now browse your repository.

* Note that PowerShell doesn’t grok the “Name=” syntax. PowerShell tries to interpret it as some sort of assignment. I haven’t bothered digging in to find out how to instruct PowerShell to treat the “Name=” literally. In the meantime, it works just fine from cmd.exe. Confused

Kenny Kerr has released Window Clippings 2.0, complete with its own website. I’ve been using Window Clippings for a few years now and it continues to be my favourite screen capture tool. Simple, efficient, elegant, and (mostly) free. He has been continuing to update it and it includes cool features like:

  • Support alpha transparency, both for windows and mouse cursors, enabling capture of non-rectangular windows.
  • Outputs to a variety of formats, including PNG, JPG, TIFF, and BMP. (Extensible through add-in model.)
  • Capturing to a variety of destinations including any combination of directory, clipboard, and OneNote.
  • Support for Aero Glass, including removing “dirty glass”.
  • 32-bit and 64-bit Windows support, including XP, Server 2003, and Vista.
  • Optional integration with PrtScn key.
  • Automatic updates.

From Day One, Kenny has provided this awesome utility free of charge. With Window Clippings 2.0, Kenny is turning this into a small business. You can download and use Window Clippings for free with all the features it had before. With 2.0, he has added some advanced features (such as post-processing PNG images and enabling add-ins) that are enabled when you buy a license. Licenses currently cost a whopping $10 USD! I have more than happily sent Kenny $10 so that he can continue development of this awesome tool.

Source control is a must when it comes to development. It doesn’t matter if you’ve got a large team of developers or if you’re the only one. You need to set up source control. For my own pet projects, I use Subversion. Simple to set up and simple to use, especially with TortoiseSVN. I’m not going to go into a long intro on how to set up and use Subversion or TortoiseSVN. There are many quickstarts kicking around the web on how to do this. You can google those as well as I can. What I am going to discuss is initial repository setup.

I usually create a Subversion repository per project. If I ever need to move a repository to another computer, I simply copy the directory containing the repository. No complicated export/import scripts required. Same is true with backup/restore. If something goes horribly wrong (which it never has, but just in case), I can retrieve the source repository from backup without affecting any other repository. The standard structure within a repository includes a number of project-level directories, including trunk, tags, and branches:

Trunk is where mainline development occurs. Most of the time, I will be working from svn://Eddings/Sample/trunk. When you create a release, I want to tag it, which involves making a copy of the files in trunk (or elsewhere) to the tags directory. For instance, using TortoiseSVN, I would Branch/Tag… to svn://Eddings/Sample/tags/v1.0. (N.B. Subversion uses a copy-on-write mechanism so that I’m only storing one copy of a file, even if I tag/branch it multiple times. It also uses a binary differencing mechanism to keep the repository small. So if I add a 10 MB binary file to my repository, change a few bytes, and push my changes back into the repository, the space occupied by the file will be 10 MB plus the few bytes of changes plus some versioning information.) Branches is exactly the same as tags, except it is typically used as temporary scratch space for changes that will later be merged into trunk or tags. For instance, let’s say I released v1.0, which is tagged. I am working on v2.0 in trunk, but I need to make a bug fix in v1.0. I branch v1.0 into branches/v1.0-Remediation and make the fix. When I’m ready to release, I tag branches/v1.0-Remediation as tags/v1.01 and delete branches/v1.0-Remediation. I will probably reverse integrate the bug fixes into the trunk.

Typically I also point my new repository to a globally-maintained user list. (Unfortunately Subversion doesn’t integrate with Windows auth out-of-the-box. I believe you can do it, but you need to run Subversion under Apache. More trouble than it’s worth for a single developer, in my opinion.) So there’s another manual step…

The main take-home message is that when I create a new repository, there is a bunch of initial setup that needs to be done. Why not automate it? I wanted to learn PowerShell and this seemed like a good mini-project to do it on. This is based on my own exploration of PowerShell and there might be better ways of doing things in PowerShell. So your mileage may vary. Don’t take this as gospel or best practices, but as one man’s fumblings through learning PowerShell.

Why PowerShell?

First question is why do we have scripting environments in the first place. Usually it’s because we need to glue together a bunch of commands to do something more complex. The complexity doesn’t warrant a full-fledged application and we want to be able to change it easily. Scripting to the rescue. It’s the main reason we’ve had the Windows Command Shell and the Windows Scripting Host on the Windows platform and bash, ksh, tcsh, … on Unix platforms.

Next question… Why PowerShell and not something with more sex appeal like Ruby? PowerShell has an attraction for me because it targets the .NET platform. 90% of learning a new environment is learning the libraries. PowerShell lets me leverage my .NET knowledge in a scripting environment. Maybe I’ll learn Ruby one day, but Ruby is a one-trick pony in my opinion — specifically Ruby on Rails. RoR is one hell of a trick for web applications, but I’m not ready to learn a whole new set of libraries just to write web apps. I don’t like web applications that much! Tongue out

Just like bash, ksh, tcsh, and other command shells before it, PowerShell lets me glue together simpler commands to create complex scripts. The Unix shells did this by having standard mechanisms to pipe the results of one command to the input of another, but everything is text. This means that each command requires its own parsing routines to handle the incoming text. PowerShell communicates between cmdlets using .NET objects. No more dealing with raw strings. Now I can examine objects, query them using reflection, or use them to perform actions. Cool stuff!

Getting Started with PowerShell

There are a number of good references for PowerShell that you should definitely keep close at hand.

I’m not going to walk through all the features of PowerShell as others have already done that. What I will do is discuss how I solved different pieces of the puzzle in building a script to create a new Subversion repository. Let’s look at the script piece-by-piece.

Execution Policy

Before we can execute a PowerShell script, we must modify execution policy. By default, PowerShell ships in a locked-down mode that prevents scripts from running. You can execute cmdlets at the PowerShell prompt, but you can’t execute “.ps1″ files containing scripts. To enable running script files, open a PowerShell prompt and execute:

Set-ExecutionPolicy unrestricted

Note that PowerShell features cmdlet completion using the tab key. So typing set-e[TAB] will auto-type the rest for you. If there are multiple cmdlets with the same name, you can tab multiple times to cycle through the options. You can even use wildcards to pattern match cmdlets and cycle through matching cmdlets using tab.


PowerShell code is in green. Discussion is in black. A discussion of implementation details are after each section of code. I’m not going to discuss the purpose of each section as that is noted in the comments heading each major section.

# CreateSvnRepo v1.2
# Copyright © 2007 by James Kovacs
# All rights reserved.

Just an informational header. Comments in PowerShell are denoted by the hash (#) sign.

# Check usage
If($args.Length -ne 1) {
  Write-Host "Usage: .\CreateSvnRepo.ps1 "
  Write-Host "  where RepoName is the name of the new repository"
  Write-Host "N.B. RepoName cannot accept a file path or url."
  Write-Host "     CreateSvnRepo assumes that svn and svnadmin are in your path."

We need to check the command line arguments and possibly print usage information. The script expects to be called like this:

.\CreateSvnRepo.ps1 <RepoName>

where RepoName is the name of the new repository.

Variables in PowerShell are prefixed by $. There are a few default variables such as $args, which is the command line arguments. (N.B. Like in .NET, the executed script is not included in the list of arguments.) $args is a string[] and we can check its Length property, just like in C# or VB.NET. Comparison operators in PowerShell do not use conventional operator syntax, but instead use “dash” syntax. For instance, -ne is not equal, -eq equal, -gt greater than, -ge greater than or equal, -lt less than, -le less than or equal, etc. There are also bitwise, matching, and type comparison operators as well as case-insensitive versions where appropriate. See Comparison Operators in the PowerShell Quick Start for a full list.

Write-Host serves the same purpose as Console.WriteLine. Notice that cmdlet calls do not use parentheses to denote arguments as this matches the flavour of calling commands in scripting environments. Also note the standard syntax used for cmdlets, which is VERB dash SINGULAR NOUN. Even if you expect multiple items, the singular noun is used. For instance, to get a list of running processes, execute Get-Process. Cmdlets are case-insensitive.

# Set up variables needed by script
$newRepoName = $args[0]

Variables are created when they are assigned. We do not have to explicitly set the type of a variable, though we can by prefixing the variable with [type]. For example, [int]$i = 42.

$currentWorkingDir = (Get-Location).Path.Replace("\", "/")

Get-Location is a cmdlet that returns the current working directory as a System.Management.Automation.PathInfo object. To execute the cmdlet and get its result, we wrap the cmdlet in parentheses. Without the parentheses, PowerShell assumes we’re looking for a cmdlet or executable named Get-Location.Path.Replace. (This is because executables often have names such as DoStuff.exe.) Once we have a PathInfo object, we can examine its Path property. Notice that the Path property returns a string and we can perform normal .NET string operations on it, in this case changing backslashes to slashes since svnadmin (the Subversion command for creating repositories) uses Unix-style path separators.

Speaking of Unix, PowerShell includes a lot of Windows and Unix aliases. Aliases are names that execute cmdlets, possibly with parameters. For instance, both “dir” and “ls” actually execute “Get-Item *”. An alias for Get-Location is “pwd” or print working directory, which should be familiar to all Unix-heads. Get-Alias lists all the currently defined aliases and Set-Alias allows you to add or modify an alias.

$newRepoSvnPath = "file:///$currentWorkingDir/$newRepoName"

There are two types of strings in PowerShell, expanded and non-expanded strings. Single-quotes are used to denote non-expanded strings, similar to string literals in C# using @”No special characters here”. Double-quotes are used to denote expanded strings. Any variables in the string are replaced with their value. So if $fortyTwo = 42, then ‘The answer to life, the universe, and everything is $fortyTwo’ has the value The answer to life, the universe, and everything is $fortyTwo whereas “The answer to life, the universe, and everything is $fortyTwo” has the value The answer to life, the universe, and everything is 42.

$repoConfigFile = Join-Path $newRepoName 'conf\svnserve.conf'

Join-Path performs the same function as System.IO.Path.Combine in that it saves you from having to worry about whether the strings have directory separators in the correct places.

$tempPath = [System.IO.Path]::GetTempPath()
$tempDirName = [System.IO.Path]::GetRandomFileName()

Here I need to access some static methods for which there is no equivalent cmdlet (as far as I know). We identify the type using square brackets followed by :: and the name of the static method.

$workingCopy = Join-Path $tempPath $tempDirName
$dirNames = 'branches', 'tags', 'trunk'

The only new thing here is that we’re creating an array of strings. Nothing special, just comma-separate the objects and assign them to a variable.

# Ensure that we were passed only a repository name and not a path
$invalidChars = [System.IO.Path]::GetInvalidFileNameChars()
If($newRepoName.IndexOfAny($invalidChars) -ne -1) {
  Write-Host "You must specify a valid repository name. It cannot be an absolute or relative path."

More of the same, except now we’re calling a method on $newRepoName, which is of type System.String. This is a standard .NET method call with parameters. So we use parentheses around the arguments, as you can see in the call to IndexOfAny. This is the main difference between calling cmdlets and calling methods on objects.

# Ensure that repository doesn't already exist
If(Test-Path $newRepoName) {
  Write-Host "Error: Repository, $newRepoName, already exists."

Here’s a new cmdlet, Test-Path, that will let us know if the path already exists or not.

The help system in PowerShell is quite useful. You access via Get-Help (or the shorter alias, help). Get-Help cmdlet will give you information on a command. Get-Help Get-Help gets help on the help system itself! Get-Help accepts wildcards. So if you want to find out everything you can do with Paths, type Get-Help *-Path. If you want to find everything you can Set, type Get-Help Set-*. This is an excellent way to poke around and find out more about available cmdlets.

# Create directory to hold the new repository
Write-Host "Creating new repository: $newRepoName"
New-Item -path . -name $newRepoName -type directory

We’re using the New-Item cmdlet, but this time we’re using named parameters. New-Item can be used to create directories, files, registry keys, and more. PowerShell uses a provider model. So as long as there is an appropriate provider, you can interact with any information store. Anyone can create a provider to extend the functionality of PowerShell. For instance, people are implementing (or have implemented) PowerShell providers for Subversion, Newsgator, SharePoint 2007, …

If(!(Test-Path $newRepoName)) {
  Write-Host "Unable to create directory, $newRepoName. Verify that you have permission to create this directory."

We can use ! or -not to negate a boolean value. Here we want to make sure that we successfully created the directory.

# Create the repository
svnadmin create $newRepoName

Svnadmin is an executable that ships with Subversion. It is used for creating repositories, among other things. I execute it just like I would from the command line. The only trick is that I’m passing it the value of a PowerShell variable.

# Clear repo configuration directory
$configFiles = Get-ChildItem -path $repoConfigDirectory
ForEach ($configFile in $configFiles) {
  Remove-Item -path $configFile.FullName
# Overwrite configuration file to point to global password directory
"[general]`r`nanon-access=none`r`npassword-db=../../passwd`r`n`r`nrealm=Default`r`n" | Out-File -filePath $repoConfigFile -encoding ASCII

Now we’re entering territory that is usually reserved for Perl-heads. (If you’ve ever read Perl code, you’ll know what I’m talking about.) I’m creating an expanded string (denoted by double quotes) that includes escaped character sequences, which are denoted by the back tick (`). I find the back tick a bit odd to read, but it has the advantage that you don’t have to escape slashes, which are used as path separators. So `r`n is a carriage return/line feed, equivalent to \r\n in most curly-brace languages. Next we write the string to a file by piping the string to Out-File. I set the encoding to ASCII since svnserve.exe doesn’t like Unicode encoding, which is the default. If you want to write Unicode text, you can out the output redirection operator (>). If you want to append to the file rather than overwrite, use the >> operator.

# Create a temporary working copy so we can commit initial setup in one go
Write-Host "Creating temporary working copy in $workingCopy"
New-Item -path $tempPath -name $tempDirName -type directory
svn checkout --non-interactive $newRepoSvnPath $workingCopy

Nothing interesting here. We’re just checking out a working copy into a temporary directory. Svn.exe is the main command line tool for Subversion that allows us to perform checkouts, updates, commits, branches, and a myriad of other operations. I typically use TortoiseSVN for performing these operations, but svn.exe is good when you need to script things. There are numerous ways I could have interacted with Subversion (Scott Hanselman has some other suggestions), but I wanted the one with the least dependencies. (i.e. You just need PowerShell and Subversion installed.)

Write-Host "Creating directories in working copy"
ForEach ($dirName in $dirNames) {
  $path = Join-Path $workingCopy $dirName
  svn mkdir $path

The only thing new here is the ForEach keyword, which does what you’d expect and iterates through the string[] of $dirNames.

# Commit changes to the repository
Write-Host "Committing changes"
svn commit $workingCopy --message "Initial repository setup"

Once again, we’re just executing svn.exe to commit our newly created directories to the repository.

# Perform cleanup
Write-Host "Cleaning up working copy"
Remove-Item -path $workingCopy -recurse -force

Lastly we clean up the mess of temporary files and directories that we created.

So that’s it. A simple PowerShell script that quickly creates a new Subversion repository for whichever pet project I’m working on. I honestly haven’t even scratched the surface of what PowerShell can do. Hopefully this gives you some ideas and a starting place for your own PowerShell scripts. Honesty the biggest benefit of PowerShell for .NET developers is that it lets us seamlessly leverage the .NET Framework. Not having another API to lug around in my head is a good thing and makes me more productive right away.

Feel free to modify the script to your heart’s content to suit your own environment. The full script can be found here.

UPDATE: Corrected the encoding of the svnserve.conf to use ASCII encoding.

Ever had the trial version of an application run just fine, but fail horribly when you register a license key? I’ve had this happen with two different and completely unrelated software products – FLStudio (awesome music authoring application) and FinalBuilder (a NAnt/MSBuild replacement). In both cases, the cause was a Data Execution Prevention (DEP) violation. (DEP is on by default in 64-bit versions of Windows, which is why it is most often encountered there. On 32-bit Windows, DEP is enabled only for critical operating system files, though it is simple to turn it on for all files.) I suspect that the licensing scheme generates code from the license key, which is then executed. The code will be generated in a data region, which is marked with the NX (No eXecute) flag on modern processors. When a modern processor tries to execute code in a portion of memory marked with the NX flag, DEP kicks in and tears down the process. The rationale behind this is that you’re not supposed to be executing data! (Apologies to the LISP folks out there.) If you need to dynamically generate code on the heap, clear the NX flag to mark it as executable.

Now you may be wondering about the .NET Framework because the CLR takes MSIL and JITs it to native code, which lives on the unmanaged heap. The CLR clears the NX flag for the regions of the heap where JIT’d methods live. The same applies to JVMs in the Java world and any other JIT’d language.

The Fix

If you’re an end user, there is no (easy) way to mark the generated code as executable. (I suppose you could hook a debugger up to the process every time you launch the application and manually clear the NX flag in the correct region. Thanks, but no.) So the solution is to exempt the executable in question from data execution prevention (DEP). On Vista, go to Computer… Properties… Advanced system settings… Performance Settings… Data Execution Prevention tab… and add the EXE to the exception list. (You should find the DEP tab in a similar place on Longhorn Server, Windows XP SP2, and Windows Server 2003.) The process doesn’t have DEP protection, but at least you can run it.

The Real Fix

If you actually wrote the software, you can really fix the issue. You must clear the NX bit in the regions where you generate code to prevent DEP from tearing down your process. Rather than using malloc or HeapAlloc, you must use VirtualAlloc or VirtualProtect with one of the following flags: PAGE_EXECUTE, PAGE_EXECUTE_READ, PAGE_EXECUTE_READWRITE, or PAGE_EXECUTE_WRITECOPY.

Why Malware Can’t Sidestep DEP

Now you may think that this opens a security hole. Can’t malware simply clear the NX flag itself? Let’s walk through the hypothetical exploit:

  1. You have an unexploited application with an undiscovered buffer overflow bug.
  2. Your application gets a malformed request attempting to exploit the bug.
  3. The buffer is overflown and return address of the current function is set to somewhere in the buffer. (This is how a typical buffer overflow exploit occurs.)
  4. The processor tries to execute the data in the buffer, which would contain the attack code. The buffer is marked NX because it is part of the current thread’s stack (or less often, the heap).
  5. DEP kicks in and tears down the process.

At no time has the attacker’s code been given a chance to run. The only way that the attacker’s code could run and call VirtualAlloc/Protect is if your code called VirtualAlloc/Protect on the buffer, which would be a pretty silly thing to do. So if malware can call VirtualAlloc/Protect, it can already run code in your process and do much worse things than dynamically generate code and mark it as executable.

Hopefully this helps some folks solve mysterious licensing failures and software authors make their code work on DEP-enabled systems, which are being more and more common.

For those of you who noticed, my site was down for the past week due to hardware and DNS issues. To avoid similar problems in the future, I’ve moved my hosting to During the move, I encountered some “technical difficulties” – namely DasBlog not running in a medium trust hosting environment. (Running ASP.NET in full trust mode in a shared web hosting environment is a plain bad idea.) GoDaddy’s support staff were excellent – friendly, knowledgeable, and courteous. I was able to upgrade from shared web hosting to a virtual dedicated server by just paying the difference. (It was either that or port everything to SubText, which does run in medium trust. I didn’t have the time to undertake that at the moment.) Anyway, I’m back and blogging. I now return you to your regularly scheduled program…

Congratulations to Jean-Paul Boodhoo on his well-deserved Microsoft MVP award! Couldn’t have happened to a nicer guy and more awesome dev. Welcome to the club, Jean-Paul.

Well, Bil Simser has tagged me, which means that I’m it. The basic gist of this blog game/chain letter is that I have to tell you five things that you probably wouldn’t know about me. As a reward, I get to pick five other hapless blogging souls who must then do the same.

  1. I am a long-time vegan and avid chef. I taught cooking classes for a number of years while living in Boston. I even got featured on the front page of the Somerville Journal, North America’s oldest newspaper.
  2. I’ve been playing the saxophone for about 20 years and have been in various jazz bands, big and small. I can carry a tune, but I’m not giving up my day job. (I take full responsibility for the “musical interludes” that grace Plumbers @ Work.)
  3. I have a Masters degree in Physical Chemistry from Harvard University. Although my business cards say “M.Sc.”, it’s actually an “A.M.” or Artus Masterus, which is Latin for Master of Arts. It’s easier to write “M.Sc.” than explain to everyone that Harvard gives out an “A.M.”, which is equivalent to every other university’s M.Sc.
  4. I love games. I collect European-style board games. Examples include Puerto Rico, Power Grid, The Princes of Florence, and The Traders of Genoa. (i.e. Not Monopoly.) BoardGameGeek is an awesome site. I spent much of my teenage years playing AD&D, Car Wars, BattleTech, Paranoia, and similar games. I was a popular dungeon master in my high school and was president of the RPG club. (In high school, dates were a fruit that grew on trees.)
  5. Unlike Bil, I have broken a bone in my body. Many years ago, I broke a toe on my left foot in a freak cooking accident when I ducked into my pantry for a potato.

My duty is done. I pass on the gauntlet to…

A few months ago, Joanne Cummings of Redmond Magazine interviewed me regarding my thoughts on Microsoft Virtual PC and how it compares to VMWare Workstation. The article was recently published and you can find it here. Joanne did a good job capturing my thoughts on the overall advantages and disadvantages of the two products. While I’m overall quite favourable toward Microsoft software (I honestly think Microsoft does a good job in most cases and a great job in many), desktop-based virtualization is one area where they fall short. Read the article to find out more. Thanks, Joanne, for the opportunity to share my thoughts on VPC and VMWare.

I must bid a fond farewell to a fellow plumber, Dan Sellers. Today was Dan’s last day in the Big House. He is stepping into a well-deserved, early retirement. Dan and I have worked together many times over the years especially on Plumbers @ Work and more recently on the Canadian Developer Security Virtual Team. (I’ve got some posts and content coming up soon.) The developer scene in Canada will not be the same without him. Congratulations, Dan. You’ll be missed.