Functions/Public/Copy-WithProgress.ps1

#!/usr/bin/env pwsh

<#
.SYNOPSIS
    This function performs a copy of a specified object recursively to a specified location.
.DESCRIPTION
    This function is a glorified Copy-Item in that it will show progress data. If moving 10,000 files that equal 2GB in size, it will show you what file you are currently on as well as how much data has been moved / what is left using Write-Progress.
.PARAMETER Source
    Source should specify the object to be copied by name. This value must be the FullPath and cannot be shortened. An example would be if you were in the C:\Scripts directory, you could not specify '.\TestFile.ps1' as the source location, you must specify 'C:\Scripts\TestFile.ps1' in this case.
.PARAMETER Destination
    Destination should specify the target location of the specified Source by name. This value must be the FullPath and cannot be shortened. An example would be if you were in the C:\Scripts directory, you could not specify '.\TestFile.ps1' as the Destination location, you must specify 'C:\Scripts\TestFile.ps1' in this case
.INPUTS
    System.String[]
        This function does not accept pipeline data. The values for all parameters must be specified.
.OUTPUTS
    None
        This function does not produce output except for the Write-Progress data.
.EXAMPLE
    PS>Copy-WithProgress -Source "C:\Scripts\TestFile.ps1" -Destination "C:\Temp\TestFile.ps1"
    Description
    -----------
    This will copy the source file to the file specified in Destination. Note that the filename for Destination can be anything and does not have to match the original.
.NOTES
    Author: Matthew J. DeGarmo
    Handle: @matthewjdegarmo
#>

function Copy-WithProgress() {
    [CmdletBinding()]
    Param (
        [Parameter(Mandatory = $true,
            ValueFromPipelineByPropertyName = $true,
            Position = 0)]
        $Source,
        [Parameter(Mandatory = $true,
            ValueFromPipelineByPropertyName = $true,
            Position = 1)]
        $Destination
    )

    Write-Progress -Activity "Gathering data from $Source"
    $Source = $Source.tolower()
    $Destination = $Destination.tolower()
    $Filelist = Get-Childitem $Source -Recurse
    $Total = $Filelist.count
    $Position = 0
    $Size = ($Filelist | Measure-Object -Property Length -Sum -ErrorAction SilentlyContinue).Sum
    
    Write-Progress -Activity "Gathering data from $Source" -Completed
    foreach ($File in $Filelist) {
        switch ($Size) {
            { $_ -ge '1000000000' } { $TotalSize = "{0:N2} GB" -f ($_ / 1GB) }
            { ($_ -lt '1000000000') -and ($_ -ge '10000000') } { $TotalSize = "{0:N2} MB" -f ($_ / 1MB) }
            { $_ -lt '1000000' } { $TotalSize = "{0:N2} KB" -f ($_ / 1KB) }
        }

        $FileSize = ($File | Measure-Object -Property Length -Sum -ErrorAction SilentlyContinue).Sum
        $Filename = $File.Fullname.ToLower().Replace($Source, '')
        $DestinationFile = ($Destination + $Filename)
        $Position++
        $Percent = [int]$(($Position / $Total) * 100)
        Write-Progress -Activity "Copying data from '$Source' to '$Destination'" -Status "Copying File $Position of $total - $TotalSize remaining..." -PercentComplete (($Position / $total) * 100) -CurrentOperation "$Percent% complete"
        #$null = New-Item -Name $File.FullName -Path $DestinationFile -ItemType File -Force
        Copy-Item $File.FullName -Destination $DestinationFile -Force -ErrorAction SilentlyContinue -Container | Out-Null
        $Size = ($Size - $FileSize)               
    }
    Write-Progress -Activity "Moving data from '$Source' to '$Destination'" -Completed 
}