Receive-Event.ps1

function Receive-Event
{
    <#
    .Synopsis
        Receives Events
    .Description
        Receives Events and output from Event Subscriptions.
    .Link
        Send-Event
    .Link
        Watch-Event
    .Example
        Get-EventSource -Subscriber | Receive-Event
    .Example
        Receive-Event -SourceIdentifier * -First 1 # Receives the most recent event with any source identifier.
    #>

    [CmdletBinding(DefaultParameterSetName='Instance')]
    [OutputType([PSObject], [Management.Automation.PSEventArgs])]
    param(
    # The event subscription ID.
    [Parameter(Mandatory,ValueFromPipelineByPropertyName,ParameterSetName='SubscriptionID')]
    [int[]]
    $SubscriptionID,

    # The event ID.
    [Parameter(Mandatory,ValueFromPipelineByPropertyName,ParameterSetName='EventIdentifier')]
    [int[]]
    $EventIdentifier,

    # The event source identifier.
    [Parameter(Mandatory,ValueFromPipelineByPropertyName,ParameterSetName='SourceIdentifier')]
    [Parameter(ValueFromPipelineByPropertyName,ParameterSetName='SubscriptionID')]
    [Parameter(ValueFromPipelineByPropertyName,ParameterSetName='EventIdentifier')]
    [string[]]
    $SourceIdentifier,

    # If provided, will return the first N events
    [int]
    $First,

    # If provided, will skip the first N events.
    [int]
    $Skip,

    # The input object.
    # If the Input Object was a job, it will receive the results of the job.
    [Parameter(ValueFromPipeline)]
    [PSObject]
    $InputObject,

    # If set, will remove events from the system after they have been returned,
    # and will not keep results from Jobs or Event Handlers.
    [switch]
    $Clear
    )



    begin {
        #region Prepare Accumulation
        # We will accumulate the events we output in case we need to -Clear them.
        $accumulated = [Collections.Arraylist]::new()
        filter accumulate {
            if (-not $skip -or ($accumulated.Count -ge $skip)) {
                $_
            }

            if (-not $First -or ($accumulated.Count -lt ($First + $skip))) {
                $null = $accumulated.Add($_)
            }
        }
        #endregion Prepare Accumulation
    }
    process {
        #region Passthru Events
        if ($PSCmdlet.ParameterSetName -eq 'EventIdentifier' -and 
            $_ -is [Management.Automation.PSEventArgs]) {
            $_ | accumulate # pass events thru and accumulate them for later.
            return
        }
        #endregion PassThru Events
        #region Receiving Events by SourceIdentifier
        if ($PSCmdlet.ParameterSetName -in 'SourceIdentifier', 'EventIdentifier') {
            :nextEvent for ($ec = $PSCmdlet.Events.ReceivedEvents.Count -1 ; $ec -ge 0; $ec--) {
                $evt = $PSCmdlet.Events.ReceivedEvents[$ec]
                if ($SourceIdentifier) {
                    foreach ($sid in $sourceIdentifier) {
                        if ($evt.SourceIdentifier -eq $sid -or $evt.SourceIdentifier -like $sid) {
                            $evt | accumulate                        
                        }
                        if ($First -and $accumulated.Count -ge ($First + $Skip)) {
                            break nextEvent
                        }
                    }
                }
                if ($EventIdentifier) {
                    foreach ($eid in $EventIdentifier) {
                        if ($evt.EventIdentifier -eq $eid) {
                            $evt | accumulate
                        }
                        if ($First -and $accumulated.Count -ge ($First + $Skip)) {
                            break nextEvent
                        }
                    }
                }
            }
            return
        }
        #endregion Receiving Events by SourceIdentifier
        #region Receiving Events by SubscriptionID
        if ($PSCmdlet.ParameterSetName -eq 'SubscriptionID') {
            $SubscriptionID |
                # Find all event subscriptions with that subscription ID
                Get-EventSubscriber -SubscriptionId { $_ } -ErrorAction SilentlyContinue |
                # that have an .Action.
                Where-Object { $_.Action } |
                # Then pipe that action to
                Select-Object -ExpandProperty Action |
                # Receive-Job (-Keep results by default unless -Clear is passed).
                Receive-Job -Keep:(-not $Clear)
            return
        }
        #endregion Receiving Events by SubscriptionID

        #region Receiving Events by InputObject
        if ($InputObject) { # If the input object was a job,
            if ($InputObject -is [Management.Automation.Job]) {
                # Receive-Job (-Keep results by default unless -Clear is passed).
                $InputObject | Receive-Job -Keep:(-not $Clear)
            } else {
                # Otherwise, find event subscribers
                Get-EventSubscriber |
                    # whose source is this input object
                    Where-Object Source -EQ $InputObject |
                    # that have an .Action.
                    Where-Object { $_.Action } |
                    # Then pipe that action to
                    Select-Object -ExpandProperty Action |
                    # Receive-Job (-Keep results by default unless -Clear is passed).
                    Receive-Job -Keep:(-not $Clear)
            }
        }
        #endregion Receiving Events by InputObject
    }

    end {
        #region -Clear accumulation (if requested)
        if ($accumulated.Count -and $Clear) { # If we accumulated events, and said to -Clear them,
            $accumulated | Remove-Event       # remove those events.
        }
        #region -Clear accumulation (if requested)
    }
}