RandomizedHarmony

View Original

Pass Objects To EXEs created with Sapien PowerShell Studio

A few years ago I was involved in a project my job at that time to create a support panel for the service desk. This panel needed to be able to perform certain tasks in the environment, and be able to work on PowerShell versions 3 through 5. The users who would be running these utilities also did not have administrative permissions on the systems which these tools needed to manipulate. The old toolset was created in Primal Forms 2009 by a former coworker and was set to run as a specific user account. This worked fine in a one domain environment, but over time the company had acquired multiple domains, and creating an executable for each domain was not something that would be sustainable. The new tool needed to allow the users to perform the work they needed regardless of what domain they were working in - even if it was a brand new one as of that day.

To meet the goals of this project, I created the new forms and targeted them to connect to the resource domains in the environment. These domains allowed for the management of the other domains without having to have a new executable for each domain. To simplify this even more, the users saw the same gui no matter which domain was being worked on. A function determined which of the two executables to use when a command was run depending on the various parameters being selected. I thought I was in the clear until I started to try to pass objects between the multiple executables that I learned a very important lesson.

When a script is built in Sapien's PowerShell Studio (which by the way is a FANTASTIC tool - well worth the money!) it is able to accept parameters being passed to the executable, but these parameters can only be strings. This was a problem. I wanted to pass an AD object to the backend script without having to pass each property of the ad object as a separate property. I also wanted to pass custom objects to the executable and then have the object updated and returned to the calling executable. With only the ability to pass strings back and forth, I was banging my head for a bit trying to figure out how to make objects work in a string environment.

Then I remembered you can serialize and deserialize data in PowerShell easily. Combine this with converting the serialized data to base64 strings, and all of a sudden the object no longer presents an issue being transmitted to the created EXE files. There is one limitation with this however, and that is that when passing strings there is a max limit to the length of a string. Small and simple objects will not hit up against this upper limit, but if you start processing extremely large objects this limit may be hit. To help with this, gzip stream compression can be used to reduce the size of the string up to 50%.

All of these elements combined allows for an easy method to pass data between executables without using named pipes (that is another post). The code is available on my github page along with a few examples of how this works below.

#converting an object to a compressed base64 string and pass this data to an external exe
$obj = New-Object -TypeName System.Management.Automation.PSObject -ArgumentList @{
            Name = "Bob";
            Job = "Burger Flipper"
        }
        $data = ConvertTo-CompressedString -object $obj
        & sample.exe $data

#converting a compressed string back to an object
$obj = ConvertFrom-CompressedString -inputString $inputstring

While this seems extremely simple, this took me a bit of research to figure out how to pass an object to Sapien's packaged EXE. If this is something helpful to you, just drop the four support functions in your packaged exe as well as your script calling the packaged exe and you can pass objects as strings as you will.

Get the code