8000 Register-EngineEvent Powershell.Exiting does not work. · Issue #8000 · PowerShell/PowerShell · GitHub
[go: up one dir, main page]

Skip to content

Register-EngineEvent Powershell.Exiting does not work. #8000

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
danielniccoli opened this issue Oct 11, 2018 · 30 comments
Open

Register-EngineEvent Powershell.Exiting does not work. #8000

danielniccoli opened this issue Oct 11, 2018 · 30 comments
Labels
Issue-Bug Issue has been identified as a bug in the product WG-Engine core PowerShell engine, interpreter, and runtime WG-NeedsReview Needs a review by the labeled Working Group
Milestone

Comments

@danielniccoli
Copy link
danielniccoli commented Oct 11, 2018

Steps to reproduce

Register-EngineEvent -SourceIdentifier Powershell.Exiting -Action { Set-Content -Value "Hello there." -Path "$env:TEMP\General Kenobi.txt" }
exit

Instead of exit, the user may also close the Powershell with the x-Button.

Expected behavior

I expect that Powershell executes every command in the -Action parameter before it exits. In this case, I expected that a file General Kenobi.txt would have been written to $env:TEMP.

Actual behavior

Powershell does not execute the action in any case. Not when exiting via exit command and not when exiting by pressing the x-button of the powershell console window.

This not only happens in PS6 but also in PS5.

Environment data

> $PSVersionTable

Name                           Value
----                           -----
PSVersion                      6.1.0
PSEdition                      Core
GitCommitId                    6.1.0
OS                             Microsoft Windows 10.0.17763
Platform                       Win32NT
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0...}
PSRemotingProtocolVersion      2.3
SerializationVersion           1.1.0.1
WSManStackVersion              3.0
@vexx32
Copy link
Collaborator
vexx32 commented Oct 11, 2018

This may be related to #6862, perhaps?

@iSazonov iSazonov added WG-Engine core PowerShell engine, interpreter, and runtime Issue-Discussion the issue may not have a clear classification yet. The issue may generate an RFC or may be reclassif labels Oct 12, 2018
@danielniccoli
Copy link
Author
danielniccoli commented Dec 11, 2018

Any news on this? I am still experiencing this issue with the current preview.

> $PSVersionTable

Name                           Value
----                           -----
PSVersion                      6.2.0-preview.3
PSEdition                      Core
GitCommitId                    6.2.0-preview.3
OS                             Microsoft Windows 10.0.15063
Platform                       Win32NT
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0...}
PSRemotingProtocolVersion      2.3
SerializationVersion           1.1.0.1
WSManStackVersion              3.0

@danielniccoli
Copy link
Author
danielniccoli commented Mar 14, 2019

Oddly enough, the following code works. But only if PS is exited via exit command. Closing by pressing the x-button does not trigger the event.

Register-EngineEvent -SourceIdentifier PowerShell.Exiting -Action {
    "PowerShell exited at {0}" -f (Get-Date) | 
        Out-File -FilePath "$env:TEMP\powershell.log" -Append
}

@danielniccoli
Copy link
Author

@vexx32 #6862 was fixed and merged. I just built from source (master) and the issue still exists.

@mklement0
Copy link
Contributor
mklement0 commented Mar 26, 2019

There are several factors at play here:

  • The event never kicks in if PowerShell is not in control of its own termination: Thus, closing the window / quitting the terminal emulator will not run the event handler.

    • This may be a fundamental limitation that is here to stay, but perhaps someone more knowledgeable in this area can tell us.
  • When PowerShell does exit by itself (whether normally or via a script-terminating error generated with throw), the handler does run, but attempts to use of much of PowerShell's regular functionality fail quietly, which is what you saw:

    • When your code is run in-process in a PowerShell session, it does work for me on exit-ing that session.

    • By contrast, if I run it via the CLI (pwsh -c ...) - whether from PowerShell or cmd.exe / Bash - it fails (see test command below). What seems to happen (I'm speculating) is that at the time the script block executes, all modules except Microsoft.PowerShell.Utility have already been unloaded, and attempts to use their commands fail silently and abort execution of the script block instantly.

      • Set-Content is part of module Microsoft.PowerShell.Management, and therefore unavailable; if I substitute Out-File in your command, which comes with Microsoft.PowerShell.Utility, the script block works as expected.
    • In either invocation scenario you also cannot use Write-Output or implicit output to send output to the display (redirection to a file works, though) - only Write-Host is effective.

At the very least, the documentation needs to be improved to clarify the constraints: I've asked for that in MicrosoftDocs/PowerShell-Docs#4061.

Here's a test command via the CLI that demonstrates that the handler is invoked, but fails when Set-Content is called:

# Call from PowerShell itself or Bash.
pwsh -nop -c '$null = Register-EngineEvent -SourceIdentifier Powershell.Exiting -Action { write-host before; try { Set-Content -ErrorAction stop -Value (Get-Date) -Path ~/t.txt } catch { write-host $_.ToString() }; write-host after }'

# Call from cmd.exe.
pwsh -nop -c "$null = Register-EngineEvent -SourceIdentifier Powershell.Exiting -Action { write-host before; try { Set-Content -ErrorAction stop -Value (Get-Date) -Path ~/t.txt } catch { write-host $_.ToString() }; write-host after }"

The above yields:

before
The 'Set-Content' command was found in the module 'Microsoft.PowerShell.Management', but the module could not be loaded. For more information, run 'Import-Module Microsoft.PowerShell.Management'.
after

@danielniccoli
Copy link
Author
danielniccoli commented Apr 5, 2019

@mklement0 Michael, thanks for addressing this. Your explanations make sense. I'm not sure what to do with this issue, though.

On one hand, this is actually by design and I probably should close my ticket.

On the other hand, the design should be improved in my opinion. The exiting Register-EngineEvent should be fired before anything is unloaded. The PowerShell would greatly benefit from that. The use-case where I actually found out about this event was to disconnect from all open Office 365 sessions when you forgot to explicitly disconnect before closing the Window. So you don't end up being locked out until the stale sessions expire. Which doesn't work when the modules are already unloaded when the event fires.

Another improvement would be to pass the close-event from the window to the Powershell, so it fires when you close by ALT-F4 or pressing the X. Most PowerShell users are using it on Windows and not on Linux, where you would actually have to run the exit command explicitly. Should I open another issue for that, or is it better to discuss this here? The context is already there.

@mklement0
Copy link
Contributor

All good points, @Borkason.

I suggest we get started here by asking for feedback from a subject-matter expert about the original design intent, what could be improved, and what cannot be changed for technical reasons.

@SteveL-MSFT, can you help?

@SteveL-MSFT SteveL-MSFT added the Issue-Enhancement the issue is more of a feature request than a bug label Apr 17, 2019
@fakcan
Copy link
fakcan commented Apr 19, 2019

I'm having the same issue, and looking forward to see any progress on enhancement.

@lzybkr
Copy link
Contributor
lzybkr commented Apr 19, 2019

The Win32 Console api su 8000 pports notifying a console application that it is closing and PowerShell is supposed to receive that notifcation here.

I know this mechanism works because PSReadLine uses it to avoid a ~6s delay when you click the X to exit. It's possible PSReadLine is getting in the way of PowerShell receiving the notification and hence not firing the event - so I'd test without PSReadLine loaded.

@ghost
Copy link
ghost commented Jul 17, 2019

I tested with Register-EngineEvent -SourceIdentifier PowerShell.Exiting -Action {Set-Content $env:TEMP/test.txt "PowerShell died."} (deleting the file when it appeared) in PowerShell 5.1.18362.145 and PowerShell 6.2.1 on Windows and a variety of exit types, and I put together a table to summarize the results.

Version exit End of -Command throw 'fatal' (via -Command) Close button
5.1 Works Works Works Broken
6.2.1 Broken Broken Broken Broken

Remove-Module PSReadLine seemed to have no effect.

@SteveL-MSFT
Copy link
Member

I tried this (explicit exit command) on Windows and macOS and both the exit event triggers the scriptblock and the file is created. Used 6.2.1 and 7-Preview.2.

@ghost
Copy link
ghost commented Jul 25, 2019

That's strange. What code did you use? Edited my previous comment to note that it was only on Windows.

@SteveL-MSFT
Copy link
Member

I used your example above: Register-EngineEvent -SourceIdentifier PowerShell.Exiting -Action {Set-Content $env:TEMP/test.txt "PowerShell died."}

I only checked with explicit exit, but the file was created with that content consistently.

@danielniccoli
Copy link
Author

I can confirm that with PowerShell 7-Preview.2 the issue is fixed, when using exit.
⚠️ But not when using the close button.

I even tried a command that takes considerably more time.

Register-EngineEvent -SourceIdentifier Powershell.Exiting -Action { Set-Content -Value (get-module -ListAvailable -All) -Path "$env:TEMP\General Kenobi.txt" }
exit

@danielniccoli
Copy link
Author
danielniccoli commented Oct 15, 2019

@SteveL-MSFT any update on this? It would be great if we would see this working when PowerShell 7 is released. This would be a great benefit for automatically gracefully terminating any forgotten open PSSession before the window is closed. Especially helpful when working with Exchange Online or other Office 365 services that block you out if you forgot to close the sessions.

Ps, happy belated birthday to this issue! 🎂 🎁

@anmenaga anmenaga self-assigned this Oct 15, 2019
@danielniccoli
Copy link
Author

I also just noticed that this is labeled as a discussion, but shouldn't it be a bug if the Exiting event does not trigger when closing the PowerShell with the X button?

@anmenaga anmenaga added Issue-Bug Issue has been identified as a bug in the product and removed Issue-Discussion the issue may not have a clear classification yet. The issue may generate an RFC or may be reclassif Issue-Enhancement the issue is more of a feature request than a bug labels Oct 15, 2019
@anmenaga
Copy link

Looks like a bug to me; the code that is supposed to handle this scenario is there but it is not working.
For console close button scenario - in debugger i see that ConsoleBreakSignal.Close event is received by ConsoleHost, but (unlike exit scenario) the action in EventManager is not invoked. This needs more investigation.
PSReadLine does not seem to have any effect; I've tried the scenario with and without it - result is the same for close button scenario.

@SteveL-MSFT SteveL-MSFT added this to the 7.0-Consider milestone Oct 15, 2019
@isxaker
Copy link
isxaker commented May 25, 2020

Any updates so far ?

@ExtremeFiretop
Copy link
ExtremeFiretop commented Feb 11, 2022

Just an FYI. Subbing to this thread as well. Found this while currently working on a script with the same issue. Compiled to a .exe it works but PowerShell ISE throws exceptions. The app being designed is without GUI and is designed to work in the background as an Tasktray icon. If you right click the Tasktray the icon scripted and select the manual exit from the generated forms submenu, it works. If you open the "addition info" prompt from the submenu and close with the X instead of a graceful exit it throws exceptions... Would be nice if we could handle the closure event with the X.

@shuffle2
Copy link

In my scenario, I tried to use Powershell.Exiting in a script which gets called by Task Scheduler. I discovered that powershell does not invoke the Action if Task Scheduler kills the task (for example, because it ran too long).

@bzm3r
Copy link
bzm3r commented Jul 13, 2023

I am finding a need for this too, just in order to properly trigger clean up functions from the profile.

@SteveL-MSFT What are the main blockers for this?

@SteveL-MSFT
Copy link
Member

It looks like the process is killed before the handler has a chance to run.

@SteveL-MSFT
Copy link
Member

It also appears that .NET has added support for POSIX signals (and translating Windows events), so maybe that can be leveraged https://github.com/dotnet/runtime/blob/904ab9a034c0d8f3ef33579db79c87a6fad70acd/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/PosixSignalRegistration.Windows.cs#L87

@bzm3r
Copy link
bzm3r commented Aug 4, 2023

It also appears that .NET has added support for POSIX signals (and translating Windows events), so maybe that can be leveraged https://github.com/dotnet/runtime/blob/904ab9a034c0d8f3ef33579db79c87a6fad70acd/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/PosixSignalRegistration.Windows.cs#L87

Ah, nice! Is the current, Windows-specific behaviour a bug, or a feature?

@microsoft-github-policy-service microsoft-github-policy-service bot added the Resolution-No Activity Issue has had no activity for 6 months or more label Jan 31, 2024
@ParadoxGBB
Copy link

I need this as well for cleanup purposes for my project, so I would love if this could please be considered in a future release.

If the goal is full parity with Windows PowerShell, Core should take it if they can, if not, should remove the feature from Core. As it stands people read the documentation and get confused when it doesn't work.

@microsoft-github-policy-service microsoft-github-policy-service bot removed the Resolution-No Activity Issue has had no activity for 6 months or more label Jan 31, 2024
@aooohan
Copy link
aooohan commented Mar 13, 2024

I need this as well for cleanup purposes for my project, so I would love if this could please be considered in a future release.

If the goal is full parity with Windows PowerShell, Core should take it if they can, if not, should remove the feature from Core. As it stands people read the documentation and get confused when it doesn't work.

Agree! I have the same purpose for cleanup, but the documentation is really confusing. 😮‍💨

aooohan added a commit to version-fox/vfox that referenced this issue Mar 13, 2024
… when the shell open.

When powershell is closed via the x button, this event will not be fired.
 See PowerShell/PowerShell#8000
ShizheChang pushed a commit to ShizheChang/vfox that referenced this issue Mar 14, 2024
… when the shell open.

When powershell is closed via the x button, this event will not be fired.
 See PowerShell/PowerShell#8000
@5HT2
Copy link
5HT2 commented Aug 9, 2024

Any updates on getting this pushed to stable?

@kilasuit kilasuit added the WG-NeedsReview Needs a review by the labeled Working Group label Aug 14, 2024
@danmacode
Copy link
danmacode commented Apr 17, 2025

@aooohan @5HT2 did you find a way to get this to work?

I'm forced to do cleanups with either trap [System.Exception] { Cleanup } or try { ... } finally{ Cleanup }.

@5HT2
Copy link
5HT2 commented Apr 26, 2025

@danmacode this appears to work now (Powershell 7.4.6):

# Helper to register disconnecting exchange when closing
function Register-DisconnectExchange {
    $null = Register-EngineEvent PowerShell.Exiting –Action {
        Write-ColoredMessage "Disconnecting from Exchange Online..." "Yellow"
        try {
            Disconnect-ExchangeOnline -Confirm:$false
        }
        catch {
            Write-ColoredMessage "Failed to disconnect from Exchange Online." "Red"
        }
    }
}

@danmacode
Copy link
danmacode commented May 2, 2025

@5HT2 sadly, it does not work for me (PowerShell 7.5.1), it only outputs the following:

Id     Name            PSJobTypeName   State         HasMoreData     Location             Command
--     ----            -------------   -----         -----------     --------             -------
4      PowerShell.Exi…                 NotStarted    False                                …

Will try with 7.4.6...

EDIT: I tried in WSL with 7.5.0 and it works, whether exiting normally or using CTRL+D, the snippet is executed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Issue-Bug Issue has been identified as a bug in the product WG-Engine core PowerShell engine, interpreter, and runtime WG-NeedsReview Needs a review by the labeled Working Group
Projects
None yet
Development

No branches or pull requests

0