Advanced files rename on SFTP/FTP server

Simple rename with operation mask

With WinSCP scripting, you can use an operation mask to do simple batch changes to file names like:

  • changing an extension: mv *.htm *.html
  • adding a suffix: mv *.html *-backup.html
  • changing leading characters: mv new*.* old*.*

Advertisement

Advanced rename with PowerShell

But for more advanced rename operations, you need to use your favorite scripting language language, like PowerShell, to generate a new name and use WinSCP .NET assembly for the actual rename (or generate a script file).

The following example renames files using a regular expression.

The script is distributed in WinSCP installer as a WinSCP extension.

# @name         Batch &Rename...
# @command      powershell.exe -ExecutionPolicy Bypass -File "%EXTENSION_PATH%" ^
#                   -sessionUrl "!S" -remotePath "!/" -pattern "%Pattern%" ^
#                   -replacement "%Replacement%" -pause -sessionLogPath "%SessionLogPath%" ^
#                   %PreviewMode% !& 
# @description  Renames remote files using a regular expression
# @flag         RemoteFiles
# @version      4
# @homepage     https://winscp.net/eng/docs/library_example_advanced_rename
# @require      WinSCP 5.13
# @option       - -run group "Rename"
# @option         Pattern -run textbox "Replace file name part matching this pattern:"
# @option         Replacement -run textbox "with:"
# @option       - -run -config group "Options"
# @option         PreviewMode -run -config checkbox "&Preview changes" "-previewMode" ^
#                     "-previewMode"
# @option       - -config group "Logging"
# @option         SessionLogPath -config sessionlogfile
# @optionspage  https://winscp.net/eng/docs/library_example_advanced_rename#options
 
param (
    # Use Generate Session URL function to obtain a value for -sessionUrl parameter.
    $sessionUrl = "sftp://user:mypassword;fingerprint=ssh-rsa-xx-xx-xx@example.com/",
    [Parameter(Mandatory = $True)]
    $remotePath,
    [Parameter(Mandatory = $True)]
    $pattern,
    $replacement,
    [Switch]
    $pause,
    $sessionLogPath = $Null,
    [Switch]
    $previewMode,
    [Parameter(Mandatory = $True, ValueFromRemainingArguments = $True, Position = 0)]
    $files
)
 
try
{
    if ($previewMode)
    {
        $anyChange = $False
        foreach ($file in $files)
        {
            $newName = $file -replace $pattern, $replacement
            Write-Host "$file => $newName"
            if ($newName -ne $file)
            {
                $anyChange = $True
            }
        }
 
        Write-Host
        
        if (!$anyChange)
        {
            Write-Host "No change to be made"
            $continue = $False
        }
        else
        {
            Write-Host -NoNewline "Continue? y/N "
            $key = [System.Console]::ReadKey()
            Write-Host
            Write-Host
            $continue = ($key.KeyChar -eq "y")
            if (!$continue)
            {
                $pause = $False
            }
        }
    }
    else
    {
        $continue = $True
    }
    
 
    if (!$continue)
    {
        $result = 1
    }
    else
    {
        # 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)
     
        $session = New-Object WinSCP.Session
 
        try
        {
            $session.SessionLogPath = $sessionLogPath
     
            # Connect
            $session.Open($sessionOptions)
 
            foreach ($file in $files)
            {
                $newName = $file -replace $pattern, $replacement
                Write-Host "$file => $newName"
 
                $fullName = [WinSCP.RemotePath]::CombinePaths($remotePath, $file)
                $fullNewName = [WinSCP.RemotePath]::CombinePaths($remotePath, $newName)
                $session.MoveFile($fullName, $fullNewName)
            }
        }
        finally
        {
            # Disconnect, clean up
            $session.Dispose()
        }
 
        & "$env:WINSCP_PATH\WinSCP.exe" "$sessionUrl" /refresh "$remotePath"
    }
 
    $result = 0
}
catch
{
    Write-Host "Error: $($_.Exception.Message)"
    $result = 1
}
 
if ($pause)
{
    Write-Host "Press any key to exit..."
    [System.Console]::ReadKey() | Out-Null
}
 
exit $result

Advertisement

Options

In the “Replace file name part matching this pattern” box, enter a regular expression pattern to look for in file name(s).

In the with box, enter a replacement string to replace the file name part that matches the regular expression with. The replacement string can use $x syntax to refer to the x-th group (subexpression in parentheses) captured by the pattern.

On the image, you can see a pattern ((\d{4})-(\d{2})-(\d{2})) and a replacement string ($2-$3-$1) that change date stamp in file names from the yyyy-mm-dd format to the mm-dd-yyyy format by changing an order of captured groups.

Check the Preview changes checkbox to see and confirm the changes in file names before actually renaming the files.

In the Session log file, you can specify a path to a session log file. The option is available on the Preferences dialog only.

In the Keyboard shortcut, you can specify a keyboard shortcut for the extension. The option is available on the Preferences dialog only. This feature is available only in the latest beta release.

Last modified: by martin