Modyfikacja wtyczki WinSCP
w Notatki / IT
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