【问题标题】:Download most recent file from FTP using PowerShell使用 PowerShell 从 FTP 下载最新文件
【发布时间】:2017-04-12 06:10:17
【问题描述】:

我正在编写一个 PowerShell 脚本,该脚本将从 FTP 站点提取文件。这些文件每小时上传到 FTP 站点,所以我需要下载最新的文件。我目前拥有的代码从今天开始下载所有文件,而不仅仅是一个文件。如何让它只下载最新的文件?

这是我目前使用的代码

$ftpPath = 'ftp://***.***.*.*'
$ftpUser = '******'
$ftpPass = '******'
$localPath = 'C:\Temp'
$Date = get-date -Format "ddMMyyyy"
$Files = 'File1', 'File2'

function Get-FtpDir ($url, $credentials)
{
  $request = [Net.FtpWebRequest]::Create($url)
  if ($credentials) { $request.Credentials = $credentials }
  $request.Method = [System.Net.WebRequestMethods+FTP]::ListDirectory
  (New-Object IO.StreamReader $request.GetResponse().GetResponseStream()) -split "`r`n" 

}

$webclient = New-Object System.Net.WebClient 
$webclient.Credentials = New-Object System.Net.NetworkCredential($ftpUser,$ftpPass)  
$webclient.BaseAddress = $ftpPath

Foreach ( $item in $Files )
{
    Get-FTPDir $ftpPath $webclient.Credentials |
      ? { $_ -Like $item+$Date+'*' } |
      % {

          $webClient.DownloadFile($_, (Join-Path $localPath $_)) 
      }
}

【问题讨论】:

    标签: powershell ftp ftpwebrequest


    【解决方案1】:

    FtpWebRequest 并不容易。对于您的任务,您需要知道文件时间戳。

    不幸的是,没有真正可靠和有效的方法来使用FtpWebRequest/.NET framework/PowerShell 提供的功能来检索时间戳,因为它们不支持 FTP MLSD 命令。 MLSD 命令以标准化的机器可读格式提供远程目录列表。命令和格式由RFC 3659标准化。

    .NET 框架支持的您可以使用的替代方案:

    • ListDirectoryDetails 方法(一个 FTP LIST 命令)检索目录中所有文件的详细信息,然后处理 FTP 服务器特定格式的详细信息(*nix 格式类似于 ls *nix 命令是最常见的,缺点是格式可能会随着时间而改变,因为较新的文件使用“May 8 17:48”格式,而旧文件使用“Oct 18 2009”格式)
    • GetDateTimestamp 方法(一个 FTP MDTM 命令)单独检索每个文件的时间戳。优点是响应由RFC 3659 标准化为YYYYMMDDHHMMSS[.sss]。缺点是您必须为每个文件发送单独的请求,这可能效率很低。

    一些参考资料:


    或者,使用支持MLSD 命令和/或支持解析专有列表格式的第 3 方 FTP 库。

    例如WinSCP .NET assembly 支持两者。

    示例代码:

    # Load WinSCP .NET assembly
    Add-Type -Path "WinSCPnet.dll"
    
    # Setup session options
    $sessionOptions = New-Object WinSCP.SessionOptions -Property @{
        Protocol = [WinSCP.Protocol]::Ftp
        HostName = "example.com"
        UserName = "user"
        Password = "mypassword"
    }
    
    $session = New-Object WinSCP.Session
    
    # Connect
    $session.Open($sessionOptions)
    
    # Get list of files in the directory
    $directoryInfo = $session.ListDirectory($remotePath)
    
    # Select the most recent file
    $latest =
        $directoryInfo.Files |
        Where-Object { -Not $_.IsDirectory } |
        Sort-Object LastWriteTime -Descending |
        Select-Object -First 1
    
    # Any file at all?
    if ($latest -eq $Null)
    {
        Write-Host "No file found"
        exit 1
    }
    
    # Download the selected file
    $sourcePath = [WinSCP.RemotePath]::EscapeFileMask($remotePath + $latest.Name)
    $session.GetFiles($sourcePath, $localPath).Check()
    

    完整代码见Downloading the most recent file (PowerShell)

    (我是 WinSCP 的作者)

    【讨论】:

    • WinSCP 是一个很棒的实用程序并且非常可靠:)
    • WinSCP 摇滚。使用 PowerShell 进行 FTP 传输非常有效。
    【解决方案2】:

    我试过这个,但我得到一个错误:

    Error: Exception calling "ListDirectory" with "1" argument(s): "Error listing directory '/path/'.
    Could not retrieve directory listing
    Can't open data connection for transfer of "/path/"
    

    我在互联网上阅读了很多有关此问题的信息,但找不到看起来相当简单的解决方案,而且我不是网络设置向导。所以我选择了不同的方法。在我们的例子中,我想要自动下载的文件的文件名中指定了日期:backup_2018_08_03_020003_1048387.bak

    所以我们可以在命令行 ftp 会话中使用mget *2018_08_03* 来获取文件。

    我们的备份程序在每天早上 1 点运行,因此我们每天都有一个可以获取的备份。

    当然,如果有一个基于备份文件时间戳获取最新备份文件的脚本会更漂亮更好,以防最新备份出现问题或备份文件命名格式更改。该脚本只是一个用于为内部开发目的获取备份的脚本,因此如果它坏了也没什么大不了的。稍后我会对此进行研究,并检查是否可以制定更清洁的解决方案。

    我用普通的 ftp 命令提示脚本编写了一个批处理脚本,它只要求今天的备份文件。

    正确设置今天日期的格式很重要。它必须正确匹配文件名中日期的格式。

    如果你想使用脚本,你应该用你自己的信息替换变量。您还应该对运行它的目录具有写入权限。

    这是我制作的脚本:

    @Echo Off
    Set _FTPServerName=xxx.xxx.xx.xxx
    Set _UserName=Username
    Set _Password=Password
    Set _LocalFolder=C:\Temp
    Set _RemoteFolder="/path/"
    Set _Filename=*%date:~-4,4%_%date:~-7,2%_%date:~-10,2%*
    Set _ScriptFile=ftptempscript
    :: Create script
     >"%_ScriptFile%" Echo open %_FTPServerName%
    >>"%_ScriptFile%" Echo %_UserName%
    >>"%_ScriptFile%" Echo %_Password%
    >>"%_ScriptFile%" Echo lcd %_LocalFolder%
    >>"%_ScriptFile%" Echo cd %_RemoteFolder%
    >>"%_ScriptFile%" Echo binary
    >>"%_ScriptFile%" Echo mget -i %_Filename%
    >>"%_ScriptFile%" Echo quit
    :: Run script
    ftp -s:"%_ScriptFile%"
    del "%_ScriptFile%"
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-04-09
      • 2015-07-27
      • 2012-02-02
      相关资源
      最近更新 更多