Skip to content

Instantly share code, notes, and snippets.

@mikesigs
Last active May 10, 2023 11:40
Show Gist options
  • Star 9 You must be signed in to star a gist
  • Fork 6 You must be signed in to fork a gist
  • Save mikesigs/3512dbccc1767d447977 to your computer and use it in GitHub Desktop.
Save mikesigs/3512dbccc1767d447977 to your computer and use it in GitHub Desktop.
PowerShell Script to Find (and delete) all excluded files in a Visual Studio Solution
<#
.SYNOPSIS
Find all files excluded from a Visual Studio solution with options to delete.
.DESCRIPTION
Finds all excluded files in all projects in the provided Visual Studio solution with options to delete the files.
.PARAMETER Solution
The path to the .sln file
.PARAMETER VsVersion
The Visual Studio version (10, 11, 12) (Used to locate the tf.exe file)
.PARAMETER DeleteFromTfs
Mark files as pending deletion in TFS
.PARAMETER DeleteFromDisk
Delete the files directly from the disk
#>
[CmdletBinding()]
param(
[Parameter(Position=0, Mandatory=$true)]
[string]$Solution,
[Parameter(Mandatory=$false)]
[ValidateRange(10,12)]
[int] $VsVersion = 12,
[switch]$DeleteFromDisk,
[switch]$DeleteFromTfs
)
$ErrorActionPreference = "Stop"
$tfPath = "${env:ProgramFiles(X86)}\Microsoft Visual Studio $VsVersion.0\Common7\IDE\TF.exe"
$solutionDir = Split-Path $Solution | % { (Resolve-Path $_).Path }
$projects = Select-String -Path $Solution -Pattern 'Project.*"(?<file>.*\.csproj)".*' `
| % { $_.Matches[0].Groups[1].Value } `
| % { Join-Path $solutionDir $_ }
$excluded = $projects | % {
$projectDir = Split-Path $_
$projectFiles = Select-String -Path $_ -Pattern '<(Compile|None|Content|EmbeddedResource) Include="(.*)".*' `
| % { $_.Matches[0].Groups[2].Value } `
| % { Join-Path $projectDir $_ }
$diskFiles = Get-ChildItem -Path $projectDir -Recurse `
| ? { !$_.PSIsContainer } `
| % { $_.FullName } `
| ? { $_ -notmatch "\\obj\\|\\bin\\|\\logs\\|\.user|\.*proj|App_Configuration\\|App_Data\\" }
(compare-object $diskFiles $projectFiles -PassThru) | Where { $_.SideIndicator -eq '<=' }
}
Write-Host "Found" $excluded.count "excluded files"
if ($DeleteFromTfs)
{
Write-Host "Marking excluded files as deleted in TFS..."
$excluded | % {
[Array]$arguments = @("delete", "`"$_`"")
& "$tfPath" $arguments
}
}
elseif($DeleteFromDisk)
{
Write-Host "Deleting excluded files from disk..."
$excluded | % { Remove-Item -Path $_ -Force -Verbose}
}
else
{
Write-Host "Neither DeleteFromTfs or DeleteFromDisk was specified. Listing excluded files only..."
$excluded
}
@JimmyJaxxon
Copy link

Hi there, I have trouble running the script. Is there an example how to make the call?
Powershell throws the error:

Select-String: The File C:\myFolder can´t be read: The access to the path "C:\myFolder" is permitted.
In C:\myFolder\DeleteExcludedFiles.ps2: 36 Char:26

@dradovic
Copy link

dradovic commented Jan 2, 2018

Thanks for sharing this script. Let me suggest an improvement for the exclusion regex. Terminate ".user" and ".*proj" with a $. Otherwise one can get:

ForEach-Object : Cannot bind argument to parameter 'ReferenceObject' because it is null.

In other words, L50 should read:

| ? { $_ -notmatch "\\obj\\|\\bin\\|\\logs\\|\.user$|\.*proj$|App_Configuration\\|App_Data\\" }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment