Event Handling in PowerShell with C# Managed Code
Introduction
Integrating C# code within PowerShell can extend its capabilities significantly. By embedding custom C# classes, PowerShell can handle more complex operations such as event handling with a higher degree of control.
In this post, I will walk you through a straightforward example of using pure C# code to instantiate a Timer object, expose its lapse event, and demonstrate how to subscribe to this event with a custom event handler in PowerShell.
The Embedded C# Code
Let’s start by embedding C# code in PowerShell.
This C# snippet defines a ProcessMonitor class that triggers an event every second, incrementing a counter each time:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
$code = @"
using System;
using System.Timers;
namespace PowerShellEventDemo
{
public class ProcessEventArgs : EventArgs
{
public string ProcessInfo { get; set; } // Holds process info
public int Counter { get; set; } // Counter value
}
public class ProcessMonitor
{
public event EventHandler<ProcessEventArgs> TimeChanged; // Event to notify when timer elapses
private int _counter = 0;
private static Timer timer; // Timer instance
public void Start()
{
timer = new Timer { Interval = 1000, AutoReset = true, Enabled = true }; // Timer setup
timer.Elapsed += Timer_Elapsed; // Attach event handler
}
private void Timer_Elapsed(object sender, ElapsedEventArgs e)
{
_counter++; // Increment counter
// Whenever the timer object emits an event it will raise our custom OnTimeChanged event that will be subscribed by our PowerShell code
OnTimeChanged(new ProcessEventArgs // Raise event
{
ProcessInfo = String.Format("Counter: {0} Time: {1}", _counter, e.SignalTime),
Counter = _counter
});
}
protected virtual void OnTimeChanged(ProcessEventArgs e)
{
TimeChanged.Invoke(this, e); // Invoke event
}
public void Stop()
{
timer.Stop(); // Stop timer
}
}
}
"@
Add-Type -TypeDefinition $code # Add the defined C# code to the current PowerShell session
Setting Up Event Handling in PowerShell
With the C# class added to our PowerShell session, we can create an instance of ProcessMonitor and register an event handler using Register-ObjectEvent:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# Creates an instance of the `ProcessMonitor` class defined in the embedded C# code
$monitor = New-Object PowerShellEventDemo.ProcessMonitor
# Registers an event handler for the `TimeChanged` event, specifying the action to take when triggered
Register-ObjectEvent -InputObject $monitor -EventName TimeChanged -Action {
# Extracts the event arguments passed to the handler
$eventArgs = $Event.SourceEventArgs
Write-Host "PowerShell received: $($eventArgs.ProcessInfo)"
# Checks if the counter has reached 10 and triggers the stop process
if ($eventArgs.Counter -eq 10) {
Write-Host "Counter: $($eventArgs.Counter) - Stop" -ForegroundColor Yellow
$monitor.Stop()
# Unregisterr the event to prevent memory leak and remove the job
Get-EventSubscriber | Unregister-Event
Get-Job | Remove-Job
}
}
# Start the timer
$monitor.Start()
Running the code you should see the events being output to the console as the timer triggers each second:
Conclusion
Embedding C# code in PowerShell scripts lets you take advantage of event handling, making it possible for automation tasks to respond dynamically to specific conditions. This example shows how PowerShell’s flexibility can be combined with the power of C# to create more advanced scripting solutions.
I hope you enjoyed this post and learned something new about PowerShell!
References
- PowerShell and Events
- Executing C# code using PowerShell script
- Timer.Elapsed
