Skip to content

Instantly share code, notes, and snippets.

@EnviableOne
Forked from indented-automation/Find-String.ps1
Created February 26, 2018 13:34
Show Gist options
  • Save EnviableOne/23a8f4d00704a42c4f00dde0ce1ff6c5 to your computer and use it in GitHub Desktop.
Save EnviableOne/23a8f4d00704a42c4f00dde0ce1ff6c5 to your computer and use it in GitHub Desktop.
Binary searcher
function Find-String {
<#
.SYNOPSIS
Find a matching string from an alphabetically sorted file.
.DESCRIPTION
Find-String is a specialised binary (half interval) searcher designed to find matches in sorted ASCII encoded text files.
.NOTES
Change log:
11/08/2014 - Chris Dent - First release.
#>
[CmdletBinding()]
[OutputType([String])]
param (
# The string to find. The string is treated as a regular expression and must match the beginning of the line.
[Parameter(Mandatory = $true)]
[String]$String,
# The name of the file to search.
[Parameter(Mandatory = $true)]
[ValidateScript( { Test-Path $_ } )]
[String]$FileName
)
$FileName = $pscmdlet.GetUnresolvedProviderPathFromPSPath($FileName)
$FileStream = New-Object IO.FileStream($FileName, [IO.FileMode]::Open)
$BinaryReader = New-Object IO.BinaryReader($FileStream)
$Length = $BinaryReader.BaseStream.Length
$Position = $Length / 2
[Int64]$HalfInterval = $Length / 2
$Position = $Length - $HalfInterval
while ($Position -gt 1 -and $Position -lt $Length -and $Position -ne $LastPosition) {
$LastPosition = $Position
$HalfInterval = $HalfInterval / 2
$BinaryReader.BaseStream.Seek($Position, [IO.SeekOrigin]::Begin) | Out-Null
# Track back to the start of the line
while ($true) {
$Character = $BinaryReader.ReadByte()
if ($BinaryReader.BaseStream.Position -eq 1) {
$BinaryReader.BaseStream.Seek(-1, [IO.SeekOrigin]::Current) | Out-Null
break
} elseif ($Character -eq [Byte][Char]"`n") {
break
} else {
$BinaryReader.BaseStream.Seek(-2, [IO.SeekOrigin]::Current) | Out-Null
}
}
# Read the line
$Characters = @()
if ($BinaryReader.BaseStream.Position -lt $BinaryReader.BaseStream.Length) {
do {
$Characters += [Char][Int]$BinaryReader.ReadByte()
} until ($Characters[-1] -eq [Char]"`n" -or $BinaryReader.BaseStream.Position -eq $BinaryReader.BaseStream.Length)
$Line = (New-Object String (,[Char[]]$Characters)).Trim()
} else {
# End of file
$FileStream.Close()
return $null
}
if ($Line -match "^$String") {
# Close the file stream and return the match immediately
$FileStream.Close()
return $Line
} elseif ($Line -lt $String) {
$Position = $Position + $HalfInterval
} elseif ($Line -gt $String) {
$Position = $Position - $HalfInterval
}
}
# Close the file stream if no matches are found.
$FileStream.Close()
}
@EnviableOne
Copy link
Author

Used in passwordTest Script for searching textbased list of hashes

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment