Welcome PowerShell User! This recipe is just one of the hundreds of useful resources contained in the PowerShell Cookbook.

If you own the book already, login here to get free, online, searchable access to the entire book's content.

If not, the Windows PowerShell Cookbook is available at Amazon, or any of your other favourite book retailers. If you want to see what the PowerShell Cookbook has to offer, enjoy this free 90 page e-book sample: "The Windows PowerShell Interactive Shell".

31.2 Create and Respond to Custom Events

Problem

You want to create new events for other scripts to consume or want to respond automatically when they occur.

Solution

Use the New-Event cmdlet to generate a custom event. Use the -Action parameter of the Register-EngineEvent cmdlet to respond to that event automatically.

PS > Register-EngineEvent -SourceIdentifier Custom.Event `
    -Action { Write-Host "Received Event" }

PS > $null = New-Event Custom.Event
Received Event

Discussion

The New-Event cmdlet lets you create new custom events for other scripts or event registrations to consume. When you call the New-Event cmdlet, PowerShell adds a new entry to the sessionwide event repository called the event queue. You can use the Get-Event cmdlet to see events added to this queue, or you can use the Register-EngineEvent cmdlet to have PowerShell respond automatically.

One prime use of the New-Event cmdlet is to adapt complex events surfaced through the generic WMI and .NET event cmdlets. By writing task-focused commands to surface this adapted data, you can offer and work with data that is simpler to consume.

To accomplish this goal, use the Register-ObjectEvent or Register-CimIndicationEvent cmdlets to register for one of their events. In the -Action script block, use the New-Event cmdlet to generate a new, more specialized event.

In this scenario, the event registrations that interact with .NET or WMI directly are merely “support” events, and users wouldn’t expect to see them when they use the Get-EventSubscriber cmdlet. To hide these event registrations by default, both the Register-ObjectEvent and Register-CimIndicationEvent cmdlets offer a -SupportEvent parameter.

Here’s an example of two functions that notify you when a new process starts:

## Enable process creation events
function Enable-ProcessCreationEvent
{
    $identifier = "WMI.ProcessCreated"
    $query = "SELECT * FROM __instancecreationevent " +
                 "WITHIN 5 " +
                 "WHERE targetinstance isa 'win32_process'"
    Register-CimIndicationEvent -Query $query -SourceIdentifier $identifier `
        -SupportEvent -Action {
            [void] (New-Event "PowerShell.ProcessCreated" `
                -Sender $sender `
                -EventArguments $EventArgs.NewEvent.TargetInstance)
        }
}

## Disable process creation events
function Disable-ProcessCreationEvent
{
   Unregister-Event -Force -SourceIdentifier "WMI.ProcessCreated"
}

When used in the shell, the experience is much simpler than working with the WMI events directly:

PS > Enable-ProcessCreationEvent
PS > calc
PS > Get-Event

ComputerName     :
RunspaceId       : feeda302-4386-4360-81d9-f5455d74950f
EventIdentifier  : 2
Sender           : System.Management.ManagementEventWatcher
SourceEventArgs  :
SourceArgs       : {calc.exe}
SourceIdentifier : PowerShell.ProcessCreated
TimeGenerated    : 2/21/2010 3:15:57 PM
MessageData      :

PS > (Get-Event).SourceArgs

(...)
Caption                    : calc.exe
CommandLine                : "C:\Windows\system32\calc.exe"
CreationClassName          : Win32_Process
CreationDate               : 20100221151553.574124-480
CSCreationClassName        : Win32_ComputerSystem
CSName                     : LEEHOLMES1C23
Description                : calc.exe
ExecutablePath             : C:\Windows\system32\calc.exe
(...)

PS > Disable-ProcessCreationEvent
PS > notepad
PS > Get-Event

ComputerName     :
RunspaceId       : feeda302-4386-4360-81d9-f5455d74950f
EventIdentifier  : 2
Sender           : System.Management.ManagementEventWatcher
SourceEventArgs  :
SourceArgs       : {calc.exe}
SourceIdentifier : PowerShell.ProcessCreated
TimeGenerated    : 2/21/2010 3:15:57 PM
MessageData      :

In addition to events that you create, engine events also represent events generated by the engine itself. PowerShell supports three of these: PowerShell.Exiting to let you do some work when the PowerShell session exits, PowerShell.OnIdle to let you coordinate activity in a PowerShell session, and PowerShell.OnScriptBlockInvoke to let you process script blocks before they’re invoked.

For an example of working with the PowerShell.Exiting event, see Recipe 1.31.

PowerShell treats engine events like any other type of event. You can use the Register-EngineEvent cmdlet to automatically react to these events, just as you can use the Register-ObjectEvent and Register-CimIndicationEvent cmdlets to react to .NET and WMI events, respectively. For information about how to respond to events automatically, see Recipe 31.1.

See Also

Recipe 1.31, “Save State Between Sessions”

Recipe 31.1, “Respond to Automatically Generated Events”