Recently, I decided to have a play with TFSPreview. I wanted to use some existing projects to see how I got on, so I decided to use a few that were already in TFS 2010. You may already know that not only does TFS insert files into your solution folders but also inserts lines/nodes in your .sln and .xxproj files, making it a pain to clean out.
A search revealed an excellent post from Jacob Lauzier entitled “Custom NAnt Task for Removing TFS Bindings” from 21 May 2008 to which was attached the source.
I decided to translate it into PowerShell and the result is below. It is mostly a straight port of Jake’s code. I was able to remove the bit dealing with the XML declaration since VS 2010 includes them and I don’t have to deal with anything older for this.
To use it, save it as Remove-TFSBindings.ps1 and run it using something like this:
.\Remove-TFSBindings.ps1 "C:\Users\Public\VS 2010\Projects\TFSPreview\EntLib-Extensions\AuditLogFormatter"
That’s it!
Source:
param([string]$solutionDir =$(Read-Host -prompt "You must provide the path to the solution folder.") )
<# ######### ######### ######### ######### ######### ######### ######### #########
# Based on Jacob Lauzier's post "Custom NAnt Task for Removing TFS Bindings" at
# http://www.atalasoft.com/cs/blogs/jake/archive/2008/05/21/2custom-nant-task-for-removing-tfs-bindings.aspx
# on 14th September, 2012.
#
# Where Jacob's NAnt task had to cope with Visual Studio 2005, which doesn't
# start .csproj files with a valid XML declaration, this was writter to cope with
# Visual Studio 2010, which does, enabling me to strip out some code. Otherwise
# it's a direct port.
#>
if ([System.String]::IsNullOrEmpty($solutionDir))
{
Write-Host "The path to the solution folder cannot be an empty string. Exiting.";
exit;
}
$solutionPattern = "*sln";
$projectPattern = "*proj";
$bindingPattern = "*scc";
function RemoveSCCElementsAttributes([System.Xml.XmlNode]$node)
{
if ($node -eq $null)
{
return;
}
if ($node.Name.Contains("#") -or $node.Name.Equals("xml"))
{
return;
}
if ($node.Name.Contains("Scc"))
{
$node.RemoveAll();
#$node.ParentNode.RemoveChild($node);
return;
}
if ($node.HasChildNodes)
{
foreach ($n in $node.ChildNodes)
{
RemoveSCCElementsAttributes($n);
}
}
foreach ($attrib in $node.Attributes)
{
if ($attrib.Name.Contains("Scc"))
{
$attrib.RemoveAll();
}
}
}
function CleanProjectFiles([System.IO.DirectoryInfo]$directory)
{
$files = $directory.GetFiles($projectPattern);
foreach ($file in $files)
{
Write-Host " Cleaning project:" $file.Name;
$file.Attributes = [System.IO.FileAttributes]::Normal;
try
{
$fs = $file.Open([System.IO.FileMode]::Open, [System.IO.FileAccess]::Read);
$reader = New-Object System.Xml.XmlTextReader $fs;
$doc = New-Object System.Xml.XmlDocument;
$doc.Load($reader);
#RemoveSCCElementsAttributes($doc);
if ($doc.HasChildNodes)
{
foreach ($n in $doc.ChildNodes)
{
RemoveSCCElementsAttributes($n);
}
}
$reader.Close();
$fs.Close();
$fs = $file.Open([System.IO.FileMode]::Truncate, [System.IO.FileAccess]::Write);
$writer = New-Object System.Xml.XmlTextWriter($fs, [System.Text.Encoding]::UTF8);
$writer.Formatting = [System.Xml.Formatting]::Indented;
$doc.Save($writer);
}
finally
{
if ($fs)
{
$reader.Close();
$writer.Close();
$fs.Close();
}
}
}
}
function CleanSolutionFiles([System.IO.DirectoryInfo]$directory)
{
$files = $directory.GetFiles($solutionPattern);
foreach ($file in $files)
{
Write-Host " Cleaning solution:" $file.Name;
$file.Attributes = [System.IO.FileAttributes]::Normal;
try
{
$fs = $file.Open([System.IO.FileMode]::Open, [System.IO.FileAccess]::Read);
$reader = New-Object System.IO.StreamReader $fs;
$buffer = New-Object System.Collections.ArrayList;
$line = $null;
while (($line = $reader.ReadLine()) -ne $null)
{
# Once you hit the Source Control section, wait until you're out of it.
if ($line.Trim().StartsWith("GlobalSection(SourceCodeControl)") -or $line.Trim().StartsWith("GlobalSection(TeamFoundationVersionControl)"))
{
while (-not $reader.ReadLine().Trim().StartsWith("EndGlobalSection")) {};
}
elseif ($line.Trim().Contains("SccProjectName"))
{
[void]$buffer.Add("SccProjectName = `"`"");
}
elseif ($line.Trim().Contains("SccAuxPath"))
{
[void]$buffer.Add("SccAuxPath = `"`"");
}
elseif ($line.Trim().Contains("SccLocalPath"))
{
[void]$buffer.Add("SccLocalPath = `"`"");
}
elseif ($line.Trim().Contains("SccProvider"))
{
[void]$buffer.Add("SccProvider = `"`"");
}
elseif (-not $line.Equals([System.String]::Empty))
{
[void]$buffer.Add($line);
}
}
$reader.Close();
$fs.Close();
$fs = $file.Open([System.IO.FileMode]::Truncate, [System.IO.FileAccess]::Write);
$writer = New-Object System.IO.StreamWriter $fs
foreach ($nl in $buffer)
{
$writer.WriteLine($nl);
}
}
finally
{
if ($fs)
{
$reader.Close();
$writer.Close();
$fs.Close();
}
}
}
}
function DeleteFiles([System.IO.DirectoryInfo]$directory)
{
$files = $directory.GetFiles($bindingPattern);
foreach ($file in $files)
{
Write-Host " Deleting file:" $file.Name
[System.IO.File]::SetAttributes($file.FullName, [System.IO.FileAttributes]::Normal);
$file.Delete();
}
}
function RemoveBindings([System.IO.DirectoryInfo]$parent)
{
Write-Host "Processing folder:" $parent.Name;
DeleteFiles($parent);
CleanSolutionFiles($parent);
CleanProjectFiles($parent);
$children = $parent.GetDirectories();
foreach ($child in $children)
{
RemoveBindings $child;
}
}
$dirInfo = New-Object "System.IO.DirectoryInfo" $solutionDir;
Write-Host Processing $dirInfo.FullName;
RemoveBindings($dirInfo)