EventSources/@PowerShellAsync.ps1
<# .Synopsis Runs PowerShell asynchronously .Description Runs PowerShell in the background. Events are fired on the completion or failure of the PowerShell command. #> [ComponentModel.InitializationEvent({ # Because of the potential for a "narrow window" timing issue, # this event source needs to return a script to run in order to start it. # $this is whatever object is returned. # If multiple objects are returned, this will be run multiple times. $Global:PowerAsyncResults[$this.InstanceID] = $this.BeginInvoke() })] [CmdletBinding(PositionalBinding=$false)] param( # The scripts you would like to run. Each script block will be counted as a distinct statement. [Parameter(Mandatory,Position=0)] [ScriptBlock[]] $ScriptBlock, # The named parameters passed to each script. [Collections.IDictionary[]] [Alias('Parameters')] $Parameter, # If provided, will run in a specified runspace. The Runspace must already be open. [Management.Automation.Runspaces.Runspace] $Runspace, # If provided, will run in a runspace pool. The RunspacePool must already be open. [Management.Automation.Runspaces.RunspacePool] $RunspacePool ) process { $psAsync = [PowerShell]::Create() $null = for ($n =0; $n -lt $ScriptBlock.Length;$n++) { $psAsync.AddStatement() $psAsync.AddScript($ScriptBlock[$n]) if ($parameter -and $Parameter[$n]) { $psAsync.AddParameters($Parameter[$n]) } } foreach ($cmd in $psAsync.Commands) { foreach ($ce in $cmd.Commands) { $ce.MergeMyResults("All", "Output") } } if (-not $Global:PowerAsyncResults) { $Global:PowerAsyncResults = @{} } if ($Runspace) { $psAsync.Runspace = $Runspace } elseif ($RunspacePool) { $psAsync.RunspacePool = $RunspacePool } $onFinishedSubscriber = Register-ObjectEvent -InputObject $psAsync -EventName InvocationStateChanged -Action { $psAsyncCmd = $event.Sender if ($psAsyncCmd.InvocationStateInfo.State -notin 'Completed', 'Failed', 'Stopped') { return } if ($Global:PowerAsyncResults[$psAsyncCmd.InstanceID]) { $asyncResults = $event.Sender.EndInvoke($Global:PowerAsyncResults[$psAsyncCmd.InstanceID]) $Global:PowerAsyncResults.Remove($psAsyncCmd.InstanceID) New-Event -SourceIdentifier "PowerShell.Async.$($psAsyncCmd.InstanceID)" -Sender $event.Sender -MessageData $asyncResults -EventArguments $event.SourceEventArgs } if ($psAsyncCmd.InvocationStateInfo.Reason) { New-Event -SourceIdentifier "PowerShell.Async.Failed.$($psAsyncCmd.InstanceID)" -Sender $psAsyncCmd -MessageData $psAsyncCmd.InvocationStateInfo.Reason } Get-EventSubscriber | Where-Object SourceObject -EQ $psAsyncCmd | Unregister-Event $psAsyncCmd.Dispose() } $psAsync | Add-Member NoteProperty SourceIdentifier @( "PowerShell.Async.$($psAsync.InstanceID)","PowerShell.Async.Failed.$($psAsync.InstanceID)" ) -Force -PassThru return } |