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.