Differences

This shows you the differences between the selected revisions of the page.

library_example_recursive_search_text 2016-02-23 library_example_recursive_search_text 2025-04-10 (current)
Line 1: Line 1:
====== Search recursively for text in remote directory / Grep files over SFTP/FTP protocol ====== ====== Search recursively for text in remote directory / Grep files over SFTP/FTP protocol ======
-The following example uses [[library|WinSCP .NET assembly]] from a [[library_powershell|PowerShell]] script. If you have another preferred language, you can easily translate it.+The following script uses [[library|WinSCP .NET assembly]] from a [[library_powershell|PowerShell]] script. If you have another preferred language, you can easily translate it.
-You can run the script (e.g. ''search.ps1'') from WinSCP GUI using [[guide_custom_commands_automation|local custom command]]:+The script is distributed in WinSCP installer as a [[extension|WinSCP extension]]. 
 + 
 +To run the script manually use:
<code> <code>
-powershell.exe -File search.ps1 -path "!/" -text !?Text:?!+powershell.exe -File SearchText.ps1 -sessionUrl "sftp://username:password;fingerprint=ssh-rsa-xxxxxxxxxxx...@example.com/" -path "/path" -text &quot;text&quot;
</code> </code>
-See also [[library_example_listing_files_matching_wildcard|Listing files matching wildcard]].+See also [[library_example_listing_files_matching_wildcard|*]].
You can alter the script for other tasks, instead of grepping the matching files. You can for example [[library_session_removefiles|remove]] or [[library_session_getfiles|download]] the matching files. Just modify the action in the ''Action on match'' block accordingly. You can alter the script for other tasks, instead of grepping the matching files. You can for example [[library_session_removefiles|remove]] or [[library_session_getfiles|download]] the matching files. Just modify the action in the ''Action on match'' block accordingly.
- 
-===== In the Beta Version ===== 
-In the latest beta version, you can simplify the implementation by using ''[[library_session_enumerateremotefiles|Session.EnumerateRemoteFiles]]''. &beta 
<code powershell - SearchText.ps1> <code powershell - SearchText.ps1>
# @name        &Search for Text... # @name        &Search for Text...
-# @command      powershell.exe -ExecutionPolicy Bypass -File "%EXTENSION_PATH%" -path "!/" -text !?Text:?! -pause +# @command      powershell.exe -ExecutionPolicy Bypass -File "%EXTENSION_PATH%" ^ 
-# @description  Searches recursively for a text in the selected remote directory +#                  -sessionUrl "!E" -path "!/" -text "%Text%&quot; -wildcard "%Wildcard%" ^ 
-# @version      1+#                  -pause -sessionLogPath "%SessionLogPath%" 
 +# @description  Searches recursively for a text in the current remote directory 
 +# @version     
 +# @homepage    ~~SELF~~ 
 +# @require      WinSCP 5.16 
 +# @option      Text -run textbox "Text:" 
 +# @option      Wildcard -run textbox "File mask:" "*.*" 
 +# @option      SessionLogPath -config sessionlogfile 
 +# @optionspage  ~~SELF~~#options
param ( param (
-    [Parameter(Mandatory)]+    # Use Generate Session URL function to obtain a value for -sessionUrl parameter. 
 +    $sessionUrl = "sftp://user:mypassword;fingerprint=ssh-rsa-xxxxxxxxxxx...@example.com/", 
 +····[Parameter(Mandatory = $True)]
    $path,     $path,
-    [Parameter(Mandatory)]+    [Parameter(Mandatory = $True)]
    $text,     $text,
-    $wildcard = "*.*"+    $wildcard = "*.*"
 +    $sessionLogPath = $Null, 
 +    [Switch] 
 +    $pause
) )
try try
{ {
 +    if (!$text)
 +    {
 +        throw "No Text was specified."
 +    }
 +
    # Load WinSCP .NET assembly     # Load WinSCP .NET assembly
    $assemblyPath = if ($env:WINSCP_PATH) { $env:WINSCP_PATH } else { $PSScriptRoot }     $assemblyPath = if ($env:WINSCP_PATH) { $env:WINSCP_PATH } else { $PSScriptRoot }
Line 37: Line 54:
    # Setup session options     # Setup session options
-    $sessionOptions = New-Object WinSCP.SessionOptions -Property @{ +    $sessionOptions = New-Object WinSCP.SessionOptions 
- ·······Protocol = [WinSCP.Protocol]::Sftp + ···$sessionOptions.ParseUrl($sessionUrl)
-        HostName = "example.com" +
-        UserName = "user" +
-        Password = "mypassword" +
-        SshHostKeyFingerprint = "ssh-rsa 2048 xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx" +
-····}+
    $session = New-Object WinSCP.Session     $session = New-Object WinSCP.Session
Line 49: Line 61:
    try     try
    {     {
 +        $session.SessionLogPath = $sessionLogPath
 +
        # Connect         # Connect
        $session.Open($sessionOptions)         $session.Open($sessionOptions)
Line 64: Line 78:
            # matching files, instead of grepping their contents             # matching files, instead of grepping their contents
-            Write-Host ("File {0} matches mask, searching contents..." -f $fileInfo.FullName) +            if ($fileInfo.FileType -eq "L")
- ···········$tempPath = ($env:temp + "\" + $fileInfo.Name) +
-            # Download file to temporary directory +
-            $transferResult = $session.GetFiles($session.EscapeFileMask($fileInfo.FullName), $tempPath) +
-            # Did the download succeeded? +
-            if (!$transferResult.IsSuccess)+
            {             {
-                # Print error (but continue with other files) +                Write-Host &quot;Skipping symlink $($fileInfo.FullName)..."
- ···············Write-Host $transferResult.Failures[0].Message+
            }             }
            else             else
            {             {
-                # Search and print lines containing "text". +                Write-Host "File $($fileInfo.FullName) matches mask, searching contents..." 
-                # Use -Pattern instead of -SimpleMatch for regex search +                $tempPath = (Join-Path $env:temp $fileInfo.Name)
-                $matchInfo = Select-String -Path $tempPath -SimpleMatch $text +
-                # Print the results +
-                foreach ($match in $matchInfo) +
-                { +
-····················Write-Host ($fileInfo.FullName + ":" + $match.LineNumber + ":" + $match.Line) +
-                } +
-                # Delete temporary local copy +
-                Remove-Item $tempPath +
-            } +
-        } +
-    } +
-    finally +
-    { +
-        # Disconnect, clean up +
-        $session.Dispose() +
-    } +
- +
-    exit 0 +
-+
-catch [Exception] +
-+
-    Write-Host $_.Exception.Message +
-    exit 1 +
-+
-</code> +
- +
-===== In the Stable Version ===== +
- +
-<code powershell> +
-param ( +
-    [Parameter(Mandatory)] +
-    $path, +
-    [Parameter(Mandatory)] +
-    $text, +
-    $wildcard = "*.*" +
-+
- +
-function SearchDirectory ($session, $path, $wildcard, $text) +
-+
-    Write-Host ("Searching directory {0} ..." -f $path) +
- +
-    $directoryInfo = $session.ListDirectory($path) +
- +
-    foreach ($fileInfo in $directoryInfo.Files) +
-    { +
-        $filePath = ($path + "/" + $fileInfo.Name)  +
-         +
-        if ($fileInfo.IsDirectory) +
-        { +
-            # Skip references to current and parent directories +
-            if (($fileInfo.Name -ne ".") -and +
-                ($fileInfo.Name -ne "..")) +
-            { +
-                # Recurse into subdirectory +
-                SearchDirectory $session $filePath $wildcard $text +
-            } +
-        } +
-        else +
-        { +
-            # Does file name match wildcard? +
-            if ($fileInfo.Name -Like $wildcard) +
-            { +
-                # Action on match +
- +
-                # Modify the code below if you want to do another task with +
-                # matching files, instead of grepping their contents +
- +
-                Write-Host ("File {0} matches mask, searching contents..." -f $filePath) +
-                $tempPath = ($env:temp + "\" + $fileInfo.Name)+
                # Download file to temporary directory                 # Download file to temporary directory
-                $transferResult = $session.GetFiles($session.EscapeFileMask($filePath), $tempPath)+                $filePath = [WinSCP.RemotePath]::EscapeFileMask($fileInfo.FullName) 
 +                $transferResult = $session.GetFiles($filePath, $tempPath)
                # Did the download succeeded?                 # Did the download succeeded?
                if (!$transferResult.IsSuccess)                 if (!$transferResult.IsSuccess)
Line 163: Line 103:
                    foreach ($match in $matchInfo)                     foreach ($match in $matchInfo)
                    {                     {
-                        Write-Host ($filePath + &quot;:&quot; + $match.LineNumber + &quot;:&quot; + $match.Line)+                        Write-Host "$($fileInfo.FullName):$($match.LineNumber):$($match.Line)"
                    }                     }
                    # Delete temporary local copy                     # Delete temporary local copy
Line 170: Line 110:
            }             }
        }         }
-    } 
-} 
- 
-try 
-{ 
-    # Load WinSCP .NET assembly 
-    Add-Type -Path "WinSCPnet.dll" 
-  
-    # Setup session options 
-    $sessionOptions = New-Object WinSCP.SessionOptions -Property @{ 
-        Protocol = [WinSCP.Protocol]::Sftp 
-        HostName = "example.com" 
-        UserName = "user" 
-        Password = "mypassword" 
-        SshHostKeyFingerprint = "ssh-rsa 2048 xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx" 
-    } 
-  
-    $session = New-Object WinSCP.Session 
-     
-    try 
-    { 
-        # Connect 
-        $session.Open($sessionOptions) 
-         
-        # Start recursive search 
-        SearchDirectory $session $path $wildcard $text 
    }     }
    finally     finally
Line 202: Line 116:
        $session.Dispose()         $session.Dispose()
    }     }
-· + 
-    exit 0+    $result = 0
} }
-catch [Exception]+catch
{ {
-    Write-Host $_.Exception.Message +    Write-Host "Error: $($_.Exception.Message)" 
-    exit 1+    $result = 1
} }
 +
 +# Pause if -pause switch was used
 +if ($pause)
 +{
 +    Write-Host "Press any key to exit..."
 +    [System.Console]::ReadKey() | Out-Null
 +}
 +
 +exit $result
</code> </code>
 +
 +===== [[options]] Options =====
 +
 +&screenshotpict(extension_recursive_search_text)
 +
 +In the //Text// box, specify the text to look for. The option is available when executing the extension only.
 +
 +In the //File mask// box, specify a [[file_mask|file mask]] to select files. The option is available when executing the extension only.
 +
 +In the //Session log file//, you can specify a path to a [[logging|session log file]]. The option is available on the [[ui_pref_commands|Preferences dialog]] only.
 +
 +In the //Keyboard shortcut//, you can specify a [[custom_key_shortcuts|keyboard shortcut]] for the extension. The option is available on the [[ui_pref_commands|Preferences dialog]] only.

Last modified: by martin