Public/Find-MediaFile.ps1

function Find-MediaFile {
    <#
    .SYNOPSIS
        Searches for media files (audio, video, pictures, and vaults) in a specified directory.
 
    .DESCRIPTION
        The Find-MediaFile function searches for media files in a specified directory.
        It supports recursive search, filtering by media type, and various output formats.
        Results can be displayed with detailed information and exported to CSV or JSON formats.
 
    .PARAMETER Path
        The directory path to search for media files. Defaults to the current directory.
 
    .PARAMETER MediaType
        The type of media to search for. Valid values: Audio, Video, Picture, Vaults, All
        Default: All
 
    .PARAMETER Recurse
        Search subdirectories recursively. Default: $true
 
    .PARAMETER ExportCSV
        Export results to a CSV file at the specified path.
 
    .PARAMETER ExportJSON
        Export results to a JSON file at the specified path.
 
    .PARAMETER ShowDetails
        Display detailed information about each file (size, creation date, modification date).
 
    .EXAMPLE
        Find-MediaFile
        Searches for all media files in the current directory and subdirectories.
 
    .EXAMPLE
        Find-MediaFile -Path "C:\Users\Documents" -MediaType Audio
        Searches for audio files only in the specified directory.
 
    .EXAMPLE
        Find-MediaFile -Path "D:\Media" -Recurse $false
        Searches for media files only in the specified directory (no subdirectories).
 
    .EXAMPLE
        Find-MediaFile -Path "C:\Media" -ExportCSV "media_results.csv" -ShowDetails
        Searches for all media files and exports detailed results to CSV.
 
    .OUTPUTS
        PSCustomObject[]
        Returns an array of custom objects containing file information.
 
    .NOTES
        Author: gdelfavero
 
    .INPUTS
        System.String
    #>


    [CmdletBinding()]
    param(
        [Parameter(Mandatory = $false, Position = 0, ValueFromPipeline = $true)]
        [string]$Path = (Get-Location).Path,

        [Parameter(Mandatory = $false)]
        [ValidateSet("Audio", "Video", "Picture", "Vaults", "All")]
        [string]$MediaType = "All",

        [Parameter(Mandatory = $false)]
        [switch]$Recurse,

        [Parameter(Mandatory = $false)]
        [string]$ExportCSV,

        [Parameter(Mandatory = $false)]
        [string]$ExportJSON,

        [Parameter(Mandatory = $false)]
        [switch]$ShowDetails,

        [Parameter(Mandatory = $false)]
        [switch]$ShowBanner
    )

    begin {
        # Define media file extensions
        $audioExtensions = @('.mp3', '.wav', '.flac', '.aac', '.ogg', '.m4a', '.wma', '.opus', '.aiff', '.ape')
        $videoExtensions = @('.mp4', '.avi', '.mkv', '.mov', '.wmv', '.flv', '.webm', '.m4v', '.mpg', '.mpeg', '.3gp', '.divx')
        $pictureExtensions = @('.jpg', '.jpeg', '.png', '.gif', '.bmp', '.tiff', '.tif', '.svg', '.webp', '.ico', '.raw', '.heic')
        $vaultExtensions = @('.kdbx', '.1pif', '.agilekeychain', '.opvault', '.bw', '.enpass', '.psafe3', '.kdb', '.keepass', '.hc', '.tc')

        Write-Verbose "Function started with Path=$Path, MediaType=$MediaType"

        $infoParams = @{ InformationAction = 'Continue' }

        if ($ShowBanner) {
            Write-Information @infoParams "PsMediaFinder - Media File Scanner"
            Write-Information @infoParams "----------------------------------"
        }

        $useRecurse = if ($PSBoundParameters.ContainsKey('Recurse')) { [bool]$Recurse } else { $true }

        Write-Information @infoParams "Searching in: $Path"
        Write-Information @infoParams "Media Type: $MediaType"
        Write-Information @infoParams "Recursive: $useRecurse"
        Write-Information @infoParams ""

        # Determine which extensions to search for
        $searchExtensions = @()
        switch ($MediaType) {
            "Audio" { $searchExtensions = $audioExtensions }
            "Video" { $searchExtensions = $videoExtensions }
            "Picture" { $searchExtensions = $pictureExtensions }
            "Vaults" { $searchExtensions = $vaultExtensions }
            "All" { $searchExtensions = $audioExtensions + $videoExtensions + $pictureExtensions + $vaultExtensions }
        }
    }

    process {
        try {
            $resolvedPath = Resolve-Path -LiteralPath $Path -ErrorAction Stop
        }
        catch {
            Write-Error "The specified path '$Path' does not exist." -ErrorAction Stop
            return
        }

        try {
            # Search for media files
            Write-Verbose "Scanning for media files..."
            $startTime = Get-Date

            $allMediaFiles = @()

            if ($useRecurse) {
                $allMediaFiles = Get-ChildItem -LiteralPath $resolvedPath -File -Recurse -ErrorAction SilentlyContinue |
                                 Where-Object { $searchExtensions -contains $_.Extension.ToLower() }
            } else {
                $allMediaFiles = Get-ChildItem -LiteralPath $resolvedPath -File -ErrorAction SilentlyContinue |
                                 Where-Object { $searchExtensions -contains $_.Extension.ToLower() }
            }

            $endTime = Get-Date
            $duration = $endTime - $startTime

            # Process and categorize results
            $results = @()
            $audioFiles = @()
            $videoFiles = @()
            $pictureFiles = @()
            $vaultFiles = @()

            foreach ($file in $allMediaFiles) {
                $fileInfo = [PSCustomObject]@{
                    Name = $file.Name
                    Path = $file.FullName
                    Directory = $file.DirectoryName
                    Extension = $file.Extension.ToLower()
                    Size = $file.Length
                    SizeFormatted = Format-FileSize -Size $file.Length
                    Created = $file.CreationTime
                    Modified = $file.LastWriteTime
                    Type = ""
                }

                # Determine file type
                if ($audioExtensions -contains $file.Extension.ToLower()) {
                    $fileInfo.Type = "Audio"
                    $audioFiles += $fileInfo
                } elseif ($videoExtensions -contains $file.Extension.ToLower()) {
                    $fileInfo.Type = "Video"
                    $videoFiles += $fileInfo
                } elseif ($pictureExtensions -contains $file.Extension.ToLower()) {
                    $fileInfo.Type = "Picture"
                    $pictureFiles += $fileInfo
                } elseif ($vaultExtensions -contains $file.Extension.ToLower()) {
                    $fileInfo.Type = "Vaults"
                    $vaultFiles += $fileInfo
                }

                $results += $fileInfo
            }

            # Display summary (ASCII only for PS5 compatibility)
            Write-Information @infoParams "Search Results"
            Write-Information @infoParams "----------------"

            Write-Information @infoParams "Search completed in: $($duration.TotalSeconds.ToString('F2')) seconds"
            Write-Information @infoParams ""
            Write-Information @infoParams "Total files found: $($results.Count)"

            if ($MediaType -eq "All" -or $MediaType -eq "Audio") {
                Write-Information @infoParams " Audio files: $($audioFiles.Count)"
            }
            if ($MediaType -eq "All" -or $MediaType -eq "Video") {
                Write-Information @infoParams " Video files: $($videoFiles.Count)"
            }
            if ($MediaType -eq "All" -or $MediaType -eq "Picture") {
                Write-Information @infoParams " Picture files: $($pictureFiles.Count)"
            }
            if ($MediaType -eq "All" -or $MediaType -eq "Vaults") {
                Write-Information @infoParams " Vault files: $($vaultFiles.Count)"
            }

            # Calculate total size
            $totalSize = ($results | Measure-Object -Property Size -Sum).Sum
            Write-Information @infoParams ""
            Write-Information @infoParams "Total size: $(Format-FileSize -Size $totalSize)"

            # Display detailed results
            if ($results.Count -gt 0) {
                Write-Information @infoParams ""
                Write-Information @infoParams "----------------------------------------"

                if ($ShowDetails) {
                    Write-Information @infoParams ""
                    Write-Information @infoParams "Detailed File List:"
                    Write-Information @infoParams "----------------------------------------"

                    foreach ($file in $results | Sort-Object Type, Name) {
                        Write-Information @infoParams ""
                        Write-Information @infoParams "[$($file.Type)] $($file.Name)"
                        Write-Information @infoParams " Path: $($file.Path)"
                        Write-Information @infoParams " Size: $($file.SizeFormatted)"
                        Write-Information @infoParams " Created: $($file.Created.ToString('yyyy-MM-dd HH:mm:ss'))"
                        Write-Information @infoParams " Modified: $($file.Modified.ToString('yyyy-MM-dd HH:mm:ss'))"
                    }
                } else {
                    Write-Information @infoParams ""
                    Write-Information @infoParams "File List (use -ShowDetails for more information):"
                    Write-Information @infoParams "----------------------------------------"

                    foreach ($file in $results | Sort-Object Type, Name) {
                        Write-Information @infoParams "[$($file.Type.PadRight(7))] $($file.Name.PadRight(40)) $($file.SizeFormatted)"
                    }
                }

                Write-Information @infoParams ""
                Write-Information @infoParams "----------------------------------------"
            }

            # Export results to CSV
            if ($ExportCSV) {
                try {
                    $results | Select-Object Name, Type, Path, Directory, Extension, SizeFormatted, Created, Modified |
                        Export-Csv -Path $ExportCSV -NoTypeInformation -Encoding UTF8
                    Write-Information @infoParams ""
                    Write-Information @infoParams "[SUCCESS] Results exported to CSV: $ExportCSV"
                } catch {
                    Write-Warning "Failed to export to CSV: $_"
                }
            }

            # Export results to JSON
            if ($ExportJSON) {
                try {
                    $results | ConvertTo-Json -Depth 3 | Out-File -FilePath $ExportJSON -Encoding UTF8
                    Write-Information @infoParams ""
                    Write-Information @infoParams "[SUCCESS] Results exported to JSON: $ExportJSON"
                } catch {
                    Write-Warning "Failed to export to JSON: $_"
                }
            }

            # Display extension breakdown
            if ($results.Count -gt 0) {
                Write-Information @infoParams ""
                Write-Information @infoParams "Extension Breakdown"
                Write-Information @infoParams "--------------------"

                $extensionStats = $results | Group-Object Extension |
                    Select-Object @{Name='Extension';Expression={$_.Name}},
                                  @{Name='Count';Expression={$_.Count}},
                                  @{Name='TotalSize';Expression={($_.Group | Measure-Object -Property Size -Sum).Sum}} |
                    Sort-Object Count -Descending

                foreach ($stat in $extensionStats) {
                    Write-Information @infoParams " $($stat.Extension.PadRight(10)) $($stat.Count.ToString().PadLeft(5)) files ($(Format-FileSize -Size $stat.TotalSize))"
                }
            }

            Write-Information @infoParams ""

            # Return results
            return $results
        }
        catch {
            Write-Error "An error occurred while searching for media files: $_"
        }
    }
}