Problem solve Get help with specific problems with your technologies, process and projects.

How to upload and download files with PowerShell FTP script

By using the .NET WebClient class and PowerShell, Windows admins can upload and download files to FTP.

Transferring files via FTP is one of those tasks every sysadmin has done at least once in their career. FTP and...

its secure components have been around for a long time. FTP moves files from one location to another either on a local network or across the internet.

Seemingly unrelated, PowerShell is a common, universal scripting language that's capable of automating many sysadmin tasks.

But what happens when you bring them together? You get a recipe for a powerful and free automation tool with the ubiquitous nature of being used in many different circumstances. Administrators can create some powerful FTP scripts using PowerShell and the .NET classes.

In this article, you'll learn how to combine the power of PowerShell with FTP to create PowerShell scripts to transfer files from IP address to IP address, source root folder to destination server and more.

Creating a simple FTP script

Let's start with a simple PowerShell FTP script: transferring a single file from one system to another with simple username/password authentication.

1. Building the script

  • Open your favorite PowerShell script editor and save a PS1 script called Upload-File.ps1. This script will contain all the code you need to upload a file via FTP.
  • Create some parameters for the script. Because PowerShell scripts are tools, it's important to be able to reuse this script for other situations. Below, you'll see three parameters that you can pass the username/password to via a PSCredential object, the local file path and the hostname of the FTP server to send the file to.
[CmdletBinding()]
param(
    [Parameter(Mandatory)]
    [pscredential]$Credential,

    [Parameter(Mandatory)]
    [string]$FilePath,

    [Parameter(Mandatory)]
    [string]$FtpServerHost
)
  • Create a .NET WebClient object. This object has methods that invoke FTP transfers as well as HTTP Once defined, provide the username and password to the Credentials property, as shown below.
$webclient = New-Object System.Net.WebClient

$ftpPassword = $Credential.GetNetworkCredential().Password
$webclient.Credentials = New-Object System.Net.NetworkCredential($Credential.Username, $ftpPassword)
  • Once the WebClient object has been created and credentials defined, define where the file should go. To do this, you must create a System.Uri .NET object, as shown below.
$remoteFileName = $FilePath | Split-Path -Leaf
$uri = New-Object System.Uri("ftp://$FtpServerHost/$remoteFileName")
  • Finally, invoke the UploadFile() method providing it the URI just created and the path received via the script The code below will upload the local file to the root directory of the FTP server.
$webclient.UploadFile($uri, $FilePath)
  • Your simple script should now look like this:
[CmdletBinding()]
param(
    [Parameter(Mandatory)]
    [pscredential]$Credential,

    [Parameter(Mandatory)]
    [string]$FilePath,

    [Parameter(Mandatory)]
    [string]$FtpServerHost
)

$webclient = New-Object System.Net.WebClient

$ftpPassword = $Credential.GetNetworkCredential().Password
$webclient.Credentials = New-Object System.Net.NetworkCredential($Credential.Username, $ftpPassword)

$remoteFileName = $FilePath | Split-Path -Leaf
$uri = New-Object System.Uri("ftp://$FtpServerHost/$remoteFileName")

$webclient.UploadFile($uri, $FilePath)

$webclient.Dispose()

2. Running the script

  • To run the script, invoke it and pass values for each parameter as shown below. The command will prompt you for a username and password. It will then use that username and password to authenticate to the ftpserver.domainname.com FTP server and transfer the C:.txt file to the FTP server's root directory.
.\Upload-File.ps1 -Credential (Get-Credential) -FilePath 'C:\Demo\file.txt' -FtpServerHost 'ftpserver.domainname.com'

Building an advanced FTP script

Now let's make that simple script more advanced. Say you want to copy a file using FTPS to encrypt the transfer across the network. To do that, you must use a .NET WebRequest object.

Using a similar technique, you can replace the Upload-Script.ps1 script with the code below. The script serves the same purpose and transfers files unencrypted, but now provides the option to securely transfer files as well.

[CmdletBinding()]
param(
    [Parameter(Mandatory)]
    [pscredential]$Credential,

    [Parameter(Mandatory)]
    [string]$FilePath,

    [Parameter(Mandatory)]
    [string]$FtpServerHost,

    [Parameter()]
    [switch]$SecureTransfer
)

## Define the FTP URI and credentials to use for connection
$ftpPassword = $Credential.GetNetworkCredential().Password
$remoteFileName = $FilePath | Split-Path -Leaf

$request = [Net.WebRequest]::Create("ftp://$FtpServerHost/$remoteFileName")
$request.Credentials = New-Object System.Net.NetworkCredential($Credential.Username, $ftpPassword)

## Only if the $SecureTransfer switch parameter is used, transfer with FTPS
if ($SecureTransfer.IsPresent) {
    $request.EnableSsl = $true
}

## Tell the request object we'll be uploading a file
$request.Method = [System.Net.WebRequestMethods+Ftp]::UploadFile

## Open the local file and conver to a request stream for transferring
$fileStream = [System.IO.File]::OpenRead($FilePath)
$ftpStream = $request.GetRequestStream()

## Transfer the file
$fileStream.CopyTo($ftpStream)

## Clean up the memory used for .NET objects
$ftpStream.Dispose()
$fileStream.Dispose()

Uploading or downloading an entire folder

Building on the advanced script above, perhaps you need to download a file. Also, you need to transfer all files in a folder rather than a single file. Below you'll find a script to do just that.

You'll find comments that give more information on what each line is doing.

[CmdletBinding()]
param(
    [Parameter(Mandatory)]
    [pscredential]$Credential,

    [Parameter(Mandatory)]
    [string]$LocalPath,

    [Parameter(Mandatory)]
    [string]$FtpServerHost,

    [Parameter(Mandatory)]
    [ValidateSet('Download','Upload')]
    [string]$Direction
)

$webclient = New-Object System.Net.WebClient

$ftpPassword = $Credential.GetNetworkCredential().Password
$webclient.Credentials = New-Object System.Net.NetworkCredential($Credential.Username, $ftpPassword)

if ($Direction -eq 'Download') {
    ## Find all files on the FTP server
    $request = [Net.WebRequest]::Create($url)
  $request.Method = [System.Net.WebRequestMethods+FTP]::ListDirectory
    $request.Credentials = $credentials
  $response = $request.GetResponse()
  $reader = New-Object IO.StreamReader $response.GetResponseStream()
    $files = while(-not $reader.EndOfStream) {
        $reader.ReadLine()
  }
  $reader.Close()
  $response.Close()
   
    ## Download each file
    foreach ($file in $files){
        $source = "$uri/$file"
    $destination = "$LocalPath/$file"
    $webclient.DownloadFile($source, $destination)
  }
} elseif ($Direction -eq 'Upload') {
    ## Find all local files and upload them
    Get-ChildItem -Path $LocalPath | ForEach-Object {
        $uri = New-Object System.Uri("ftp://$FtpServerHost/$($_.Name)")
        $webclient.UploadFile($uri, $_.FullName)
    }
}

Monitoring progress

Finally, perhaps you're transferring a large file and need to know how much has transferred. One way to monitor progress in PowerShell is to use the Write-Progress cmdlet. This cmdlet provides a graphical progress bar that gives you an indication of how far along it is.

In the following script, you'll see some common code from the examples above. The biggest difference is how the file is transferred.

To get a process indicator, you must upload the file in chunks rather than all at once and use the Write-Progress cmdlet generate an ongoing progress bar.

[CmdletBinding()]
param(
    [Parameter(Mandatory)]
    [pscredential]$Credential,

    [Parameter(Mandatory)]
    [string]$LocalPath,

    [Parameter(Mandatory)]
    [string]$FtpServerHost
)

$remoteFileName = $FilePath | Split-Path -Leaf
$request = [Net.WebRequest]::Create("ftp://$FtpServerHost/$remoteFileName")

$ftpPassword = $Credential.GetNetworkCredential().Password
$webclient.Credentials = New-Object System.Net.NetworkCredential($Credential.Username, $ftpPassword)

$request.Method = [System.Net.WebRequestMethods+Ftp]::UploadFile

$fileStream = [System.IO.File]::OpenRead($LocalFilePath)
$ftpStream = $request.GetRequestStream()

$buffer = New-Object Byte[] 10240
while (($read = $fileStream.Read($buffer, 0, $buffer.Length)) -gt 0) {
    $ftpStream.Write($buffer, 0, $read)
    $pct = ($fileStream.Position / $fileStream.Length)
        $prgParams = @{
            'Activity' =  'Uploading'
            'Status' =  ("{0:P0} complete:" -f $pct)
      'PercentComplete' = ($pct * 100)
        }
    Write-Progress @prgParams
}

$fileStream.CopyTo($ftpStream)

$ftpStream.Dispose()
$fileStream.Dispose()

If you're a sysadmin, you probably don't understand all the advanced .NET code in this article. But one of the best things about scripting out tasks like this is that you don't have to. Take advantage of the existing code provided here and begin running the scripts themselves rather than digging into the code.

Next Steps

Use PowerShell variables to prevent accidental changes to a script

Understand common automatic variables in PowerShell

Dig Deeper on Windows Server storage management

Join the conversation

6 comments

Send me notifications when other members comment.

Please create a username to comment.

Have you used FTP with PowerShell to move files?
Cancel
Should use sftp with a .ppk cert when possible. Transmitting over ftp is unnecessarily risky.
Cancel
It's ridiculous, isn't it, that after all these decades we don't have something more intuitive and user friendly than this?
Cancel
Hi Peter,

Yes. I agree. There are more secure ways to transfer files. I wouldn't suggest doing something like this over the Internet unless the data being transmitted isn't too important or sensitive.

I've built other PowerShell scripts that use SFTP. Perhaps I should do an article on that in the future.
Cancel
Hi Sharon,

There are plenty of other ways to transfer files via FTP. In this article, I'm just showing you the nuts and bolts of how it can be doing with .NET and PowerShell. One of the nice things about PowerShell is that you can wrap up all this code into a function which you can then do something like Download-File or Upload-File. It takes all the messiness out of it. :)
Cancel
how to upload power bi reports to server using power shell
Cancel

-ADS BY GOOGLE

SearchServerVirtualization

SearchCloudComputing

SearchSQLServer

SearchEnterpriseDesktop

SearchVirtualDesktop

Close