Add -RenamePattern/-RenameReplacement for renaming files before upload
This commit is contained in:
@@ -42,6 +42,8 @@ The script auto-searches these locations in order:
|
||||
| `-CredentialFile` | No | — | Path to saved credential XML (see below) |
|
||||
| `-KeyFilePath` | No | — | Path to SSH private key (`.ppk`) |
|
||||
| `-SshHostKeyFingerprint` | No | — | SSH host key fingerprint for verification |
|
||||
| `-RenamePattern` | No | — | Regex pattern to match in filename for renaming before upload |
|
||||
| `-RenameReplacement` | No | — | Replacement string for `-RenamePattern` (supports capture groups like `$1`) |
|
||||
| `-Recurse` | No | `false` | Scan subdirectories |
|
||||
| `-DeleteAfterTransfer` | No | `false` | Delete local files after successful upload |
|
||||
| `-DryRun` | No | `false` | Preview transfers without uploading |
|
||||
@@ -125,6 +127,30 @@ The `-FileFilter` parameter uses PowerShell regex (case-insensitive by default).
|
||||
-Recurse -FileFilter '\.pdf$'
|
||||
```
|
||||
|
||||
## Renaming Files Before Upload
|
||||
|
||||
Use `-RenamePattern` (regex) and `-RenameReplacement` together to rename files on the remote side without touching the local files.
|
||||
|
||||
| Goal | Pattern | Replacement |
|
||||
|------|---------|-------------|
|
||||
| Add date before extension | `'^(.+?)(\.[^.]+)$'` | `'${1}_20260416${2}'` |
|
||||
| Add prefix | `'^'` | `'processed_'` |
|
||||
| Add suffix before extension | `'^(.+?)(\.[^.]+)$'` | `'${1}_done${2}'` |
|
||||
| Strip `_draft` from name | `'_draft'` | `''` |
|
||||
| Replace spaces with underscores | `' '` | `'_'` |
|
||||
|
||||
Rename uses PowerShell's `-replace` operator (regex, case-insensitive). The local file is **not** modified — only the remote destination path changes.
|
||||
|
||||
### Add today's date to every filename
|
||||
```powershell
|
||||
$date = Get-Date -Format 'yyyyMMdd'
|
||||
.\Send-FilesToSftp.ps1 -LocalPath "C:\exports" -RemotePath "/incoming" `
|
||||
-HostName "sftp.example.com" -UserName "uploader" `
|
||||
-RenamePattern '^(.+?)(\.[^.]+)$' -RenameReplacement "${date}_`$1`$2"
|
||||
```
|
||||
|
||||
> **Tip:** Use `-DryRun` first to preview the renamed remote paths before committing to the transfer.
|
||||
|
||||
## SSH Host Key Fingerprint
|
||||
|
||||
For production use, always provide the host key fingerprint to prevent MITM attacks:
|
||||
|
||||
+43
-3
@@ -43,6 +43,15 @@
|
||||
.PARAMETER Recurse
|
||||
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
|
||||
Delete local files after successful upload (move behavior).
|
||||
|
||||
@@ -60,6 +69,18 @@
|
||||
.\Send-FilesToSftp.ps1 -LocalPath "C:\exports" -RemotePath "/incoming" `
|
||||
-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
|
||||
# Unattended with saved credentials and move behavior
|
||||
.\Send-FilesToSftp.ps1 -LocalPath "C:\exports" -RemotePath "/incoming" `
|
||||
@@ -106,6 +127,10 @@ param(
|
||||
|
||||
[string]$KeyFilePath,
|
||||
|
||||
[string]$RenamePattern,
|
||||
|
||||
[string]$RenameReplacement,
|
||||
|
||||
[switch]$Recurse,
|
||||
|
||||
[switch]$DeleteAfterTransfer,
|
||||
@@ -169,11 +194,18 @@ function Find-WinScpDll {
|
||||
# ── Main ─────────────────────────────────────────────────────────────────────
|
||||
|
||||
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 "Local path : $LocalPath"
|
||||
Write-Log "Remote path : $RemotePath"
|
||||
Write-Log "File filter : $FileFilter"
|
||||
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 }
|
||||
|
||||
# ── Find and load WinSCP ─────────────────────────────────────────────
|
||||
@@ -228,10 +260,13 @@ try {
|
||||
if ($DryRun) {
|
||||
Write-Log "Files that would be transferred:" -Level INFO
|
||||
foreach ($f in $allFiles) {
|
||||
$destName = if ($RenamePattern) { $f.Name -replace $RenamePattern, $RenameReplacement } else { $f.Name }
|
||||
$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)
|
||||
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
|
||||
exit 0
|
||||
@@ -294,8 +329,13 @@ try {
|
||||
$relativePath = $file.DirectoryName.Substring($LocalPath.TrimEnd('\').Length) -replace '\\', '/'
|
||||
}
|
||||
|
||||
$destName = if ($RenamePattern) { $file.Name -replace $RenamePattern, $RenameReplacement } else { $file.Name }
|
||||
$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 {
|
||||
# Ensure subdirectory exists on remote when recursing
|
||||
|
||||
Reference in New Issue
Block a user