Search code examples
powershellget-childitem

Powershell copying specific files from source directory, excluding several folders, but then recursive with wildcard for files


Here is my current script and it works fine. Not efficient running same code twice but I don't know how to combine the wildcards... anyway on to the bigger issue.

The below code searches through my $sourceDir, excludes the files listed in $ExclusionFiles, copies all folders and structure as well as any .jpg or any .csv files, then puts them into the $targetDir.

$sourceDir = 'c:\sectionOne\Graphics\Data'
$targetDir = 'C:\Test\'
$ExclusionFiles = @("InProgress.jpg", "input.csv", "PCMCSV2.csv")

# Get .jpg files
Get-ChildItem $sourceDir -filter "*.jpg" -recurse -Exclude $ExclusionFiles | `
    foreach{
        $targetFile = $targetDir + $_.FullName.SubString($sourceDir.Length);
        New-Item -ItemType File -Path $targetFile -Force;
        Copy-Item $_.FullName -destination $targetFile
    }

# Get .csv files
Get-ChildItem $sourceDir -filter "*.csv" -recurse -Exclude $ExclusionFiles | `
    foreach{
        $targetFile = $targetDir + $_.FullName.SubString($sourceDir.Length);
        New-Item -ItemType File -Path $targetFile -Force;
        Copy-Item $_.FullName -destination $targetFile
    }

My list of files in the main $sourceDir that I need to exclude is getting longer and there are folders I want to exclude as well. Can someone tell me how to,

  • Copy only a list of specific files in the $sourceDir
  • Exclude certain folders in $sourceDir from copying
  • Combine the wildcard search for .jpg and .csv into one statement

I'm still learning so any help would be greatly appreciated!


Solution

  • This is a case where a little bit of Regex will go a long way:

    You can filter multiple extensions by using a pretty basic match:

    $extensions = 'jpg', 'csv'
    $endsWithExtension = "\.(?>$($extensions -join '|'))$"
    Get-ChildItem -Recurse |
       Where-Object Name -Match $endsWithExtension
    

    You can exclude a list of specific files with one more Where-Object and the -In parameter:

    $extensions = 'jpg', 'csv'
    $endsWithExtension = "\.(?>$($extensions -join '|'))$"
    $ExcludeFileNames = @("InProgress.jpg", "input.csv", "PCMCSV2.csv")
    
    Get-ChildItem -Recurse |
       Where-Object Name -Match $endsWithExtension |
       Where-Object Name -NotIn $ExcludeFileNames
    

    From there on in, your Foreach-Object is basically correct (nice touch making sure the file exists by using New-Item, though I'd personally assign it's output to null and -PassThru the Copy-Item).

    Get-ChildItem $sourceDir -Recurse |
       Where-Object Name -Match $endsWithExtension |
       Where-Object Name -NotIn $ExcludeFileNames | 
       Foreach-Object {
            $targetFile = $targetDir + $_.FullName.SubString($sourceDir.Length);
            New-Item -ItemType File -Path $targetFile -Force;
            Copy-Item $_.FullName -destination $targetFile
        }