0

I can execute a PowerShell script from C# with arguments and receive a return value. However, I'm now looking to use PowerShell more like a scripting language (similar to LUA) in my C# application. Specifically, I want to be able to call in PowerShell methods of my running C# application and return a value.

Some sample code:

The C# application calculates in certain time intervals some data and stores it in Manager.CalculatedData.

public int GetSomeData() => Manager.CalculatedData;

And the PowerShell script should be able to call this method and receive the actual data.

$foo = ? # call to the method of the running C# application
# do something with 'foo'

However, it is important to me that the PowerShell code remains simple so that the user can call the method very easily.

My question is: How can I use C# and PowerShell to achieve this bidirectional interaction?

2
  • you can't just call some arbitrary code of any arbitrary process. You can only execute processes. You could make your program a (web-)service, so you can perform some action upon a request. Alternativly use some messanging-BUS, e.g. SignalR or similar. Commented Oct 18, 2023 at 14:05
  • 1
    I'm pretty sure you can inject custom variables into a powershell session to provide a sort of context object that can be called from the scripts - Octopus Deploy does this with project variables, and the Ansible powershell plugin also exposes runtime variables to script tasks this way. I've not seen an explicit C# code example though, but I'm working on one :-)... Commented Oct 18, 2023 at 14:37

1 Answer 1

3

Based on Set via C# Powershell Variable:

  • Create a new C# WinForms project to host the example

  • Add a reference to the Microsoft.PowerShell.SDK nuget package

  • On the default form add a textbox and button that look like this:

![enter image description here

  • In the code-behind for the button add this:
private void button1_Click(object sender, EventArgs e)
{

    var appContext = new AppContext();

    var runspace = RunspaceFactory.CreateRunspace();
    runspace.Open();
    runspace.SessionStateProxy.SetVariable("MyAppContext", appContext);

    var powershell = PowerShell.Create();
    powershell.Runspace = runspace;

    powershell.AddScript(this.textBox1.Text);
    var result = powershell.Invoke();

}
  • Finally, add a new class that will contain the functionlity you want to expose to the PowerShell script:
namespace WinFormsApp1
{
    internal class AppContext
    {
        public int Add(int left, int right)
        {
            return left + right;
        }
        public void Alert(string msg)
        {
            MessageBox.Show(msg);
        }
    }
}
  • Now run the project. You can enter some PowerShell script into the textbox and hit the button to execute it. There'll be a default variable called $MyAppContext that is hooked up to the value you passed into the session using SetVariable in the C# code, so for example the following script:
$x = $MyAppContext.Add(100, 200);

$MyAppContext.Alert($x);

Will do this when you execute it:

enter image description here

  • Now all you need to do is make sure the functionality you expose to scripts can't be abused to get extra privileges on the system, and sanitise the script to ensure the user can't perform actions you didn't intend to be available :-).
Sign up to request clarification or add additional context in comments.

1 Comment

And that's why I love C# and PowerShell ... Thank you very much! This is exactly what I was looking for.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.