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...
ScriptRunner Blog
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.
Before we delve into the details of PowerShell events, we first need to understand classes and objects.
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).
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.
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[]>
The New-Event cmdlet creates a new PowerShell event
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]
[]
The Get-Event cmdlet gets events in the PowerShell event queue for the current session
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]
[]
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.
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 ]
[]
Get-EventSubscriber
[[-SourceIdentifier] ]
[-Force]
[]
Get-EventSubscriber
[-SubscriptionId]
[-Force]
[]
By using the Register-EngingeEvent cmdlet we subscribe to “MyEvent” event
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
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]
[]
Unregistering the event subscriber
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:
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.
Exited event for System.Diagnostic.Process class in .NET
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[]>]
[]
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 ]
[]
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:
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
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:
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:
Unregistering an event subscriber with the Unregister-Event cmdlet
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:
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 }
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
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
There are few things which we need to keep in mind:
In the next part we will be discussing, how to handle WMI eventing with PowerShell.
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.
Jan 28, 2025 by Jeffery Hicks
Changelogs keep your software updates clear and organized. Learn the best practices for creating and managing them in...
Dec 19, 2024 by Jeffery Hicks
Boost IT efficiency with Winget and PowerShell! Learn how to automate app installations, updates, and management...
Dec 17, 2024 by Sonny Jamwal
Extend PowerShell with .NET for powerful event automation. Learn how to monitor and handle system events like a pro!...
Sonny is a self-proclaimed PowerShell preacher who lives in the beautiful city of Halifax on the east coast of Canada. Sonny has worked in Cybersecurity for more than 10 years and has acted as the primary technical lead and subject matter expert on many Cyber Security Assessments for various private and public organizations. Sonny regularly speaks at various security conferences such as BSides, AtlSecCon, ISACA, OWASP etc.