Functions/GenXdev.FileSystem/Find-Item.ps1

################################################################################
<#
.SYNOPSIS
Performs advanced file and directory searches with content filtering capabilities.
 
.DESCRIPTION
A powerful search utility that combines file/directory pattern matching with
content filtering. Supports recursive searches, multi-drive operations, and
flexible output formats. Can search by name patterns and content patterns
simultaneously.
 
.PARAMETER SearchMask
File or directory pattern to match against. Supports wildcards (*,?).
Default is "*" to match everything.
 
.PARAMETER Pattern
Regular expression to search within file contents. Only applies to files.
Default is ".*" to match any content.
 
.PARAMETER RelativeBasePath
Base directory for generating relative paths in output.
Only used when -PassThru is not specified.
 
.PARAMETER AllDrives
When specified, searches across all available filesystem drives.
 
.PARAMETER Directory
Limits search to directories only, ignoring files.
 
.PARAMETER FilesAndDirectories
Includes both files and directories in search results.
 
.PARAMETER PassThru
Returns FileInfo/DirectoryInfo objects instead of paths.
 
.PARAMETER IncludeAlternateFileStreams
Include alternate data streams in search results.
 
.PARAMETER NoRecurse
Prevents recursive searching into subdirectories.
 
.EXAMPLE
# Find all files with that have the word "translation" in their content
Find-Item -Pattern "translation"
 
# or in short
l -mc translation
 
.EXAMPLE
# Find any javascript file that tests a version string in it's code
Find-Item -SearchMask *.js -Pattern "Version == `"\d\d?\.\d\d?\.\d\d?`""
 
# or in short
l *.js "Version == `"\d\d?\.\d\d?\.\d\d?`""
 
.EXAMPLE
# Find any node_modules\react-dom folder on all drives
Find-Item -SearchMask "node_modules\react-dom" -Pattern "Version == `"\d\d?\.\d\d?\.\d\d?`""
 
# or in short
l *.js "Version == `"\d\d?\.\d\d?\.\d\d?`""
 
.EXAMPLE
# Find all directories in the current directory and its subdirectories
Find-Item -Directory
 
# or in short
l -dir
 
.EXAMPLE
# Find all files with the .log extension in all drives
Find-Item -SearchMask "*.log" -AllDrives
 
# or in short
l *.log -all
 
.EXAMPLE
# Find all files with the .config extension and search for the pattern "connectionString" within the files
Find-Item -SearchMask "*.config" -Pattern "connectionString"
 
# or in short
l *.config connectionString
 
.EXAMPLE
# Find all files with the .xml extension and pass the objects through the pipeline
Find-Item -SearchMask "*.xml" -PassThru
 
# or in short
l *.xml -PassThru
 
.EXAMPLE
# Find all files and also include alternate data streams
Find-Item -IncludeAlternateFileStreams
 
# or in short
l -ads
 
.EXAMPLE
# Find only the alternate data streams (not the base files) for all .jpg files
Find-Item -SearchMask "*.jpg:"
 
# This syntax automatically enables -IncludeAlternateFileStreams
 
.EXAMPLE
# Find jpg files that have a stream named "Zone.Identifier"
Find-Item -SearchMask "*.jpg:Zone.Identifier"
 
# No need to specify -IncludeAlternateFileStreams, it's automatically enabled
 
.EXAMPLE
# Find all alternate filestreams in the current directory and beyond
# containing "secret" text in their content
Find-Item -SearchMask "*:*" -Pattern "secret"
 
# This will find all alternate streams in any file that contain the word "secret"
 
.EXAMPLE
# Find files with Zone.Identifier streams and return them as objects
Find-Item "*:Zone*" -PassThru
 
# Returns System.IO.FileInfo.AlternateDataStream objects with full FileInfo compatibility
#>

function Find-Item {

    [CmdletBinding(DefaultParameterSetName = "Default")]
    [Alias("l")]
    [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseUsingScopeModifierInNewRunspaces", "")]
    [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidTrailingWhitespace", "")]
    param(
        ########################################################################
        [Parameter(
            Position = 0,
            Mandatory = $false,
            ValueFromPipeline = $true,
            ValueFromPipelineByPropertyName = $true,
            HelpMessage = "File name or pattern to search for. Default is '*'"
        )]
        [Alias("like", "l", "Path", "Name", "file", "Query", "FullName")]
        [ValidateNotNullOrEmpty()]
        [SupportsWildcards()]
        [string[]] $SearchMask = "*",
        ########################################################################
        [Parameter(
            Position = 1,
            Mandatory = $false,
            ParameterSetName = 'WithPattern',
            HelpMessage = "Regular expression pattern to search within content"
        )]
        [Alias("mc", "matchcontent")]
        [ValidateNotNull()]
        [SupportsWildcards()]
        [string] $Pattern = ".*",
        ########################################################################
        [Parameter(
            Position = 2,
            Mandatory = $false,
            HelpMessage = "Base path for resolving relative paths in output"
        )]
        [Alias("base")]
        [ValidateNotNullOrEmpty()]
        [string] $RelativeBasePath = ".\",
        ########################################################################
        [Parameter(
            Mandatory = $false,
            HelpMessage = "Search across all available drives"
        )]
        [Alias("all")]
        [switch] $AllDrives,
        ########################################################################
        [Parameter(
            Mandatory = $false,
            ParameterSetName = 'DirectoriesOnly',
            HelpMessage = "Search for directories only"
        )]
        [Alias("dir")]
        [switch] $Directory,
        ########################################################################
        [Parameter(
            Mandatory = $false,
            ParameterSetName = 'DirectoriesOnly',
            HelpMessage = "Include both files and directories"
        )]
        [Alias("both")]
        [switch] $FilesAndDirectories,
        ########################################################################
        [Parameter(
            Mandatory = $false,
            HelpMessage = "Output matched items as objects"
        )]
        [switch] $PassThru,
        ########################################################################
        [Parameter(
            Mandatory = $false,
            HelpMessage = "Include alternate data streams in search results"
        )]
        [Alias("ads")]
        [switch] $IncludeAlternateFileStreams,
        ########################################################################
        [Parameter(
            Mandatory = $false,
            HelpMessage = "Do not recurse into subdirectories"
        )]
        [switch] $NoRecurse
        ########################################################################
    )

    begin {
        # log function entry with parameters for debugging
        Microsoft.PowerShell.Utility\Write-Information "BEGIN Find-Item: Initializing with parameters:"
        Microsoft.PowerShell.Utility\Write-Information " SearchMask: $($SearchMask -join ', ')"
        Microsoft.PowerShell.Utility\Write-Information " Pattern: $Pattern"
        Microsoft.PowerShell.Utility\Write-Information " RelativeBasePath: $RelativeBasePath"
        Microsoft.PowerShell.Utility\Write-Information " AllDrives: $AllDrives"
        Microsoft.PowerShell.Utility\Write-Information " Directory: $Directory"
        Microsoft.PowerShell.Utility\Write-Information " FilesAndDirectories: $FilesAndDirectories"
        Microsoft.PowerShell.Utility\Write-Information " PassThru: $PassThru"
        Microsoft.PowerShell.Utility\Write-Information " IncludeAlternateFileStreams: $IncludeAlternateFileStreams"
        Microsoft.PowerShell.Utility\Write-Information " NoRecurse: $NoRecurse"

        # Track whether we have an implicit ADS request for specific masks
        $processedSearchMasks = @()
        $streamPatterns = @{}
        $searchMasksWithAds = @()

        # Process SearchMask for alternate data stream patterns
        foreach ($mask in $SearchMask) {
            # Skip empty masks
            if ([string]::IsNullOrWhiteSpace($mask)) {
                continue
            }

            # Expand the mask to a full path to handle drive specifications correctly
            try {
                $expandedMask = GenXdev.FileSystem\Expand-Path $mask -ErrorAction SilentlyContinue
            }
            catch {
                # If expansion fails, just use the original mask
                $expandedMask = $mask
                Microsoft.PowerShell.Utility\Write-Information "Failed to expand path '$mask': $($_.Exception.Message)"
            }

            Microsoft.PowerShell.Utility\Write-Information "Expanded mask '$mask' to '$expandedMask'"

            # Count the number of colons in the path
            $colonCount = ($expandedMask -split ':').Length - 1
            Microsoft.PowerShell.Utility\Write-Information "Found $colonCount colons in expanded mask"

            # If we have more than 1 colon (one for drive spec, others for stream)
            if ($colonCount -gt 1) {
                $lastColonIndex = $expandedMask.LastIndexOf(':' )

                # Extract the file pattern (everything before the last colon)
                $filePattern = $expandedMask.Substring(0, $lastColonIndex)

                # Extract the stream pattern (everything after the last colon)
                $streamPattern = $expandedMask.Substring($lastColonIndex + 1)

                # If stream pattern is empty, use wildcard to match all streams
                if ([string]::IsNullOrWhiteSpace($streamPattern)) {
                    $streamPattern = "*"
                }

                Microsoft.PowerShell.Utility\Write-Information "Found ADS pattern in SearchMask. File pattern: $filePattern, Stream pattern: $streamPattern"

                # Store the stream pattern for the expanded file path only
                $streamPatterns[$filePattern] = $streamPattern

                # Add only the file pattern to the processed masks and mark it as needing ADS
                $processedSearchMasks += $filePattern
                $searchMasksWithAds += $filePattern

                Microsoft.PowerShell.Utility\Write-Information "Added file pattern to SearchMasksWithAds: $filePattern"
            }
            else {
                # No ADS pattern, add the mask as is
                $processedSearchMasks += $mask

                # If IncludeAlternateFileStreams switch is provided, also add this mask to SearchMasksWithAds
                if ($IncludeAlternateFileStreams) {
                    $searchMasksWithAds += $mask
                    Microsoft.PowerShell.Utility\Write-Information "Added mask to SearchMasksWithAds due to IncludeAlternateFileStreams: $mask"
                }
            }
        }

        # Replace the original SearchMask with the processed one
        $SearchMask = $processedSearchMasks

        # No need to store in script: variables when using $using: in parallel

        Microsoft.PowerShell.Utility\Write-Information "Modified SearchMask: $($SearchMask -join ', ')"
        Microsoft.PowerShell.Utility\Write-Information "SearchMasksWithAds: $($searchMasksWithAds -join ', ')"
        Microsoft.PowerShell.Utility\Write-Information "Stream patterns: $(($streamPatterns | Microsoft.PowerShell.Utility\Out-String))"

        # user-friendly verbose message about what the function will do
        Microsoft.PowerShell.Utility\Write-Verbose "Starting search for $($SearchMask -join ', ')$(if(![string]::IsNullOrWhiteSpace($Pattern) -and $Pattern -ne '.*'){" containing text matching pattern: '$Pattern'"})"
    }

    process {
        # log process block entry for debugging
        Microsoft.PowerShell.Utility\Write-Information "PROCESS Find-Item: Starting search processing"

        # log high-level search information for users
        Microsoft.PowerShell.Utility\Write-Verbose "Searching for $(if($Directory){'directories'}elseif($FilesAndDirectories){'files and directories'}else{'files'}) matching $($SearchMask -join ', ')"

        # if searching across drives, inform the user
        if ($AllDrives) {
            Microsoft.PowerShell.Utility\Write-Verbose "Searching across all available drives - this may take some time"
            Microsoft.PowerShell.Utility\Write-Information "Searching across all available drives"
        }

        # parallel search across all filesystem drives if AllDrives switch is provided
        ($AllDrives ? ( & {
                # get all filesystem drives with single-letter names
                Microsoft.PowerShell.Utility\Write-Information "Getting available filesystem drives"
                $drives = Microsoft.PowerShell.Management\Get-PSDrive -ErrorAction SilentlyContinue |
                Microsoft.PowerShell.Core\Where-Object {
                    ($PSItem.Provider -Like "*FileSystem") -and ($PSItem.Name.Length -eq 1)
                }
                Microsoft.PowerShell.Utility\Write-Verbose "Found drives: $($drives.Name -join ', ')"
                Microsoft.PowerShell.Utility\Write-Information "Found drives: $($drives.Name -join ', ')"
                $drives
            }
        ) : $null) |
        Microsoft.PowerShell.Core\ForEach-Object -ThrottleLimit 8 -Parallel {
            # Access parent scope variables with $using:
            $streamPatterns = $using:streamPatterns
            $searchMasksWithAds = $using:searchMasksWithAds
            $includeAlternateFileStreams = $using:IncludeAlternateFileStreams

            Microsoft.PowerShell.Utility\Write-Information "Stream patterns in parallel block: $(($streamPatterns | Microsoft.PowerShell.Utility\Out-String))"

            # helper function to search file contents using regex, including alternate data streams
            function Search-FileContent {
                param (
                    [string] $filePath,
                    [string] $pattern,
                    [string] $streamName = $null
                )

                Microsoft.PowerShell.Utility\Write-Information "Searching file content: $filePath$(if($streamName){":$streamName"}) for pattern: '$pattern'"

                # Debug information to help identify issues
                Microsoft.PowerShell.Utility\Write-Information "Pattern type: $($pattern.GetType().FullName), Length: $($pattern.Length)"

                try {
                    # If a stream name is provided, search in that specific stream content
                    if ($streamName) {
                        # Get the stream content as a string
                        [string] $content = Microsoft.PowerShell.Management\Get-Content -LiteralPath $filePath -Stream $streamName -Raw -ErrorAction Stop

                        if ($content) {
                            # Now apply the regex to the actual content
                            [bool] $matchResult = $content -match $pattern
                            Microsoft.PowerShell.Utility\Write-Information "Stream content match result: $matchResult (explicit regex)"
                            return $matchResult
                        }
                        else {
                            Microsoft.PowerShell.Utility\Write-Information "Stream content is empty"
                            return $false
                        }
                    }
                    # For regular files, use the same regex matching approach for consistency
                    else {
                        # Read the file content directly to use the same matching logic for both
                        [string] $fileContent = Microsoft.PowerShell.Management\Get-Content -LiteralPath $filePath -Raw -ErrorAction Stop
                        if ($fileContent) {
                            [bool] $matchResult = $fileContent -match $pattern
                            Microsoft.PowerShell.Utility\Write-Information "File content match result: $matchResult (explicit regex)"
                            return $matchResult
                        }
                        else {
                            Microsoft.PowerShell.Utility\Write-Information "File is empty"
                            return $false
                        }
                    }
                }
                catch {
                    Microsoft.PowerShell.Utility\Write-Information "Error searching content: $($_.Exception.Message)"
                    return $false
                }
            }

            # helper function to recursively search directories
            function Search-DirectoryContent {
                param (
                    [string] $searchPhrase,
                    [bool] $includeAds = $false,
                    [bool] $hasStreamPattern,
                    [string] $expandedSearchMask = $null,
                    [hashtable] $streamPatterns,
                    [bool] $passThru,
                    [string] $relativeBasePath,
                    [string] $pattern,
                    [bool] $directory,
                    [bool] $filesAndDirectories,
                    [bool] $noRecurse
                )

                Microsoft.PowerShell.Utility\Write-Information "Search-DirectoryContent: Starting with phrase: $searchPhrase, includeAds: $includeAds, mask: $expandedSearchMask"

                # handle empty search phrase by defaulting to current directory
                if ([string]::IsNullOrWhiteSpace($searchPhrase)) {
                    $searchPhrase = ".\*"
                    Microsoft.PowerShell.Utility\Write-Information "Search phrase was empty, defaulting to: $searchPhrase"
                }

                # clean up and normalize the search path
                $searchPhrase = $searchPhrase.Trim()
                Microsoft.PowerShell.Utility\Write-Information "Normalized search phrase: $searchPhrase"

                # ensure proper path termination for directories
                $endedWithPathSeparator = $searchPhrase.EndsWith(
                    [System.IO.Path]::DirectorySeparatorChar)

                if ($endedWithPathSeparator) {
                    $searchPhrase += "*"
                    Microsoft.PowerShell.Utility\Write-Information "Path ended with separator, appended wildcard: $searchPhrase"
                }

                # convert to absolute path
                Microsoft.PowerShell.Utility\Write-Information "Converting to absolute path: $searchPhrase"
                $searchPhrase = GenXdev.FileSystem\Expand-Path $searchPhrase
                Microsoft.PowerShell.Utility\Write-Information "Absolute path: $searchPhrase"
                $remainingPath = $searchPhrase

                # initialize stack for directory traversal
                Microsoft.PowerShell.Utility\Write-Information "Initializing directory traversal stack"
                [System.Collections.Generic.Stack[System.Collections.Hashtable]] `
                    $directories = @()

                # find the next path separator character
                $index = $remainingPath.IndexOf([System.IO.Path]::DirectorySeparatorChar)
                Microsoft.PowerShell.Utility\Write-Information "First path separator index: $index"
                $indexOriginal = $index

                # find the first wildcard character (* or ?)
                $indexWildcard = $remainingPath.IndexOf("*")
                $indexQuestionMark = $remainingPath.IndexOf("?")
                Microsoft.PowerShell.Utility\Write-Information "First wildcard positions - * at: $indexWildcard, ? at: $indexQuestionMark"

                # if question mark comes before asterisk, use that as the wildcard position
                if ($indexQuestionMark -ge 0 -and
                    ($indexWildcard -lt 0 -or $indexQuestionMark -lt $indexWildcard)) {
                    $indexWildcard = $indexQuestionMark
                    Microsoft.PowerShell.Utility\Write-Information "Using ? as first wildcard at position: $indexWildcard"
                }

                # determine if we're at the last path component
                $last = $index -eq -1
                Microsoft.PowerShell.Utility\Write-Information "Is last path component: $last"

                # be more efficient by skipping directories that don't require a match
                # have no wildcard or a wildcard in the path that comes after next directory separator?
                if ((-not $last) -and (($indexWildCard -lt 0) -or ($indexWildcard -gt $index))) {
                    Microsoft.PowerShell.Utility\Write-Information "Optimizing directory traversal path"

                    # determine start position for searching wildcard preceding directory separator
                    $index = $indexWildcard -lt 0 ? $index : $indexWildcard
                    Microsoft.PowerShell.Utility\Write-Information "Adjusted index: $index"

                    # determine if there is a wildcard after the wildcard character
                    $index2 = $indexWildcard -lt 0 ? -1 :
                    $remainingPath.IndexOf([System.IO.Path]::DirectorySeparatorChar, $indexWildcard)
                    Microsoft.PowerShell.Utility\Write-Information "Wildcard delimiter index: $index2"

                    # if wildcard was found, search for the preceding directory separator character
                    if ($indexWildCard -ge 0) {
                        Microsoft.PowerShell.Utility\Write-Information "Finding directory separator before wildcard"
                        while ($index -ge 1 -and
                               ($remainingPath[$index] -ne [System.IO.Path]::DirectorySeparatorChar)) {
                            $index--
                        }
                        Microsoft.PowerShell.Utility\Write-Information "Found at index: $index"
                    }

                    # wildcard was found and did not have a preceding directory separator character?
                    if ($index2 -lt 0) {
                        # set last flag to true, for later processing
                        $last = $true
                        Microsoft.PowerShell.Utility\Write-Information "Setting last flag to true as wildcard has no following separator"

                        # if wildcard was present, adjust position to exclude directory with wildcard
                        if ($indexWildcard -ge 0) {
                            # move cursor to one character before directory separator
                            $index--;
                            Microsoft.PowerShell.Utility\Write-Information "Adjusted index position: $index"
                        }
                        else {
                            # if no wildcard was found, move cursor to the last directory separator
                            $index = $remainingPath.LastIndexOf(
                                [System.IO.Path]::DirectorySeparatorChar) - 1;
                            Microsoft.PowerShell.Utility\Write-Information "No wildcard found, moved to last separator: $index"
                        }

                        # exclude the directory holding the wildcard from our next directory scan
                        Microsoft.PowerShell.Utility\Write-Information "Excluding directory with wildcard from scan"
                        while ($index -ge 1 -and
                               ($remainingPath[$index] -ne [System.IO.Path]::DirectorySeparatorChar)) {
                            $index--
                        }
                        Microsoft.PowerShell.Utility\Write-Information "Final index position: $index"
                    }
                }

                # prepare the search path for the first directory scan
                $searchPath = "$($currentPath)*"
                Microsoft.PowerShell.Utility\Write-Information "Initial search path: $searchPath"

                # have no wildcard or a wildcard in the path that comes after next directory separator?
                if (($index -ge 0) -and
                    (($indexWildcard -lt 0) -or ($indexWildcard -gt $index))) {
                    Microsoft.PowerShell.Utility\Write-Information "Adjusting search path based on wildcard position"

                    # wildcard was found and did not have a preceding directory separator character?
                    if ($last) {
                        # find the last directory separator character
                        $i = $remainingPath.LastIndexOf([System.IO.Path]::DirectorySeparatorChar)
                        Microsoft.PowerShell.Utility\Write-Information "Last directory separator at: $i"

                        # set the appropriate path to search
                        $searchPath = "$($currentPath)$($remainingPath.Substring(0, $i))\*"
                        Microsoft.PowerShell.Utility\Write-Information "Updated search path: $searchPath"
                    }
                    else {
                        # set the appropriate path to search
                        $searchPath = "$($currentPath)$($remainingPath.Substring(0, $indexWildcard))*"
                        Microsoft.PowerShell.Utility\Write-Information "Updated search path with wildcard: $searchPath"
                    }
                }

                # push the first directory scan onto the stack
                Microsoft.PowerShell.Utility\Write-Information "Pushing first directory scan to stack"
                $null = $directories.Push(
                    @{
                        currentPath   = $remainingPath.Substring(0, $index + 1)
                        remainingPath = $remainingPath.Substring($index + 1)
                        currentDepth  = 0
                    }
                )
                Microsoft.PowerShell.Utility\Write-Information "Stack entry - currentPath: $($directories.Peek().currentPath), remainingPath: $($directories.Peek().remainingPath)"

                # process directories using a stack for efficient traversal
                [hashtable]$folder = $null
                Microsoft.PowerShell.Utility\Write-Information "Starting directory stack processing loop"
                $stackProcessCount = 0
                $totalDirsProcessed = 0
                $totalFilesChecked = 0
                $totalMatches = 0

                while ($directories.TryPop([ref]$folder)) {
                    $stackProcessCount++
                    $totalDirsProcessed++

                    # every 10 directories, update the verbose message for users
                    if ($totalDirsProcessed % 10 -eq 0) {
                        Microsoft.PowerShell.Utility\Write-Verbose "Searched $totalDirsProcessed directories, found $totalMatches matches so far..."
                    }

                    Microsoft.PowerShell.Utility\Write-Information "Processing stack item #$stackProcessCount - currentPath: $($folder.currentPath), remainingPath: $($folder.remainingPath), depth: $($folder.currentDepth)"

                    # find the next directory separator in the remaining path
                    $index = $folder.remainingPath.IndexOf([System.IO.Path]::DirectorySeparatorChar)
                    Microsoft.PowerShell.Utility\Write-Information "Next directory separator in remaining path: $index"

                    # save the original index for later use
                    $indexOriginal = $index

                    # find the first wildcard in the remaining path
                    $indexWildcard = $folder.remainingPath.IndexOf("*")
                    $indexQuestionMark = $folder.remainingPath.IndexOf("?")
                    Microsoft.PowerShell.Utility\Write-Information "Wildcards in remaining path - * at: $indexWildcard, ? at: $indexQuestionMark"

                    # if question mark comes before asterisk, use that as the wildcard position
                    if ($indexQuestionMark -ge 0 -and
                        ($indexWildcard -lt 0 -or $indexQuestionMark -lt $indexWildcard)) {
                        $indexWildcard = $indexQuestionMark
                        Microsoft.PowerShell.Utility\Write-Information "Using ? as wildcard position: $indexWildcard"
                    }

                    # determine if this is the last directory in the path
                    $last = $index -eq -1
                    Microsoft.PowerShell.Utility\Write-Information "Is last directory component: $last"

                    # be more efficient by skipping directories that don't require a match
                    # have no wildcard or a wildcard in the path that comes after next directory separator?
                    if ((-not $last) -and
                        (($indexWildCard -lt 0) -or ($indexWildcard -gt $index))) {
                        Microsoft.PowerShell.Utility\Write-Information "Optimizing intermediate directory traversal"

                        # determine start position for searching wildcard preceding directory separator
                        $index = $indexWildcard -lt 0 ? $index - 1 : $indexWildcard
                        Microsoft.PowerShell.Utility\Write-Information "Adjusted intermediate index: $index"

                        # determine if there is a wildcard after the wildcard character
                        $index2 = $indexWildcard -lt 0 ? -1 :
                        $folder.remainingPath.IndexOf(
                            [System.IO.Path]::DirectorySeparatorChar, $indexWildcard);
                        Microsoft.PowerShell.Utility\Write-Information "Intermediate wildcard delimiter index: $index2"

                        # if wildcard was found, search for the preceding directory separator character
                        if ($indexWildCard -ge 0) {
                            Microsoft.PowerShell.Utility\Write-Information "Finding directory separator before intermediate wildcard"
                            while ($index -ge 1 -and
                                  ($folder.remainingPath[$index] -ne [System.IO.Path]::DirectorySeparatorChar)) {

                                $index--
                            }
                            Microsoft.PowerShell.Utility\Write-Information "Found at intermediate index: $index"
                        }

                        # wildcard was found and did not have a preceding directory separator character?
                        if ($index2 -lt 0) {
                            Microsoft.PowerShell.Utility\Write-Information "Intermediate wildcard has no following separator"
                            # set last flag to true, for later processing
                            $last = $true

                            # if wildcard was present, adjust position to exclude directory with wildcard
                            if ($indexWildcard -ge 0) {
                                # move cursor to one character before directory separator
                                $index--;
                                Microsoft.PowerShell.Utility\Write-Information "Adjusted intermediate index position: $index"
                            }
                            else {
                                # if no wildcard was found, move cursor to the last directory separator
                                $index = $remainingPath.LastIndexOf(
                                    [System.IO.Path]::DirectorySeparatorChar) - 1;
                                Microsoft.PowerShell.Utility\Write-Information "No intermediate wildcard found, moved to last separator: $index"
                            }

                            # exclude directory holding the wildcard from our next directory scan
                            Microsoft.PowerShell.Utility\Write-Information "Excluding intermediate directory with wildcard from scan"
                            while ($index -ge 1 -and
                                  ($folder.remainingPath[$index] -ne [System.IO.Path]::DirectorySeparatorChar)) {

                                $index--
                            }
                            Microsoft.PowerShell.Utility\Write-Information "Final intermediate index position: $index"
                        }
                    }

                    # prepare the search path for the next directory scan
                    $searchPath = "$($folder.currentPath)*"
                    Microsoft.PowerShell.Utility\Write-Information "Next search path: $searchPath"

                    # have no wildcard or a wildcard in the path that comes after next directory separator?
                    if (($index -ge 0) -and
                        (($indexWildcard -lt 0) -or ($indexWildcard -gt $index))) {
                        Microsoft.PowerShell.Utility\Write-Information "Adjusting next search path based on wildcard position"

                        # wildcard was found and did not have a preceding directory separator character?
                        if ($last) {
                            Microsoft.PowerShell.Utility\Write-Information "Last directory with wildcard handling"
                            # find the last directory separator character
                            $i = $folder.remainingPath.LastIndexOf(
                                [System.IO.Path]::DirectorySeparatorChar)
                            Microsoft.PowerShell.Utility\Write-Information "Last directory separator at: $i"

                            # set the appropriate path to search
                            $searchPath = "$($folder.currentPath)$($folder.remainingPath.Substring(0, $i))\*"
                            Microsoft.PowerShell.Utility\Write-Information "Updated final search path: $searchPath"

                            # set the name to match for the next directory scan
                            $nameToMatch = $folder.remainingPath.Substring($i + 1)
                            Microsoft.PowerShell.Utility\Write-Information "Name pattern to match: $nameToMatch"
                        }
                        else {
                            Microsoft.PowerShell.Utility\Write-Information "Intermediate directory with wildcard handling"
                            # set the appropriate path to search
                            $searchPath = "$($folder.currentPath)$($folder.remainingPath.Substring(0, $indexWildcard))*"
                            Microsoft.PowerShell.Utility\Write-Information "Updated intermediate search path: $searchPath"

                            # set the name to match for the next directory scan
                            $nameToMatch = $folder.remainingPath
                            Microsoft.PowerShell.Utility\Write-Information "Intermediate name pattern to match: $nameToMatch"
                        }
                    }
                    else {
                        # are we following a /**/ pattern but haven't found the first matching directory yet?
                        if ($folder.forwardSearch) {
                            Microsoft.PowerShell.Utility\Write-Information "Following /**/ recursive pattern search"
                            # set the name to match for the next directory scan
                            $nameToMatch = $folder.nameToMatch
                            Microsoft.PowerShell.Utility\Write-Information "Recursive pattern name to match: $nameToMatch"

                            # force the last flag to true to keep following /**/ pattern without
                            # losing information about directory to match next
                            $last = $folder.remainingPath.Substring(3).IndexOf(
                                [System.IO.Path]::DirectorySeparatorChar) -lt 0;
                            Microsoft.PowerShell.Utility\Write-Information "Updated last flag for recursive pattern: $last"
                        }
                        else {
                            Microsoft.PowerShell.Utility\Write-Information "Standard pattern matching"
                            # set the name to match for the next directory scan
                            $nameToMatch = $folder.remainingPath
                            Microsoft.PowerShell.Utility\Write-Information "Standard name pattern to match: $nameToMatch"

                            # log that we've reached the end of the path pattern
                            Microsoft.PowerShell.Utility\Write-Information (
                                "No more directories to match in " +
                                "$($folder.currentPath) - setting last flag to true")
                        }
                    }

                    # if we are not at the last directory in the path
                    if (-not $last) {
                        Microsoft.PowerShell.Utility\Write-Information "Not at last directory, processing intermediate directories"

                        # and we are not following a /**/ pattern
                        if (-not $folder.forwardSearch) {
                            Microsoft.PowerShell.Utility\Write-Information "Not in /**/ pattern search mode"
                            # set next directory to match to be the next directory in the path
                            $nameToMatch = $folder.remainingPath.Substring(0, $indexOriginal)
                            Microsoft.PowerShell.Utility\Write-Information "Directory name to match: $nameToMatch"
                        }

                        # get only directories since there are more directories to match
                        $directorySearchOption = [System.IO.SearchOption]::TopDirectoryOnly
                        Microsoft.PowerShell.Utility\Write-Information "Getting directories from: $searchPath"

                        try {
                            # use System.IO.Directory to get directories instead of Get-ChildItem
                            $searchDir = [System.IO.Path]::GetDirectoryName($searchPath)
                            $searchPattern = [System.IO.Path]::GetFileName($searchPath)
                            Microsoft.PowerShell.Utility\Write-Information "Search directory: $searchDir, pattern: $searchPattern"

                            $directories_to_process = [System.IO.Directory]::GetDirectories(
                                $searchDir, $searchPattern, $directorySearchOption)
                            Microsoft.PowerShell.Utility\Write-Information "Found $(if($directories_to_process){$directories_to_process.Count}else{0}) directories to process"

                            foreach ($dirPath in $directories_to_process) {
                                # create DirectoryInfo object to match PowerShell behavior
                                $dirInfo = Microsoft.PowerShell.Utility\New-Object System.IO.DirectoryInfo($dirPath)
                                Microsoft.PowerShell.Utility\Write-Information "Processing directory: $($dirInfo.FullName)"

                                # are we following a /**/ pattern?
                                if ($folder.forwardSearch) {
                                    Microsoft.PowerShell.Utility\Write-Information "In /**/ search mode, checking if directory matches pattern: $($folder.nameToMatch)"

                                    # is this the next directory to match
                                    if ($dirInfo.Name -like $nameToMatch) {
                                        Microsoft.PowerShell.Utility\Write-Information "Found matching directory for /**/ pattern: $($dirInfo.Name)"

                                        $remainingPath = $folder.remainingPath.Substring(3);
                                        $i = $remainingPath.IndexOf([System.IO.Path]::DirectorySeparatorChar)
                                        if ($i -ge 0) {
                                            $remainingPath = $remainingPath.Substring($i + 1)
                                        }
                                        Microsoft.PowerShell.Utility\Write-Information "Remaining path after match: $remainingPath"

                                        # schedule directory scan that stops following the /**/ pattern
                                        $null = $directories.Push(
                                            @{
                                                remainingPath = $remainingPath
                                                currentPath   = "$($folder.currentPath)$($dirInfo.Name)\"
                                                currentDepth  = $folder.currentDepth + 1
                                            }
                                        )

                                        Microsoft.PowerShell.Utility\Write-Information (
                                            "Ending /**/ search for $nameToMatch in " +
                                            "$($directories.Peek().currentPath)")
                                    }
                                    else {
                                        Microsoft.PowerShell.Utility\Write-Information "Directory doesn't match /**/ pattern, continuing search"
                                        # schedule directory scan that will continue following /**/ pattern
                                        $null = $directories.Push(
                                            @{
                                                forwardSearch = $true
                                                remainingPath = $folder.remainingPath
                                                currentPath   = "$($folder.currentPath)$($dirInfo.Name)\"
                                                currentDepth  = $folder.currentDepth + 1
                                                nameToMatch   = $folder.remainingPath.Substring(3).Split(
                                                    [System.IO.Path]::DirectorySeparatorChar)[0]
                                            }
                                        )

                                        Microsoft.PowerShell.Utility\Write-Information (
                                            "Continuing following /**/ search for " +
                                            "$($directories.Peek().$nameToMatch) in " +
                                            "$($directories.Peek().currentPath)")
                                    }
                                }
                                # check if we are entering a /**/ pattern
                                elseif ($nameToMatch -eq "**") {
                                    Microsoft.PowerShell.Utility\Write-Information "Entering /**/ recursive search pattern"

                                    # schedule directory scan that will start following the /**/ pattern
                                    $null = $directories.Push(
                                        @{
                                            forwardSearch = $true
                                            remainingPath = $folder.remainingPath
                                            currentPath   = "$($folder.currentPath)$($dirInfo.Name)\"
                                            currentDepth  = $folder.currentDepth + 1
                                            nameToMatch   = $folder.remainingPath.Substring(3).Split(
                                                [System.IO.Path]::DirectorySeparatorChar)[0]
                                        }
                                    )

                                    Microsoft.PowerShell.Utility\Write-Information (
                                        "Starting /**/ search for " +
                                        "$($directories.Peek().$nameToMatch) in " +
                                        "$($directories.Peek().currentPath)")
                                }
                                # only schedule directories that match the name to match
                                elseif ($dirInfo.Name -like $nameToMatch) {
                                    Microsoft.PowerShell.Utility\Write-Information "Directory name '$($dirInfo.Name)' matches pattern '$nameToMatch'"

                                    # push directory onto stack for processing
                                    $null = $directories.Push(
                                        @{
                                            remainingPath = $folder.remainingPath.Substring($index + 1)
                                            currentPath   = "$($folder.currentPath)$($dirInfo.Name)\"
                                            currentDepth  = $folder.currentDepth + 1
                                        }
                                    )

                                    Microsoft.PowerShell.Utility\Write-Information (
                                        "Matched next directory for $nameToMatch in " +
                                        "$($directories.Peek().currentPath)")
                                }
                                else {
                                    Microsoft.PowerShell.Utility\Write-Information "Directory name '$($dirInfo.Name)' does not match pattern '$nameToMatch'"
                                }
                            }
                        }
                        catch {
                            # log any errors accessing directories
                            Microsoft.PowerShell.Utility\Write-Information (
                                "Error accessing directory: $([System.IO.Path]::GetDirectoryName($searchPath)) - $($_.Exception.Message)")
                        }

                        # skip to next directory in the stack
                        Microsoft.PowerShell.Utility\Write-Information "Continuing to next directory in stack"
                        continue;
                    }

                    # we are at the last directory of the SearchPhrase supplied
                    Microsoft.PowerShell.Utility\Write-Information "Reached last directory component, performing final matching"

                    # get both files and directories for final matching
                    try {
                        $searchOption = [System.IO.SearchOption]::TopDirectoryOnly
                        $searchDir = [System.IO.Path]::GetDirectoryName($searchPath)
                        $searchPattern = [System.IO.Path]::GetFileName($searchPath)
                        Microsoft.PowerShell.Utility\Write-Information "Final search in directory: $searchDir with pattern: $searchPattern"
                        Microsoft.PowerShell.Utility\Write-Verbose "Searching in directory: $searchDir"

                        # get directories if requested
                        Microsoft.PowerShell.Utility\Write-Information "Directory search enabled: $($directory -or $filesAndDirectories -or (-not $directory))"
                        $directories_found = @()
                        if ($directory -or $filesAndDirectories -or (-not $directory)) {
                            Microsoft.PowerShell.Utility\Write-Information "Searching for directories matching pattern"
                            $directories_found = [System.IO.Directory]::GetDirectories(
                                $searchDir, $searchPattern, $searchOption)
                            Microsoft.PowerShell.Utility\Write-Information "Found $(if($directories_found){$directories_found.Count}else{0}) matching directories"
                        }

                        # get files if not directories only
                        $files_found = @()
                        if (-not $directory) {
                            Microsoft.PowerShell.Utility\Write-Information "Searching for files matching pattern"
                            $files_found = [System.IO.Directory]::GetFiles(
                                $searchDir, $searchPattern, $searchOption)
                            $totalFilesChecked += $files_found.Count
                            Microsoft.PowerShell.Utility\Write-Information "Found $(if($files_found){$files_found.Count}else{0}) matching files"
                        }

                        # combine results
                        $all_items = $directories_found + $files_found
                        Microsoft.PowerShell.Utility\Write-Information "Total items found in this directory: $(if($all_items){$all_items.Count}else{0})"

                        foreach ($itemPath in $all_items) {
                            # create appropriate info object based on item type
                            $isDirectory = [System.IO.Directory]::Exists($itemPath)
                            $itemInfo = $isDirectory ?
                                (Microsoft.PowerShell.Utility\New-Object System.IO.DirectoryInfo($itemPath)) :
                                (Microsoft.PowerShell.Utility\New-Object System.IO.FileInfo($itemPath))
                            Microsoft.PowerShell.Utility\Write-Information "Processing $(if($isDirectory){'directory'}else{'file'}): $($itemInfo.FullName)"

                            # if we find directories, recurse if not disabled
                            if ($isDirectory -and (-not $noRecurse)) {
                                Microsoft.PowerShell.Utility\Write-Information "Will recurse into directory: $($itemInfo.FullName)"

                                # schedule directory scan for this additionally found directory
                                $null = $directories.Push(
                                    @{
                                        remainingPath = ($Last) ? "$nameToMatch" : "*"
                                        currentPath   = "$($itemInfo.FullName)\"
                                        currentDepth  = $folder.currentDepth + 1
                                    }
                                )

                                Microsoft.PowerShell.Utility\Write-Information (
                                    "Recursing after last matched directory in " +
                                    "$($directories.Peek().currentPath)")
                            }

                            # if item doesn't match name pattern, skip it
                            if (-not ($itemInfo.Name -like $nameToMatch)) {
                                Microsoft.PowerShell.Utility\Write-Information "Skipping item: '$($itemInfo.FullName)' - doesn't match name pattern: '$nameToMatch'"
                                continue
                            }

                            Microsoft.PowerShell.Utility\Write-Information "Item name '$($itemInfo.Name)' matches pattern '$nameToMatch'"

                            # check if item type matches what user wants
                            $typeOk = ($isDirectory -and ($directory -or $filesAndDirectories)) -or
                                      ((-not $directory) -and (-not $isDirectory))

                            if (-not $typeOk) {
                                Microsoft.PowerShell.Utility\Write-Information "Skipping item: item type doesn't match requested type"
                                continue
                            }

                            Microsoft.PowerShell.Utility\Write-Information "Item type matches filter criteria"

                            $hasStreamPattern = $null -ne $streamPatterns[$expandedSearchMask]

                            # if this is a file, check content pattern if specified
                            $contentMatch = $isDirectory -or ($hasStreamPattern) -or
                                [string]::IsNullOrWhiteSpace($pattern) -or
                                ($pattern -eq ".*")

                            if (-not $contentMatch) {

                                Microsoft.PowerShell.Utility\Write-Information "Checking file content against pattern: $pattern"
                                # Fix: Use the actual boolean result instead of checking if non-null
                                $contentMatch = Search-FileContent -FilePath ($itemInfo.FullName) -Pattern $pattern
                                Microsoft.PowerShell.Utility\Write-Information "Content match result: $contentMatch"
                            }

                            if ($contentMatch) {
                                $totalMatches++
                                Microsoft.PowerShell.Utility\Write-Information "Found matching item: $($itemInfo.FullName)"
                                Microsoft.PowerShell.Utility\Write-Verbose "Found match: $($itemInfo.FullName)"

                                # Determine if we should output the base file - simplified check
                                # Only check if the expanded path has a stream pattern

                                $shouldOutputFile = -not $hasStreamPattern

                                if ($shouldOutputFile) {

                                    # output FileInfo/DirectoryInfo objects if -PassThru is specified
                                    if ($passThru) {
                                        Microsoft.PowerShell.Utility\Write-Information "Returning object directly (PassThru mode)"
                                        Microsoft.PowerShell.Utility\Write-Output $itemInfo
                                    }
                                    else {
                                        # output relative path of the found item
                                        Microsoft.PowerShell.Utility\Write-Information "Resolving relative path with base: $relativeBasePath"
                                        $rp = Microsoft.PowerShell.Management\Resolve-Path -LiteralPath $itemInfo.FullName `
                                            -Relative -RelativeBasePath:$relativeBasePath

                                        Microsoft.PowerShell.Utility\Write-Information "Relative path: $rp"
                                        Microsoft.PowerShell.Utility\Write-Output $rp
                                    }
                                }
                                else {
                                    Microsoft.PowerShell.Utility\Write-Information "Skipping base file because a stream pattern was specified for this search mask"
                                }
                            }
                            else {
                                Microsoft.PowerShell.Utility\Write-Information "Item content doesn't match pattern, skipping"
                            }

                            # If IncludeAlternateFileStreams is specified and this is a file
                            if ((-not $isDirectory) -and $includeAds) {

                                Microsoft.PowerShell.Utility\Write-Information "Getting alternate data streams for file: $($itemInfo.FullName)"
                                try {
                                    # Get all streams for this file
                                    $streams = Microsoft.PowerShell.Management\Get-Item -LiteralPath $itemInfo.FullName -Stream * -ErrorAction SilentlyContinue |
                                    Microsoft.PowerShell.Core\Where-Object { ($_.Stream -ne ':$DATA') -or $hasStreamPattern }  # Skip the default stream

                                    Microsoft.PowerShell.Utility\Write-Information "Found $(if($streams){$streams.Count}else{0}) alternate data streams"

                                    # Check if we have specific stream patterns to match against
                                    $streamPatternsForFile = $streamPatterns."$expandedSearchMask"
                                    if ([string]::IsNullOrWhiteSpace($streamPatternsForFile)) {

                                        $streamPatternsForFile = "*"
                                    }

                                    foreach ($stream in $streams) {

                                        Microsoft.PowerShell.Utility\Write-Information "Processing stream: $($stream.Stream) of size: $($stream.Length)"

                                        # If we have specific stream patterns, check if this stream matches
                                        $streamNameMatch = $true

                                        if ($streamPatternsForFile) {
                                            $streamNameMatch = $stream.Stream -like $streamPatternsForFile
                                            Microsoft.PowerShell.Utility\Write-Information "Checking stream name '$($stream.Stream)' against pattern '$streamPatternsForFile': $streamNameMatch"
                                        }

                                        # Skip this stream if it doesn't match the stream pattern
                                        if (-not $streamNameMatch) {
                                            Microsoft.PowerShell.Utility\Write-Information "Stream name doesn't match pattern, skipping"
                                            continue
                                        }

                                        # Check if Pattern parameter is specified and not the default value
                                        $streamContentMatch = [string]::IsNullOrWhiteSpace($pattern) -or ($pattern -eq ".*")

                                        if (-not $streamContentMatch) {
                                            # Search for pattern in stream content
                                            Microsoft.PowerShell.Utility\Write-Information "Checking stream content against pattern: $pattern"
                                            # Fix: Use the actual boolean result instead of checking if non-null
                                            $streamContentMatch = Search-FileContent -FilePath $itemInfo.FullName -Pattern $pattern -StreamName $stream.Stream
                                            Microsoft.PowerShell.Utility\Write-Information "Stream content match result: $streamContentMatch"
                                        }

                                        # Only process streams that match the pattern (if specified)
                                        if ($streamContentMatch) {
                                            if ($passThru) {
                                                # Create a PSCustomObject clone of the FileInfo with stream info
                                                # This maintains compatibility with FileInfo while including stream information
                                                $properties = @{}

                                                # Copy all properties from the original FileInfo object
                                                foreach ($property in $itemInfo.PSObject.Properties) {
                                                    if ($property.Name -eq 'FullName') {
                                                        $properties['FullName'] = "$($itemInfo.FullName):$($stream.Stream)"
                                                    }
                                                    elseif ($property.Name -eq 'Name') {
                                                        $properties['Name'] = "$($itemInfo.Name):$($stream.Stream)"
                                                    }
                                                    else {
                                                        $properties[$property.Name] = $property.Value
                                                    }
                                                }

                                                # Add additional stream properties
                                                $properties['Stream'] = $stream.Stream
                                                $properties['StreamLength'] = $stream.Length

                                                # Create the custom object with the properties
                                                $streamObj = [PSCustomObject]$properties

                                                # Add a type name to help with type conversion
                                                $streamObj.PSObject.TypeNames.Insert(0, "System.IO.FileInfo.AlternateDataStream")
                                                $streamObj.PSObject.TypeNames.Insert(1, "System.IO.FileInfo")

                                                Microsoft.PowerShell.Utility\Write-Output $streamObj
                                            }
                                            else {
                                                # For path output format the path with stream
                                                $rp = Microsoft.PowerShell.Management\Resolve-Path -LiteralPath $itemInfo.FullName `
                                                    -Relative -RelativeBasePath:$relativeBasePath
                                                Microsoft.PowerShell.Utility\Write-Output "$rp`:$($stream.Stream)"
                                            }
                                        }
                                        else {
                                            Microsoft.PowerShell.Utility\Write-Information "Stream content doesn't match pattern, skipping"
                                        }
                                    }
                                }
                                catch {
                                    Microsoft.PowerShell.Utility\Write-Information "Error accessing alternate data streams: $($_.Exception.Message)"
                                }
                            }
                        }
                    }
                    catch {
                        # log any errors processing directories
                        Microsoft.PowerShell.Utility\Write-Information (
                            "Error processing directory: $searchDir - $($_.Exception.Message)")
                        Microsoft.PowerShell.Utility\Write-Verbose "Error accessing $searchDir - $($_.Exception.Message)"
                    }
                }

                Microsoft.PowerShell.Utility\Write-Information "Directory stack processing complete - processed $stackProcessCount items"
                Microsoft.PowerShell.Utility\Write-Verbose "Search complete: Examined $totalDirsProcessed directories and $totalFilesChecked files, found $totalMatches matches"
            }

            # process each search mask provided
            foreach ($currentSearchPhrase in $using:SearchMask) {

                Microsoft.PowerShell.Utility\Write-Information "Processing search pattern: $currentSearchPhrase"
                Microsoft.PowerShell.Utility\Write-Verbose "Processing search pattern: $currentSearchPhrase"

                $expandedSearchMask = GenXdev.FileSystem\Expand-Path $currentSearchPhrase

                # Check if this specific search mask should include alternate data streams
                # Simplified to only check the expanded search mask
                $hasStreamPattern = $null -ne $streamPatterns[$expandedSearchMask]
                $includeAds = $includeAlternateFileStreams -or $hasStreamPattern

                if ($includeAds) {
                    Microsoft.PowerShell.Utility\Write-Information "This search mask should include ADS: $currentSearchPhrase"
                }

                # if not a multi-drive search or currently processing root context
                if ($null -eq $PSItem) {

                    Microsoft.PowerShell.Utility\Write-Information "Searching in current context (not drive-specific)"
                    Search-DirectoryContent -SearchPhrase $currentSearchPhrase `
                                           -IncludeAds $includeAds `
                                           -HasStreamPattern $hasStreamPattern `
                                           -ExpandedSearchMask $expandedSearchMask `
                                           -StreamPatterns $streamPatterns `
                                           -PassThru $using:PassThru `
                                           -RelativeBasePath $using:RelativeBasePath `
                                           -Pattern $using:Pattern `
                                           -Directory $using:Directory `
                                           -FilesAndDirectories $using:FilesAndDirectories `
                                           -NoRecurse $using:NoRecurse
                }
                else {
                    $expandedSearchMask = GenXdev.FileSystem\Expand-Path $currentSearchPhrase `
                        -ForceDrive $PSItem.Name
                                            # force the search to start from the specific drive
                    Microsoft.PowerShell.Utility\Write-Information "Searching on drive $($PSItem.Name)"
                    Microsoft.PowerShell.Utility\Write-Verbose "Searching on drive $($PSItem.Name)"
                    Microsoft.PowerShell.Utility\Write-Information "Expanded path for drive $($PSItem.Name): $expandedSearchMask"

                    Search-DirectoryContent -SearchPhrase $expandedSearchMask `
                                           -IncludeAds $includeAds `
                                           -HasStreamPattern $hasStreamPattern `
                                           -ExpandedSearchMask $expandedSearchMask `
                                           -StreamPatterns $streamPatterns `
                                           -PassThru $using:PassThru `
                                           -RelativeBasePath $using:RelativeBasePath `
                                           -Pattern $using:Pattern `
                                           -Directory $using:Directory `
                                           -FilesAndDirectories $using:FilesAndDirectories `
                                           -NoRecurse $using:NoRecurse
                }
            }
        }

        Microsoft.PowerShell.Utility\Write-Information "PROCESS Find-Item: Search processing completed"
        Microsoft.PowerShell.Utility\Write-Verbose "Search completed"
    }

    end {
        Microsoft.PowerShell.Utility\Write-Information "END Find-Item: Function execution completed"
    }
}
################################################################################