Tuesday, December 23, 2014

PowerShellAsync - library to build async-enabled PowerShell CmdLets

I love PowerShell.

Yes, I know it is not as good as <insert your favorite shell here>, but on Windows it makes my life easier.
I've been using it for many years now, built my own scripts for easy stuff and CmdLets for more interesting scenarios.   

Lately .NET - based coding starts moving into asynchronous territory with a great speed - most of the modern libraries introduced a Task-based asynchronous API. Using these APIs we can write much more efficient code. And with introduction of .NET 4.5 and async keyword in C#, there are no excuses NOT to write asynchronous code anymore.

Unless you work on a PowerShell Cmdlet.

In typical CmdLet you implement at least one method:



For more advanced scenarios, focused on processing pipelined data you may also consider implementing these methods:

From inside these methods you can interact with PowerShell using a family of Write-* methods like Write-Host, Write-Warning, Write-Verbose, etc.

Also you can ask user to confirm operations using ShouldProcess and ShouldContinue methods.

The only problem is that you can use these methods only from the main thread!

PowerShell validates the stack of the method call and if it is not initiated from one of the 4 primary CmdLet methods, it will throw an exception.

It makes writing asynchronous code using modern libraries a difficult task.
There are many ways to solve this problem, but my goal was to make writing async PowerShell code as easy as a normal one, and have a way to upgrade an existing CmdLet with a minimum effort.

Introducing PowerShellAsync library

First of all, to build a new async-enabled CmdLet or upgrade an existing one, you need to install PowerShellAsync from nuget:

 PM> Install-Package TTRider.PowerShellAsync.dll
(https://www.nuget.org/packages/TTRider.PowerShellAsync.dll/)

And if you curious about implementation, feel free to take a look at the source: https://github.com/ttrider/PowerShellAsync

So now, instead of implementing the original methods, you have to implements their async counterparts! And all of the  Write-* methods will work as if they been called from a main thread!


So, if you want your CmdLet to execute T-SQL statement on multiple databases at the same time using modern async API, here is your naive PowerShell CmdLet:

For the complete example, please take a look at Github: https://github.com/ttrider/PowerShellAsync/tree/master/PowerShellAsyncExample

Happy Coding !

No comments:

Post a Comment