2011-12-02 22 views
7

Quiero ejecutar algún código antes de que se cierre la ventana de PowerShell 2.0. Para esto probé:Cómo gestionar el evento cerrado de la ventana de PowerShell si el usuario hace clic en el botón Cerrar ('X')

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

Funciona bien si el usuario cierra la ventana de PowerShell con el comando de salida (es decir, sale). Pero no funciona si el usuario lo cierra haciendo clic en el botón Cerrar ('X') en la esquina superior derecha.

No he podido encontrar ninguna manera de manejar esto. También traté de hacerlo de la siguiente manera, pero esto tampoco funciona:

PS> $ query = "Seleccionar * de __InstanceDeletionEvent DENTRO DE 5 WHERE TargetInstance ISA 'Win32_Process' Y TargetInstance.Name = 'powershell.exe'"

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

Por favor, indique cómo puedo lograr esta tarea.


ACTUALIZACIÓN: Con un poco de entrada útil a partir de un útil en línea profesional que también trató el siguiente:

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

Pero, de nuevo, no funciona. Según Microsoft, el evento "DomainUnload ocurre cuando un AppDomain está a punto de descargarse". Pero no funciona cuando cierro la ventana (o incluso escribo exit para ese asunto).

ACTUALIZACIÓN:

Con la ayuda de otros profesionales en línea & un poco de esfuerzo que podría lograr esto con el código siguiente.

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

PERO Theres un tema que estoy frente a .... Si me quedo cualquier cmdlet en la consola después de registrar este controlador (por ejemplo get-date, get-process). Luego, la aplicación se bloqueará cada vez que ocurra un evento (por ejemplo, Ctrl + C, cierre). ¿Puede alguien ayudarme con esto?

Respuesta

2

Desafortunadamente, no puede hacer esto. La única vez que se llamará a un evento de salida es si escribe "exit" en el indicador de PowerShell.

Así es como me conecto el caso de salir:

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

con la ayuda de otros profesionales en línea y un poco de esfuerzo que podría lograr esto con el código siguiente. – JST

+1

PS v3 enganchó el botón de cerrar la ventana hasta el evento de salida – Timbo

0

Al hacer clic en la X para cerrar que está cerrando el alojamiento de aplicaciones PowerShell. Esta aplicación necesitaría manejar la situación de salida. Creo que el host de PS predeterminado es la consola de Windows, que obviamente no está haciendo lo que necesita. Puede alojar PowerShell en un custom host y manejar los eventos de salida. Estoy en una Mac en este momento, pero tal vez correr bajo PS ISE podría manejar esto por ti?

+0

Creo que no puede manejar eso en absoluto con una aplicación de consola, de todos modos. Técnicamente, creo que estás cerrando conhost, que finaliza la aplicación que aloja (que hospeda PowerShell). – Joey

1

La excepción no controlada se produce porque la recolección de basura ya ha eliminado su controlador en el momento en que se llama al método no administrado. Usted puede conseguir alrededor de ese almacenándolo en un campo estático:

private static HandlerRoutine s_rou; 

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