Regular Expressions, Search-and-Replace Interpolation and Delegates
This (and the previous post) stem from me stumbling onto this page:
https://stackoverflow.com/questions/17229866/powershell-hex-to-string-conversion/19151495
Last time, we looked at hex-decoding a string. In the above, the original poster had file of space-delimited lines, each with three fields: the username, the user’s domain, and the hex-encoded password. The requested solution was to only hex-decode only the third field.
Using regular expressions, targeting the last field is easy:
$line –match “\S+$”
Then, we beat on $Matches
. Now, the problem requests that the last field be replaced with the hex-decoded string, so we can do something like this:
$hex = $line –replace “.*\s”
$userData = $line –replace '”\S+$”
We can then hex-decode $hex
with the magic from yesterday and concatenate with $userData
. But wait – we can interpolate the matched string into the replacement pattern:
$line –replace “(\S+)$”, ‘*$1*’
This highlights the last field by bracketing it with asterisks. Can we toss it through our function?
$line –replace “(\S+)$”, Convert-HexToString(‘$1’)
$line –replace “(\S+)$”, “$(Convert-HexToString(`$1))”
Neither work. In fact, I can’t find a way to get it to work with the plain -replace operator
. Now, -replace
is just a PSH language element to expose the [RegEx]
class. We can do this with the class, but it’s ugly. First, we define the regular expression:
[RegEx]$regEx = ‘(\S+)$’;
Next, we need to define what we want to do with the matched string. In this case, we re-implement the Convert-HexToString function.
$delegateScriptBlock = {
param ($match);
-join ( $match.Groups[1].Value -split '(..)' | ? { $_; } | % { [Char]( [Convert]::ToInt16($_, 16) ); } );
};
Finally, we do the actual heavy lifting:
Get-Content file.txt | % { $regEx.Replace($_, $delegateScriptBlock); }
Now, in the $delegateScriptBlock, we see this snippet:
$match.Groups[1].Value
What’s happening is the RegEx is populating a variable that is similar to $Matches
, then passing it into the scriptblock as a parameter. Now, debugging a scriptblock is as fun as it usually is. We can’t save it to a $global:scope variable, nor can we Export-Clixml –path someFile. In this case:
$debugScriptBlock = { param ($parameter); $parameter; }
$myMatches = $regEx.Match($line, $debugScriptBlock);;
By running this at the prompt, having debugScriptBlock
simply return the parameter, and saving that variable, we can look at what it provides the scriptblock. Here, we can examine the $match
we’re accepting as the parameter.
Finally, why do this instead using $userData
and $hex
? For me, there’s a certain appeal in implementing Perl’s search-and-evaluate capability, even if it’s pretty involved.