2011-12-02 16 views
7

Desidero eseguire un codice prima che la finestra di PowerShell 2.0 venga chiusa. Per questo ho provato:Come gestire l'evento di chiusura della finestra di PowerShell se l'utente fa clic sul pulsante Chiudi ('X')

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

Funziona correttamente se l'utente chiude la finestra di PowerShell utilizzando il comando exit (es. uscita). Ma non funziona se l'utente lo chiude facendo clic sul pulsante Chiudi ('X') in alto a destra.

Non ho trovato alcun modo per gestire questo. Ho anche provato a farlo nel seguente modo, ma questo non funziona neanche:

PS> $ query = "Seleziona * da __InstanceDeletionEvent ENTRO 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}

Per favore, guida come posso ottenere questo compito.


UPDATE: Con qualche utile contributo da una linea professionale utile Ho anche provato il seguente:

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

Ma ancora una volta, non funziona. Come da Microsoft "l'evento DomainUnload si verifica quando un AppDomain sta per essere scaricato". Ma non funziona quando chiudo la finestra (o anche scrivo exit per quella materia).

UPDATE:

con qualche aiuto da altri professionisti in linea & un piccolo sforzo ho potuto raggiungere questo obiettivo con codice seguente.

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

ma c'è una questione che sto affrontando .... Se eseguo qualsiasi cmdlet su console dopo aver registrato questo gestore (ad esempio get-date, get-processo). Quindi l'applicazione si blocca ogni volta che si verifica un evento (ad esempio Ctrl + C, chiuso). Qualcuno può aiutarmi per favore con questo?

risposta

2

Sfortunatamente, non è possibile farlo. L'unica volta che viene chiamato un evento in uscita è se si digita "exit" al prompt di PowerShell.

Questo è come mi collego il mio evento in uscita:

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

con qualche aiuto da altri professionisti in linea e un piccolo sforzo che potrebbe raggiungere questo obiettivo con codice seguente. – JST

+1

PS v3 ha agganciato il pulsante di chiusura della finestra fino all'evento in uscita – Timbo

0

Quando si fa clic sulla X per chiudere si sta chiudendo l'applicazione di hosting PowerShell. Questa applicazione dovrebbe gestire la situazione di uscita. Credo che l'host PS predefinito sia la console di Windows che ovviamente non sta facendo quello che ti serve. È possibile ospitare PowerShell in un custom host e gestire gli eventi di uscita. Sono su un Mac in questo momento, ma forse correre sotto PS ISE potrebbe gestire questo per te?

+0

Penso che non sia possibile gestirlo affatto con un'applicazione console, comunque. Tecnicamente suppongo che tu stia chiudendo conhost che termina l'applicazione che ospita (che ospita PowerShell). – Joey

1

L'eccezione non gestita si verifica perché la garbage collection ha già disposto il gestore nel momento in cui viene chiamato il metodo non gestito. Si può andare in giro che, riporlo in un campo statico:

private static HandlerRoutine s_rou; 

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