如果用户单击“关闭”(“X”)按钮,如何处理PowerShell窗口的关闭事件

时间:2011-12-02 08:26:47

标签: powershell

我希望在PowerShell 2.0窗口关闭之前运行一些代码。为此我尝试了:

PS> register-engineevent PowerShell.Exiting -action {get-process | out-file c:\ work \ powershellexiteventcalled.txt}

如果用户使用exit命令关闭PowerShell窗口(即退出),它可以正常工作。 但如果用户点击右上角的关闭('X')按钮关闭它,则无效。

我找不到办法解决这个问题。我也尝试过以下方式,但这也不起作用:

PS> $ query =“从__InstanceDeletionEvent WITHIN 5中选择*,其中TargetInstance ISA'Win32_Process'和TargetInstance.Name ='powershell.exe'”

PS> Register-WmiEvent -Query $ query -Action {get-process | out-file c:\ work \ powershellexiteventcalled.txt}

请指导我如何完成这项任务。


更新:通过在线专业人士的一些有用的输入,我也尝试了以下内容:

  

$ appCurrentDomain = [System.AppDomain] :: CurrentDomain   Register-ObjectEvent -Action {get-process | out-file c:\ work \ powershellexiteventcalled.txt} -InputObject $ appCurrentDomain -EventName DomainUnload

但同样,它不起作用。根据Microsoft“当AppDomain即将被卸载时发生DomainUnload事件。”但是当我关闭窗口时它不起作用(或者甚至键入退出)。

更新:

在网上和其他专业人士的帮助下我可以通过以下代码实现这一点。

PS..> $code = @"

        using System;
        using System.Runtime.InteropServices;
        using System.Management.Automation;
        using System.Management.Automation.Runspaces;

        namespace MyNamespace
        {
            public static class MyClass
            {
                public static void SetHandler()
                {
                    SetConsoleCtrlHandler(new HandlerRoutine(ConsoleCtrlCheck), true);
                }

                private static bool ConsoleCtrlCheck(CtrlTypes ctrlType)
                {
                    switch (ctrlType)
                    {
                        case CtrlTypes.CTRL_C_EVENT:
                            Console.WriteLine("CTRL+C received!");
                            return false;

                        case CtrlTypes.CTRL_CLOSE_EVENT:
                            Console.WriteLine("CTRL_CLOSE_EVENT received!");
                            return true;

                        case CtrlTypes.CTRL_BREAK_EVENT:
                            Console.WriteLine("CTRL+BREAK received!");
                            return false;

                        case CtrlTypes.CTRL_LOGOFF_EVENT:
                            Console.WriteLine("User is logging off!");
                            return false;

                        case CtrlTypes.CTRL_SHUTDOWN_EVENT:
                            Console.WriteLine("User is shutting down!");
                            return false;
                    }
                    return false;
                }

                [DllImport("Kernel32")]
                public static extern bool SetConsoleCtrlHandler(HandlerRoutine Handler, bool Add);

                // A delegate type to be used as the handler routine
                // for SetConsoleCtrlHandler.
                public delegate bool HandlerRoutine(CtrlTypes CtrlType);

                // An enumerated type for the control messages
                // sent to the handler routine.
                public enum CtrlTypes
                {
                    CTRL_C_EVENT = 0,
                    CTRL_BREAK_EVENT,
                    CTRL_CLOSE_EVENT,
                    CTRL_LOGOFF_EVENT = 5,
                    CTRL_SHUTDOWN_EVENT
                }
            }
        }"@

PS..> $text = Add-Type  -TypeDefinition $code -Language CSharp
PS..> $rs = [System.Management.Automation.Runspaces.Runspace]::DefaultRunspace
PS..> [MyNamespace.MyClass]::SetHandler()      

但我遇到的问题是......如果我在注册此处理程序后在控制台上运行任何cmdlet(例如get-date,get-process)。然后,只要发生事件,应用程序就会崩溃(例如Ctrl + C,关闭)。有人可以帮帮我吗?

3 个答案:

答案 0 :(得分:2)

不幸的是,你不能这样做。如果您在PowerShell提示符下键入“exit”,则唯一一次调用exiting事件。

这是我联系我现有活动的方式:

 $null = Register-EngineEvent -SourceIdentifier `
     ([System.Management.Automation.PsEngineEvent]::Exiting) -Action { # Put code to run here }

答案 1 :(得分:1)

发生未处理的异常是因为垃圾收集在调用非托管方法时已经处理了处理程序。您可以通过将其存储在静态字段中来解决这个问题:

private static HandlerRoutine s_rou;

public static void SetHandler()
{
    if (s_rou == null)
    {
        s_rou = new HandlerRoutine(ConsoleCtrlCheck);
        SetConsoleCtrlHandler(s_rou, true);
    }
}

答案 2 :(得分:0)

当您单击要关闭的X时,您将关闭托管PowerShell的应用程序。此应用程序需要处理退出情况。我相信默认的PS主机是Windows控制台,显然没有做你需要的。您可以在custom host中托管PowerShell并处理退出事件。我现在在Mac上,但是可能在PS ISE下运行会为你处理这个问题吗?