1
votes

I have created a simple Powershell script to copy files during a deployment from a target directory to a source directory and I would like to exclude a list of files. The caveat however is that I would like the ability to exclude files only from a sub directory if specified. This is the snippet I'm using to perform the copy and exclude a list of files:

$SourceDirectory = "C:\Source"
$DestinationDirectory = "C:\Destination"
$Exclude = @("*.txt*", "*.xml*") 

Get-ChildItem $SourceDirectory -Recurse -Exclude $Exclude | Copy-Item -Destination {Join-Path $DestinationDirectory $_.FullName.Substring($SourceDirectory.length)}

This will exclude the specified files wherever they appear in the directory tree. Where I would like to get to with the Exclude list is something like this:

$Exclude = @("*Sub1\.txt*", "*.xml*").

This would exclude .txt files only under the Sub1 folder while .xml files would be excluded throughout. I know this doesn't work, but I hope that it helps to better demonstrate the problem I'm trying to solve.

I have considered using a multidimensional array, but I'm not sure if that might be overkill. Any help would be appreciated.

2
Beryllium - Thank you for catching the typos and helping to format my response better. I'm not certain why you removed the word "Powershell" from my post since there are many posts that start with the same word and because my question is specific to Powershell. Would this not have the affect of getting lost with other similar types of posts that are not Powershell specific?Nimblejoe

2 Answers

4
votes

This is one way to do it

$SourceDirectory = 'C:\Source'
$DestinationDirectory = 'C:\Destination'
$ExcludeExtentions = '*.txt*', '*.xml*' 

$ExcludeSubDirectory = 'C:\Source\bad_directory1', 'C:\Source\bad_directory2'

Get-ChildItem $SourceDirectory -Recurse -Exclude $ExcludeExtentions | 
Where-Object { $ExcludeSubDirectory -notcontains $_.DirectoryName } |
Copy-Item -Destination $DestinationDirectory

Your best friend here is Where-Object, or where. It takes a scriptblock as parameter and uses that scriptblock to validate each object that goes through pipeline. Only objects that make script return $true are passed through Where-Object.

Also, take a look at the object that represents a file you get from Get-ChildItem. It has Name, Directory and DirectoryName containing pieces of file's FullName already split respectively. Directory is actually an object that represents parent directory, and DirectoryName is a string. Get-Member commandlet will help you to discover hidden gems like.

1
votes
$SourceDirectory =   'C:\Source'
$DestinationDirectory = 'C:\Destintation'
$ExcludeExtentions1 = "^(?=.*?(SubDirectory1))(?=.*?(.xml)).*$"
$ExcludeExtentions2 = "^(?=.*?(SubDirectory2))(?=.*?(.config)).*$"
$ExcludeExtentions3 = "^(?=.*?(.ps1))((?!SubDirectory1|SubDirectory2).)*$"
$ExcludeExtentions4 = ".txt|.datasource"

$files = Get-ChildItem $SourceDirectory -Recurse

foreach ($file in $files)
{
    if ($file.FullName -notmatch $ExcludeExtentions1 -and $file.FullName -notmatch $ExcludeExtentions2 -and $file.FullName -notmatch $ExcludeExtentions3-and $file.FullName -notmatch $ExcludeExtentions4)
    {
       $CopyPath = Join-Path $DestinationDirectory $file.FullName.Substring($SourceDirectory.length)
       Copy-Item $file.FullName -Destination $CopyPath
    }
}

In this solution, using regex and -notmatch I am able to exclude specific file types from specific directories. $ExcludeExtentions1 will exclude xml files only from SubDirectory1, $ExcludeExtentions2 will exclude config files only from SubDirectory2, $ExcludeExtentions3 will exclude ps1 files as long as they are not in either of the two SubDirectories, $ExcludeExtentions4 will exclude txt and datasource files throughout the entire tree.

We are not actually using all of these matches in our solution, but since I was working on this, I thought I would add multiple conditions in case others could benefit from this approach.

Here are a couple of links that also helped: http://www.tjrobinson.net/?p=109 http://dominounlimited.blogspot.com/2007/09/using-regex-for-matching-multiple-words.html