0
votes

I've put together a script that recursively copies from one directory to another, skipping files with a certain pattern in the filename:

function Copy-RevitFiles ([string]$source, [string]$destination, [boolean]$recurse) {

    $pattern = '\.\d\d\d\d\.[RVT]'

    if ($recurse) {$files = Get-ChildItem $source -Recurse}
    else {$files = Get-ChildItem $source}


    $files | ForEach-Object {
    if ((Select-String -InputObject $_.Name -pattern $pattern -AllMatches -quiet) -eq $null) {
        #Write-Host $_.Name
        #Write-Host $_.Fullname
        #Write-Host "$($destination)\$($_.FullName.TrimStart($source))"
        Copy-Item $_.FullName -Destination "$($destination)\$($_.FullName.TrimStart($source))" #add on full name of item, less $source start end of file path
        #Write-Host "----------"
        }
    }
}

It works well, for the most part. The problem I have though is that it creates an additional subfolder inside each folder with files in it. For example:

If input the source as a directory with this structure:

Source
-file1.rvt
-file1.0225.rvt (will not copy as it matches the pattern)
-file1.0226.rvt (will not copy as it matches the pattern)
-folder1
 |-file2.rvt
 |-file2.0121.rvt (will not copy as it matches the pattern)
 |-file2.0122.rvt (will not copy as it matches the pattern)
-folder2

I am expecting the following structure to be created in the destination folder:

Destination
-file1.rvt
-folder1
 |-file2.rvt
-folder2

But instead, I am getting:

Destination
-file1.rvt
-folder1
 |-file2.rvt
 |-folder1 (extra folder not in source)
-folder2

Any idea where I am going wrong?

1

1 Answers

0
votes

It's the way you construct the destination and also how you handle the returned value for the Select-STring cmdlet with option -Quiet.
Using the Quiet switch will have the cmdlet return a Boolean value ($true or $false), but you are testing for equality to $null.

If I use the Join-Path cmdlet (along with some other adjustments to your function) like this:

function Copy-RevitFiles {
    [CmdletBinding()]
    Param(
        [string]$source, 
        [string]$destination,
        [string]$pattern, 
        [switch]$recurse
    )

    # test if the destination folder exists
    if (!(Test-Path -Path $destination -PathType Container)) {
        New-Item -ItemType Directory -Path $destination -Force | Out-Null
    }

    $files = Get-ChildItem $source -Recurse:$recurse

    $files | ForEach-Object {
    if (!(Select-String -InputObject $_.Name -Pattern $pattern -AllMatches -Quiet)) {
        #Write-Host $_.Name
        #Write-Host $_.Fullname
        $target = Join-Path -Path $destination -ChildPath $_.Fullname.TrimStart($source)
        #Write-Host "Copying '$_.Fullname' to '$target'" 
        $_ | Copy-Item -Destination $target
        #Write-Host "----------"
        }
    }
}

and use it according to your Source example:

Copy-RevitFiles -source "D:\Source" -destination "D:\Destination" -pattern '\.\d\d\d\d\.[RVT]' -recurse

It will result in:

Destination
|   file1.rvt
|
+---folder1
|       file2.rvt
|
\---folder2