get-workspace.ps1 - easier access to that wonderful Workspace instance

Along with easier TeamFoundationServer access, one of the things I found myself wanting was easier access to the wonderful Workspace instance.  As before, the goal here is just to make it a little easier to get access to the instance of a useful object model class for interactive use.

Times when get-workspace will "just work" (no need to pass a hint, "$ws = get-workspace" works fine)

  • If you're sitting in a mapped dir
  • If you're sitting above a mapped dir, but the only mappings below you are to a single workspace
  • If you only have one workspace in your cache file

If none of those are the situation, you just have to pass a hint that tells us which workspace you mean, either passing:

  • A substring of the workspace name to identify the workspace OR
  • A local path that identifies the workspace (as above, either mapped or such that all the mappings under it are in the same workspace)

Also as with the TeamFoundationServer script, all these example usages are just usage of the object model - to see everything you can do, you should check the Workspace class along with others in the object model.

Path-based hint (defaults to current dir) matching multiple workspaces

C:\> $ws = get-workspace
More than one workspace matches the workspace hint "C:\": buckh2, chunks, dogfood, jmanning-dev_tsadt_1
At C:\Users\jmanning\Documents\bin\get-workspace.ps1:44 char:14
+ throw <<<< 'More than one workspace matches the workspace hint "{0}": {1}' -f

Specifying a path-based hint that uniquely identifies a workspace
C:\> $ws = get-workspace D:\dd\tsadt_2
C:\>

Specifying a name-based hint that identifies a workspace

C:\> $ws = get-workspace ao
More than one workspace matches the workspace hint "ao": jmanning-dev_TFSAO02_1, jmanning-dev_tfsao03_1
At C:\Users\jmanning\Documents\bin\get-workspace.ps1:44 char:14
+ throw <<<< 'More than one workspace matches the workspace hint "{0}": {1}' -f
C:\> $ws = get-workspace ao03
C:\>

Using the "just works" to query my pending changes

D:\dd\tsadt_2\src> $ws = get-workspace
D:\dd\tsadt_2\src> $ws.GetPendingChanges().count
6

Alternatively skipping the assignment to a var and printing out some properties of the entries

D:\dd\tsadt_2\src> (get-workspace).getpendingchanges() | fl filename,creationdate,changetype

FileName : Global.asax.cs
CreationDate : 9/21/2006 2:05:38 PM
ChangeType : Edit

FileName : DalExceptionManager.cs
CreationDate : 9/21/2006 2:05:38 PM
ChangeType : Edit

FileName : Microsoft.TeamFoundation.Common.asmmeta
CreationDate : 9/21/2006 2:05:38 PM
ChangeType : Edit

FileName : RecordLogger.cs
CreationDate : 9/21/2006 2:05:38 PM
ChangeType : Edit

FileName : TeamFoundationConstants.cs
CreationDate : 9/21/2006 2:05:38 PM
ChangeType : Edit

FileName : TeamFoundationServiceException.cs
CreationDate : 9/21/2006 2:05:38 PM
ChangeType : Edit

Pend an edit on a file (inner parens to get resolve-path to resolve as an expression)

D:\dd\Lab26VSTS_1\src> (get-workspace).pendedit((resolve-path dd.sln))
1

Undo a change

D:\dd\Lab26VSTS_1\src> (get-workspace).undo((resolve-path dd.sln))
1

Attempt undo again, show it has nothing to undo

D:\dd\Lab26VSTS_1\src> (get-workspace).undo((resolve-path dd.sln))
0

  
  
 # Script to find a Team Foundation workspace
param(
    [string] $workspaceHint = $(get-location).Path
)

begin
{
    # load the needed client dll's
    [void][System.Reflection.Assembly]::LoadWithPartialName("Microsoft.TeamFoundation.Client")
    [void][System.Reflection.Assembly]::LoadWithPartialName("Microsoft.TeamFoundation.VersionControl.Client")

    # fetches a Workspace instance matching the WorkspaceInfo found in the cache file
    function getWorkspaceFromWorkspaceInfo($wsInfo)
    {
        $tfs = [Microsoft.TeamFoundation.Client.TeamFoundationServerFactory]::GetServer($wsInfo.ServerUri.AbsoluteUri)
        $vcs = $tfs.GetService([Microsoft.TeamFoundation.VersionControl.Client.VersionControlServer])
        $vcs.GetWorkspace($wsInfo)
        # TODO: likely add some convenience properties/methods for easier scripting support
    }
}

process
{
    # is there only 1 workspace in our cache file?  If so, use that one regardless of the hint
    $workspaceInfos = [Microsoft.TeamFoundation.VersionControl.Client.Workstation]::Current.GetAllLocalWorkspaceInfo()
    if ($workspaceInfos.Length -eq 1)
    {
        return getWorkspaceFromWorkspaceInfo($workspaceInfos[0])
    }

    if (test-path $workspaceHint)
    {
        # workspace hint is a local path, get potential matches based on path
        $workspaceInfos = [Microsoft.TeamFoundation.VersionControl.Client.Workstation]::Current.GetLocalWorkspaceInfoRecursively($workspaceHint)
    }
    else
    {
        # workspace hint is NOT a local path, get potential matches based on name
        $workspaceInfos = @($workspaceInfos | ?{ $_.name -match $workspaceHint })
    }

    if ($workspaceInfos.Length -gt 1)
    {
        throw 'More than one workspace matches the workspace hint "{0}": {1}' -f
                $workspaceHint, [string]::join(', ', @($workspaceInfos | %{ $_.Name}))
    }
    elseif ($workspaceInfos.Length -eq 1)
    {
        return getWorkspaceFromWorkspaceInfo($workspaceInfos[0])
    }
    else
    {
        throw "Could not figure out a workspace based on hint $workspaceHint"
    }
}

get-workspace.ps1