Asynchronicity in PowerShell

I’ve been playing with XAML and WPF for a while now. One thing that always bothers me is the fact that when you’re using PowerShell for this everything runs in the UI thread. The resultant outcome is that any long running process basically brings the UI to a dead stop until it is finished. If you were working in C# you would just hive off this process to a new thread and use syncronous variables to pass things back and forth between the threads. Which lead me to thinking it must be possible to do the same in PowerShell.

Enter one of the lesser known functions: [HashTable]::Synchronized(). Esentially this allows you to map an existing hash table to a syncronized variable for use between threads:

$sharedData = [HashTable]::Synchronized(@{})
$sharedData.Foo = "bar"

So now we know how to map data between threads, how do you actually create a new thread? PowerShell uses the concept of RunSpaces – each of which can be set up to run as either MTA (multi-threaded appartment) or STA (single-threaded appartment).  So we can create a new RunSpace easily using PowerShell v2.0:

$newRunspace = [RunSpaceFactory]::CreateRunspace()
$newRunspace.ApartmentState = "STA"
$newRunspace.ThreadOptions = "ReuseThread"

Now that we have a runspace, we need to tell it about the synchronized hash table we created earlier:

$newRunspace.SessionStateProxy.setVariable("sharedData", $sharedData)

Great. So now we have a RunSpace with its own thread, and we have a synchronized variable we can use from both the parent and child thread. So how do we run something in the child thread? With a [PowerShell] class. This class is able to run the classic “BeginInvoke()” for any scriptblock you would like to pass to it, and you can associate it with a given RunSpace:

$newPowerShell = [PowerShell]::Create()
$newPowerShell.Runspace = $newRunspace
$newPowerShell.AddScript({$sharedData.Foo = "fred"}).BeginInvoke()

This should give you enough to get started on writing your own multi-threaded PowerShell apps. In future blogs I will probably take this further, looking at the InitialSessionState object for initializing new RunSpaces, using the RunSpacePool for managing threads, and how to tie this all together with a WPF/XAML based GUI from inside PowerShell.

  1. No comments yet.
  1. October 19, 2012 at 11:07 pm

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: