Building a Professional File Transfer Script in PowerShell

Building a Professional File Transfer Script in PowerShell

Posted on November 27, 2017 0 Comments

A detailed guide on creating a FTP script in PowerShell to move files between servers.

File transfers are not created equal and are of varying importance. One day you might be at home copying over some MP3s to your personal computer and the next you’re at work performing an application upgrade copying over critical files to keep the business running. We’re here today to talk about the second approach.

We’re here to build a tool in PowerShell that would seem overkill if performing a simple copy but when it comes to making copies of critical data, there’s no amount of safeguards that are too many.

Getting Started with the FTP Script

Let’s build a PowerShell function that’ll act as our scaffolding:

function Move-Stuff {
    param(
        [Parameter(Mandatory)]
        [string]$Path,

        [Parameter(Mandatory)]
        [string]$DestinationPath
    )
}

Now that we have a base to work from, let’s get to adding some code. Before we transfer any files over the network, we need to ensure the transport is efficient as possible. Since we’re working with lots of files, it’s generally faster to transfer one file vs. thousands. One way to get thousands of files across a network in one go as efficiently as possible is compressing them. Before we begin the transfer, we’ll compress all of these files into a ZIP file. I’ll use the Compress-Archive cmdlet for that.

$zipFile = Compress-Archive -Path $Path -DestinationPath "$Path\($(New-Guid).Guid).zip" -CompressionLevel Optimal -PassThru

You can see that I’m creating a zip file with a GUID in the same folder. I use a GUID because I know it’ll be unique and this ZIP file is just temporary anyway.

Now that we have our files compressed into a single file, we now need to take a hash of it. We’re taking a hash because we want to ensure the hash the file is before the transfer, and the one afterward are exactly the same. If they are not, something was modified in transit.

$beforeHash = (Get-FileHash -Path $zipFile.FullName).Hash
 

File Transfer Options with PowerShell

Now we can begin the file transfer. In PowerShell, we’ve got a few ways to transfer files. We can transfer files with the Copy-Item which is, by far, the most common but we’ve also got some cmdlets to transfer files via BITS. BITS is a smarter way to transfer files and uses a protocol that’s less susceptible to network flakiness among other things. First of all, we’re going to scrap the Copy-Item cmdlet and use BITS instead. PowerShell has many built-in cmdlets to interact with BITS. For this script, we’re going to be using Start-BitsTransfer just to get the transfer started.

## Transfer to a temp folder
$destComputer = $DestinationPath.Split('\')[2]
$remoteZipFilePath = "\\$destComputer\c$\Temp"
Start-BitsTransfer -Source $zipFile.FullName -Destination $remoteZipFilePath

The last of the tasks should be done locally on the remote server, so we’ll use PowerShell remoting so we’ll create a PSSession to use.

$destComputer = $DestinationPath.Split('\')[2]
$session = New-PSSession -ComputerName $destComputer

Once all of the files have been transferred, we then check to ensure the hash is the same by using our session.

## Assuming we're using the c$ admin share
$localFolderPath = $DestinationPath.Replace("\\$destComputer\c$\",'C:\')
$localZipFilePath = $remoteZipFilePath.Replace("\\$destComputer\c$\",'C:\')
$afterHash = Invoke-Command -Session $session -ScriptBlock { (Get-FileHash -Path "$using:localFolderPath\$localZipFilePath").Hash }
if ($beforeHash -ne $afterHash) {
    throw 'File modified in transit!'
}

If they are the same, we can then unzip the file.

Invoke-Command -Session $session -ScriptBlock { Expand-Archive -Path "$using:localFolderPath\$localZipFilePath" -DestinationPath $using:localFolderPath }

PowerShell File Transfer Function

The final function will look like this:

function Move-Stuff {
    param(
        [Parameter(Mandatory)]
        [string]$Path,

        [Parameter(Mandatory)]
        [string]$DestinationPath
    )
    try {
        ## Zip up the folder
        $zipFile = Compress-Archive -Path $Path -DestinationPath "$Path\($(New-Guid).Guid).zip" -CompressionLevel Optimal -PassThru

        ## Create the before hash
        $beforeHash = (Get-FileHash -Path $zipFile.FullName).Hash

        ## Transfer to a temp folder
        $destComputer = $DestinationPath.Split('\')[2]
        $remoteZipFilePath = "\\$destComputer\c$\Temp"
        Start-BitsTransfer -Source $zipFile.FullName -Destination $remoteZipFilePath

        ## Create a PowerShell remoting session
        $destComputer = $DestinationPath.Split('\')[2]
        $session = New-PSSession -ComputerName $destComputer

        ## Compare the before and after hashes
        ## Assuming we're using the c$ admin share
        $localFolderPath = $DestinationPath.Replace("\\$destComputer\c$\",'C:\')
        $localZipFilePath = $remoteZipFilePath.Replace("\\$destComputer\c$\",'C:\')
        $afterHash = Invoke-Command -Session $session -ScriptBlock { (Get-FileHash -Path "$using:localFolderPath\$localZipFilePath").Hash }
        if ($beforeHash -ne $afterHash) {
            throw 'File modified in transit!'
        }

        ## Decompress the zip file
        Invoke-Command -Session $session -ScriptBlock { Expand-Archive -Path "$using:localFolderPath\$localZipFilePath" -DestinationPath $using:localFolderPath }
    } catch {
        $PSCmdlet.ThrowTerminatingError($_)
    } finally {
        ## Cleanup
        Invoke-Command -Session $session -ScriptBlock { Remove-Item "$using:localFolderPath\$localZipFilePath" -ErrorAction Ignore }
        Remove-Item -Path $zipFile.FullName -ErrorAction Ignore
        Remove-PSSession -Session $session -ErrorAction Ignore
    }
}

You now have a PowerShell function you can reuse to efficiently transfer a folder from one server to another!

 

Adam Bertram

Adam Bertram is a 25+ year IT veteran and an experienced online business professional. He’s a successful blogger, consultant, 6x Microsoft MVP, trainer, published author and freelance writer for dozens of publications. For how-to tech tutorials, catch up with Adam at adamtheautomator.com, connect on LinkedIn or follow him on X at @adbertram.

Comments

Comments are disabled in preview mode.
Topics

Sitefinity Training and Certification Now Available.

Let our experts teach you how to use Sitefinity's best-in-class features to deliver compelling digital experiences.

Learn More
Latest Stories
in Your Inbox

Subscribe to get all the news, info and tutorials you need to build better business apps and sites

Loading animation