Modyfikacja wtyczki WinSCP

Modyfikacja wtyczki WinSCP

Dodałem funkcję której mi brakowało

Case

Używam WinSCP do synchronizacji zdalnego katalogu FTP z lokalnym folderem. Pliki są automatycznie pobierane z katalogu i wczytywane do Lightrooma. Na serwer FTP pliki są wgrywane bezpośrednio z apartu podłączonego do sieci.

+---------+       FTP Upload        +------------+
|  Camera | ----------------------> | FTP Server |
+---------+  (smartphone hotspot)   +------------+
                                         |
                                         | Sync via
                                         | WinSCP
                                         v
                                   +--------------+
                                   |   Computer   |
                                   |  (Local Dir) |
                                   +--------------+
                                         |
                                         | Auto-import
                                         v
                                  +------------------+
                                  | Adobe Lightroom  |
                                  +------------------+

Zmiany

  • Dodałem opcję pobierania tylko plików króych czas modyfikacji jest starszy niż określona ilość sekund. Rozwiązuje to prawie całkowicie problem pobierania niekompletnych plików które są właśnie wgrywane na serwer.
  • Dodałem funkcję do automatycznego usuwania plików z serwera po ich pobraniu.

Kod wtyczki

Lokalizacja pliku wtyczki: ~\WinSCP\Extensions\KeepLocalUpToDate.WinSCPextension.ps1

# @name         &Keep Local Directory up to Date and Delete Remote...
# @command      powershell.exe -ExecutionPolicy Bypass -File "%EXTENSION_PATH%" ^
#                   -sessionUrl "!E" -localPath "%LocalPath%" -remotePath "%RemotePath%" ^
#                   %Delete% %DeleteRemote% %Beep% %ContinueOnError% -interval "%Interval%" ^
#                   -fileMask "%FileMask%" -pause -sessionLogPath "%SessionLogPath%" -minDownloadAge "%MinDownloadAge%"
# @description  Periodically scans for changes in a remote directory, ^
#                   reflects them on a local directory and optionally deletes remote files
# @version      14
# @homepage     https://winscp.net/eng/docs/library_example_keep_local_directory_up_to_date
# @require      WinSCP 5.16
# @option       - -run group "Directories"
# @option         RemotePath -run textbox "&Watch for changes in the remote directory:" "!/"
# @option         LocalPath -run textbox ^
#                     "... &and automatically reflect them on the local directory:" "!\"
# @option       - -config -run group "Options"
# @option         Delete -config -run checkbox "&Delete local files" "" -delete 
# @option         DeleteRemote -config -run checkbox "Delete &remote files after download" "" -deleteRemote
# @option         Beep -config -run checkbox "&Beep on change" "" -beep
# @option         ContinueOnError -config -run checkbox "Continue on &error" "" -continueOnError
# @option         Interval -config -run textbox "&Interval (in seconds):" "30"
# @option         FileMask -config -run textbox "File &mask:" ""
# @option         MinDownloadAge -config -run textbox "Minimum download age (in seconds):" "5"
# @option       - -config group "Logging"
# @option         SessionLogPath -config sessionlogfile

param (
    $sessionUrl = "sftp://user:mypassword;[email protected]/",
    [Parameter(Mandatory = $True)]
    $localPath,
    [Parameter(Mandatory = $True)]
    $remotePath,
    [Switch]
    $delete,
    [Switch]
    $deleteRemote,
    [Switch]
    $beep,
    [Switch]
    $continueOnError,
    $sessionLogPath = $Null,
    $interval = 30,
    $fileMask = $Null,
    [Switch]
    $pause,
    $minDownloadAge = 5
)

function Beep() {
    if ($beep) {
        [System.Console]::Beep()
    }
}

function HandleException ($e) {
    if ($continueOnError) {
        Write-Host -ForegroundColor Red $_.Exception.Message
        Beep
    }
    else {
        throw $e
    }
}

function SetConsoleTitle ($status) {
    if ($sessionOptions) {
        $status = "$sessionOptions - $status"
    }
    $Host.UI.RawUI.WindowTitle = $status
}

try {
    # Load WinSCP .NET assembly
    $assemblyPath = if ($env:WINSCP_PATH) { $env:WINSCP_PATH } else { $PSScriptRoot }
    Add-Type -Path (Join-Path $assemblyPath "WinSCPnet.dll")

    # Setup session options
    $sessionOptions = New-Object WinSCP.SessionOptions
    $sessionOptions.ParseUrl($sessionUrl)

    $transferOptions = New-Object WinSCP.TransferOptions -Property @{ FileMask = $fileMask };

    $session = New-Object WinSCP.Session
    
    try {
        $session.SessionLogPath = $sessionLogPath

        Write-Host "Connecting..."
        SetConsoleTitle "Connecting"
        $session.Open($sessionOptions)

        while ($True) {
            Write-Host -NoNewline "Looking for changes..."
            SetConsoleTitle "Looking for changes"
            try {
                # Track successfully downloaded files
                $downloadedFiles = @()

                $differences =
                $session.CompareDirectories(
                    [WinSCP.SynchronizationMode]::Local, $localPath, $remotePath, $delete,
                    $False, [WinSCP.SynchronizationCriteria]::Time, $transferOptions)

                Write-Host
                if ($differences.Count -eq 0) {
                    Write-Host "No changes found."   
                }
                else {
                    Write-Host "Synchronizing $($differences.Count) change(s)..."
                    SetConsoleTitle "Synchronizing changes"
                    

                    foreach ($difference in $differences) {
                        $action = $difference.Action
                        if ($action -eq [WinSCP.SynchronizationAction]::DownloadNew) {
                            $message = "Downloading new $($difference.Remote.FileName)..."
                        }
                        elseif ($action -eq [WinSCP.SynchronizationAction]::DownloadUpdate) {
                            $message = "Downloading updated $($difference.Remote.FileName)..."
                        }
                        elseif ($action -eq [WinSCP.SynchronizationAction]::DeleteLocal) {
                            $message = "Deleting local $($difference.Local.FileName)..."
                        }
                        else {
                            throw "Unexpected difference $action"
                        }

                        Write-Host -NoNewline $message

                        try {
                            # Check if the file's last modification date is older than the specified minimum age
                            $lastWriteTime = $difference.Remote.LastWriteTime
                            $currentTime = [System.DateTime]::Now
                            $timeDifference = $currentTime - $lastWriteTime

                            if ($timeDifference.TotalSeconds -gt $minDownloadAge) {
                                $difference.Resolve($session, $transferOptions) | Out-Null
                                Write-Host " Done."
                                Beep

                                # Track successfully downloaded files
                                if (($action -eq [WinSCP.SynchronizationAction]::DownloadNew) -or 
                                    ($action -eq [WinSCP.SynchronizationAction]::DownloadUpdate)) {
                                    $downloadedFiles += $difference.Remote
                                }
                            } else {
                                Write-Host " Skipping download of $($difference.Remote.FileName) as it was modified less than $minDownloadAge seconds ago."
                            }
                        }
                        catch {
                            Write-Host
                            HandleException $_
                        }
                    }

                    # Delete only the files that were successfully downloaded
                    if ($deleteRemote -and $downloadedFiles.Count -gt 0) {
                        Write-Host "Deleting successfully downloaded remote files..."
                        foreach ($remoteFile in $downloadedFiles) {
                            try {
                                # Konstrukcja poprawnej ścieżki
                                $remoteFilePath = [System.IO.Path]::Combine($remotePath.TrimEnd('/'), $remoteFile.FileName).Replace('\', '/')
                                Write-Host "Attempting to delete: $remoteFilePath"
                                $result = $session.RemoveFiles($remoteFilePath)
                                if ($result.IsSuccess) {
                                    Write-Host "Deleted: $($remoteFile.FileName)"
                                } else {
                                    Write-Host "Failed to delete: $($remoteFile.FileName)"
                                    Write-Host -ForegroundColor Red $result.Failures[0].Message
                                }
                            }
                            catch {
                                Write-Host
                                HandleException $_
                            }
                        }
                    }
                }
            }
            catch {
                Write-Host
                HandleException $_
            }

            SetConsoleTitle "Waiting"
            $wait = [int]$interval
            # Wait for 1 second in a loop, to make the waiting breakable
            while ($wait -gt 0) {
                Write-Host -NoNewLine "`rWaiting for $wait seconds, press Ctrl+C to abort... "
                Start-Sleep -Seconds 1
                $wait--
            }

            Write-Host
            Write-Host
        }
    }
    finally {
        Write-Host # to break after "Waiting..." status
        Write-Host "Disconnecting..."
        # Disconnect, clean up
        $session.Dispose()
    }
}
catch {
    $continueOnError = $True
    HandleException $_
    SetConsoleTitle "Error"
}

# Pause if -pause switch was used
if ($pause) {
    Write-Host "Press any key to exit..."
    [System.Console]::ReadKey() | Out-Null
}

# Never exits cleanly
exit 1

© 2024. Wszelkie prawa zastrzeżone.

Powered by Hydejack v9.2.1