I'm building event-oriented Powershell scripts. For asynchronous network operations, I usually use Begin/End calls such as BeginAcceptTcpClient / EndAcceptTcpClient for a System.Net.Sockets.TcpListener object. These calls use an IAsyncResult object to reference the asynchronous operation.
To generate events that can be easily used by Powershell and mixed with native Powershell events, I use the New-ScriptblockCallback function provided by Microsoft.
function New-ScriptblockCallback {
param (
[parameter(Mandatory = $True)]
[ValidateNotNullOrEmpty()]
[ScriptBlock] $Callback
)
# is this type already defined?
if (-not ("CallbackEventBridge" -as [type])) {
Add-Type @"
using System;
public sealed class CallbackEventBridge
{
public event AsyncCallback CallbackComplete = delegate { };
private CallbackEventBridge() {}
private void CallbackInternal(IAsyncResult result)
{
CallbackComplete(result);
}
public AsyncCallback Callback
{
get { return new AsyncCallback(CallbackInternal); }
}
public static CallbackEventBridge Create()
{
return new CallbackEventBridge();
}
}
"@
}
$bridge = [callbackeventbridge]::create()
Register-ObjectEvent -InputObject $bridge -EventName callbackcomplete -Action $Callback -MessageData $args > $null
$bridge.callback
}
This function can easily be used in asynchronous calls. For instance
$this.AcceptBlock = {
param( System.IAsyncResult] $AsyncResult )
[object] $listener = $AsyncResult.AsyncState
[System.Net.Sockets.TcpClient] $tcpClient = $listener.tcpListener.EndAcceptTcpClient($AsyncResult)
…. perform custom operations
}
$this.AcceptContextHandler = New-ScriptblockCallback -Callback $this.AcceptBlock
$this.tcpListener = New-Object System.Net.Sockets.TcpListener( $this.IP, $this.port)
$this.tcpListener.Start()
$this.AcceptIAsyncResult = $this.tcpListener.BeginAcceptTcpClient( $this.AcceptContextHandler, $this )
Then the event ‘callbackcomplete’ is raised when the operation completes and the ($this.)AcceptBlock scriptblock is called with the ‘IAsyncResult’ as parameter.
But, from what I've read/understood, the Begin/End methods are going to be abandoned, and what's more, some network calls no longer support/not supported these methods (e.g. Net.WebSockets.ClientWebSocket). Microsoft recommends using the ‘somethingAsync’ methods, which use a 'Task' object to reference the operation.
So my questions are: How can I get these calls to generate an event that can be used simply by Powershell when they are completed ? Is there a function similar to New-ScriptblockCallback that could help me?
I tried to use the Task object in place of IAsyncResult object without any success. To be honest, I wasn't very confident about the results of my tests, even having read that it was possible to cast the Task object as an IAsyncResult object.