Ok, so I wrote a console application (.Net 4):
THIS DOES NOT HAVE WITHOUT A TELL I DO NOT PROVIDE ANY WARRANTY OF THIS IT - IT WILL DESTROY THE ITEMS IN TFS !!!!
Update (May 8, 2012) If you run this in a folder with masses and masses (I mean thousands or tens of thousands) of deleted items, they may not finish before the TFS command line expires. Most of the time this command takes is to create a .tfc script. If you run it and find that this is happening, try moving some child folders first
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.IO; using System.Text.RegularExpressions; using System.Diagnostics; namespace TFDestroyDeleted { class Program { static void Main(string[] args) { if (args.Length < 1 || args.Length > 3) Usage(); bool prepareOnly = false; bool previewOnly = false; if (args.Any(s => StringComparer.InvariantCultureIgnoreCase .Compare(s, "preview") == 0)) previewOnly = true; if (args.Any(s => StringComparer.InvariantCultureIgnoreCase .Compare(s, "norun") == 0)) prepareOnly = true; string tfOutput = null; Process p = new Process(); p.StartInfo = new ProcessStartInfo("tf") { Arguments = string.Format ("dir /recursive /deleted \"{0}\"", args[0]), UseShellExecute = false, RedirectStandardOutput = true, RedirectStandardError = true, RedirectStandardInput = true }; p.Start(); tfOutput = p.StandardOutput.ReadToEnd(); p.WaitForExit(); string basePath = null; string nextDelete = null; List<string> toDelete = new List<string>(); using (var ms = new MemoryStream(Encoding.Default.GetBytes(tfOutput))) { using (StreamReader sr = new StreamReader(ms)) { while (!sr.EndOfStream) { nextDelete = null; string line = sr.ReadLine(); if (string.IsNullOrWhiteSpace(line)) basePath = null; else { if (basePath == null) { if (line.EndsWith(":")) basePath = line.Substring(0, line.Length - 1); else continue; } else { nextDelete = Regex.Match(line, @"^.*?;X[0-9]+").Value; if (!string.IsNullOrWhiteSpace(nextDelete)) { toDelete.Add( string.Format ( "{0}/{1}", basePath, nextDelete.StartsWith("$") ? nextDelete.Substring(1) : nextDelete )); } } } } } } using (var fs = File.OpenWrite("destroy.tfc")) { fs.SetLength(0); using (var sw = new StreamWriter(fs)) {
You must transfer the TFS folder for deletion, for example '$ / folder'. If you just pass it on, then all relevant deleted items will be detected and destroyed one by one.
For some reason - if you accidentally transfer a folder that doesnโt actually exist, the operation is done forever. Of course, CTRL + C will stop it.
An application executes a recursive directory in a folder using the /deleted switch.
Then it goes through each line in the output, looking for a delete hint, i.e. elements c ;Xnnnnnnn . If found, it adds the full tfs list for this item to the list.
After completion, the list is sorted by length in descending order and the contents recorded in the tfc response file for the tf.exe command line.
If the preview parameter is specified, then tf commands are written using the / preview switch (see TFS Destroy on MSDN). Then deletions are not actually performed.
Finally, you can specify norun , which causes the tfc file to be created, but is not actually executed.