Differences
This shows you the differences between the selected revisions of the page.
| 2016-09-29 | 2016-09-29 | ||
| typo (martin) | reimplemeting using EnumerateRemoteFiles and FullName (martin) | ||
| Line 18: | Line 18: | ||
| # @description Searches for duplicate files on the server, starting from the current directory | # @description Searches for duplicate files on the server, starting from the current directory | ||
| # @flag RemoteFiles | # @flag RemoteFiles | ||
| - | # @version 2 | + | # @version 3 |
| - | # @homepage ~~SELF~~ | + | # @homepage https://winscp.net/eng/docs/library_example_find_duplicate_files |
| - | # @require WinSCP 5.8.4 | + | # @require WinSCP 5.9.1 |
| # @option RemoteChecksumAlg -config -run combobox "&Checksum:" "local" "local=Local sha-1" "sha1=Remote sha-1" "sha256=Remote sha-256" "md5=Remote md5" | # @option RemoteChecksumAlg -config -run combobox "&Checksum:" "local" "local=Local sha-1" "sha1=Remote sha-1" "sha256=Remote sha-256" "md5=Remote md5" | ||
| # @option SessionLogPath -config sessionlogfile | # @option SessionLogPath -config sessionlogfile | ||
| - | # @optionspage ~~SELF~~#options | + | # @optionspage https://winscp.net/eng/docs/library_example_find_duplicate_files#options |
| + | · | ||
| param ( | param ( | ||
| # Use Generate URL function to obtain a value for -sessionUrl parameter. | # Use Generate URL function to obtain a value for -sessionUrl parameter. | ||
| Line 35: | Line 35: | ||
| $pause = $False | $pause = $False | ||
| ) | ) | ||
| + | · | ||
| function FileChecksum ($remotePath) | function FileChecksum ($remotePath) | ||
| { | { | ||
| Line 46: | Line 46: | ||
| $localPath = [System.IO.Path]::GetTempFileName() | $localPath = [System.IO.Path]::GetTempFileName() | ||
| $transferResult = $session.GetFiles($remotePath, $localPath) | $transferResult = $session.GetFiles($remotePath, $localPath) | ||
| + | · | ||
| if ($transferResult.IsSuccess) | if ($transferResult.IsSuccess) | ||
| { | { | ||
| Line 54: | Line 54: | ||
| Write-Host ("Downloaded file {0} checksum is {1}" -f $remotePath, $checksum) | Write-Host ("Downloaded file {0} checksum is {1}" -f $remotePath, $checksum) | ||
| + | · | ||
| Remove-Item $localPath | Remove-Item $localPath | ||
| } | } | ||
| Line 69: | Line 69: | ||
| Write-Host ("File {0} checksum is {1}" -f $remotePath, $checksum) | Write-Host ("File {0} checksum is {1}" -f $remotePath, $checksum) | ||
| } | } | ||
| + | · | ||
| $checksums[$remotePath] = $checksum | $checksums[$remotePath] = $checksum | ||
| } | } | ||
| + | · | ||
| return $checksums[$remotePath] | return $checksums[$remotePath] | ||
| - | } | ||
| - | |||
| - | function FindDuplicatesInDirectory ($remotePath) | ||
| - | { | ||
| - | Write-Host ("Finding duplicates in directory {0} ..." -f $remotePath) | ||
| - | |||
| - | try | ||
| - | { | ||
| - | $directoryInfo = $session.ListDirectory($remotePath) | ||
| - | |||
| - | foreach ($fileInfo in $directoryInfo.Files) | ||
| - | { | ||
| - | $remoteFilePath = $session.CombinePaths($remotePath, $fileInfo.Name) | ||
| - | |||
| - | if ($fileInfo.IsDirectory) | ||
| - | { | ||
| - | # Skip references to current and parent directories | ||
| - | if (($fileInfo.Name -ne ".") -and | ||
| - | ($fileInfo.Name -ne "..")) | ||
| - | { | ||
| - | # Recurse into subdirectories | ||
| - | FindDuplicatesInDirectory $remoteFilePath | ||
| - | } | ||
| - | } | ||
| - | else | ||
| - | { | ||
| - | Write-Host ("Found file {0} with size {1}" -f $remoteFilePath, $fileInfo.Length) | ||
| - | |||
| - | if ($sizes.ContainsKey($fileInfo.Length)) | ||
| - | { | ||
| - | $checksum = FileChecksum($remoteFilePath) | ||
| - | |||
| - | foreach ($otherFilePath in $sizes[$fileInfo.Length]) | ||
| - | { | ||
| - | $otherChecksum = FileChecksum($otherFilePath) | ||
| - | |||
| - | if ($checksum -eq $otherChecksum) | ||
| - | { | ||
| - | Write-Host ("Checksums of files {0} and {1} are identical" -f $remoteFilePath, $otherFilePath) | ||
| - | $duplicates[$remoteFilePath] = $otherFilePath | ||
| - | } | ||
| - | } | ||
| - | } | ||
| - | else | ||
| - | { | ||
| - | $sizes[$fileInfo.Length] = @() | ||
| - | } | ||
| - | |||
| - | $sizes[$fileInfo.Length] += $remoteFilePath | ||
| - | } | ||
| - | } | ||
| - | } | ||
| - | catch [Exception] | ||
| - | { | ||
| - | Write-Host ("Error processing directory {0}: {1}" -f $remotePath, $_.Exception.Message) | ||
| - | } | ||
| } | } | ||
| Line 147: | Line 91: | ||
| { | { | ||
| $session.SessionLogPath = $sessionLogPath | $session.SessionLogPath = $sessionLogPath | ||
| + | · | ||
| # Connect | # Connect | ||
| $session.Open($sessionOptions) | $session.Open($sessionOptions) | ||
| + | # Handle errors when enumerating the files | ||
| + | $session.add_Failed( { | ||
| + | Write-Host ("Error: {0}" -f $_.Error.Message) | ||
| + | } ) | ||
| + | |||
| $sizes = @{} | $sizes = @{} | ||
| $checksums = @{} | $checksums = @{} | ||
| Line 156: | Line 105: | ||
| $sha1 = [System.Security.Cryptography.SHA1]::Create() | $sha1 = [System.Security.Cryptography.SHA1]::Create() | ||
| + | |||
| + | $files = $session.EnumerateRemoteFiles($remotePath, "*", [WinSCP.EnumerationOptions]::AllDirectories) | ||
| - | # Start recursion | + | foreach ($fileInfo in $files) |
| - | FindDuplicatesInDirectory $remotePath | + | { |
| + | Write-Host ("Found file {0} with size {1}" -f $fileInfo.FullName, $fileInfo.Length) | ||
| + | |||
| + | if ($sizes.ContainsKey($fileInfo.Length)) | ||
| + | { | ||
| + | $checksum = FileChecksum($fileInfo.FullName) | ||
| + | |||
| + | foreach ($otherFilePath in $sizes[$fileInfo.Length]) | ||
| + | { | ||
| + | $otherChecksum = FileChecksum($otherFilePath) | ||
| + | |||
| + | if ($checksum -eq $otherChecksum) | ||
| + | { | ||
| + | Write-Host ("Checksums of files {0} and {1} are identical" -f $fileInfo.FullName, $otherFilePath) | ||
| + | $duplicates[$fileInfo.FullName] = $otherFilePath | ||
| + | } | ||
| + | } | ||
| + | } | ||
| + | else | ||
| + | { | ||
| + | $sizes[$fileInfo.Length] = @() | ||
| + | } | ||
| + | |||
| + | $sizes[$fileInfo.Length] += $fileInfo.FullName | ||
| + | } | ||
| } | } | ||
| finally | finally | ||
| Line 165: | Line 140: | ||
| $session.Dispose() | $session.Dispose() | ||
| } | } | ||
| + | · | ||
| # Print results | # Print results | ||
| Write-Host | Write-Host | ||
| + | · | ||
| if ($duplicates.Count -gt 0) | if ($duplicates.Count -gt 0) | ||
| { | { | ||
| Write-Host "Duplicates found:" | Write-Host "Duplicates found:" | ||
| + | · | ||
| foreach ($path1 in $duplicates.Keys) | foreach ($path1 in $duplicates.Keys) | ||
| { | { | ||
| Line 182: | Line 157: | ||
| Write-Host "No duplicates found." | Write-Host "No duplicates found." | ||
| } | } | ||
| + | · | ||
| $result = 0 | $result = 0 | ||
| } | } | ||
| Line 197: | Line 172: | ||
| [System.Console]::ReadKey() | Out-Null | [System.Console]::ReadKey() | Out-Null | ||
| } | } | ||
| + | · | ||
| exit $result | exit $result | ||
| </code> | </code> | ||