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: $_"
}
}
}
|