There are a few times when you want to do a mass search-and-replace on your workspace mappings.

  • Change a drive letter
  • created a workspace with tf workspace /new /template and need to change the paths
  • rearranging source trees
  • Moving your workspace from one area in the source tree to another (kinda like "svn switch")

What a lot of people do today is to copy-paste from the workspace editing UI, do the search-and-replace in a UI like gvim or notepad, and then paste back into the UI.  Most of the time this works fine.  However, it's also the kind of thing that is pretty straightforward to do in PowerShell.

This also gives us an opportunity to leverage the get-workspace.ps1 script that's already doing the heavy lifting of getting the TFS version control workspace instance.  Letting it do that bit of work for us, we just need the logic to build up the new mappings and then use the object model to update the workspace (if any of the mappings indeed need to change).

Interesting things to note:

  • We're using the WorkingFolder ctor that includes the mapping type - this is important to make sure cloaks stay cloaks, for instance
  • We're doing the search and replace on both the local and server paths (server path changes in case there's been a rename or you want to work on a different branch or whatever)
  • We're leverage WorkingFolder's overload of Equals so we can do direct equality checks to see whether the new and old mappings "match"

I really like it as an example of leveraging the heavy lifting of get-workspace.ps1.  Hopefully it'll serve as an example to inspire others. :)

 

param(
  $workspace = $(throw 'must specify a workspace'),
  [string] $search = $(throw 'need a search string'),
  [string] $replace = $(throw 'need a replace string')
)

[void] [reflection.assembly]::loadwithpartialname("Microsoft.TeamFoundation.VersionControl.Client")

if ($workspace -is [string])
{
    $workspace = get-workspace $workspace
}

if ($workspace -isnot [microsoft.teamfoundation.versioncontrol.client.workspace])
{
    throw 'Must specify workspace as an instance of Workspace or a string that works with get-workspace'
}

[microsoft.teamfoundation.versioncontrol.client.workingfolder[]] $newMappings = @()
foreach ($existingMapping in $workspace.Folders)
{
    trap { 'Failure during creation of new mapping - check your search and replace strings'; break; }
    $newMapping = new-object 'microsoft.teamfoundation.versioncontrol.client.workingfolder' `
        ($existingMapping.ServerItem -replace $search,$replace), `
        ($existingMapping.LocalItem -replace $search,$replace), `
        $existingMapping.Type
    if ($existingMapping -ne $newMapping)
    {
        write-host ('Changing {0}={1} to {2}={3} [{4}]' -f
            $existingMapping.ServerItem, $existingMapping.LocalItem,
            $newMapping.ServerItem, $newMapping.LocalItem, $newMapping.Type)
        $needToUpdate=$true
    }
    else
    {
        write-host ('Keeping {0}={1} [{2}]' -f
            $existingMapping.ServerItem, $existingMapping.LocalItem, $existingMapping.Type)
    }
    $newMappings += $newMapping
}

if ($needToUpdate)
{
    $workspace.Update($workspace.Name, $workspace.Comment, $newMappings)
    write-host "Successfully updated mappings for workspace $($workspace.DisplayName)"
}
else
{
    write-host 'No mappings changed'
}