How do I query a file on FTP server in PowerShell

2019-01-27 04:28发布

问题:

The project is an MVC website coded and built using VS2017 and (on premises) TFS2017. The Build Definition is currently working and publishing to the staging location upon check-in.

The PowerShell script below, derived from David Kittle's website, is being used but it uploads all files every time. I abbreviated the listing using comments to focus on the part of the script for which I'd like to ask for help/guidance.

# Setup the FTP connection, destination URL and local source directory
# Put the folders and files to upload into $Srcfolders and $SrcFiles
# Create destination folders as required

# start file uploads
foreach($entry in $SrcFiles)
{
    #Create full destination filename from $entry and put it into $DesFile
    $uri = New-Object System.Uri($DesFile) 

    #NEED TO GET THE REMOTE FILE DATA HERE TO TEST AGAINST THE LOCAL FILE
    If (#perform a test to see if the file needs to be uploaded)
        { $webclient.UploadFile($uri, $SrcFullname) }
}

In the last few lines of the script above I need to determine if a source file requires upload. I am assuming I can check the time stamp to determine this. So;

If my assumption is wrong, please advise the best way to check for a required upload.

If my assumption is correct, how do I (1) retrieve the time stamp from the remote server and then (2) make the check against the local file?

回答1:

You can use the FtpWebRequest class with its GetDateTimestamp FTP "method" and parse the UTC timestamp string it returns. The format is specified by RFC 3659 to be YYYYMMDDHHMMSS[.sss].

That would work only if the FTP server supports MDTM command that the method uses under the cover (most servers do, but not all).

$ftprequest =
    [System.Net.FtpWebRequest]::Create("ftp://ftp.example.com/remote/folder/file.txt")

$ftprequest.Method = [System.Net.WebRequestMethods+Ftp]::GetDateTimestamp

$response = $ftprequest.GetResponse().StatusDescription

$tokens = $response.Split(" ")

$code = $tokens[0]

if ($code -eq 213)
{
    Write-Host "Timestamp is $($tokens[1])"
}
else
{
    Write-Host "Error $response"
}

It would output something like:

Timestamp is 20171019230712

Now you parse it, and compare against a UTC timestamp of a local file:

(Get-Item "file.txt").LastWriteTimeUtc

Or save yourself some time and use an FTP library/tool that can do this for you.

For example with WinSCP .NET assembly, you can synchronize whole local folder with a remote folder with one call to the Session.SynchronizeDirectories. Or your can limit the synchronization to a set of files only.

# Load WinSCP .NET assembly
Add-Type -Path "WinSCPnet.dll"

# Setup session options
$sessionOptions = New-Object WinSCP.SessionOptions
$sessionOptions.Protocol = [WinSCP.Protocol]::Ftp
$sessionOptions.HostName = "ftpsite.com"

$session = New-Object WinSCP.Session

# Connect
$session.Open($sessionOptions)

$session.SynchronizeDirectories(
    [WinSCP.SynchronizationMode]::Remote, "C:\local\folder", "/remote/folder").Check()

To use the assembly, just extract a contents of .NET assembly package to your script folder. No other installation is needed.

The assembly supports not only the MDTM, but also other alternative methods to retrieve the timestamp.

(I'm the author of WinSCP)