Как реализовать обработку событий в PowerShell с классами - PullRequest
4 голосов
/ 05 апреля 2019

Я хочу иметь возможность создавать настраиваемое событие, которое будет запускать функции или объекты в целом, которые подписаны на это событие.Я рассмотрел некоторые функции, такие как: New-Event и Register-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 Ответ

2 голосов
/ 05 апреля 2019

Сначала мои извинения за стену текста.Вы должны посмотреть на New-Event , Register-EngineEvent , Unregister-Event , Get-Event , Get-EventSubscriber и Remove-Event командлеты.Вот краткий пример работы с этими событиями для запуска и обработки ваших собственных событий.

Сначала мы настроим 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 обработчика событий.Мы будем делать это по одному, проверять подписчиков и запускать событие после каждого.

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
----------------------------
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...