I recently was involved at work with a project to create a support panel for our service desk. This panel needed to be able to perform certain tasks in our environment, and be able to work on powershell 3 - 5 with no guarantee that I would have access to 5 (aka no jea :( ). 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 (yes that old!) and was set to run as a different user. This worked fine and dandy in a one domain environment, but over time we have acquired multiple domains at work, and creating a gui form PER domain was not seen as something that would be sustainable with the new toolset. The new tool needed to allow our technicians 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 facilitate this I created a module which determined which packaged exes to run depending on the domain being targeted. This worked great and I thought I was home free. Then I started to try to pass data to these packaged exes and quickly found something that threw me for a loop.
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. (See here for details) This was a problem when I wanted to pass an AD object to the backend script to be processed or I wanted to pass a custom object to the executable and then have the object updated and returned to me when the executables was done. What made matters more complex, was that I had multiple executables running as different accounts across multiple domains (so much for being able to return data right back to the calling shell - but thats for another time).
So with the stage set, and if you are still following along here, I would like to present my solution to allow you to be able to pass objects to Sapien’s packaged powershell executables.
The overview for passing an object to a packaged executable is as follows.
Convert the object to clixml Convert the clixml object to a base64 string Pass the string to the packaged executable Once in the packaged executable, use the reverse functions to convert the string from base64 to clixml Convert the clixml object back to the original object Normally when converting an object to it’s clixml format you have to export the data to a file, this would create a lot of overhead and IO’s and would be unnecessary. Doing some Googling around I found a function which allows you to create a clixml representation of an object and send it to the pipeline. The code as posted needed a little configuration, but it was a great starting point. (Original function). Using this as the basis, I cobbled together a few functions to accommodate this functionality and as of this week this will be running in a production environment.
These functions, when used together, allows for the passing of objects (including entire AD objects with all properties) to a packaged executable. So the overview and theory show how this work - how does this work in practice? First off you will want to get the code from the following location: PassObjectsToSapienExe
Included in the ps1 file are four functions - two will be called directly (ConvertTo-Base64String, ConvertFrom-Base64ToObject) with the other two acting as supporting functions (and broken out this way so these functions can be used in other scripts if need be)
To illustrate how this script works, I created a simple test object:
I then convert this object to a base 64 string using the function ConvertTo-Base64String.
Below is the resulting base64 string of the function ConvertTo-Base64String. This shows that the data passed to the packaged executable is not an object but instead just a very long string. Since this is now a string, it can be passed to the packaged executable without issue.
I then created a packaged powershell script in Powershell studio as below - I excluded the code pasted at Github to make it shorter.
Once this script is packaged I then passed the string to the executable. The resulting output is below:
To prove that the data being worked on in the executable is truly an object, I modified return line in the script to read : return $data.first
The resulting output is below.
The output returned above (return $data) returns an array of strings - this is probably a feature of Sapien as well. In order to get around this, the same procedure used to pass an object to the packaged executable can be used to pass an object back to the calling shell.
So 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 you wish to use this, just drop the four support functions in your packaged exe as well as your script calling the packaged exe and you can pass data back and forth as you will.
I will put a disclaimer - since this is really early - I have not included any testing (pester) and have not included full documentation for the functions. These will be added over time - but I felt it was more important to get this out there than to wait until documentation was fully finished.