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*.*

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 file using regular expression
# @flag         RemoteFiles
# @version      1
# @homepage     https://winscp.net/eng/docs/library_example_advanced_rename
# @require      WinSCP 5.8.4
# @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 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 ("{0} => {1}" -f $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 ("{0} => {1}" -f $file, $newName)
 
                $fullName = $session.CombinePaths($remotePath, $file)
                $fullNewName = $session.CombinePaths($remotePath, $newName)
                $session.MoveFile($fullName, $fullNewName)
            }
        }
        finally
        {
            # Disconnect, clean up
            $session.Dispose()
        }
 
        & "$env:WINSCP_PATH\WinSCP.exe" "$sessionUrl" /refresh "$remotePath"
    }
 
    $result = 0
}
catch [Exception]
{
    Write-Host $_.Exception.Message
    $result = 1
}
 
if ($pause)
{
    Write-Host "Press any key to exit..."
    [System.Console]::ReadKey() | Out-Null
}
 
exit $result

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.

 
  library_example_advanced_rename.txt · Last modified: by martin
 

Search Documentation

This page

Donate

About donations

$9   $19   $49   $99

About donations

Recommend

Associations

Site design by Black Gate