How to run C# code with different type definitions

Hey all

I’ve been playing around in this space and have been trying to find a way of getting Add-Type to load an existing type but with a changed definition without opening a new process. The fruit of my labours if PSCSharpInvoker.

I created this code as after after reading online, the general consensus I found people ended up at was it isn’t possible unless you create a new process. This wasn’t really what I was looking for the following reasons;

  • Start-Job is quite slow, it takes around 3 seconds to run a simple script and return the output compared to .3 seconds for Add-Type to add and run
  • Starting a new process is faster than Start-Job but it’s harder to marshal your variables between a current session and the spawned process

So digging a little deeper I came across the idea of creating our own AppDomain and loading, running our C# code in that domain. The beautify of this process is that the C# code is loaded entirely in the new AppDomain and doesn’t pollute the main PowerShell domain meaning we can run a bit of C# code that changes without creating unique class names.

As an example, I have created a custom C# method that outputs an argument to the console

$code = @' using System; public class PSCSharpInvoker { public static void Run(string arg) { string res = String.Format("Running in the domain '{0}' with arg '{1}'", System.AppDomain.CurrentDomain.FriendlyName, arg); Console.WriteLine(res); } } '@ Invoke-CSharpMethod -Code $code -Class PSCSharpInvoker -Method Run -Arguments "my argument" 

I’ve decided I no longer want to write to the console but rather return the value back to me. Normally I would have to kill the current process and start a new one, but with Invoke-CSharpMethod that is no longer the case;

$code = @' using System; public class PSCSharpInvoker { public static string Run(string arg) { string res = String.Format("Running in the domain '{0}' with arg '{1}'", System.AppDomain.CurrentDomain.FriendlyName, arg); return res; } } '@ Invoke-CSharpMethod -Code $code -Class PSCSharpInvoker -Method Run -Arguments "my argument" 

There are some limitations with this approach with the major one being that you can only marshal variables between the AppDomains if they have the SerializableAttribute but that covers all the base types and collection types which is good enough for me.

This was really a proof of concept but it worked well enough that I thought it best to put in a module and share it for others who are interested. Feel free to ask any specific questions or try it out if you want to learn more.

submitted by /u/jborean93
[link] [comments]

Leave a Reply