Solving the Dark Faction’s PowerShell Challenge

Not too long ago the Dark Faction posted a challenge for those of you who felt worthy to call yourself an Iron Scripter.? Now that this year’s Iron Scripter battle is complete, the Chairman has arranged for a solution to the Dark Faction’s challenge. You could have written a single script or broken the task down into steps. Naturally, as with most things PowerShell, there are plenty of variations.

Retrieve the Content

The first step is to retrieve the encoded text from the Internet. Sure, you could manually save the file but where’s the fun in that!

$link = "http://bit.ly/DarkFactionMessage"
$cypherFile = "d:\temp\dark.txt"
Invoke-WebRequest -uri $link -OutFile $cypherFile -DisableKeepAlive
$c = get-content $cypherfile

The encoded contents are now stored in a variable, $c.

A PowerShell Encoded Message

Testing for Solutions

The contents of $c are small enough that you could try decoding the entire text. However, it might be faster to test different approaches on a subset. The variable $c is an array of 13 lines, which you can see by $c.count. You might consider testing a subset of data.

$sample = $c[0][0..20]

$Sample is now an array of characters. The Caesar cipher is substituting one alphanumeric character for another. In PowerShell, each [char] object can be interpreted as an [int] and the [int] can be transformed into a [char].

Converting between [char] and [int]

It makes sense then to test a range of numbers going backward and forwards. You are helped a bit by the fact that you can’t move too far in either direction as you can end up with unprintable characters. With that in mind, you can probably safely test values going backward and forward 20 characters.

$out = for ($i = -20; $i -le 20; $i++) {
    [pscustomobject]@{
        Offset = $i
        Text   = (($sample).foreach({[char](([char]$_ -as [int]) + ($i)) })) -join ""
    }
}

Using the For loop, each character in the sample is treated as an [int], increased by the testing value and then turned back into a [char]. This entire array is then joined back into a string. The testing code is creating a custom object to make it easier to view the results.

Reviewing sample results

Reviewing the output it is clear that the offset of -5 produces English output.

Decoding the Rest

Excellent. Each original character was rolled back 5 places which mean to decode each character needs to roll forward 5. The code you used in the testing snippet can serve as the basis for decoding the text. One thing to keep in mind is that encoded message appears to have blank lines, so you only want to decode lines that contain characters. You can use a simple regular expression pattern for that.

$off = 5
foreach ($line in $c) {
    if ($line -match "\w+") {
        #need to undo the offset is the line has characters
        (($line.ToCharArray()).foreach( {[char](([char]$_ -as [int]) - ($off))})) -join ""
    }
    else {
        #blank line
        $line
    }
}

If all goes well you should get a result like this:

The decoded text

Yes, this is the opening to the Monad Manifesto by Jeffrey Snover which lays the foundation for PowerShell.

Do More, Learn More

The Chairman is a firm believer in learning by doing. To that end, you are encouraged to create a set of functions that will encode and decode text using this PowerShell version of a Caesar Cipher. Sure, there may not be a practical use, but the scripting constructs and techniques are things you will use repeatedly.

The Dark Faction issued a follow-up challenge and the Chairman will be back later with some guidance on how you might solve it.


One Reply to “Solving the Dark Faction’s PowerShell Challenge”

Comments are closed.