How to remove TFS source control info from a VS solution

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)

Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>