2011-12-02 65 views
7

我想在PowerShell 2.0窗口關閉之前運行一些代碼。爲此,我嘗試過:如果用戶點擊關閉('X')按鈕,如何處理PowerShell窗口的關閉事件

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

如果用戶使用exit命令關閉PowerShell窗口(即退出),它可以正常工作。 但是,如果用戶通過單擊右上角的關閉('X')按鈕關閉它,則不起作用。

我找不到處理這個問題的方法。我也嘗試按照以下方式執行此操作,但這也不起作用:

PS> $ query =「Select * from __InstanceDeletionEvent WITHIN 5 WHERE TargetInstance ISA'Win32_Process'AND TargetInstance.Name ='powershell.exe'」

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

請指導我如何完成這項任務。


UPDATE:從一個有用的專業網上一些有用的投入我也試過如下:

$ appCurrentDomain = [System.AppDomain] :: CurrentDomain 註冊-ObjectEvent -Action {GET-過程| out-file c:\ work \ powershellexiteventcalled.txt} -InputObject $ appCurrentDomain -EventName DomainUnload

但是,它不起作用。按照Microsoft的說法,「當AppDomain即將被卸載時發生DomainUnload事件」。但是當我關閉窗口時(或者甚至爲此輸入exit)它不起作用。

UPDATE:

與其他專業人士一些幫助在線&一點力氣,我可以用下面的代碼實現這一目標。

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()  

但theres一個問題,我面對....如果我註冊這個處理程序運行後,控制檯上的任何小命令(例如獲取最新,得到處理)。然後,應用程序將在發生事件時崩潰(例如,Ctrl + C,關閉)。有人可以幫助我嗎?

回答

2

不幸的是,你不能這樣做。只有在PowerShell提示符下鍵入「exit」時,退出事件纔會被調用。

這是我勾了我的退出事件:

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

與其他專業人士一些幫助在線和一點點努力,我可以用下面的代碼實現這一目標。 – JST

+1

PS v3掛鉤了窗口關閉按鈕,直到退出事件 – Timbo

0

當您單擊X關閉你正在關閉託管PowerShell中的應用。此應用程序需要處理退出情況。我相信默認的PS主機是Windows控制檯,顯然不是你需要的。您可以在custom host中託管PowerShell並處理退出事件。我現在在Mac上,但也許在PS ISE下運行會爲您處理這個問題?

+0

我想你根本無法用控制檯應用程序處理這個問題。技術上,我猜你正在關閉conhost,它終止了它所託管的應用程序(託管PowerShell)。 – Joey

1

發生未處理的異常是因爲在調用非託管方法時垃圾回收已經處理了您的處理程序。您可以通過將其存儲在一個靜態字段繞開這個問題:

private static HandlerRoutine s_rou; 

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