|
@@ -43,6 +43,15 @@
|
|
|
.PARAMETER Recurse
|
|
.PARAMETER Recurse
|
|
|
Scan subdirectories in LocalPath.
|
|
Scan subdirectories in LocalPath.
|
|
|
|
|
|
|
|
|
|
+.PARAMETER RenamePattern
|
|
|
|
|
+ Regex pattern to match in the filename for renaming before upload.
|
|
|
|
|
+ Must be used together with -RenameReplacement.
|
|
|
|
|
+ Supports capture groups (e.g. '(.+)\.csv$' with replacement '$1_processed.csv').
|
|
|
|
|
+
|
|
|
|
|
+.PARAMETER RenameReplacement
|
|
|
|
|
+ Replacement string for the -RenamePattern match. Supports regex capture groups ($1, ${1}, etc.).
|
|
|
|
|
+ Use '$0' to reference the full match.
|
|
|
|
|
+
|
|
|
.PARAMETER DeleteAfterTransfer
|
|
.PARAMETER DeleteAfterTransfer
|
|
|
Delete local files after successful upload (move behavior).
|
|
Delete local files after successful upload (move behavior).
|
|
|
|
|
|
|
@@ -60,6 +69,18 @@
|
|
|
.\Send-FilesToSftp.ps1 -LocalPath "C:\exports" -RemotePath "/incoming" `
|
|
.\Send-FilesToSftp.ps1 -LocalPath "C:\exports" -RemotePath "/incoming" `
|
|
|
-HostName "sftp.example.com" -UserName "uploader" -FileFilter '\.csv$'
|
|
-HostName "sftp.example.com" -UserName "uploader" -FileFilter '\.csv$'
|
|
|
|
|
|
|
|
|
|
+.EXAMPLE
|
|
|
|
|
+ # Rename files by appending today's date before the extension
|
|
|
|
|
+ .\Send-FilesToSftp.ps1 -LocalPath "C:\exports" -RemotePath "/incoming" `
|
|
|
|
|
+ -HostName "sftp.example.com" -UserName "uploader" `
|
|
|
|
|
+ -RenamePattern '^(.+?)(\.[^.]+)$' -RenameReplacement "`$1_$(Get-Date -Format 'yyyyMMdd')`$2"
|
|
|
|
|
+
|
|
|
|
|
+.EXAMPLE
|
|
|
|
|
+ # Add a prefix to every uploaded file
|
|
|
|
|
+ .\Send-FilesToSftp.ps1 -LocalPath "C:\exports" -RemotePath "/incoming" `
|
|
|
|
|
+ -HostName "sftp.example.com" -UserName "uploader" `
|
|
|
|
|
+ -RenamePattern '^' -RenameReplacement 'processed_'
|
|
|
|
|
+
|
|
|
.EXAMPLE
|
|
.EXAMPLE
|
|
|
# Unattended with saved credentials and move behavior
|
|
# Unattended with saved credentials and move behavior
|
|
|
.\Send-FilesToSftp.ps1 -LocalPath "C:\exports" -RemotePath "/incoming" `
|
|
.\Send-FilesToSftp.ps1 -LocalPath "C:\exports" -RemotePath "/incoming" `
|
|
@@ -106,6 +127,10 @@ param(
|
|
|
|
|
|
|
|
[string]$KeyFilePath,
|
|
[string]$KeyFilePath,
|
|
|
|
|
|
|
|
|
|
+ [string]$RenamePattern,
|
|
|
|
|
+
|
|
|
|
|
+ [string]$RenameReplacement,
|
|
|
|
|
+
|
|
|
[switch]$Recurse,
|
|
[switch]$Recurse,
|
|
|
|
|
|
|
|
[switch]$DeleteAfterTransfer,
|
|
[switch]$DeleteAfterTransfer,
|
|
@@ -169,11 +194,18 @@ function Find-WinScpDll {
|
|
|
# ── Main ─────────────────────────────────────────────────────────────────────
|
|
# ── Main ─────────────────────────────────────────────────────────────────────
|
|
|
|
|
|
|
|
try {
|
|
try {
|
|
|
|
|
+ # ── Validate rename parameters ───────────────────────────────────────
|
|
|
|
|
+ if (($RenamePattern -and -not $RenameReplacement) -or ($RenameReplacement -and -not $RenamePattern)) {
|
|
|
|
|
+ Write-Log "-RenamePattern and -RenameReplacement must be used together." -Level ERROR
|
|
|
|
|
+ exit 1
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
Write-Log "═══ SFTP Transfer Starting ═══"
|
|
Write-Log "═══ SFTP Transfer Starting ═══"
|
|
|
Write-Log "Local path : $LocalPath"
|
|
Write-Log "Local path : $LocalPath"
|
|
|
Write-Log "Remote path : $RemotePath"
|
|
Write-Log "Remote path : $RemotePath"
|
|
|
Write-Log "File filter : $FileFilter"
|
|
Write-Log "File filter : $FileFilter"
|
|
|
Write-Log "Host : ${HostName}:${Port}"
|
|
Write-Log "Host : ${HostName}:${Port}"
|
|
|
|
|
+ if ($RenamePattern) { Write-Log "Rename : '$RenamePattern' → '$RenameReplacement'" }
|
|
|
if ($DryRun) { Write-Log "*** DRY RUN MODE - No files will be transferred ***" -Level WARN }
|
|
if ($DryRun) { Write-Log "*** DRY RUN MODE - No files will be transferred ***" -Level WARN }
|
|
|
|
|
|
|
|
# ── Find and load WinSCP ─────────────────────────────────────────────
|
|
# ── Find and load WinSCP ─────────────────────────────────────────────
|
|
@@ -228,10 +260,13 @@ try {
|
|
|
if ($DryRun) {
|
|
if ($DryRun) {
|
|
|
Write-Log "Files that would be transferred:" -Level INFO
|
|
Write-Log "Files that would be transferred:" -Level INFO
|
|
|
foreach ($f in $allFiles) {
|
|
foreach ($f in $allFiles) {
|
|
|
|
|
+ $destName = if ($RenamePattern) { $f.Name -replace $RenamePattern, $RenameReplacement } else { $f.Name }
|
|
|
$relativePath = $f.FullName.Substring($LocalPath.TrimEnd('\').Length)
|
|
$relativePath = $f.FullName.Substring($LocalPath.TrimEnd('\').Length)
|
|
|
- $remoteDest = ($RemotePath.TrimEnd('/') + $relativePath) -replace '\\', '/'
|
|
|
|
|
|
|
+ $remoteDir = ($RemotePath.TrimEnd('/') + ($f.DirectoryName.Substring($LocalPath.TrimEnd('\').Length) -replace '\\', '/'))
|
|
|
|
|
+ $remoteDest = "$remoteDir/$destName"
|
|
|
$sizeKB = [math]::Round($f.Length / 1KB, 1)
|
|
$sizeKB = [math]::Round($f.Length / 1KB, 1)
|
|
|
- Write-Log " $($f.FullName) → $remoteDest (${sizeKB} KB)"
|
|
|
|
|
|
|
+ $renameNote = if ($RenamePattern -and $destName -ne $f.Name) { " [renamed from $($f.Name)]" } else { '' }
|
|
|
|
|
+ Write-Log " $($f.FullName) → $remoteDest (${sizeKB} KB)$renameNote"
|
|
|
}
|
|
}
|
|
|
Write-Log "DRY RUN complete. $($allFiles.Count) file(s) would be transferred." -Level SUCCESS
|
|
Write-Log "DRY RUN complete. $($allFiles.Count) file(s) would be transferred." -Level SUCCESS
|
|
|
exit 0
|
|
exit 0
|
|
@@ -294,8 +329,13 @@ try {
|
|
|
$relativePath = $file.DirectoryName.Substring($LocalPath.TrimEnd('\').Length) -replace '\\', '/'
|
|
$relativePath = $file.DirectoryName.Substring($LocalPath.TrimEnd('\').Length) -replace '\\', '/'
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ $destName = if ($RenamePattern) { $file.Name -replace $RenamePattern, $RenameReplacement } else { $file.Name }
|
|
|
$targetDir = $RemotePath.TrimEnd('/') + $relativePath
|
|
$targetDir = $RemotePath.TrimEnd('/') + $relativePath
|
|
|
- $targetPath = "$targetDir/$($file.Name)"
|
|
|
|
|
|
|
+ $targetPath = "$targetDir/$destName"
|
|
|
|
|
+
|
|
|
|
|
+ if ($RenamePattern -and $destName -ne $file.Name) {
|
|
|
|
|
+ Write-Log "Renaming: $($file.Name) → $destName"
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
try {
|
|
try {
|
|
|
# Ensure subdirectory exists on remote when recursing
|
|
# Ensure subdirectory exists on remote when recursing
|