functions/Copy-ItemFiltered.ps1


function Copy-ItemFiltered {
[CmdletBinding()]
param(
[Parameter(Mandatory=$true)]
[string] $SourceDir,
[Parameter(Mandatory=$true)]
[string] $TargetDir,
[switch] $Force,
[string[]] $Excludes,
$message = "Copying items...",
[switch][bool]$ClearDest = $false
) 
    $SourceDir = (get-item $SourceDir).FullName
    #$activity = "$message $sourcedir => $targetDir"
    try {
        import-module pathutils
        
        $Excludes = $Excludes | % { $_.replace("\","/") }
        $Excludes = $Excludes | % { if ($_.StartsWith("/")) { $_.substring(1) } else { $_ } }
        #$excludedDirs = $Excludes | where { $_ -match "\\*\\" } | foreach { $_.Replace("\","\\") }

        Write-Verbose "excludes: $excludes"
        if (!(test-path $targetdir)) { $null = New-Item -ItemType Directory $targetdir }

        #Write-Progress $activity -Status "getting list of directories"
        #get directories (recursively) to copy
        $dirs = @(pathutils\Get-Listing -Path $SourceDir -Recursive -Excludes $excludes -Dirs)
        
        #Write-Progress $activity -Status "preparing... ($($dirs.length) dirs)"
        Write-Verbose "dirs: $dirs"
    
        #create matching direcctory structure
        foreach( $d in $dirs ) {
            if ($d -eq $null) { 
                continue 
            }
            $fullname = $d.FullName
            if ($fullname -eq $null) { 
                $fullname = $d.Name 
            }
            Write-Verbose "d.name=$($d.Name) fullname=$fullname tmpPath=$tmpPath"
            $tmpPath = Join-Path $targetdir (Get-RelativePath $SourceDir $fullname)

            if (!(test-path $tmpPath)) { $null = New-Item -ItemType Directory -Path $tmpPath }
        }
    
        
        $items = $dirs
        $items += get-item $sourcedir
        <#
        #get top-level dirs
        $items += Get-Listing $SourceDir -Exclude $excludes -Recursive:$false -Dirs
 
        Write-Verbose "items: $items"
 
        foreach( $d in $dirs ) {
            if ($d -eq $null) {
                continue
            }
            Write-Progress $activity -Status "preparing... listing '$($d.name)'"
            $curItems = Get-Listing $($d.FullName) -Exclude $excludes -Recursive:$false -Dirs
            if ($curItems -ne $null) {
                $items += $curItems
            }
        }
        #>


        if($ClearDest){
            remove-item -path "$dest\*" -Recurse -Force -Exclude @Excludes
        }
        #$i = 0
        $items | foreach {
            #$i++
            #Write-Progress -Activity $activity -Status " directory '$_' ($i/$($items.Length))" -PercentComplete ($i/[float]$($items.Length) * 100)
            $dir = $_
            try {     
                $dest = Join-Path $targetdir (Get-RelativePath $SourceDir $_.fullname)
                $files = get-childitem $($_.fullname) -File -Recurse:$false
                #$j = 0
                $files | % { 
                    #$j++
                    #Write-Progress -Activity $activity -Status " directory '$dir' ($i/$($items.Length)) | file $_ ($j/$($files.length)) ($($_.length)B)" -PercentComplete ($i/[float]$($items.Length) * 100)
                    try {
                        Copy-Item "$($_.fullname)" -Force:$Force -Destination $dest -Verbose
                    } catch {
                        # replace exceptions with errors, so ErrorAction could take effect
                        write-error $_
                    } 
                }
             }
             catch [System.Exception] {
                write-host "failed to copy dir $dir : $($_.Exception)"
             }
         }
     } 
     finally {
        #write-progress -Activity $activity -completed
     }
}