Hosting PowerShell: PowerShell vs. Runspace vs. RunspacePool vs. Pipeline
Asked Answered
H

2

19

I attempting to add some fairly limited PowerShell support in my application: I want the ability to periodically run a user-defined PowerShell script and show any output and (eventually) be able to handle progress notification and user-prompt requests. I don't need command-line-style interactive support, or (I think) remote access or the ability to run multiple simultaneous scripts, unless the user script does that itself from within the shell I host. I'll eventually want to run the script asynchronously or on a background thread, and probably seed the shell with some initial variables and maybe a cmdlet but that's as "fancy" as this feature is likely to get.

I've been reading the MSDN documentation about writing host application code, but while it happily explains how to create a PowerShell object, or Runspace, or RunspacePool, or Pipeline, there's no indication about why one would choose any of these approaches over another.

I think I'm down to one of these two, but I've like some feedback about which approach is a better one to take:

PowerShell shell = PowerShell.Create();
shell.AddCommand(/* set initial state here? */);
shell.AddStatement();
shell.AddScript(myScript);
shell.Invoke(/* can set host! */);

or:

Runspace runspace = RunspaceFactory.CreateRunspace(/* can set host and initial state! */);
PowerShell shell = PowerShell.Create();
shell.Runspace = runspace;
shell.AddScript(myScript);
shell.Invoke(/* can set host here, too! */);

(One of the required PSHost-derived class methods is EnterNestedPrompt(), and I don't know whether the user-defined script I run could cause that to get called or not. If it can, then I'll be responsible for "starting a new nested input loop" (as per here)... if that impacts which path to take above, that would also be good to know.)

Thanks!

Hassett answered 2/5, 2013 at 2:33 Comment(2)
You don't actually need a host. Just make sure to avoid calls to Write-Host, Read-Host, etc. There is a way to check if PS has a host attached, but I don't recall it at the moment.Chappelka
I may not need a PSHost, but I want one in my case... I'm expecting the user-defined script to have the occasional diagnostic message which I want to be able to show. (I'll edit the original post to make that more clear.)Hassett
R
6

What are they?

  • Pipeline

A Pipeline is a way to concatenate commands inside a powershell script. Example: You "pipe" the output from Get-ChildeItem to Where-Object with | to filter them:

Get-ChildItem | Where-Object {$_}
  • PowerShell Object

The PowerShell object referes to a powershell session, like the one you would get when you start powershell.exe.

  • Runspace

Every powershell session has its own runspace (You'll always get output from Get-Runspace). It defines the state of the powershell session. Hence the InitialSessionState object/property of a runspace. You may decide to create a new powershell session, with its own runspace from within a powershell, to enable a kind of multithreading.

  • RunspacePool

Last but not least the RunspacePool. Like the name says, it's a pool of runspaces (or powershell sessions) that can be used to process a lot of complecated tasks. As soon as one of the runspaces in the pool has finished its task it may take the next task till everything is done. (100 things to do with 10 runspaces: on avarage they process 10 each but one may process 8 while two others process 11...)


When to use what?

  • Pipeline

The pipeline is used insed of scripts. It makes it easier to build complex scripts and should be used as often as possible.

  • PowerShell Object

The powershell object is used when ever you need a new powershell session. You can create one inside of an existing script, be it C# or Powershell. It's usefull for easy multithreading. On its own it will create a default session.

  • Runspace

If you want to create a non standard session of powershell, you can manipulate the runspace object before you create a powershell session with it. It's usefull when you want to share synchronized variables, functions or classes in the extra runspaces. Slightly more complex multithreading.

  • RunspacePool

Like mentioned before it's a heavy tool for heavy work. When one execution of a script takes hours and you need to do it very often.E.g. In combination with remoting you could simultanly install something on every node of a big cluster and the like.

Remiss answered 29/1, 2019 at 9:40 Comment(0)
M
0

You are overthinking it. The code you show in samples is a good start. Now you just need to read the result of Invoke() and check the error and warning streams.

PowerShell host provides some hooks that RunSpace can use to communicate with user, like stream and format outputs, show progress, report errors, etc. For what you want to do you do not need PowerShell Host. You can read results back from script execution using PowerShell class, check for errors, warnings, read output streams and show notification to the user using facilities of your application. This will be much more straightforward and effective than write entire PowerShell host to show a message box if errors detected.

Also, PowerShell object HAS a Runspace when it is created, you do not need to give it one. If you need to retain the runspace to preserve the environment just keep entire PowerShell object and clear Commands and all Streams each time after you call Invoke.

The next question you should ask is how to process result of PowerShell::Invoke() and read PowerShell::Streams.

Motte answered 10/1, 2014 at 20:24 Comment(2)
Hey! Could you expand on how you "keep entire PowerShell object and clear Commands and all Streams each time after you call Invoke"? I am currently not using runspaces and was looking to implement them for this reason, but it appears I can achieve this using just the PowerShell method? Thanks!!Beckman
Ask a proper question please. There is no points for answering questions in comments. ;)Motte

© 2022 - 2024 — McMap. All rights reserved.