【问题标题】:How to compare age of local file with file on FTP server and download if remote copy is newer in PowerShell如何比较本地文件的年龄与 FTP 服务器上的文件并在 PowerShell 中的远程副本较新时下载
【发布时间】:2015-07-09 01:02:56
【问题描述】:

我正在编写一个 PowerShell 脚本,以帮助为我的工作设置新 PC。希望这不仅仅是我一个人使用的,所以我正在尝试考虑一切。

我在我们的 FTP 服务器上保存了离线安装程序(java、flash、阅读器等),如果本地副本尚未保存在创建的 Apps 目录中,脚本会下载这些安装程序。随着新版本程序的发布,FTP 服务器上的文件会定期更新。我希望脚本可以选择检查安装程序的较新版本,以防有人喜欢随身携带本地副本而忘记不时检查服务器。它还需要在 Windows 7 中工作,而无需导入其他模块,除非有一种简单的方法可以同时在多台 PC 上执行此操作。我知道 import 命令,但是我的经验需要我将模块文件复制到 PC 上的多个位置才能工作。

现在我没有太多运气找到任何解决方案。我找到了检查本地文件或本地服务器上文件的修改日期的代码,但除了上传\下载文件之外,没有任何处理 FTP 的代码。

这是我尝试的最后一件事。我尝试将我发现的本地文件与 FTP 结合起来。效果不太好。

我是 PowerShell 的新手,但到目前为止,我一直很擅长将整个事情拼凑起来。但是,这个想法变得很麻烦。

感谢您的帮助。

$ftpsite = "ftp://ftpsite.com/folder/"

$firefox = (Get-Item $dir\Apps\install_firefox.exe).LastWriteTime.toString("MM/dd/yyyy")

if ($firefoxftp = (Get-ChildItem $ftpsite/install_firefox.exe | Where{$_.LastWriteTime -gt $firefox})) {

    $File = "$dir\Apps\install_firefox.exe"
    $ftp = "ftp://ftpsite.com/folder/install_firefox.exe"
    $webclient = New-Object System.Net.WebClient
    $uri = New-Object System.Uri($ftp)
    $webclient.DownloadFile($uri, $File)

}

更新:

这是在 Martin 的帮助下我得到的。它有点工作。它从 FTP 下载文件,但没有正确比较远程和本地。远程文件返回 20150709140505,本地文件返回 07/09/2015 2:05:05 PM。如何在比较之前将一个格式设置为看起来像另一个,并且“-gt”是正确的比较吗?

谢谢!

function update {

    $ftprequest = [System.Net.FtpWebRequest]::Create("ftp://ftpsite.com/Script_Apps/install_firefox.exe")
    $ftprequest.Method = [System.Net.WebRequestMethods+Ftp]::GetDateTimestamp
    $response = $ftprequest.GetResponse().StatusDescription
    $tokens = $response.Split(" ")
    $code = $tokens[0]

    $localfile = (Get-Item "$dir\Apps\install_firefox.exe").LastWriteTimeUtc

    if ($tokens -gt $localfile) {

        write-host "Updating Firefox Installer..."
        $File = "$dir\Apps\install_firefox.exe"
        $ftp = "ftp://ftpsite.com/Script_Apps/install_firefox.exe"
        $webclient = New-Object System.Net.WebClient
        $uri = New-Object System.Uri($ftp)
        $webclient.DownloadFile($uri, $File)

        "Updated Firefox" >> $global:logfile

        mainmenu

    }

    else {
        Write-Host "Local Copy is Newer."
        sleep 3
        mainmenu
    }

}

更新 2:

似乎正在工作!这是代码。感谢您的帮助!

function update {

    $ftprequest = [System.Net.FtpWebRequest]::Create("ftp://ftpserver.com/Script_Apps/install_firefox.exe")
    $ftprequest.Method = [System.Net.WebRequestMethods+Ftp]::GetDateTimestamp
    $response = $ftprequest.GetResponse().StatusDescription
    $tokens = $response.Split(" ")
    $code = $tokens[0]

    $localtime = (Get-Item "$dir\Apps\install_firefox.exe").LastWriteTimeUtc

    if ($code -eq 213) {

        $tokens = $tokens[1]
        $localtime = "{0:yyyymmddHHmmss}" -f [datetime]$localtime

    }

    if ($tokens -gt $localtime) {

        write-host "Updating Firefox Installer..."
        $File = "$dir\Apps\install_firefox.exe"
        $ftp = "ftp://ftpserver.com/Script_Apps/install_firefox.exe"
        $webclient = New-Object System.Net.WebClient
        $uri = New-Object System.Uri($ftp)
        $webclient.DownloadFile($uri, $File)

        "Updated Firefox" >> $global:logfile

        mainmenu

    }

    else {
        Write-Host "Local Copy is Newer."
        sleep 3
        mainmenu
    }

}

【问题讨论】:

  • 您的最终代码应该可以正常工作,除了您应该将整个 if ($tokens -gt $localtime) 块移动到 if ($code -eq 213) 块中。否则,如果时间戳检索失败,则您正在比较未定义的变量。

标签: windows powershell ftp


【解决方案1】:

您不能使用WebClient 类来检查远程文件时间戳。

您可以使用FtpWebRequest class 及其GetDateTimestamp FTP "method" 并解析它返回的UTC 时间戳字符串。格式由RFC 3659 指定为YYYYMMDDHHMMSS[.sss]

只有当 FTP 服务器支持该方法在后台使用的MDTM 命令时才有效(大多数服务器支持,但不是全部)。

$url = "ftp://ftpsite.com/folder/install_firefox.exe"
$ftprequest = [System.Net.FtpWebRequest]::Create($url)

$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
}

它会输出如下内容:

Timestamp is 20150709065036

现在您解析它,并与本地文件的 UTC 时间戳进行比较:

(Get-Item "install_firefox.exe").LastWriteTimeUtc

或者为自己节省一些时间并使用可以为您执行此操作的 FTP 库/工具。

例如使用WinSCP .NET assembly,您可以通过一次调用Session.SynchronizeDirectories 将整个远程文件夹与具有本地副本的安装程序同步。或者您可以将同步限制为仅单个文件。

# 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)

$transferOptions = New-Object WinSCP.TransferOptions
# Synchronize only this one file.
# If you remove the file mask, all files in the folder are synchronized:
$transferOptions.FileMask = "install_firefox.exe"

$session.SynchronizeDirectories(
    [WinSCP.SynchronizationMode]::Local, "$dir\Apps", "/folder",
    $False, $False, [WinSCP.SynchronizationCriteria]::Time, 
    $transferOptions).Check()

要使用该程序集,只需将.NET assembly package 的内容提取到您的脚本文件夹。无需其他安装。

该程序集不仅支持MDTM,还支持其他检索时间戳的替代方法。

另请参阅related Powershell example,其中显示了上述代码和其他技术。

(我是 WinSCP 的作者)

【讨论】:

  • 谢谢马丁!第一个选项似乎可以很好地返回日期和时间,所以我现在正在使用它。请查看我上面的更新代码。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2010-11-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-10-02
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多