Challenge

Solving the Dark Faction’s PowerShell Transport Challenge

Before the most recent PowerShell + DevOps Global Summit, the Dark Faction issued a second challenge. Certainly, working code that produces the desired results is important. But equally important is how you might approach this problem. What tools or techniques might you consider? How you work is as important to the Dark Faction as your final code. The Chairman has had his own Iron Scripters working on the challenge and this is one way the problem might be attacked.

Define the Command and Parameters

The first step is to define the code that should be security transported and executed on a different computer. For the sake of this article, we will use this scriptblock.

Nothing too exciting. The challenge is to securely transport this over open networks. To simplify the process, we can convert the scriptblock, which is really just a special type of string into a base64 encoded string.

The scriptblock now looks like this.

A PowerShell scriptblock encoded as base64

The challenge was to also include a set of parameter values.

You can even test the scriptblock and params by splatting the latter.

Splatting parameters to the PowerShell scriptblock

OK so far?

Create an Object to Encode

While not a requirement, it was suggested in the challenge to include some metadata such as the original author and location.

This code is using the .NET Framework directly with an eye towards cross-platform compatibility. Normally referencing items from the ENV: PSDrive should suffice but with the current version of PowerShell Core this isn’t always an option. Evertything created thus far can be turned into an object.

The object to transport

This is the object that needs to be securely transported. Let’s serialize this object to a JSON file.

Now for the fun part. This content can be protected as a CMS message using a document encryption certificate installed locally.

This is the file that can be transported.

Unwrapping the File

At the other end, the process needs to be undone to unwrap and decode the contents into the original PowerShell command and parameters. Assuming the other party has a copy of the document encryption certificate installed, they can unprotect the document, convert the base64 string back into scriptblock and extract the parameters.

They can look at the code in $cmd or run with the parameters.

Shipping the Certificate

However, what if the document encryption certificate was not installed on the other end? Here’s one way that might be handled. First, the certificate is exported to a pfx file and password protected.

The password will eventually need to be securely communicated between parties. We’ll assume the Dark Faction has existing mechanisms.

Because the Dark Faction is a bit paranoid, we can encode the certificate file further using the certutil.exe command line utility.

This file, because it is all text, is easier to transport along with the PowerShell command.

Decoding and Executing

At the other end, the transport.json file can be brought back into PowerShell.

The encoded certificate is in $t.cert.value and the code is in $t.cmd.value. Using certutil.exe again, the certificate can be recreated and imported.

With the certificate in place, decoding and executing the rest is as we did above.

Conclusion

Naturally, to make this a seamless process you want to create a set of reusable commands, most likely packaged as a module. You might have commands to easily encode any PowerShell command expression and parameters, with an option to include the document encryption certificate. And of course, you would want an easy set of commands to consume the encoded file. The Chairman will leave these exercises to you.