aboutsummaryrefslogtreecommitdiff
path: root/Invoke-FileSearch.ps1
blob: 4124548b61b8f54d0cb7b6912b973fdf15eae06b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
<#
.SYNOPSIS
    Searches for files with specified extensions in a directory and optionally searches file contents for a regex pattern.

.DESCRIPTION
    The Invoke-FileSearch function searches for files in a specified directory, either recursively or non-recursively, 
    matching either a predefined set of extensions (e.g., .ps1, .bat) or user-specified extensions. It can also search 
    file contents for a provided regex pattern, streaming results to stdout as they are found. The function supports 
    local and network paths and handles errors gracefully.

.PARAMETER Path
    The root directory path to start the search. Supports local paths and UNC paths (e.g., \\server\share).
    This parameter is mandatory.

.PARAMETER Extensions
    An array of file extensions to search for (e.g., 'ps1', 'bat'). Extensions can be specified with or without 
    the leading '*.'. Used with the 'Specific' parameter set. If not provided, the function defaults to the 'All' 
    parameter set.

.PARAMETER All
    Specifies to search for a predefined set of file extensions (.ps1, .cmd, .vbs, .vba, .conf, .jobx, .bat, .ini, .bak).
    Used with the 'All' parameter set, which is the default.

.PARAMETER RegexPattern
    A regular expression pattern to search for within file contents. Requires the -IncludeContent switch.

.PARAMETER Recurse
    If specified, searches subdirectories recursively. Defaults to $true.

.PARAMETER IncludeContent
    If specified, enables searching file contents for the provided -RegexPattern. Without this switch, only file paths are returned.

.EXAMPLE
    Invoke-FileSearch -Path "C:\Scripts" -Recurse
    Searches recursively for files with default extensions (.ps1, .cmd, etc.) in C:\Scripts and outputs their full paths to stdout.

.EXAMPLE
    Invoke-FileSearch -Path "\\server\share\Scripts" -Extensions "ps1", "bat" -Recurse
    Searches recursively for .ps1 and .bat files in the specified network share and outputs their full paths to stdout.

.EXAMPLE
    Invoke-FileSearch -Path "C:\Scripts" -All -RegexPattern "function\s+\w+" -IncludeContent
    Searches recursively for files with default extensions, checks their contents for PowerShell function declarations,
    and outputs custom objects with file paths and matches to stdout.

.EXAMPLE
    Invoke-FileSearch -Path "C:\Scripts" -Extensions "ini" -Recurse:$false
    Searches non-recursively for .ini files in C:\Scripts and outputs their full paths to stdout.

.INPUTS
    System.String
        Accepts a string input for the -Path parameter via pipeline.

.OUTPUTS
    System.String
        Outputs full file paths as strings when -RegexPattern and -IncludeContent are not used.
    PSCustomObject
        Outputs custom objects with FilePath (string) and Matches (MatchInfo) properties when -RegexPattern and -IncludeContent are used.

.NOTES
    - The function streams output to stdout, making it memory-efficient for large directories.
    - Errors accessing directories or reading files are handled gracefully, with warnings for file-specific issues.
    - Network shares are supported, but authentication may require additional configuration (e.g., credentials via PSDrive).
    - Performance may be slower when using -IncludeContent due to file content reading, especially on network shares.

.LINK
    Get-ChildItem
    Select-String
#>
function Invoke-FileSearch {
    [CmdletBinding(DefaultParameterSetName = 'All')]
    param (
        [Parameter(Mandatory = $true, Position = 0, ValueFromPipeline = $true)]
        [string]$Path,

        [Parameter(ParameterSetName = 'Specific')]
        [string[]]$Extensions,

        [Parameter(ParameterSetName = 'All')]
        [switch]$All,

        [Parameter()]
        [string]$RegexPattern,

        [Parameter()]
        [switch]$Recurse = $true,

        [Parameter()]
        [switch]$IncludeContent
    )

    begin {
        $defaultExtensions = @('*.ps1', '*.cmd', '*.vbs', '*.vba', '*.conf', '*.jobx', '*.bat', '*.ini', '*.bak')
        
        $searchExtensions = if ($PSCmdlet.ParameterSetName -eq 'All') {
            $defaultExtensions
        } else {
            $Extensions | ForEach-Object { if ($_ -notmatch '^\*\.') { "*.$_" } else { $_ } }
        }
    }

    process {
        try {
            Get-ChildItem -Path $Path -Recurse:$Recurse -Include $searchExtensions -File -ErrorAction SilentlyContinue | 
                ForEach-Object {
                    $filePath = $_.FullName
                    
                    if ($RegexPattern -and $IncludeContent) {
                        try {
                            $content = Get-Content -Path $filePath -Raw -ErrorAction SilentlyContinue
                            if ($content -match $RegexPattern) {
                                $result = [PSCustomObject]@{
                                    FilePath = $filePath
                                    Matches  = ($content | Select-String -Pattern $RegexPattern).Matches
                                }
                                Write-Output $result
                            }
                        }
                        catch {
                            Write-Warning "Error reading file: $filePath - $_"
                        }
                    }
                    else {
                        Write-Output $filePath
                    }
                }
        }
        catch {
            Write-Error "Error searching files: $_"
        }
    }
}