Cleanup workspaces

To be honest, how many of you do cleanup of workspaces when people leave or just get a new computer?

It is one of those tasks that it is good to execute regularly, to keep the numbers low, as it affects the upgrade speed of the TFS server.

There are currently no API we can use directly in Powershell to access workspace information, so we have two options: either call the .Net interfaces in VS client or automate calls to TF.exe. Lets go with the easiest one…One issue we need to get around is that if we have old obsoleted workspaces we aren’t able to remove them the normal way, as TF can’t find it:

tf workspace /delete myWS;PETERC
TF14061:  The workspace myWS;PETERC does not exist.

To get around this, we have to use User Guid instead of the name. To extract this we have to use the xml output form. To extract all workspaces:

TF.exe VC Workspaces /collection:[CollectionURL]/Owner:* /Computer:* /format:xml >c:\tfs\ws.xml

With this xml file, the fun begins. We load this file, and remove all workspaces that hasn’t been access within the last 3 years:

$TFSCollection = [TFSCollectionURL]
$TFPath= "C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\Common7\IDE\CommonExtensions\Microsoft\TeamFoundation\Team Explorer\TF.exe"
$MaxAge = 3 #Years. Workspaces with older accessdate, will be deleted

#Extract workspaces by running the command TF.exe VC Workspaces /Owner:* /Computer:* /format:xml >c:\tfs\ws.xml
[xml] $TFSWS = Get-Content C:\tfs\ws.xml
$OldWS = $TFSWS.SelectNodes("/Workspaces/Workspace") | where {[datetime]$_.LastAccessDate -lt (Get-Date).AddYears(-$MaxAge)}
foreach ($WS in $OldWS)
{
    #get stderror and exitcode from process
    $ProcessInfo = New-Object System.Diagnostics.ProcessStartInfo 
    $ProcessInfo.FileName = $TFPath
    $ProcessInfo.RedirectStandardError = $true 
    $ProcessInfo.RedirectStandardOutput = $true 
    $ProcessInfo.UseShellExecute = $false 
    $ProcessInfo.Arguments = "VC Workspace /collection:$($TFSCollection) /noprompt /Delete `"$($WS.name);$($WS.Owner)`"" 
    $p = New-Object System.Diagnostics.Process
    $p.StartInfo = $ProcessInfo
    $p.Start() | Out-Null
    $p.WaitForExit()
    $stderr = $p.StandardError.ReadToEnd()
    if ($p.ExitCode -ne 0)
    {
        Write-Output $stderr 
    }
    else
    {
        Write-Output "Removed `"$($WS.name);$($WS.Owner)`" Workspace"
    }
}

You need to have the permissions to remove other peoples workspaces to run this.

Enjoy

Author: KimC

TFS admin and deployment fellow

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s