使用 WinSCP .NET 程序集下载后移动(不复制)远程文件

Moving (not copying) remote files after download with WinSCP .NET assembly

我有这个脚本可以下载所有 .txt 和 .log 文件。但是我需要在下载后将它们移动到服务器上的另一个目录。

到目前为止,我一直收到类似 "cannot move "file" to "/file" 这样的错误。

try
{
    # Load WinSCP .NET assembly
    Add-Type -Path "C:\Program Files (x86)\WinSCP\WinSCPnet.dll"

    # Setup session options
    $sessionOptions = New-Object WinSCP.SessionOptions
    $sessionOptions.Protocol = [WinSCP.Protocol]::ftp
    $sessionOptions.HostName = "host"
    $sessionOptions.PortNumber = "port"
    $sessionOptions.UserName = "user"
    $sessionOptions.Password = "pass"

    $session = New-Object WinSCP.Session

    try
    {
        # Connect
        $session.DisableVersionCheck = "true"
        $session.Open($sessionOptions)

        $localPath = "C:\users\user\desktop\file"
        $remotePath = "/"
        $fileName = "*.txt"
        $fileNamee = "*.log"
        $remotePath2 = "/completed"
        $directoryInfo = $session.ListDirectory($remotePath)
        $directoryInfo = $session.ListDirectory($remotePath2)

        # Download the file
        $session.GetFiles(($remotePath + $fileName), $localPath).Check()
        $session.GetFiles(($remotePath + $fileNamee), $localPath).Check()

        $session.MoveFile(($remotePath + $fileName, $remotePath2)).Check()
        $session.MoveFile(($remotePath + $fileNamee, $remotePath2)).Check() 

    }
    finally
    {
        # Disconnect, clean up
        $session.Dispose()
    }

    exit 0
}
catch [Exception]
{
    Write-Host $_.Exception.Message
    exit 1
}

您是否检查过以确保您的进程有权将文件移动到新目录?

你的代码有很多问题:


Session.MoveFile 方法的 targetPath 参数是 move/rename 文件的路径。

因此,如果您使用目标路径 /complete,您正试图将文件移动到根文件夹并将其重命名为 complete。虽然您可能想将文件移动到 /complete 文件夹并保留其名称。为此,使用目标路径 /complete/(或 /complete/* 使其更明显)。

您当前的代码失败,因为您正在将文件重命名为现有文件夹的名称。


您实际上在 .GetFiles 中有相同的错误。您正在将所有文件(*.txt*.log)下载到文件夹 C:\users\user\desktop 并将它们全部保存到相同的名称 file,相互覆盖。


你用括号错误地包围了两个参数,而不是只包围了第一个参数。虽然我不是 PowerShell 专家,但我实际上会说您以这种方式完全省略了该方法的第二个参数。


此外,请注意 MoveFile 方法不会 return 任何东西(与 GetFiles 相反)。所以没有对象可以调用 .Check() 方法。


MoveFile(注意单数,与GetFiles相比),只移动一个文件。所以你不应该使用文件掩码。实际上,当前的实现允许使用文件掩码,但这种使用没有记录在案,可能会在未来的版本中弃用。

无论如何,最好的解决方案是迭代实际下载文件的列表,如 GetFiles 编辑的 return 并一个一个地移动文件。

这样可以避免竞争条件,下载文件集,添加新文件(您没有下载)并且错误地将它们移动到 "completed" 文件夹。


代码应该如下所示(仅针对第一组文件,即 *.txt):

$remotePath2 = "/completed/"

...

$transferResult = $session.GetFiles(($remotePath + $fileName), $localPath)
$transferResult.Check()

foreach ($transfer in $transferResult.Transfers)
{
    $session.MoveFile($transfer.FileName, $remotePath2) 
}

请注意,这不包括对 $localPath 的修复,因为我不确定路径 C:\users\user\desktop\file 的实际含义。


实际上有一个非常相似的示例代码可用:
Moving local files to different location after successful upload

我正在按照 Martin 在这里的建议行事,并取得了成功。

但我有时会卡住。

运行“session.MoveFile()”后,源文件夹中的文件消失了,但目标文件夹中没有显示。

文件将在一段时间后(我猜是大约 30 分钟)自动处理“会话”后显示到目的地。

为避免这种混淆,请释放会话。 像这样:

session.Dispose();

我知道这是微不足道的,但我希望你不要陷入同样的​​问题。