Parcourir la source

Add -RenamePattern/-RenameReplacement for renaming files before upload

Blance il y a 1 jour
Parent
commit
6a451044dd
2 fichiers modifiés avec 69 ajouts et 3 suppressions
  1. 26 0
      README.md
  2. 43 3
      Send-FilesToSftp.ps1

+ 26 - 0
README.md

@@ -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
Send-FilesToSftp.ps1

@@ -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