DiskCleaner.psm1

#Requires -Version 5.1

<#
.SYNOPSIS
    DiskCleaner - A Windows disk cleanup utility module.

.DESCRIPTION
    Provides functions to analyze and clean temporary files, browser caches,
    and other unnecessary files to free up disk space.
#>


function Get-TempFileInfo {
    <#
    .SYNOPSIS
        Analyzes temporary files and shows potential space savings.

    .DESCRIPTION
        Scans common temporary file locations and reports the total size
        of files that can be safely removed.

    .PARAMETER IncludeBrowserCache
        Include browser cache folders in the analysis.

    .EXAMPLE
        Get-TempFileInfo
        Shows temp file analysis for the current user.

    .EXAMPLE
        Get-TempFileInfo -IncludeBrowserCache
        Includes browser caches in the analysis.
    #>

    [CmdletBinding()]
    param(
        [switch]$IncludeBrowserCache
    )

    $locations = @(
        @{ Name = "Windows Temp"; Path = "$env:TEMP" },
        @{ Name = "User Temp"; Path = "$env:LOCALAPPDATA\Temp" },
        @{ Name = "Windows Prefetch"; Path = "$env:SystemRoot\Prefetch" },
        @{ Name = "Thumbnail Cache"; Path = "$env:LOCALAPPDATA\Microsoft\Windows\Explorer" }
    )

    if ($IncludeBrowserCache) {
        $locations += @(
            @{ Name = "Chrome Cache"; Path = "$env:LOCALAPPDATA\Google\Chrome\User Data\Default\Cache" },
            @{ Name = "Edge Cache"; Path = "$env:LOCALAPPDATA\Microsoft\Edge\User Data\Default\Cache" },
            @{ Name = "Firefox Cache"; Path = "$env:LOCALAPPDATA\Mozilla\Firefox\Profiles" }
        )
    }

    $results = @()
    $totalSize = 0

    foreach ($location in $locations) {
        if (Test-Path $location.Path) {
            try {
                $files = Get-ChildItem -Path $location.Path -Recurse -File -ErrorAction SilentlyContinue
                $size = ($files | Measure-Object -Property Length -Sum).Sum
                if ($null -eq $size) { $size = 0 }

                $results += [PSCustomObject]@{
                    Location  = $location.Name
                    Path      = $location.Path
                    FileCount = $files.Count
                    SizeMB    = [math]::Round($size / 1MB, 2)
                }
                $totalSize += $size
            }
            catch {
                Write-Verbose "Could not access: $($location.Path)"
            }
        }
    }

    Write-Host "`n=== DiskCleaner Analysis ===" -ForegroundColor Cyan
    $results | Format-Table -AutoSize

    Write-Host "Total Potential Savings: " -NoNewline
    Write-Host "$([math]::Round($totalSize / 1MB, 2)) MB" -ForegroundColor Green
    Write-Host "($([math]::Round($totalSize / 1GB, 2)) GB)`n" -ForegroundColor Green

    return $results
}

function Clear-TempFiles {
    <#
    .SYNOPSIS
        Removes temporary files to free up disk space.

    .DESCRIPTION
        Safely removes temporary files from common Windows temp locations.
        Skips files that are currently in use.

    .PARAMETER IncludeBrowserCache
        Also clear browser cache folders.

    .PARAMETER Force
        Skip confirmation prompt.

    .PARAMETER WhatIf
        Show what would be deleted without actually deleting.

    .EXAMPLE
        Clear-TempFiles
        Cleans temp files with confirmation prompt.

    .EXAMPLE
        Clear-TempFiles -Force
        Cleans temp files without asking for confirmation.

    .EXAMPLE
        Clear-TempFiles -WhatIf
        Shows what would be deleted without deleting anything.
    #>

    [CmdletBinding(SupportsShouldProcess)]
    param(
        [switch]$IncludeBrowserCache,
        [switch]$Force
    )

    $locations = @(
        "$env:TEMP",
        "$env:LOCALAPPDATA\Temp"
    )

    if ($IncludeBrowserCache) {
        $locations += @(
            "$env:LOCALAPPDATA\Google\Chrome\User Data\Default\Cache",
            "$env:LOCALAPPDATA\Microsoft\Edge\User Data\Default\Cache"
        )
    }

    if (-not $Force -and -not $WhatIfPreference) {
        $confirm = Read-Host "This will delete temporary files. Continue? (Y/N)"
        if ($confirm -notmatch '^[Yy]') {
            Write-Host "Operation cancelled." -ForegroundColor Yellow
            return
        }
    }

    $deletedCount = 0
    $deletedSize = 0
    $errorCount = 0

    foreach ($path in $locations) {
        if (Test-Path $path) {
            Write-Host "Cleaning: $path" -ForegroundColor Cyan

            Get-ChildItem -Path $path -Recurse -File -ErrorAction SilentlyContinue | ForEach-Object {
                try {
                    $size = $_.Length
                    if ($PSCmdlet.ShouldProcess($_.FullName, "Delete")) {
                        Remove-Item $_.FullName -Force -ErrorAction Stop
                        $deletedCount++
                        $deletedSize += $size
                    }
                }
                catch {
                    $errorCount++
                    Write-Verbose "Skipped (in use): $($_.Name)"
                }
            }
        }
    }

    Write-Host "`n=== Cleanup Complete ===" -ForegroundColor Green
    Write-Host "Files deleted: $deletedCount"
    Write-Host "Space freed: $([math]::Round($deletedSize / 1MB, 2)) MB"
    if ($errorCount -gt 0) {
        Write-Host "Files skipped (in use): $errorCount" -ForegroundColor Yellow
    }
}

function Get-DiskUsage {
    <#
    .SYNOPSIS
        Shows disk usage information for all drives.

    .DESCRIPTION
        Displays used and free space for all fixed drives with a visual bar.

    .PARAMETER Drive
        Specific drive letter to check (e.g., "C").

    .EXAMPLE
        Get-DiskUsage
        Shows usage for all drives.

    .EXAMPLE
        Get-DiskUsage -Drive C
        Shows usage for C: drive only.
    #>

    [CmdletBinding()]
    param(
        [string]$Drive
    )

    $drives = Get-CimInstance -ClassName Win32_LogicalDisk -Filter "DriveType=3"

    if ($Drive) {
        $drives = $drives | Where-Object { $_.DeviceID -eq "${Drive}:" }
    }

    Write-Host "`n=== Disk Usage ===" -ForegroundColor Cyan

    foreach ($d in $drives) {
        $usedSpace = $d.Size - $d.FreeSpace
        $percentUsed = [math]::Round(($usedSpace / $d.Size) * 100, 1)
        $percentFree = 100 - $percentUsed

        # Create visual bar
        $barLength = 30
        $usedBars = [math]::Round($barLength * ($percentUsed / 100))
        $freeBars = $barLength - $usedBars

        $color = if ($percentUsed -gt 90) { "Red" }
                 elseif ($percentUsed -gt 70) { "Yellow" }
                 else { "Green" }

        Write-Host "`nDrive $($d.DeviceID)" -ForegroundColor White
        Write-Host "[" -NoNewline
        Write-Host ("=" * $usedBars) -NoNewline -ForegroundColor $color
        Write-Host ("." * $freeBars) -NoNewline -ForegroundColor DarkGray
        Write-Host "] $percentUsed% used"

        Write-Host " Total: $([math]::Round($d.Size / 1GB, 2)) GB"
        Write-Host " Used: $([math]::Round($usedSpace / 1GB, 2)) GB" -ForegroundColor $color
        Write-Host " Free: $([math]::Round($d.FreeSpace / 1GB, 2)) GB" -ForegroundColor Green
    }
    Write-Host ""
}

function Get-RecycleBinInfo {
    <#
    .SYNOPSIS
        Shows recycle bin size and item count.

    .DESCRIPTION
        Analyzes the recycle bin and displays the total size and number of items
        that can be permanently deleted to free up space.

    .EXAMPLE
        Get-RecycleBinInfo
        Shows recycle bin statistics.
    #>

    [CmdletBinding()]
    param()

    $shell = New-Object -ComObject Shell.Application
    $recycleBin = $shell.NameSpace(0xA)
    $items = $recycleBin.Items()

    $totalSize = 0
    $itemCount = $items.Count

    foreach ($item in $items) {
        $totalSize += $recycleBin.GetDetailsOf($item, 2) -replace '[^\d]', '' -as [long]
    }

    # Alternative method using COM for accurate size
    try {
        $query = "SELECT * FROM Win32_LogicalDisk WHERE DriveType=3"
        $disks = Get-CimInstance -Query $query
        $rbSize = 0

        foreach ($disk in $disks) {
            $rbPath = "$($disk.DeviceID)\`$Recycle.Bin"
            if (Test-Path $rbPath) {
                $size = (Get-ChildItem -Path $rbPath -Recurse -Force -ErrorAction SilentlyContinue |
                         Measure-Object -Property Length -Sum -ErrorAction SilentlyContinue).Sum
                if ($size) { $rbSize += $size }
            }
        }
        $totalSize = $rbSize
    }
    catch {
        Write-Verbose "Could not calculate exact size"
    }

    Write-Host "`n=== Recycle Bin ===" -ForegroundColor Cyan
    Write-Host "Items: $itemCount"
    Write-Host "Size: $([math]::Round($totalSize / 1MB, 2)) MB" -ForegroundColor Yellow
    Write-Host " ($([math]::Round($totalSize / 1GB, 2)) GB)" -ForegroundColor Yellow

    return [PSCustomObject]@{
        ItemCount = $itemCount
        SizeBytes = $totalSize
        SizeMB    = [math]::Round($totalSize / 1MB, 2)
        SizeGB    = [math]::Round($totalSize / 1GB, 2)
    }
}

function Clear-RecycleBin {
    <#
    .SYNOPSIS
        Empties the Windows recycle bin.

    .DESCRIPTION
        Permanently deletes all items in the recycle bin to free up disk space.

    .PARAMETER Force
        Skip confirmation prompt.

    .PARAMETER WhatIf
        Show what would happen without actually emptying the bin.

    .EXAMPLE
        Clear-RecycleBin
        Empties recycle bin with confirmation.

    .EXAMPLE
        Clear-RecycleBin -Force
        Empties recycle bin without confirmation.
    #>

    [CmdletBinding(SupportsShouldProcess)]
    param(
        [switch]$Force
    )

    # Get current recycle bin info
    $shell = New-Object -ComObject Shell.Application
    $recycleBin = $shell.NameSpace(0xA)
    $itemCount = $recycleBin.Items().Count

    if ($itemCount -eq 0) {
        Write-Host "`nRecycle bin is already empty." -ForegroundColor Green
        return
    }

    Write-Host "`nRecycle bin contains $itemCount item(s)." -ForegroundColor Yellow

    if (-not $Force -and -not $WhatIfPreference) {
        $confirm = Read-Host "Permanently delete all items? (Y/N)"
        if ($confirm -notmatch '^[Yy]') {
            Write-Host "Operation cancelled." -ForegroundColor Yellow
            return
        }
    }

    if ($PSCmdlet.ShouldProcess("Recycle Bin", "Empty $itemCount items")) {
        try {
            Clear-RecycleBin -Force:$true -ErrorAction Stop
        }
        catch {
            # Use alternative method
            $null = (New-Object -ComObject Shell.Application).NameSpace(0xA).Items() | ForEach-Object {
                Remove-Item $_.Path -Recurse -Force -ErrorAction SilentlyContinue
            }
        }

        # Use the built-in cmdlet if available (PS 5.1+)
        if (Get-Command Microsoft.PowerShell.Management\Clear-RecycleBin -ErrorAction SilentlyContinue) {
            Microsoft.PowerShell.Management\Clear-RecycleBin -Force -ErrorAction SilentlyContinue
        }
        else {
            # Fallback for older systems
            $shell = New-Object -ComObject Shell.Application
            $shell.NameSpace(0xA).Items() | ForEach-Object {
                Remove-Item -Path $_.Path -Recurse -Force -ErrorAction SilentlyContinue
            }
        }

        Write-Host "`n=== Recycle Bin Emptied ===" -ForegroundColor Green
        Write-Host "Deleted $itemCount item(s)" -ForegroundColor Green
    }
}

# Export functions
Export-ModuleMember -Function Get-TempFileInfo, Clear-TempFiles, Get-DiskUsage, Get-RecycleBinInfo, Clear-RecycleBin