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..."
) 
    $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 = 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
            }
        }
        #>


        $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)
                    Copy-Item "$($_.fullname)" -Force:$Force -Destination $dest 
                }
             }
             catch [System.Exception] {
                write-host "failed to copy dir $dir : $($_.Exception)"
             }
         }
     } 
     finally {
        write-progress -Activity $activity -completed
     }
}