This is my feeble attempt at blogging again. Now that blogging is out of fashion and we trust AI to tell us what to think, drink and eat, it’s probably as good a time to do it as ever. So, this was prompted (pardon the pun) by a need to find any and all references in my sprawling warehouse of festering code (GitHub) that mention “Invoke-WebRequest” which might be used on a Windows machine. The goal being to make sure to include -UseBasicParsing for safety reasons.

As Matthew Dowst explains in his recent YouTube video, this is related to CVE-2025-54100 and only affects Windows PowerShell 5.1. It does not apply to PowerShell 7, and therefore doesn’t apply to PowerShell running on MacOS or Linux.
Assumptions
- You are familiar with GitHub and have a GitHub account
- You are familiar with PowerShell (on Windows, Mac or Linux)
- You need to search through a bunch of old code, like me.
- You have GitHub CLI installed and operational
- You have no life and are too broke to do something more fun
- Your kids are grown and moved out, so you have nothing else going on
- You haven’t won the lottery or inherited a fortune from a dead relative
- You are addicted to some sort of caffeinated liquid substances like me
If you meet these conditions, you’re good to go.
Why?
Aside from having no life and being addicted to coffee, sometimes you might need to quickly search through a lot of source code, which may or may not be cloned to a local place (hard drive). Matt covers this scenario in the video linked above. All my code is hiding in old GitHub repositories and gists. Oh, and I don’t have a life.
Caveates, Disclaimers, etc.
This code was tested with Windows PowerShell 5.1 and PowerShell 7.5.4 on Linux. Why both? Because it was either that or crawl in the attic to get Christmas stuff down, and it’s cold up there today. I also don’t have a life.
Your results may vary. Test thoroughly in non-production environments on non-production code for non-production use. Or test it on mission critical life-supporting systems in production, because you ignore warnings like this anyway. Don’t blame me if it crashes anything important.
Searching through Code
There’s quite a few options for searching content within GitHub Repositories and Gists, from the obvious web portal search tools, to various PowerShell scripts and modules (sort of), REST API, and my recent favorite: GitHub CLI.
After sampling a dozen or so scripts, which were close, but not quite what I was looking for, I searched PowerShell Gallery (using AI assistance) but using Find-PsResource -Tag 'github' didn’t find more than a handful, but still not what I was looking for. That’s not to say there aren’t any, but
in a time crunch, I wasn’t able to locate something close enough. So I started playing with GitHub CLI.
PowerShell: Searching Repos
The source code: Get it here instead of copying from this blog.
function Search-GitHubRepository {
[CmdletBinding()]
param (
[parameter(Mandatory = $true)][string]$SearchValue,
[parameter(Mandatory = $false)][string]$Owner,
[parameter(Mandatory = $false)][switch]$Summary
)
try {
if ([string]::IsNullOrEmpty($SearchValue)) {
throw "No SearchValue was provided"
}
if (-not (Get-Command "gh")) {
throw "Install GitHub CLI first."
}
if ($IsLinux) {
$cmd = "gh"
} else {
$cmd = "gh.exe"
}
$ghArgs = @('search', 'code', $SearchValue)
if (![string]::IsNullOrEmpty($Owner)) {
$ghArgs += "--owner=$Owner"
}
$ghArgs += @('--json', 'repository,path,url,textMatches')
Write-Verbose "Command: $cmd $($arglist -join ' ')"
$textmatches = & $cmd $ghArgs | ConvertFrom-Json
Write-Verbose "$($textmatches.count) matches found" -ForegroundColor Cyan
if ($Summary.IsPresent) {
$textmatches | Select-Object -Property @{l = 'Repository'; e = { $_.repository.nameWithOwner } } |
Select-Object -Property Repository | Sort-Object -Unique -Property Repository
} else {
$textmatches |
Select-Object -Property path,url,@{l = 'Repository'; e = { $_.repository.nameWithOwner } },
@{l = 'Text'; e = { $_.textMatches.fragment } } |
Sort-Object -Property Repository
}
} catch {
[pscustomobject]@{
Status = "Error"
Message = $_.Exception.Message
Trace = $_.Exception.ScriptStackTrace
Category = $_.Exception.CategoryInfo.Activity
}
}
}
Example:
Search-GitHubRepository -SearchValue "Invoke-WebRequest" -Owner "username" -Summary
This returns names of Repositories and matching items to provide a summary of matches.
Search-GitHubRepository -SearchValue "Invoke-WebRequest" -Owner "username"
This returns repository and file names and matching content as well.
PowerShell: Search Gists
The source: Get it here
function Search-GitHubGist {
[CmdletBinding()]
param (
[parameter(Mandatory=$true)][string]$SearchValue,
[parameter(Mandatory=$false)][switch]$IncludeContent,
[parameter(Mandatory=$false)][int]$Limit = 100
)
try {
if ([string]::IsNullOrEmpty($SearchValue)) {
throw "No SearchValue was provided"
}
if (-not (Get-Command "gh")) {
throw "Install GitHub CLI first."
}
if ($IsLinux) {
$cmd = "gh"
} else {
$cmd = "gh.exe"
}
$ghArgs = @('gist', 'list', '--filter', $SearchValue, '--include-content', '--limit', $Limit)
$gists = & $cmd @ghArgs
<#
Filter results to map lines to properties as follows:
b5db0c256f73f300eaea8c50d7973f9d boxstarter_sample2.txt
BoxStarter Examples
Invoke-WebRequest https://chocolatey.org/install.ps1 -UseBasicParsing | iex
No spaces at the beginning of the line = id and filename
4 spaces at the beginning of the line = description
8 spaces at the beginning of the line = matching content
#>
$results = @()
for ($i = 0; $i -lt $gists.Count; $i++) {
$line = $gists[$i]
if (![string]::IsNullOrEmpty($line)) {
if (-not $line.StartsWith(" ")) {
# Line with no leading spaces = id and filename
$gistId = $line.Substring(0, 32)
$filename = $line.Substring(33)
$description = ""
$content = ""
# Check next lines for description (4 spaces) and content (8 spaces)
if ($i + 1 -lt $gists.Count -and $gists[$i + 1].StartsWith(" ") -and -not $gists[$i + 1].StartsWith(" ")) {
$description = $gists[$i + 1].Trim()
if ($i + 2 -lt $gists.Count -and $gists[$i + 2].StartsWith(" ")) {
$content = $gists[$i + 2].Trim()
}
}
$results += [pscustomobject]@{
id = $gistId
filename = $filename
gistname = $description
content = $content
}
}
}
}
$results | foreach-object {
$gistId = $_.id
$filename = $_.filename
Write-Verbose "gist id: $gistId - filename: $filename"
$gistContent = gh gist view $gistId --raw
if ($IncludeContent.IsPresent) {
Write-Verbose "Including content in results"
$gistContent | select-string -Pattern $SearchValue -List |
select-object -Property @{l='gistId';e={$gistId}}, @{l='filename';e={$filename}}, @{l='line';e={$_.LineNumber}}, @{l='match';e={$_.Line}}
} else {
$gistContent | select-string -Pattern $SearchValue -List |
select-object -Property @{l='gistId';e={$gistId}}, @{l='filename';e={$filename}}, @{l='line';e={$_.LineNumber}}
}
}
} catch {
[pscustomobject]@{
Status = "Error"
Message = $_.Exception.Message
Trace = $_.Exception.StackTrace
Category = $_.Exception.CategoryInfo.Activity
}
}
}
Example:
Search-GitHubGist -SearchValue "Invoke-WebRequest"
This returns a summary of Gists and filenames with matching content, but not the actual matching content in the output.
Search-GitHubGist -SearchValue "Invoke-WebRequest" -IncludeContent
This returns all matching Gists and filenames as well as matching line numbers and content portions for each.
Conclusion
You might find some mistakes, or notice that I conveniently forgot to include support for filtering Gists by Public or Secret (GitHub CLI supports that, by the way). If you think this blows chunks, please be kind, but any feedback is welcome, especially if it includes winning lottery numbers.
You can get a lot done when you don’t have enough money to do something else. Coffee helps too.
Go to the following link for more information on the GitHub CLI Comment Reference
