Last active
March 19, 2025 12:24
-
-
Save zett42/a880ccb19762d06513e2aaba22e8c742 to your computer and use it in GitHub Desktop.
PowerShell Console Control Handler Demo (using script block)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| $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 | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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