2011-12-02 15 views
7

Chcę uruchomić kod, zanim okno PowerShell 2.0 zostanie zamknięte. Do tego próbowałem:Jak obsługiwać zdarzenie close okna PowerShell, jeśli użytkownik kliknie przycisk Zamknij ("X")

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

Działa poprawnie jeśli użytkownik zamyka okno PowerShell za pomocą polecenia exit (tzn. exit). Ale to nie działa, jeśli użytkownik zamyka go, klikając przycisk Zamknij ("X") w prawym górnym rogu.

Nie mogłem znaleźć żadnego sposobu, aby sobie z tym poradzić. Próbowałem też zrobić to w następujący sposób, ale to też nie działa:

PS> $ query = "Wybierz * z __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}

Proszę wskazać, w jaki sposób mogę osiągnąć to zadanie.


UPDATE: Z jakiegoś użytecznego wkładu ze strony pomocnego profesjonalnego Online Próbowałem również:

$ appCurrentDomain = [System.AppDomain] :: currentDomain Rejestracja-ObjectEvent -action {korzystać z telefonu proces | out-file C: \ praca \ powershellexiteventcalled.txt} -InputObject $ appCurrentDomain -EventName DomainUnload

Ale znowu, to nie działa. Jak na Microsoft "Zdarzenie DomainUnload występuje, gdy AppDomain ma zostać rozładowany.". Ale to nie działa, gdy zamykam okno (lub nawet wpisuję wyjście).

UPDATE:

Z pomocą innych specjalistów w Internecie & trochę wysiłku mogę osiągnąć z następującego kodu.

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

ale tam problem jestem stoi .... Jeśli mogę uruchomić żadnej komandletu na konsoli po rejestracji tej obsługi (np uzyskać aktualne, Get-Process). Następnie aplikacja zostanie zawieszona po wystąpieniu zdarzenia (np. Ctrl + C, zamknij). Czy ktoś mógłby mi z tym pomóc?

Odpowiedz

2

Niestety, nie możesz tego zrobić. Jedynym momentem wywołania zdarzenia wyjścia jest wpisanie "exit" w wierszu PowerShell.

To jak ja podłączyć mój wychodzącego wydarzenie:

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

z pomocą innych specjalistów online i trochę wysiłku mogłem osiągnąć dzięki poniższemu kodowi. – JST

+1

PS v3 zahaczył o przycisk zamykania okna aż do zdarzenia wyjściowego. – Timbo

0

Gdy klikniesz przycisk X, aby zamknąć jesteś zamknięciem aplikacji hostingu PowerShell. Ta aplikacja musiałaby obsłużyć sytuację wyjściową. Wierzę, że domyślnym hostem PS jest konsola systemu Windows, która oczywiście nie robi tego, czego potrzebujesz. Można hostować PowerShell w custom host i obsługiwać zdarzenia wyjściowe. Jestem teraz na Macu, ale może działając pod PS ISE poradziłbym sobie z tym?

+0

Myślę, że w ogóle nie poradzisz sobie z aplikacją konsolową. Technicznie myślę, że zamykasz conhost, który kończy aplikację, którą hostuje (czyli hostuje PowerShell). – Joey

1

Nieobsługiwany wyjątek występuje, ponieważ odśmiecanie usunęło już program obsługi do czasu wywołania metody niezarządzanej. Możesz obejść to, przechowując go w polu statycznym:

private static HandlerRoutine s_rou; 

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