首页 文章

使用PowerShell从FTP下载最新文件

提问于
浏览
5

我正在开发一个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 $_)) 
      }
}

2 回答

  • 0

    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 命令的第三方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的作者)

  • 8

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

    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 session中使用 mget *2018_08_03* 来获取文件 .

    我们的备份程序每天早上01.00运行,因此我们每天都有备份我们可以获取 .

    当然,根据备份文件时间戳获取最新备份文件的脚本会更漂亮,更好,以防最新备份出现问题或备份文件命名格式发生变化 . 该脚本只是一个脚本,用于获取内部开发目的的备份,因此如果它中断,它就没什么大不了的 . 我稍后会研究这个问题,检查一下是否可以制作更清洁的解决方案 .

    我制作了一个批处理脚本,它只是用普通的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%"
    

相关问题