all repos — fast-scripts @ 4cc24033f9f7af95a0a2a0e504ff61b89eba05bb

scripts que podem ser uteis para meu dia a dia

Organizar/achar-duplicados.cmd (view raw)

 1
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
 100
 101
 102
 103
 104
 105
 106
 107
 108
<# :
@echo off
powershell -NoLogo -NoProfile -ExecutionPolicy Bypass -Command "Invoke-Expression ([System.IO.File]::ReadAllText('%~f0',[System.Text.Encoding]::UTF8))"
exit /b %errorlevel%
#>

# ============================================================
#  Achar duplicados - encontra arquivos iguais por conteúdo (hash)
#  Desenvolvido por Pablo Murad - 2026
# ============================================================

try { [Console]::OutputEncoding = [System.Text.Encoding]::UTF8 } catch {}
try { $Host.UI.RawUI.WindowTitle = 'Achar duplicados' } catch {}

function Pausar { Write-Host ''; Write-Host 'Pressione Enter para fechar...' -ForegroundColor DarkGray; [void][System.Console]::ReadLine() }
function Titulo($t) {
    Write-Host ''
    Write-Host '============================================================' -ForegroundColor DarkCyan
    Write-Host "  $t" -ForegroundColor Cyan
    Write-Host '============================================================' -ForegroundColor DarkCyan
}
function Tam($bytes) { if ($bytes -ge 1GB) { '{0:N2} GB' -f ($bytes/1GB) } elseif ($bytes -ge 1MB) { '{0:N1} MB' -f ($bytes/1MB) } else { '{0:N0} KB' -f ($bytes/1KB) } }

Titulo 'Achar duplicados'
Write-Host '  Desenvolvido por Pablo Murad - 2026' -ForegroundColor DarkGray

$pasta = $null
while (-not $pasta) {
    Write-Host ''
    $p = (Read-Host 'Cole o caminho da pasta (verifica também as subpastas)').Trim().Trim('"')
    if (Test-Path -LiteralPath $p -PathType Container) { $pasta = (Resolve-Path -LiteralPath $p).Path } else { Write-Host '[!] Pasta não encontrada.' -ForegroundColor Yellow }
}

Write-Host ''
Write-Host 'Analisando... (agrupa por tamanho e depois compara o conteúdo)' -ForegroundColor Gray
$todos = @(Get-ChildItem -LiteralPath $pasta -Recurse -File -ErrorAction SilentlyContinue | Where-Object { $_.Length -gt 0 })

# 1) agrupa por tamanho (rápido); 2) só calcula hash de quem tem tamanho repetido
$porTamanho = $todos | Group-Object Length | Where-Object { $_.Count -gt 1 }
$grupos = @()
foreach ($g in $porTamanho) {
    $porHash = $g.Group | Group-Object { (Get-FileHash -LiteralPath $_.FullName -Algorithm SHA256).Hash }
    foreach ($h in ($porHash | Where-Object { $_.Count -gt 1 })) {
        $grupos += ,@($h.Group | Sort-Object FullName)
    }
}

if ($grupos.Count -eq 0) { Titulo 'Resultado'; Write-Host 'Nenhum arquivo duplicado encontrado.' -ForegroundColor Green; Pausar; exit 0 }

$totalDup = 0; $espaco = 0
foreach ($grp in $grupos) { $totalDup += ($grp.Count - 1); $espaco += ($grp.Count - 1) * $grp[0].Length }

Titulo 'Duplicados encontrados'
Write-Host ("Grupos de iguais: {0}   |   Cópias extras: {1}   |   Espaço recuperável: {2}" -f $grupos.Count, $totalDup, (Tam $espaco)) -ForegroundColor Cyan
Write-Host ''
$mostra = [Math]::Min($grupos.Count, 15)
for ($i=0; $i -lt $mostra; $i++) {
    $grp = $grupos[$i]
    Write-Host ("Grupo {0} ({1} cópias, {2} cada):" -f ($i+1), $grp.Count, (Tam $grp[0].Length)) -ForegroundColor White
    for ($j=0; $j -lt $grp.Count; $j++) {
        $marca = if ($j -eq 0) { '[manter] ' } else { '[extra]  ' }
        $cor   = if ($j -eq 0) { 'Green' } else { 'DarkGray' }
        Write-Host ("   $marca" + $grp[$j].FullName) -ForegroundColor $cor
    }
}
if ($grupos.Count -gt $mostra) { Write-Host ("... e mais {0} grupo(s)." -f ($grupos.Count - $mostra)) -ForegroundColor DarkGray }

Titulo 'O que fazer com as cópias extras?'
Write-Host '  [1] Só listar (nada é alterado) - padrão' -ForegroundColor White
Write-Host '  [2] Mover as cópias extras para uma subpasta "_Duplicados"' -ForegroundColor White
Write-Host '  [3] Apagar as cópias extras (mantém sempre 1 original)' -ForegroundColor White
$acao = Read-Host 'Opção (Enter = 1)'
if ([string]::IsNullOrWhiteSpace($acao)) { $acao = '1' }

if ($acao -eq '1') { Write-Host ''; Write-Host 'Nada foi alterado. Relatório acima.' -ForegroundColor Gray; Pausar; exit 0 }

if ($acao -eq '3') {
    Write-Host ''
    Write-Host 'ATENÇÃO: isto APAGA as cópias extras permanentemente.' -ForegroundColor Red
    $conf = Read-Host 'Digite APAGAR para confirmar'
    if ($conf -cne 'APAGAR') { Write-Host 'Cancelado.' -ForegroundColor Yellow; Pausar; exit 0 }
}

$feitos=0;$err=0
$destDup = Join-Path $pasta '_Duplicados'
foreach ($grp in $grupos) {
    for ($j=1; $j -lt $grp.Count; $j++) {
        $f = $grp[$j]
        try {
            if ($acao -eq '2') {
                New-Item -ItemType Directory -Path $destDup -Force | Out-Null
                $base=[System.IO.Path]::GetFileNameWithoutExtension($f.Name); $ext=$f.Extension
                $dest=Join-Path $destDup $f.Name; $n=1
                while (Test-Path -LiteralPath $dest) { $dest=Join-Path $destDup ("$base ($n)$ext"); $n++ }
                Move-Item -LiteralPath $f.FullName -Destination $dest -ErrorAction Stop
            } else {
                Remove-Item -LiteralPath $f.FullName -Force -ErrorAction Stop
            }
            $feitos++
        } catch { Write-Host "   [ERRO] $($f.Name): $($_.Exception.Message)" -ForegroundColor Red; $err++ }
    }
}
Titulo 'Concluído'
$verbo = if ($acao -eq '2') { 'Movidas' } else { 'Apagadas' }
Write-Host "$verbo`: $feitos cópia(s) extra(s)" -ForegroundColor Green
Write-Host "Erros:   $err" -ForegroundColor $(if ($err -gt 0){'Red'}else{'Gray'})
if ($acao -eq '2') { Write-Host "Movidos para: $destDup" }
Pausar