Skip to content

Instantly share code, notes, and snippets.

@zett42
Last active March 19, 2025 12:24
Show Gist options
  • Select an option

  • Save zett42/a880ccb19762d06513e2aaba22e8c742 to your computer and use it in GitHub Desktop.

Select an option

Save zett42/a880ccb19762d06513e2aaba22e8c742 to your computer and use it in GitHub Desktop.
PowerShell Console Control Handler Demo (using script block)
$ErrorActionPreference = 'Stop'
# Compile the cmdlet and import it as a module
Add-Type -TypeDefinition (Get-Content $PSScriptRoot\PSConsoleCtrlHandler.cs -Raw) -PassThru | Import-Module -Assembly { $_.Assembly }
# Add the handler
Add-ConsoleCtrlHandler {
param( [ConsoleCtrlEvent] $ctrlType )
$logPath = (New-Item $env:temp\_MyPS\console.log -Force).Fullname
"[$(Get-Date)] console ctrl event received: $ctrlType" | Add-Content $logPath
}
while( $true ) {
"Running"
Start-Sleep 1
}
using System;
using System.Management.Automation;
using System.Runtime.InteropServices;
using System.Collections.Generic;
using System.ComponentModel;
public enum ConsoleCtrlEvent : uint
{
CTRL_C_EVENT = 0,
CTRL_BREAK_EVENT = 1,
CTRL_CLOSE_EVENT = 2,
CTRL_LOGOFF_EVENT = 5,
CTRL_SHUTDOWN_EVENT = 6
}
[Cmdlet(VerbsCommon.Add, "ConsoleCtrlHandler")]
public class PSAddConsoleCtrlHandler : PSCmdlet
{
[DllImport("Kernel32", SetLastError = true)]
private static extern bool SetConsoleCtrlHandler(HandlerRoutine handler, bool add);
private delegate bool HandlerRoutine(ConsoleCtrlEvent ctrlType);
// Static lists to store handler routines and PowerShell runspaces to prevent objects from being destroyed prematurely by GC.
private static List< HandlerRoutine > s_handlerList = new List< HandlerRoutine >();
private static List< PowerShell > s_runspaceList = new List< PowerShell >();
[Parameter(Mandatory = true, Position = 0)]
public ScriptBlock ScriptBlock { get; set; }
protected override void EndProcessing()
{
PowerShell powershell = PowerShell
.Create(RunspaceMode.NewRunspace)
.AddScript(ScriptBlock.ToString());
var handler = new HandlerRoutine((s) =>
{
powershell.AddArgument(s).Invoke();
return false;
});
if( SetConsoleCtrlHandler(handler, true) ) {
s_runspaceList.Add(powershell);
s_handlerList.Add(handler);
}
else {
int errorCode = Marshal.GetLastWin32Error();
WriteError(new ErrorRecord(
new Win32Exception(errorCode),
"SetConsoleCtrlHandlerFailed",
ErrorCategory.InvalidOperation,
ScriptBlock
));
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment