Skip to the main content.

ScriptRunner Blog

How to Leverage .NET in PowerShell for event-driven scripting

Table of contents

Post Featured Image

Extend PowerShell with .NET for powerful event automation. Learn how to monitor and handle system events like a pro! The article answers how to tap into .NET classes to monitor events and trigger automated responses, expanding PowerShell’s capabilities for efficient system management.

The Oxford dictionary defines an event as "a thing that happens, especially something important". In the computing world, most people associate events with logging, however events go beyond that. In fact, a log is nothing but an output from an event.

This blog post covers two types of events, PowerShell Engine Events and .NET Object Events (click here for the second part, Master PowerShell WMI: Automate system event monitoring effortlessly). 

Keep on reading if you want to learn how to handle both PowerShell Engine Events and .NET Object Events and which PowerShell commandlets will get you there.

 

The basics: From PowerShell classes and objects to events

Before we delve into the details of PowerShell events, we first need to understand classes and objects.

  • A class is a collection of properties and methods.
  • An object is an instance of the class which is being used to access properties and methods.

Simple, right? Let’s simplify this using a real-world example.

I’m an object of my parents class. My parents have certain properties such as black hair, brown eyes etc. and certain methods such as cooking, dancing etc.

Let’s take a simple example of a class defined in PowerShell:

 
#Define a class
class PrintName {
   #Property
[Int] $count
#Function
[Void] WriteHello([string] $Name){ Write-Host "Hello $Name" } }
#Instantiate an Object
$Obj = [PrintName]::new()

#Assign value for count property
$Obj.count = 1 Write-Host "Property Value " $obj.count

#Call GetProcessPath method
$Obj.WriteHello('Sonny') "`n"

 

Which delivers the following output:


Property Value 1
Hello Sonny

In the example above we created a class called "PrintName" with one property called "count" and method called "WriteHello". But why are we talking about classes?

Well, to understand events we need to first understand class structure because an event is nothing but a special kind of method.

Special, because other pieces of code can subscribe to events (this is also known as event subscription).

 

PowerShell engine events

In order to enable other programs to be informed about certain actions or state changes by a specific program, we need to create events in that program.

Thus, other programs can subscribe to these events and get informed when certain actions or state changes happen in your program (don’t worry, when we discuss .NET Framework events things would become clearer).

PowerShell provides different cmdlets for working with events. Let’s start with the New-Event cmdlet, which, as the name suggests, creates a new Event.

 

Creating an event: New-Event cmdlet

PowerShell provides different cmdlets for working with events. Let’s start with the New-Event cmdlet, which, as the name suggests, creates a new Event.


New-Event
[-SourceIdentifier]
[[-Sender] ]    
[[-EventArguments] <psobject[]>]    
[[-MessageData] ]    
[]</psobject[]>

Source: Microsoft

 

The New-Event cmdlet creates a new PowerShell event

 

Viewing the event queue: Get-Event cmdlet

Once an Event is created it is added to the event queue. To view the event queue, we use the Get-Event cmdlet. You can see below that there are two events in the queue.


Get-Event
[[-SourceIdentifier] ]
[]

Get-Event
[-EventIdentifier]
[]

Source: Microsoft

 

The output of the Get-Event cmdlet shows, that there are currently two events in the event queue

The Get-Event cmdlet gets events in the PowerShell event queue for the current session

 

Removing events from the queue: Remove-Event cmdlet

Now how do we remove events from the queue? We use the Remove-Event cmdlet as shown below:


Remove-Event
[-SourceIdentifier]
[-WhatIf]
[-Confirm]
[]

 


Remove-Event
[-EventIdentifier]
[-WhatIf]
[-Confirm]
[]

Source: Microsoft

 

Remove-Event cmdlet deletes events from the event queue

The Remove-Event cmdlet deletes events from the event queue in the current session.

 

As we can see, we only have one event left in the event queue.

Before we move on, let’s clear the event queue by running the following cmdlet


Remove-Event -SourceIdentifier *

At this point there are no events in our event queue.

 

Subscribing to an event: Register-EngineEvent and Get-EventSubscriber cmdlet

Events are not useful unless someone has subscribed to them. In order to subscribe to an event, we use the Register‑EngineEvent cmdlet as shown below. Just like events, event subscription is added to the session.

In order to view current subscriptions in a session, use the Get-EventSubscriber cmdlet. Both Register-EngineEvent and Get-EventSubscriber cmdlet are shown here.


Register-EngineEvent
[-SourceIdentifier]
[[-Action] ]
[-MessageData ]
[-SupportEvent]
[-Forward]
[-MaxTriggerCount ]
[]

Source: Microsoft

 


Get-EventSubscriber
[[-SourceIdentifier] ]
[-Force]
[]

 


Get-EventSubscriber
[-SubscriptionId]
[-Force]
[]

Source: Microsoft

 

Subscribing to 'MyEvent' by using the Register-EngineEvent cmdlet

By using the Register-EngingeEvent cmdlet we subscribe to “MyEvent” event

 

Raising events in PowerShell

In the example above we create a new subscription for an event called "MyEvent". Now let’s raise the event named "MyEvent".

As we can see in now, when we raise the event named "MyEvent", the event subscriber is invoked and executes the Action Script Block.

The Action block is being executed when a new event named "MyEvent" is invoked

The Action block is being executed when a new event named "MyEvent" is invoked 

 

Unsubscribing from an event: Unregister-Event cmdlet

In order to remove the subscription from the current session we use the Unregister-Event cmdlet:


Unregister-Event
[-SourceIdentifier]
[-Force]
[-WhatIf]
[-Confirm]
[]

 


Unregister-Event
[-SubscriptionId]
[-Force]
[-WhatIf]
[-Confirm]
[]

Source: Microsoft

 

Cancelling an event subscription with the Unregister-Event cmdlet in PowerShell

Unregistering the event subscriber

 

.NET framework events

So far, we have discussed PowerShell engine event. Now let’s switch our focus to .NET framework events. A complete reference for .NET can be found at .NET API browser.

Let’s start by taking a simple example of the Process class which is part of the System.Diagnostic namespace.

As we can see, the Process class has constructor, properties, methods and events. Collectively they are also known as class members. The Process class also has three events:

  • ErrorDataReceived
  • Exited and
  • OutputDataReceived

In order to access class members, we need to either instantiate a new Object or use existing objects. Once we have an object, we can use it to subscribe to the events.

Figure 7: Exited event for System.Diagnostic.Process class

Exited event for System.Diagnostic.Process class in .NET

 

Example: Handling Process.Exited events in PowerShell

PowerShell provides the Register-ObjectEvent cmdlet to subscribe to .NET framework events.

Let’s take an example, suppose that we want to subscribe to the “exiting” event of Process class. In order to do so, we first need an Object of Process class. We can then use the object to subscribe to the Member events of the Process class.

The exiting event is invoked when a process exits. In our example we will use the calculator process object to subscribe to the exiting event.

Any process running on Windows is an Object. To get a list of process objects on windows we can use the Get‑CimInstance cmdlet. As you can see, the Get-CimInstance returns the objects and by combining it with the Get-Member cmdlet we can view the class members.


Get-CimInstance 
[-ClassName]
[-ComputerName <string[]>]
[-KeyOnly]
[-Namespace ]
[-OperationTimeoutSec ]
[-QueryDialect ]
[-Shallow ]
[-Filter ]
[-Property <string[]>]
[]

Source: Microsoft

Figure 8: Using Get-CimInstance cmdlet to view running processes

Using Get-CimInstance cmdlet to view running processes

 

For our example we launch the calculator process in our code. We always have the option to use an already existing process object. In the code below we are first starting the calculator process and capturing the object in $CalcProcessObj variable.


$CalcProcessObj = [System.Diagnostics.Process]::Start("calc.exe") Register-ObjectEvent -InputObject 
$CalcProcessObj -EventName Exited -Action { cmd.exe /c ping -n 2 8.8.8.8 }

 

Next, we use the Register-ObjectEvent cmdlet to subscribe to the exited event for the calculator process.


Register-ObjectEvent
[-InputObject]
[-EventName]
[[-SourceIdentifier] ]
[[-Action] ]
[-MessageData ]
[-SupportEvent]
[-Forward]
[-MaxTriggerCount ]
[]

Source: Microsoft

 

When the calculator process exits our action block will be executed. The Action block contain a simple command to send 2 pings to IP address 8.8.8.8.  

This is the output that we have successfully subscribed to the event:

Figure 9: Output after running the Register-ObjectEvent cmdlet

Output after running the Register-ObjectEvent cmdlet

 

Once we exit the calculator process, we can see that the Action Script block was executed and resulted in 2 pings being sent to IP address 8.8.8.8

Figure 10: Wireshark showing 2 pings sent to IP address 8.8.8.8

Wireshark showing 2 pings sent to IP address 8.8.8.8

 

As we have seen before we can use the Get-EventSubscriber cmdlet for getting a list of all event subscriptions.

The output in our example is shown here:

Figure 11: List of event subscribers for current session

Retrieving a list of event subscribers for the current session with Get-EventSubscriber cmdlet

 

Similarly, we can use the Unregister-Event cmdlet to unregister an event subscription (don’t you love the verb-noun representation of cmdlets 😊), as can be seen here:

Figure 12: Unregistering an event subscriber with the Unregister-Event cmdlet

Unregistering an event subscriber with the Unregister-Event cmdlet

 

Example: Handling FileSystemWatcher Class Events in PowerShell

Let’s take another example of FileSystemWatcher class which provide some interesting Events that we can subscribe to, such as file or directory creation, deletion etc.

Suppose we want to subscribe to file/directory creation event.

We follow the same steps from our last example:

  • first we need to get the object
  • then we use the Register-ObjectEvent cmdlet to subscribe to the event

 

Figure 13: Events for FileSystemWatcher class

Events for FileSystemWatcher class in .NET

 

Let’s first create an Object of FileSystemWatcher class


$testobj1 = New-Object -TypeName System.IO.FileSystemWatcher

 

Next, we give our object the directory path to watch for file/directory creation


$testobj1.Path = "C:\Users\Public"

 

Lastly, we use the Register-ObjectEvent cmdlet to subscribe to the event.


Register-ObjectEvent -InputObject $testobj1 -EventName Created -Action { cmd.exe /c ping -n 2 8.8.8.8 }

 

 

Example: Handling System.Diagnostics.EventLog Class Events in PowerShell

Here’s another example: the System.Diagnostics.EventLog class provides an Event called “EntryWritten” which is raised when a log entry is written.

We follow the same steps as before: we instantiate an object, set the Log property for the object (= which log we want to watch) and then use the Register-ObjectEvent cmdlet to subscribe to the EntryWritten event.


$testobj1 = New-Object -TypeName System.Diagnostics.EventLog

$testobj1.Log = "Security"

Register-ObjectEvent -InputObject $testobj1 -EventName EntryWritten -Action { Write-Host "Meow" }

 

Please note: this code requires admin level permission as we are working with logging.

EntryWritten event for EventLog class

EntryWritten event for EventLog class

 

For this demonstration I switched from VS Code to ISE. We subscribed to the EntryWritten event for Security logs. Our action blocks write “Meow” each time the event is invoked.

Subscribing for “EntryWritten” event

Subscribing for “EntryWritten” event 

 

Conclusion

There are few things which we need to keep in mind:

  • Events, event subscriptions, and the event queue exist only in the current session. If we close the current session, the event queue is discarded, and the event subscription is canceled.
  • There are two separate cmdlets to work with PowerShell engine events (Register-EngineEvent) and .NET Framework events (Register-ObjectEvent)

In the next part we will be discussing, how to handle WMI eventing with PowerShell.

 

Good2know

Your ultimate PowerShell Cheat Sheet

Unleash the full potential of PowerShell with our handy poster. Whether you're a beginner or a seasoned pro, this cheat sheet is designed to be your go-to resource for the most important and commonly used cmdlets.

The poster is available for download and in paper form.

PowerShell Poster 2023

Get your poster here!

 

 

Related links 

Related posts

13 min read

Mastering Changelog Management with PowerShell

Changelogs keep your software updates clear and organized. Learn the best practices for creating and managing them in...

14 min read

How to Use Winget and PowerShell for Efficient App Deployment

Boost IT efficiency with Winget and PowerShell! Learn how to automate app installations, updates, and management...

17 min read

How to Leverage .NET in PowerShell for event-driven scripting

Extend PowerShell with .NET for powerful event automation. Learn how to monitor and handle system events like a pro!...

About the author: