Upload a file with ftp using PowerShell

Recently I needed a script to upload log files from one server to another server. The servers were in separate networks so I could not use a simple copy command like xcopy or robocopy. For this I had to use FTP. I had already a simple old batch file that uses the built-in ftp command. But I wanted to use PowerShell so that I could make it more advanced. After some searching on PowerShell websites I found some examples. I used these as a start for my function.

function Send-FileToFtp {
    [CmdletBinding()]
    [OutputType([System.Int32])]
    param(
        [Parameter(Position=0, Mandatory=$true)]
        [ValidateNotNullOrEmpty()]
        [System.Object]$SourceFile,

        [Parameter(Position=1, Mandatory=$true)]
        [ValidateNotNullOrEmpty()]
        [System.String]$Destination,
        
        [Parameter(Position=2, Mandatory=$true)]
        [ValidateNotNullOrEmpty()]
        [System.String]$UserName,
        
        [Parameter(Position=3, Mandatory=$true)]
        [ValidateNotNullOrEmpty()]
        [System.String]$Password
    )

    Process {
        try {
            # Get the object used to communicate with the server. 
            $Request = [System.Net.FtpWebRequest]::Create("ftp://$Destination/$($SourceFile.Name)") 
            $Request.Method = $Request.Method = [System.Net.WebRequestMethods+ftp]::UploadFile 
             
            # This example assumes the FTP site uses anonymous logon. 
            $Request.Credentials = New-Object System.Net.NetworkCredential $UserName,$Password 
             
            # Copy the contents of the file to the request stream. 
            $FileContents = [System.IO.File]::ReadAllBytes($SourceFile.FullName) 
            $Request.ContentLength = $fileContents.Length
            $RequestStream = $request.GetRequestStream() 
            $RequestStream.Write($FileContents, 0, $FileContents.Length) 
            $RequestStream.Close()
            $Response = $Request.GetResponse() 
            $Response.StatusDescription
        }
        catch {
            throw "ERROR: Unable to upload file $($SourceFile.name), status {0}"
        }
        $Response.StatusDescription
        }
    }

The function takes 4 parameters as you can see in the script. Most of them will be self explaining. But the parameter $SourceFile will need some explanation. Instead of using a string I decided to use an object. I did this so I can use the object to construct the filename of the source and also use it to construct the ftp request. To use the function you can write something like this.

$files = Get-ChildItem -Path "c:\windows\system32\logfiles\" -Filter "*.log"
if ($files -ne $null) {
    Foreach ($file in $files) {
        $result = Send-FileToFtp -SourceFile $file -Destination "ftp.domain.com/folder" -UserName "user" -Password "password"
        if ($Result -match "226*"){
            "Upload completed, now deleting source file: $($File.Name)"
        } else {
            "Upload failed!"
        }
    }
}

It gets all the log files from the c:\windows\system32logfiles directory and places them in the variable $files. For every file object in the variable $files it runs the function Send-FileToFtp. If the upload succeeds, the function returns a StatusDescription with the code 226, you can delete the original file or do something else. When the upload fails you can output a message or do somethings else.

For what I wanted to do this works perfect. But for other things it possibly needs to get changed a bit.

Advertisements