Copy files from source directory to target directo

2019-08-07 05:34发布

问题:

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.

回答1:

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.



回答2:

$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