1

I have recently rewrote my function to restore backup from "MyBackupFolder" using Start-BitsTransfer, because it shows a progress bar and I would like to have it.

However, I noticed it does not copy nested folders and files recursively, like my former function did (meaning it will not copy my folders and subfolders with files within them at all).

1.) Is there a way to use Start-BitsTransfer recursively so it would do that? 2.) IF not, is there a way to use Copy-Item with loading bar?

This is an example of the aforementioned folder structure:

c:\Users\username\AppData\Local\MyBackupFolder\Folder1\Subfolder1\user.config
c:\Users\username\AppData\Local\MyBackupFolder\Folder2\file.xml
c:\Users\username\AppData\Local\MyBackupFolder\Folder3\Subfolder2\severalFiles

This is how the function formerly looked like:

function Restore-From-Backup($Source, $Destination) { 
    Copy-Item -Path $Source -Destination $Destination -Recurse      
}

This is how it looks now:

function Restore-From-Backup($Source, $Destination) {   
    Start-BitsTransfer -Source $Source -Destination $Destination -TransferType Download     
}

Blu3Rat
  • 49
  • 7

1 Answers1

0

Is there a way to use Start-BitsTransfer recursively so it would do that?

Yes, you need to list the files in that folder and call Start-BitsTransfer for each one of them.
If you need an overall progress, you can use nested progress bars.
However, this is not efficient, nor practical.

IF not, is there a way to use Copy-Item with loading bar?

Yes, multiple actually.
You could use file streams, as suggested here.
Is very practical, simple and it works, however it's not efficient.
I use a function I wrote a while back.
There is no error handling, so be aware.

function Copy-File {

    [CmdletBinding()]
    param (
        [Parameter(Mandatory, Position = 0)]
        [string]$Path,

        [Parameter(Mandatory, Position = 1)]
        [string]$Destination
    )

    $signature = @'
    namespace Utilities {

        using System;
        using System.Runtime.InteropServices;
    
        public class FileSystem {
            
            [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
            [return: MarshalAs(UnmanagedType.Bool)]
            static extern bool CopyFileEx(
                string lpExistingFileName,
                string lpNewFileName,
                CopyProgressRoutine lpProgressRoutine,
                IntPtr lpData,
                ref Int32 pbCancel,
                CopyFileFlags dwCopyFlags
            );
        
            delegate CopyProgressResult CopyProgressRoutine(
            long TotalFileSize,
            long TotalBytesTransferred,
            long StreamSize,
            long StreamBytesTransferred,
            uint dwStreamNumber,
            CopyProgressCallbackReason dwCallbackReason,
            IntPtr hSourceFile,
            IntPtr hDestinationFile,
            IntPtr lpData);
        
            int pbCancel;
        
            public enum CopyProgressResult : uint
            {
                PROGRESS_CONTINUE = 0,
                PROGRESS_CANCEL = 1,
                PROGRESS_STOP = 2,
                PROGRESS_QUIET = 3
            }
        
            public enum CopyProgressCallbackReason : uint
            {
                CALLBACK_CHUNK_FINISHED = 0x00000000,
                CALLBACK_STREAM_SWITCH = 0x00000001
            }
        
            [Flags]
            enum CopyFileFlags : uint
            {
                COPY_FILE_FAIL_IF_EXISTS = 0x00000001,
                COPY_FILE_RESTARTABLE = 0x00000002,
                COPY_FILE_OPEN_SOURCE_FOR_WRITE = 0x00000004,
                COPY_FILE_ALLOW_DECRYPTED_DESTINATION = 0x00000008
            }
        
            public void CopyWithProgress(string oldFile, string newFile, Func<long, long, long, long, uint, CopyProgressCallbackReason, System.IntPtr, System.IntPtr, System.IntPtr, CopyProgressResult> callback)
            {
                CopyFileEx(oldFile, newFile, new CopyProgressRoutine(callback), IntPtr.Zero, ref pbCancel, CopyFileFlags.COPY_FILE_RESTARTABLE);
            }
        }
    }
'@

    Add-Type -TypeDefinition $signature

    [Func[long, long, long, long, System.UInt32, Utilities.FileSystem+CopyProgressCallbackReason, System.IntPtr, System.IntPtr, System.IntPtr, Utilities.FileSystem+CopyProgressResult]]$copyProgressDelegate = {

        param($total, $transfered, $streamSize, $streamByteTrans, $dwStreamNumber, $reason, $hSourceFile, $hDestinationFile, $lpData)

        Write-Progress -Activity "Copying file" -Status "$Path ~> $Destination. $([Math]::Round(($transfered/1KB), 2))KB/$([Math]::Round(($total/1KB), 2))KB." -PercentComplete (($transfered / $total) * 100)
    }

    $fileName = [System.IO.Path]::GetFileName($Path)
    $destFileName = [System.IO.Path]::GetFileName($Destination)
    if ([string]::IsNullOrEmpty($destFileName) -or $destFileName -notlike '*.*') {
        if ($Destination.EndsWith('\')) {
            $destFullName = "$Destination$fileName"
        }
        else {
            $destFullName = "$Destination\$fileName"
        }
    }

    $wrapper = New-Object Utilities.FileSystem
    $wrapper.CopyWithProgress($Path, $destFullName, $copyProgressDelegate)
}
FranciscoNabas
  • 505
  • 3
  • 9