# Saturday, July 18, 2009

updated 2009/7/20: added link to PSEventing for v1.0 event handling
updated 2009/7/24: added link to Get-Delegate script for v1.0 callbacks

There have been some nice improvements made in the latest build of PowerShell with respect to interop with the "callback” pattern in .NET. What exactly are callbacks anyway? It’s exactly what it sounds like, pretty much. In .NET there are sometimes APIs you need to call that expect you to hand them delegates (pointers to methods) which that API will call some time in the future, usually based on certain conditions being fulfilled. If that sounds a bit like .NET events, you’d be right. An event is a much gussied-up callback - it’s just a way of permitting multiple methods to be invoked in response to some condition.

Synchronous Callbacks in PowerShell v1.0

In .NET there are two types of callbacks: Asynchronous (non-blocking) and synchronous (blocking). In PowerShell v1.0, the only callbacks that were catered for were for EventHandler Delegates. This is the method signature that most of the Windows Forms controls expect to call back to in response to button clicks etc. You may have seen code similar to:

$button = new-object system.windows.forms.button
$button.add_Click( { $form.Close() } )

This works because in PowerShell v1.0, there is specialized support for this kind of callback to methods with the EventHandler signature, that is to say, methods with parameters of (object sender, EventArgs e). PowerShell is able to run the ScriptBlock in response to the button being clicked and will even pass the two arguments to the scriptblock for you. When the form is shown from a PowerShell script, there is a single thread that is running the message loop for the application. It is this same thread that handles running the script. In the PowerShell engine, there is a pool of threads created at startup, and each of them has its own “Runspace” for running scripts. Because it is one of the PowerShell threads that is running the application, that same thread is able to run the ScriptBlocks in its Runspace when called upon to do so. Although it is in a slightly roundabout way, this is an example of a synchronous callback. This single application thread is effectively waiting (blocked) for the callback to occur in response to a button click (in reality, it’s doing other things while waiting, but it’s still waiting.)

Some rather creative folks, namely one of the primary developers of PowerShell, wrote a delegate/scriptblock binder in pure script some years ago which you can use to pass script to a .NET api to be called back to in a synchronous manner.  See: Creating arbitrary delegates to ScriptBlocks.

If you want to work with .NET events in version 1.0 of PowerShell, you’ll need an add-on, like my PSEventing Snap-In.

Synchronous Callbacks in PowerShell v2.0

In the latest and greatest version of PowerShell, v2.0 RC (which comes with the public Windows 7 RC), synchronous callbacks got a whole lot easier. PowerShell is now able to deal with pretty much ANY delegate signature, automatically. Lets test this by using the .NET 3.5 System.Func<T, TResult> delegate. This is a generic delegate which lets us pass a method to an API expecting a callback to a method which has one parameters of type T1, and will return type T2. Because it’s generic, we get to pick which parameters. Lets demo creating a ScriptBlock that will be passed a DateTime and returns a String:

add-type –assembly system.core # load .net 3.5
$callback = [system.func[datetime, string]] { param($date); "the date is $date" }
$callback.Invoke( [datetime]::now )
# returns
”the date is 2009/07/14 21:50:35”

We can even take advantage of PowerShell’s super-versatile parameter binder by passing it in a string and having it get coerced to DateTime with ne’er a Parse in sight!

$callback.Invoke(“1/1/2009”)
”the date is 2009/01/01 00:00:00”

So, what’s the point of all this? Why go to all that trouble? Why not just write a function? The point is that functions cannot be called by .NET directly. So when would you need a callback like this in a PowerShell script?

Calling Web Services with Invalid, Untrusted or Expired SSL Certificates

The title says it all – sometimes you need to do this. Usually it’s because you’re working with self-signed, expired or otherwise invalid certificates on a QA or Development system. The New-WebServiceProxy Cmdlet in v2.0 is great for calling Web Services, but it doesn’t have a switch to ignore invalid certificates. If you were writing .NET code in C# or VB.NET, the way go about this is to pass a callback method to an API that expects a RemoteCertificateValidationCallback Delegate. This delegate is designed to point to a method that is passed a handful of arguments describing the attempted connection, and is expected to return a boolean; that is to say, true or false. True means “sure, the connection looks fine – go for it.” A value of False being returned tells .NET to stop the connection before it happens.

The amount of .NET code needed to do this is not a ton, but it’s still a fair handful of lines. Check out this example here: http://blog.jameshiggs.com/2008/05/01/c-how-to-accept-an-invalid-ssl-certificate-programmatically/

Now let’s see how much PowerShell script is needed for this same task:

[System.Net.ServicePointManager]::ServerCertificateValidationCallback = { $true }

Bwahahahah! Eat that, Mr. C# coder! Again, PowerShell’s binder comes into play here and automatically casts our ScriptBlock to a RemoteCertificateValidateCallback delegate (it’s not really a cast – there is no conversion – it’s a sizeable chunk of code.) From this point on, any attempts to use the New-WebServiceProxy Cmdlet with dodgy SSL certificates will succeed without so much as a warning. In fact, pretty much any other classes, like WebRequest will behave the same way. It’s important to note that this only affects the current AppDomain, that is to say, the current PowerShell process. Other processes on the system will continue to stick their nose up at dodgy SSL certs. Quit PowerShell and restart it -- or set that ServerCertificateValidationCallback property to $null -- and all is right in the world again. This works as long as you use one of PowerShell’s threads to do the work of connecting; i.e. don’t use an asynchronous request. This ensures there is a Runspace available to execute this ScriptBlock.

Converting Synchronous Callbacks into Events

This is really quite straightforward. Taking the previous example, we would generate an event inside the scriptblock using New-Event, and then bind one or more event handlers using the Register-EngineEvent Cmdlet:

[System.Net.ServicePointManager]::ServerCertificateValidationCallback = {
		new-event -SourceIdentifier SslCheck -MessageData $args > $null
		$true
	}
# dump out arguments to cert validate callback
Register-EngineEvent -SourceIdentifier SslCheck -Action { write-output $args }
Next time, we'll get into some meatier stuff. Have fun!

In Part Two: Asynchronous Callbacks in PowerShell v1.0 and v2.0

posted on Saturday, July 18, 2009 4:22:00 AM (Eastern Daylight Time, UTC-04:00)  #    Comments [0] Trackback
# Thursday, May 14, 2009

Hey, so we did the unthinkable. We released another version of the PowerShell Community Extensions. We’re calling it a beta, because we’ve be so swamped with Real Life stuff that we’re not 100% confident that it is defect-free. It’s not going to murder your servers or anything, but there might be some documentation missing and other minor stuff. We’d really appreciate it if you can give it a test-drive. If you’re running PowerShell v1.0 or v2.0 CTP3, please use the MSI installer. It will upgrade your Pscx 1.1.1 install if you have one. If, on the other hand, you are running Windows 7 RC and/or have a later version of PowerShell than v2 CTP3, you can download the zipped module and unzip to your user profile module directory at ~\documents\windowspowershell\modules\ and load it using “import-module pscx.”

Thanks for your infinite patience (yes, it’s been a while and we’re sorry) and please leave comments and issues on the tracker at http://pscx.codeplex.com/

View the 1.2 Beta release page.

posted on Thursday, May 14, 2009 8:28:13 PM (Eastern Daylight Time, UTC-04:00)  #    Comments [0] Trackback
# Tuesday, August 12, 2008

It’s getting harder to post useful scripting tips for PowerShell these days as there are so many talented hardcore scripting bloggers around. My day to day is job is not system/network/server administrator; I’m a .NET developer, having started the C# habit about eight or nine years ago with the early CLR 1.0 beta. So, from here on in, I’ve decided that a better direction for me to take from now on is that of a PowerShell developer,  as opposed to a scripter. There are very few (if any?) dedicated PowerShell developer blogs around, and so I figured I should try to fill that gap as best I can. I have a not insignificant amount of experience writing providers, cmdlets and other widgety bits, so it’s a good time to share my experiences. Of course, my way is not “the” way, so please reply with your own experiences/advice/mocking/whatever. ;-)

That said, I am not eschewing scripting altogether – I have some stuff in the pipeline (har-har) concerning areas I’m interested in, like eventing and jobs/remoting.

posted on Tuesday, August 12, 2008 10:03:20 AM (Eastern Daylight Time, UTC-04:00)  #    Comments [0] Trackback
# Monday, July 28, 2008

In the latest PowerShellCX changeset, archive read and extract support is finally available. Sorry there are no binary builds yet. Use the Extract-Archive cmdlet as a stand-alone to extract all files. Use Read-Archive to generate ArchiveEntry objects which can be piped through Where-Object for filtering and eventual consumption by Extract-Archive (which can accept ArchiveEntry as well as FileInfo pipeline input). I’ve got progress reporting working too for extract. I’ve added support for reading/extracting SevenZip, Arj, BZip2, Cab, Chm, Cpio, Deb, GZip, Iso, Lzh, Lzma, Nsis, Rar, Rpm, Tar, Wim, Z & Zip.  Yes, you did see ISO support in that list ;-) Write support is only zip, bzip2, tar and gzip still.

There are more features coming, including encrypted archive support.

posted on Monday, July 28, 2008 5:28:00 AM (Eastern Daylight Time, UTC-04:00)  #    Comments [0] Trackback
# Friday, December 14, 2007

In case anyone is interested, here are my slides in PowerPoint PPTX format from the most recent PS Virtual User Group. It covers the new Path handling infrastructure for PscxCmdlets in the upcoming PowerShell Community Extensions 1.2 and some brief information on my PowerShell Eventing snap-in for PowerShell.

psvug2_oisin_grehan.zip (152 KB)

(updated to a zip: it appears DasBlog will not serve pptx files?)

posted on Friday, December 14, 2007 11:04:07 AM (Eastern Standard Time, UTC-05:00)  #    Comments [2] Trackback
# Wednesday, March 07, 2007

Well, we've done it! Head on over to grab the latest release of PowerShell's most advanced and feature-rich snap-in!

http://www.codeplex.com/PowerShellCX

I'm pretty proud of this one. I wrote the archive cmdlets write-zip, write-bzip2, write-tar and write-gzip. I also wrote a general purpose assembly resolver cmdlet, resolve-assembly, and also an AssemblyCache provider; yes, the GAC.

 

posted on Wednesday, March 07, 2007 10:42:21 AM (Eastern Standard Time, UTC-05:00)  #    Comments [0] Trackback