FolderTools.psm1

<#
    FolderTools - Versão 5.6
    Autor: Joilson
    Descrição: Ferramentas avançadas para análise de pastas, perfis e armazenamento.
    Última atualização: 12/04/2026
 
    Histórico:
    - 5.4: Versão inicial estável
    - 5.5: Overview por perfil corrigido
    - 5.6: Correção completa de caminhos, perfil atual, barra final e cabeçalho incluído
#>


function Format-Size {
    param([long]$bytes)
    if ($bytes -eq $null) { return "0 bytes" }
    if ($bytes -ge 1TB) { return ("{0:N2} TB" -f ($bytes / 1TB)) }
    if ($bytes -ge 1GB) { return ("{0:N2} GB" -f ($bytes / 1GB)) }
    if ($bytes -ge 1MB) { return ("{0:N2} MB" -f ($bytes / 1MB)) }
    if ($bytes -ge 1KB) { return ("{0:N2} KB" -f ($bytes / 1KB)) }
    return "$bytes bytes"
}

function Print-Row {
    param($Mode, $Tamanho, $Bytes, $Nome, $NoBytes)
    if ($Bytes -eq $null) { $Bytes = 0 }
    if ($Tamanho -eq $null) { $Tamanho = "0 bytes" }
    if ($NoBytes) {
        Write-Host ($Mode.PadRight(6)) ($Tamanho.PadRight(12)) $Nome
    } else {
        Write-Host ($Mode.PadRight(6)) ($Tamanho.PadRight(12)) ($Bytes.ToString().PadRight(12)) $Nome
    }
}

function Get-DriveSize {
    $drives = Get-PSDrive -PSProvider FileSystem
    Write-Host "Drive Total Usado Livre %Usado Tipo"
    Write-Host "----- ----------- ----------- ----------- ------ ------"
    foreach ($d in $drives) {
        $total = $d.Used + $d.Free
        $pct = 0
        if ($total -gt 0) { $pct = [math]::Round(($d.Used / $total) * 100) }
        $tipo = "Desconhecido"
        try { $tipo = (New-Object System.IO.DriveInfo($d.Root)).DriveType } catch {}
        Write-Host ($d.Name.PadRight(5)) (Format-Size $total).PadRight(12) (Format-Size $d.Used).PadRight(12) (Format-Size $d.Free).PadRight(12) (($pct.ToString() + "%").PadRight(7)) $tipo
    }
}

function Get-StorageOverview {
    param([string]$UserPath = $null)

    # Remove barra final
    if ($UserPath) { $UserPath = $UserPath.TrimEnd("\") }

    # Detecta drive automaticamente
    if ($UserPath) {
        $resolved = Resolve-Path $UserPath -ErrorAction SilentlyContinue
        if (-not $resolved) { Write-Host "Caminho invalido: $UserPath"; return }
        $UserPath = $resolved.Path
        $Drive = $UserPath.Substring(0,1)
    } else {
        $Drive = "C"
    }

    # Drive info
    $d = Get-PSDrive -PSProvider FileSystem | Where-Object { $_.Name -ieq $Drive }
    if (-not $d) { Write-Host "Unidade '$Drive' nao encontrada."; return }

    $total = $d.Used + $d.Free
    $used  = $d.Used
    $free  = $d.Free
    $root  = "$Drive`:"

    # Detecta usuário a partir do caminho
    if ($UserPath) {
        $userName = Split-Path $UserPath -Leaf
        $userBase = "C:\Users\$userName"
    } else {
        $userBase = "C:\Users\$env:USERNAME"
    }

    # Pastas do perfil
    $docs   = Join-Path $userBase "Documents"
    $desk   = Join-Path $userBase "Desktop"
    $temp   = Join-Path $userBase "AppData\Local\Temp"

    # Pastas do sistema
    $win    = Join-Path $root "Windows"
    $pgm    = Join-Path $root "Program Files"
    $pgm86  = Join-Path $root "Program Files (x86)"
    $pdata  = Join-Path $root "ProgramData"

    function Sum-Folder([string]$path) {
        try {
            if (Test-Path $path -ErrorAction Stop) {
                return (Get-ChildItem $path -Recurse -File -Force -ErrorAction SilentlyContinue |
                        Measure-Object Length -Sum).Sum
            }
        } catch { return 0 }
        return 0
    }

    # Calcula tamanhos
    $sizeWin   = Sum-Folder $win
    $sizePgm   = Sum-Folder $pgm
    $sizePgm86 = Sum-Folder $pgm86
    $sizePData = Sum-Folder $pdata
    $sizeDocs  = Sum-Folder $docs
    $sizeDesk  = Sum-Folder $desk
    $sizeTemp  = Sum-Folder $temp

    $sizeSistema = $sizeWin + $sizePData
    $sizeApps    = $sizePgm + $sizePgm86
    $sumKnown = $sizeSistema + $sizeApps + $sizeDocs + $sizeDesk + $sizeTemp
    $sizeOther = [math]::Max([decimal]0, ([decimal]$used - [decimal]$sumKnown))

    Write-Host "======================"
    Write-Host " STORAGE OVERVIEW"
    Write-Host "======================"
    Write-Host ""
    Write-Host "Disco: $root\"
    Write-Host ("Total: " + (Format-Size $total))
    Write-Host ("Usado: " + (Format-Size $used))
    Write-Host ("Livre: " + (Format-Size $free))
    Write-Host "----------------------"
    Write-Host ""
    Write-Host "Perfil analisado: $userBase"
    Write-Host ""
    Write-Host "Categorias:"
    Write-Host "----------------------------------------------"
    Write-Host ("{0,-28} {1}" -f "Sistema e reservado", (Format-Size $sizeSistema))
    Write-Host ("{0,-28} {1}" -f "Aplicativos instalados", (Format-Size $sizeApps))
    Write-Host ("{0,-28} {1}" -f "Documentos", (Format-Size $sizeDocs))
    Write-Host ("{0,-28} {1}" -f "Arquivos temporarios", (Format-Size $sizeTemp))
    Write-Host ("{0,-28} {1}" -f "Outros", (Format-Size $sizeOther))
    Write-Host ("{0,-28} {1}" -f "Area de Trabalho", (Format-Size $sizeDesk))
    Write-Host "----------------------------------------------"
    Write-Host ""
    Write-Host "*Valores aproximados baseados no conteudo da unidade."
}

function Get-FolderSize {
    param(
        [string]$Path = ".",
        [switch]$All,
        [switch]$Recurse,
        [switch]$Full,
        [switch]$Drivers,
        [switch]$NoBytes,
        [switch]$Overview,
        [switch]$Help,
        [string]$Sort
    )

    if ($Help) {
    Write-Host "==========================="
    Write-Host " FOLDERTOOLS 5.6 - HELP"
    Write-Host "==========================="
    Write-Host ""
    Write-Host "Get-FolderSize [path]"
    Write-Host " -All Lista todas as pastas recursivamente"
    Write-Host " -Recurse Lista todos os arquivos recursivamente"
    Write-Host " -Full Lista pastas + arquivos recursivamente"
    Write-Host " -Drivers Mostra informacoes dos discos"
    Write-Host " -Overview Resumo estilo Windows (aceita caminho de perfil)"
    Write-Host " -Sort Size Ordena por tamanho"
    Write-Host " -Sort Name Ordena por nome"
    Write-Host " -NoBytes Oculta a coluna de bytes"
    Write-Host " -Help Exibe esta ajuda"
    Write-Host ""
    Write-Host "Exemplos:"
    Write-Host " Get-FolderSize -Overview"
    Write-Host " Get-FolderSize -Overview C:\Users\adm"
    Write-Host " Get-FolderSize -Full C:\Projetos"
    Write-Host ""

    #
    Write-Host "Resumo dos comandos:"
    Write-Host "------------------------------------------------------------"
    Write-Host "Get-FolderSize - Lista pastas"
    Write-Host "Get-FolderSize -All - Pastas recursivas"
    Write-Host "Get-FolderSize -Recurse - Arquivos recursivos"
    Write-Host "Get-FolderSize -Full - Pastas + arquivos"
    Write-Host "Get-FolderSize -Sort Size - Ordena por tamanho"
    Write-Host "Get-FolderSize -Sort Name - Ordena por nome"
    Write-Host "Get-FolderSize -Overview - Resumo estilo Windows"
    Write-Host "Get-DriveSize - Info dos discos"
    Write-Host "Get-StorageOverview - Resumo direto"
    Write-Host "------------------------------------------------------------"
    Write-Host ""

    return
}


    if ($Overview) { Get-StorageOverview $Path; return }
    if ($Drivers) { Get-DriveSize; return }
    if ($All -and $Recurse) { Write-Host "Os parametros -All e -Recurse nao podem ser usados juntos."; return }

    $Path = (Resolve-Path $Path).Path

    if ($NoBytes) {
        Write-Host "Mode Tamanho Nome"
        Write-Host "----- ----------- ----------------------------------------"
    } else {
        Write-Host "Mode Tamanho Bytes Nome"
        Write-Host "----- ----------- ----------- ----------------------------------------"
    }
    Write-Host ""

    $results = @()

    if ($Full) {
        $items = Get-ChildItem -Path $Path -Recurse -Force -ErrorAction SilentlyContinue
        foreach ($i in $items) {
            if ($i.PSIsContainer) {
                $bytes = (Get-ChildItem $i.FullName -Recurse -File -Force -ErrorAction SilentlyContinue | Measure-Object Length -Sum).Sum
                $mode = "d-----"
            } else {
                $bytes = $i.Length
                $mode = "-a----"
            }
            if ($bytes -eq $null) { $bytes = 0 }
            $nome = $i.FullName.Replace($Path, "").TrimStart("\")
            $results += [PSCustomObject]@{ Mode=$mode; Size=$bytes; Name=$nome }
        }
    }
    elseif ($Recurse) {
        $files = Get-ChildItem -Path $Path -Recurse -File -Force -ErrorAction SilentlyContinue
        foreach ($f in $files) {
            $bytes = $f.Length
            if ($bytes -eq $null) { $bytes = 0 }
            $nome = $f.FullName.Replace($Path, "").TrimStart("\")
            $results += [PSCustomObject]@{ Mode="-a----"; Size=$bytes; Name=$nome }
        }
    }
    elseif ($All) {
        $dirs = Get-ChildItem -Path $Path -Directory -Recurse -Force -ErrorAction SilentlyContinue
        foreach ($d in $dirs) {
            $bytes = (Get-ChildItem $d.FullName -Recurse -File -Force -ErrorAction SilentlyContinue | Measure-Object Length -Sum).Sum
            if ($bytes -eq $null) { $bytes = 0 }
            $nome = $d.FullName.Replace($Path, "").TrimStart("\")
            $results += [PSCustomObject]@{ Mode="d-----"; Size=$bytes; Name=$nome }
        }
    }
    else {
        $dirs = Get-ChildItem -Path $Path -Directory -Force -ErrorAction SilentlyContinue
        foreach ($d in $dirs) {
            $bytes = (Get-ChildItem $d.FullName -Recurse -File -Force -ErrorAction SilentlyContinue | Measure-Object Length -Sum).Sum
            if ($bytes -eq $null) { $bytes = 0 }
            $results += [PSCustomObject]@{ Mode="d-----"; Size=$bytes; Name=$d.Name }
        }
    }

    if ($Sort -eq "Size") { $results = $results | Sort-Object Size -Descending }
    elseif ($Sort -eq "Name") { $results = $results | Sort-Object Name }

    foreach ($r in $results) {
        $tam = Format-Size $r.Size
        Print-Row $r.Mode $tam $r.Size $r.Name $NoBytes
    }
}

Export-ModuleMember -Function Get-FolderSize, Format-Size, Get-DriveSize, Get-StorageOverview