powershell - 使用PowerShell中的WinSCP .NET程序集从FTP/SFTP服务器上的文件夹集中下载文件和电子邮件结果

标签 powershell ftp sftp winscp winscp-net

我有正在使用的PowerShell脚本。导入CSV文件可获取源路径和目标路径。目的是将文件从SFTP / FTP服务器移至目标位置并发送电子邮件报告。

任务计划程序将每小时运行一次此代码。如果有新文件,则将发送电子邮件。

差不多完成了,但是缺少两件事:

  • 检查文件是否已经存在,并且正文电子邮件似乎为空:出现以下错误:无法验证参数'Body'上的参数。参数为null或为空。提供一个不是
    null或为空,然后重试该命令。
  • 我想要一些有关如何检查文件是否存在以及如果将新文件删除并复制到目标列表
  • 的电子邮件的帮助。
    $SMTPBody = ""
    
    $SMTPMessage  = @{
      "SMTPServer" = ""
      "From" = ""
      "To" = ""
      "Subject" = "New File"
    }
    try {
      # Load WinSCP .NET assembly
      Add-Type -Path "C:\Program Files (x86)\WinSCP\WinSCPnet.dll"
    
      # Setup session options
      $sessionOptions = New-Object WinSCP.SessionOptions -Property @{
        Protocol = [WinSCP.Protocol]::sftp
        HostName = ""
        UserName = ""
        Password = ""
        PortNumber = "22"
        FTPMode = ""
        GiveUpSecurityAndAcceptAnySshHostKey = $true
      }
      $session = New-Object WinSCP.Session
      try
      {
        # Connect
        $session.Open($sessionOptions)
        # Download files
        $transferOptions = New-Object WinSCP.TransferOptions
        $transferOptions.TransferMode = [WinSCP.TransferMode]::Binary
    
        Import-Csv -Path "D:\FILESOURCE.csv" -ErrorAction Stop |  foreach {
    
          $synchronizationResult = $session.SynchronizeDirectories(
            [WinSCP.SynchronizationMode]::Local, $_.Destination, $_.Source, $False)
          $synchronizationResult.Check()
    
          foreach ($download in $synchronizationResult.Downloads ) {
            Write-Host "File $($download.FileName) downloaded" -ForegroundColor Green
            $SMTPBody +=
              "`n Files: $($download.FileName -join ',    ') `n" +
              "Current Location: $($_.Destination)`n"
            Send-MailMessage @SMTPMessage  -Body $SMTPBody
          }
    
          $transferResult =
            $session.GetFiles($_.Source, $_.Destination, $False, $transferOptions)
          #Find the latest downloaded file
          $latestTransfer =
            $transferResult.Transfers |
            Sort-Object -Property @{ Expression = { (Get-Item $_.Destination).LastWriteTime }
            } -Descending |Select-Object -First 1
        }
    
        if ($latestTransfer -eq $Null) {
          Write-Host "No files found."
          $SMTPBody += "There are no new files at the moment"
        }
        else
        {
          $lastTimestamp = (Get-Item $latestTransfer.Destination).LastWriteTime
          Write-Host (
            "Downloaded $($transferResult.Transfers.Count) files, " +
            "latest being $($latestTransfer.FileName) with timestamp $lastTimestamp.")
          $SMTPBody += "file : $($latestTransfer)"
        }
    
        Write-Host "Waiting..."
        Start-Sleep -Seconds 5
      }  
      finally
      {
        Send-MailMessage @SMTPMessage  -Body  $SMTPBody
        # Disconnect, clean up
        $session.Dispose()
      }
    }
    catch
    {
      Write-Host "Error: $($_.Exception.Message)"
    }
    

    最佳答案

    我相信您的代码有比您想象的更多的问题。

  • 您的SynchronizeDirectoriesGetFiles组合可疑。您首先通过SynchronizeDirectories仅下载新文件,然后通过GetFiles下载所有文件。我不认为你想要那样。
  • 发生任何错误时,都会引发.Check调用,并且您不会将错误收集到报告中。
  • 您一直在foreach循环中通过Send-MailMessage发送部分报告

  • 这是我对您的问题的看法,希望我已正确理解您要实现的目标:
    $SMTPBody = ""
    
    Import-Csv -Path "FILESOURCE.csv" -ErrorAction Stop |  foreach {
    
        Write-Host "$($_.Source) => $($_.Destination)"
        $SMTPBody += "$($_.Source) => $($_.Destination)`n"
    
        $synchronizationResult =
            $session.SynchronizeDirectories(
                [WinSCP.SynchronizationMode]::Local, $_.Destination, $_.Source, $False)
    
        $downloaded = @()
        $failed = @()
        $latestName = $Null
        $latest = $Null
        foreach ($download in $synchronizationResult.Downloads)
        {
            if ($download.Error -eq $Null)
            {
                Write-Host "File $($download.FileName) downloaded" -ForegroundColor Green
                $downloaded += $download.FileName
                $ts = (Get-Item $download.Destination).LastWriteTime
                if ($ts -gt $latest)
                {
                    $latestName = $download.FileName;
                    $latest = $ts
                }
            }
            else
            {
                Write-Host "File $($download.FileName) download failed" -ForegroundColor Red
                $failed += $download.FileName
            }
        }
    
        if ($downloaded.Count -eq 0)
        {
            $SMTPBody += "No new files were downloaded`n"
        }
        else
        {
            $SMTPBody += 
                "Downloaded $($downloaded.Count) files:`n" +
                ($downloaded -join ", ") + "`n" +
                "latest being $($latestName) with timestamp $latest.`n"
        }
    
        if ($failed.Count -gt 0)
        {
            $SMTPBody += 
                "Failed to download $($failed.Count) files:`n" +
                ($failed -join ", ") + "`n"
        }
    
        $SMTPBody += "`n"
    }
    

    它将为您提供如下报告:

    /source1 => C:\dest1`
    Downloaded 3 files:
    /source1/aaa.txt, /source1/bbb.txt, /source1/ccc.txt
    latest being /source1/ccc.txt with timestamp 01/29/2020 07:49:07.
    
    /source2 => C:\dest2
    Downloaded 1 files:
    /source2/aaa.txt
    latest being /source2/aaa.txt with timestamp 01/29/2020 07:22:37.
    Failed to download 1 files:
    /source2/bbb.txt
    

    关于powershell - 使用PowerShell中的WinSCP .NET程序集从FTP/SFTP服务器上的文件夹集中下载文件和电子邮件结果,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59954950/

    相关文章:

    rest - PowerShell REST内部主体

    sql-server - 为什么 Invoke-Sqlcmd -OutputAs DataTables 为一条记录和多条记录返回不同的类型

    python - 是否有用于上传整个目录(包括子目录)的 python ftp 库?

    Android 异步 FTP

    java - 尚未为 channel 适配器定义轮询器

    php - 将文件上传到 SFTP 服务器

    powershell - Azure 通过自动部署启用 Web 部署

    powershell - PowerShell 中由 null dsquery 引发的错误处理

    android - 如何在 Android 应用程序中将图像上传到 FTP 服务器?

    sftp - 使用 sftp -b 批处理文件的权限被拒绝