如何使用类在PowerShell中实现事件处理

时间:2019-04-05 03:09:56

标签: powershell oop event-handling

我希望能够创建一个自定义事件,该事件将触发通常订阅该事件的函数或对象。我看过一些功能,例如:New-EventRegister-ObjectEvent,但我不确定如何有效地将它们组合在一起。

我想要的想法是使某个函数在发生某个事件时自动执行并自动执行操作。例如,我附上了一个小程序,从概念上讲,它将向订阅者(TestEvent::SendMessage())引发一个事件(TestSubscribeEvent::DisplayMessage())。这只是出于想法,但是我不确定如何在PowerShell中正确实现此功能。

我当前正在使用PowerShell 6.2。如果需要其他信息,请告诉我。

class TestSubscribeEvent
{
    # This function would be subscribed to SendMessage from the class TestEvent.
    [void] DisplayMessage([string] $msg)
    {
        Write-Host "EVENT REPLIED WITH THIS MESSAGE:`r`n$($msg)";
    } # DisplayMessage()
} # CLASS :: TestSubscribeEvent



class TestEvent
{
    [void] SendMessage([string] $msg)
    {
        # SEND THIS MESSAGE VIA EVENTS
        #  Allow all subscribers to see the message
        # Message can be any literal string, such as "Hello".
    } # SendMessage()
} # CLASS :: TestEvent



function main()
{
    # Create a new instance of these objects
    [TestEvent] $testEvent = [TestEvent]::new();
    [TestSubscribeEvent] $testSub = [TestSubscribeEvent]::new();

    # Send the message; TestSubscribeEvent should already be subscribed to TestEvent.
    $testEvent.SendMessage("All these squares make a circle.");
} # main()



# Jump to main, start the program.
main;

在此代码中,尽管只是出于思想上的考虑,$testSub.DisplayMessage()应该在$testEvent.SendMessage()引发新事件后自动执行。 $testSub.DisplayMessage()的输出将取决于$testEvent.SendMessage()通过事件消息提供的消息。

希望这是有道理的;如果需要-如果需要,我可以进一步说明。

感谢您的时间,

1 个答案:

答案 0 :(得分:2)

首先,我对文字墙表示歉意。您应该查看New-EventRegister-EngineEventUnregister-EventGet-EventGet-EventSubscriberRemove-Event cmdlet。这是有关处理这些事件以触发并处理您自己的事件的快速示例。

首先,我们将设置2个小功能。这会将一些自动变量写入控制台:

function Write-EventToConsole ($evt)
{
    Write-Host "Write info to the console from a function"
    Write-Host $Evt.MessageData
    Write-Host $Evt.Sender
    Write-Host $Evt.TimeGenerated      
    Write-Host $Evt.SourceArgs
}

这只是将它们附加到文件中:

function Save-EventToFile ($evt, $filepath)
{
    "Writing to file"                            | Out-File $filepath -Append
    "Message Data   : {0}" -f $Evt.MessageData   | Out-File $filepath -Append
    "Sender         : {0}" -f $Evt.Sender        | Out-File $filepath -Append
    "Time Generated : {0}" -f $Evt.TimeGenerated | Out-File $filepath -Append     
    "Source Args    : {0}" -f $Evt.SourceArgs    | Out-File $filepath -Append
}

接下来,我们将设置3个事件处理程序。我们将一次处理这1个事件,检查订阅者,并在每个事件之后触发一个事件。

Register-EngineEvent -SourceIdentifier "MyEventIdentifier" -Action {
    Write-EventToConsole $Event    
} -SupportEvent

下一步检查我们的事件订阅者是否在那里。

Get-EventSubscriber -Force

SubscriptionId   : 1
SourceObject     : 
EventName        : 
SourceIdentifier : MyEventIdentifier
Action           : System.Management.Automation.PSEventJob
HandlerDelegate  : 
SupportEvent     : True
ForwardEvent     : False

然后我们触发事件

$null = New-Event -SourceIdentifier "MyEventIdentifier" `
                  -Sender "MyObject" `
                  -EventArguments "Some arguments that I want to pass" `
                  -MessageData "This is some message data I want to pass"

并查看写入控制台的数据。

just write to console
This is some message data I want to pass
MyObject
MyObject
4/5/2019 1:54:27 PM
Some arguments that I want to pass
Some arguments that I want to pass

添加其他事件:

Register-EngineEvent -SourceIdentifier "MyEventIdentifier" -Action {
    Write-EventToConsole $Event    
} -SupportEvent

Register-EngineEvent -SourceIdentifier "MyEventIdentifier" -Action {
    Save-EventToFile $Event C:\temp\event.txt
} -SupportEvent

检查事件订阅者:

Get-EventSubscriber -Force

SubscriptionId   : 1
SourceObject     : 
EventName        : 
SourceIdentifier : MyEventIdentifier
Action           : System.Management.Automation.PSEventJob
HandlerDelegate  : 
SupportEvent     : True
ForwardEvent     : False

SubscriptionId   : 2
SourceObject     : 
EventName        : 
SourceIdentifier : MyEventIdentifier
Action           : System.Management.Automation.PSEventJob
HandlerDelegate  : 
SupportEvent     : True
ForwardEvent     : False

SubscriptionId   : 3
SourceObject     : 
EventName        : 
SourceIdentifier : MyEventIdentifier
Action           : System.Management.Automation.PSEventJob
HandlerDelegate  : 
SupportEvent     : True
ForwardEvent     : False

现在,如果我们触发一个事件:

$null = New-Event -SourceIdentifier "MyEventIdentifier" `
                  -Sender "MyObject" `
                  -EventArguments "Some arguments that I want to pass" `
                  -MessageData "This is some message data I want to pass"

我们可以看到写入控制台的2个事件订阅者已被触发:

just write to console
This is some message data I want to pass
MyObject
MyObject
4/5/2019 1:54:27 PM
Some arguments that I want to pass
Some arguments that I want to pass

Write info to the console from a function
This is some message data I want to pass
MyObject
4/5/2019 1:54:27 PM
Some arguments that I want to pass

写入文件的事件订阅者被触发:

Get-Content C:\temp\event.txt

Writing to file
Message Data   : This is some message data I want to pass
Sender         : MyObject
Time Generated : 4/5/2019 1:54:27 PM
Source Args    : Some arguments that I want to pass

最后要删除活动订阅者,您可以使用:

Get-EventSubscriber -Force | `
    Where-Object { $_.SourceIdentifier -eq 'MyEventIdentifier' } | `
    Unregister-Event -Force

希望这有助于解释这一点。如果没有,请告诉我,我将更新答案以解决所有问题。

编辑: 这也适用于类。这是一个快速示例。请注意,如果您返回一个值,则使用-SupportEvent可能无法使用。删除SupportEvent将以PSEventJob的形式运行操作。这将使您可以使用Get-Job和Receive-Job来检索值。

# Define a class
class TestSubscribeEvent
{
   # Static method
   static [void] DisplayMessage($evt)
   {
        Write-Host "Written from static handler"
        Write-Host $Evt.MessageData
        Write-Host $Evt.Sender
        Write-Host $Evt.TimeGenerated      
        Write-Host $Evt.SourceArgs
        Write-Host '----------------------------'
   }

   [string] DisplayMessage2($evt)
   {
        return "You wont see this if you use supportevent"
   }

   [void] SetSomeProperty($evt)
   {
        $this.SomeProperty ="Set from internal instance`n`t{0}`n`t{1}`n`t{2}`n`t{3}" -f $Evt.MessageData, $Evt.Sender, $Evt.TimeGenerated, $Evt.SourceArgs
   }

   [string] $SomeProperty
}

# Define a class
class TestEvent
{
   # Static method
   static [void] SendMessage($msg)
   {
        $null = New-Event -SourceIdentifier "MyEventIdentifier" `
                  -Sender "MyObject" `
                  -EventArguments "Sent from static" `
                  -MessageData $msg
   }

   [void] SendMessage2($msg)
   {
        $null = New-Event -SourceIdentifier "MyEventIdentifier" `
                  -Sender "MyObject" `
                  -EventArguments "Sent from instance" `
                  -MessageData $msg
   }
}

制作一些对象:

$subObj = New-Object TestSubscribeEvent
$testEvent = New-Object TestEvent

注册一些事件处理程序

#register static handler
Register-EngineEvent -SourceIdentifier "MyEventIdentifier" -Action {
    [TestSubscribeEvent]::DisplayMessage($event)   
} -SupportEvent

#register instance handler
Register-EngineEvent -SourceIdentifier "MyEventIdentifier" -Action {
    $subObj.DisplayMessage2($event) 
} -SupportEvent

#register instance handler without Support Event
#this creates a PSEventJob which we swallow with $null, we check it later
$null = Register-EngineEvent -SourceIdentifier "MyEventIdentifier" -Action {
    $subObj.DisplayMessage2($event) 
}

#register instance handler that updates a property
Register-EngineEvent -SourceIdentifier "MyEventIdentifier" -Action {
    $subObj.SetSomeProperty($event)
} -SupportEvent

现在,我们将调用事件生成器:

#call static generator
[TestEvent]::SendMessage("Static called message")

这将向控制台生成以下内容:

Written from static handler
Static called message
MyObject
4/9/2019 8:51:20 AM
Sent from static
----------------------------

我们可以看到它是一个被调用的静态方法,新事件是在静态方法中创建的,并且静态处理程序已将其获取。

我们还可以使用get-job查看PSEventJob的运行情况。

Id     Name            PSJobTypeName   State         HasMoreData     Location             Command                  
--     ----            -------------   -----         -----------     --------             -------                  
47     MyEventIdent...                 Running       True                            ...                      

然后您可以使用Get-Job 47 | Receive-Job -keep来获取输出

You wont see this if you use supportevent

请注意,另一个调用相同方法并返回一个值并使用SupportEvent的处理程序基本上会丢失所有输出。没有创建PSEventJob,因此输出无处可寻。

我们还可以看到该属性是在实例对象上设置的。

$subObj.SomeProperty

Set from internal instance
    Static called message
    MyObject
    4/9/2019 9:05:26 AM
    System.Object[]

实例版本实际上只是传递不同的值而做同样的事情。

#call instance generator
$testEvent.SendMessage2("Instance called message")

这给出了以下内容:

Written from static handler
Instance called message
MyObject
4/9/2019 9:02:02 AM
Sent from instance
----------------------------