Most of you who work with runspaces in PowerShell are familiar with the most common way to pull out data that is waiting in another runspace by simply calling Invoke() on the PowerShell instance or using EndInvoke(<handle>) to stop one that is running in the background. Doing either of these will instantly bring back the output that is waiting on the end of that runspace.
There is actually yet another way to kick off a runspace in the background and then get the data back without having to call the EndInvoke() method in the PowerShell instance if you are running these asynchronously. It requires just a little bit more work to build out an object to support this but provides the data that you are expecting. Of course, you still need to properly dispose of your runspace when you are done to prevent potential memory leaks from occurring in your console/ISE.
To highlight which one I will be using with BeginInvoke(), you can find it in the image below and I will explain the process after the image.
To do this we will begin setting up our runspace in the usual manner by creating the PowerShell instance and adding a script that will run to create an object within it.
$PowerShell = [powershell]::Create() [void]$PowerShell.AddScript({ [pscustomobject]@{ Test = 'test' } })
Ok, nothing really new here yet, but now we need to build a System.Management.Automation.PSDataCollection[T] object that will be used both as an input object but also an output object as shown in the method overloads. The TInput is merely saying that we need to provide some sort of object type that goes with the PSDataCollection object that is being built in which this type of collection is called a generic collection as it is strongly typed and will only allow use to store types that are specified to this collection. Now that we have covered that topic, let’s build this out.
$Object = New-Object 'System.Management.Automation.PSDataCollection[psobject]'
All that we have left to do now is to call BeginInvoke() and supplying this object twice as the Input/Output and then after the command has finished, check out the results.
$Handle = $PowerShell.BeginInvoke($Object,$Object)
Instead of calling EndInvoke(), I can just view the $Object variable instead and see the output.
As I mentioned earlier, even though I have my results, I still need to clean up after myself by disposing of the PowerShell instance that will then close down the runspace.
$PowerShell.Dispose()
And like that, I have another way to gather my data from a runspace!
Great post!
Is there a way to get output from a runspace while it is running? I know this can be done in a workflow, but I’m looking to get some experience working with runspaces instead.
Pingback: Yet Another Way to Get Output from a Runspace, Reflection Edition | Learn Powershell | Achieve More
Nice one Boe! As is often the case reading your posts, I learned something new, and I love learning new stuff! 🙂 Keep up the good stuff, and geek on 😉
Thank you!