2

I want to catch a PowerShell script as it finishes so that I can do some final processing before it stops. Register-EngineEvent -SourceIdentifier PowerShell.Exiting seems to be the way to do it but it does not work for anything other than trivial applications.

Simple examples work. For example:

Register-EngineEvent -SourceIdentifier PowerShell.Exiting -Action {write-host "This is trivial"}

will print "This is trivial" when the script finishes. However, any action block that needs data passed to it does not get that data. For example:

Register-EngineEvent -SourceIdentifier PowerShell.Exiting -Action {write-host ">> " $($event.MessageData)} -MessageData "This doesn't work"

will only print the two leading angle brackets and not the string "This doesn't work".

Note that I'm calling the script from a Command Prompt (cmd.exe) and it is there that the Write-Host ultimately prints, after PowerShell has exited.

Furthermore, with the exception of the $Event automatic variables, all the others such as $Sender, $Args, $EventArgs etc. are not populated. Also some of the properties of $Event are not populated. For example, $Event.ComputerName prints nothing, but $Event.TimeGenerated prints the current date and time. My computer has a name.

I have included a tiny example program which demonstrates either that I am doing it wrong or that there is some limitation in what can be done with Register-EngineEvent maybe it is even a bug I suppose.

I have spent quite a lot of time searching web sites but I haven't found any examples where they are passing data to an action block for Register-EngineEvent.

sleep 1
write-host "Starting"
sleep 1
write-host "Finished"
Register-EngineEvent -SourceIdentifier PowerShell.Exiting -MessageData "This doesn't work" -Action {write-host ">> " $($event.MessageData)}
sleep 2

I would expect that little script to print "Starting" followed 1 second later by "Finished" and then, after a further 2 seconds the event handler to print ">> This doesn't work". I do get the first two messages but all I get from the handler is ">>".

I am running on Windows 10 with Powershell V5. I am not running it in ISE. I use the command line powershell -file .\try6.ps1 where try6.ps1 is the script I've included above.

If anyone can suggest what I am doing wrong or alternative ways of doing this that would be great but even if it is just that it is a known bug or that I have misunderstood what PowerShell.exiting or Register-EngineEvent are and they can't be used in the way I am trying that would be very helpful as well.

3
  • So you're trying to Write-host back into the same PS session you're exiting from? I can't see how that is supposed to work. What if you write out your message data to file? If that works better, there's your problem. Commented Mar 26, 2019 at 4:07
  • @Trix: Colin is calling the PS script from cmd.exe, which is where the Write-Host output prints after the PS process exits - I've updated the question to make that clearer. Commented Mar 26, 2019 at 21:32
  • Yet another argument for abolishing CMD wrappers for PS scripts. As time goes on, I really don't get why people still do this. Commented Mar 27, 2019 at 0:27

1 Answer 1

1

Note: While this answer contains hopefully useful background information, it does not solve the OP's problem of wanting to pass custom event data to a PowerShell.Exiting event handler.

What Colin encountered is apparently a known bug: see GitHub issue #7000.


Generally, just to clarify: the PowerShell.Exiting event only fires on exiting a PowerShell session, not a script run inside a session.

Using it in the running session itself (as opposed to using it in a remote session that forwards the event to the caller) limits you to:

  • taking behind-the-scenes action when the session ends
  • using Write-Host to write output that the calling process potentially sees (use of implicit output or Write-Output is no longer an option, because PowerShell's output streams are no longer available at the time the event fires).

You're running a script locally via PowerShell's CLI, powershell.exe which means that the limitations above apply to you.

The automatic event-related variables documented in about_Automatic_Variables do not seem to contain much information when the event fires, as the following command demonstrates:

PS> powershell -c '$null = 
     Register-EngineEvent -SourceIdentifier PowerShell.Exiting -Action {
      $Event, $EventSubscriber, $Sender, $EventArgs, $Args | Out-string | Write-Host 
     }'
ComputerName     :
RunspaceId       : 1a763430-5cd8-4b74-aaaf-7a90e514518d
EventIdentifier  : 1
Sender           :
SourceEventArgs  :
SourceArgs       : {}
SourceIdentifier : PowerShell.Exiting
TimeGenerated    : 3/26/19 12:15:48 AM
MessageData      :

SubscriptionId   : 1
SourceObject     :
EventName        :
SourceIdentifier : PowerShell.Exiting
Action           : System.Management.Automation.PSEventJob
HandlerDelegate  :
SupportEvent     : False
ForwardEvent     : False
  • $Event exists, and provides the runspace ID and a time stamp reflecting the time of the event.

    • $Event.ComputerName is presumably only populated if the event was forwarded (via Register-EngineEvent's -Forward switch) from a different computer in the context of remoting; if the property is empty, the implication is that the event fired on the local machine.
  • $EventSubscriber exists, but doesn't contain any useable information.

  • $EventArgs, $Sender and $Args are not populated.

Given the above, you could streamline your output to only contain the time stamp of the event and the local computer name's name:

PS> powershell -c '
     $null = 
       Register-EngineEvent -SourceIdentifier PowerShell.Exiting -Action {
       [pscustomobject] @{ TimeGenerated = $Event.TimeGenerated; ComputerName = $env:COMPUTERNAME }| Format-List | Out-String | Write-Host 
     }
     # ... call your script 
     .\try6.ps1
   '


TimeGenerated : 3/26/2019 8:57:53 AM
ComputerName  : Workstation10
Sign up to request clarification or add additional context in comments.

1 Comment

Thanks for your help and advice and especially for the link to the bug. I did wonder if it was by design since the programmer might argue that there is little point in populating the automatic variable as the session is ending but I see from the bug report that it isn't just for PowerShell.Exiting that this problem exists. Anyway, I have done what I actually wanted to do a different way and that is working fine so all is well. Thanks also to @Trix for the suggestions. Strangely it does work. I did wonder if that was the problem too but it seems not.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.