-
Notifications
You must be signed in to change notification settings - Fork 7.1k
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
Read-Host
should have a -TimeoutSecond
parameter
#19664
Comments
This comment was marked as outdated.
This comment was marked as outdated.
hi all guys: |
Hmmm. I only see read host being used (a) where the program is written like 1970s BASIC
(b) Where people are using it as "Hit enter to continue", and here having a time out might help. |
As @SeeminglyScience pointed out, we think this would require an async |
That's also a can of worms though. We only got away with that in PSES because of the |
I would like to raise the stakes here and say that why can we not have a termination mechanism on any command, rather than piecemeal by each Cmdlet? A PowerShell command is invoked with a new PowerShell and that has a StopAsync method. So in theory any command or pipeline can be stopped. The standard mechanism in dotnet core is to use a CancellationToken for a client/caller to indicate when a command should be cancelled. So instead of each command having a timeout parameter, you could add CancellationToken support to Invoke-Command so that would do the equivalent of the following
Ideally each PowerShell Runspace should have a global CancellationToken so that code that is not in a Cmdlet can know when to terminate, also when invoking a new command the new CancellationToken should both be cancelled by the current cancellation token and allow it to set new criteria for the new invocation scope. This means that any code could set up a CancellationToken for their current local requirements and then use Invoke-Command to use that for the child script block. In this scenario the Invoke-Command would accept a script block, arguments and cancellation token. In the case of the the cancellation token being invoked it would throw an exception.
If nested/child PowerShell invocations already propagate the Stop/StopAsync then the global cancellation token might not be required. It could be even better if every command accepted a cancellation token directly with CommonParameters where that automatically stopped the command when the cancellation was triggered and threw an exception. |
There should also be a parameter here: |
Unfortunately the Read-Host Cmdlet does not respond to the PowerShell being stopped. Although Microsoft.PowerShell.PSConsoleReadLine does implement a ReadLine that takes a CancellationToken it doesn't work until a key has been entered.
So even though the five seconds has elapsed, the ReadLine does not return until a key has been pressed. |
It doesn't cancel properly due to the issues I outlined above. In PSES we make it work by injecting our own A generic cancellable |
On Linux/POSIX input can be done with non-blocking IO and select/read after using cfmakeraw on file description zero On Windows, ( I have not tried this ) you can use WaitForSingleObject on the file descriptor from GetStdHandle(STD_INPUT_HANDLE). Then use GetNumberOfConsoleInputEvents to determine if anything to process. This is documented at ReadConsoleInput. In this the only thing blocking is the WaitForSingleObject, but I don't see an issue with a single background thread per process dedicated to reading that once you have loaded PSReadLine module. |
Keep in mind that the amount of code that it takes the BCL to translate VT input into uniform structures we can use is quite large and updated somewhat frequently. In PSES we did a variant of what you're referring to in order to poll for input pending. At the time I did not see a way to do a non-blocking read while still retaining the console attributes we needed and not consume the input anyway when cancelled (ofc I didn't look very hard either as it would have meant reimplementing everything the BCL does, definitely last resort). That's not to say that we can never duplicate code that is in the BCL, but the impact needs to match the maintenance cost.
Both of those can still be used to poll for input, but that's not free either. If you're polling then it's very difficult not to create some lag somewhere or end up using too much CPU. In PSES we had staged timeouts depending on when the last key press was but even that ended up a little janky in some places (after a long pause there was noticeable delay in the first key stroke, right click copy paste was very slow). That was something we dealt with in PSES because the impact was very high. If you can't actually cancel reading input, then you can't step through code with the debugger, I do not personally think that |
Thank you for that overview. You could treat a console app much like a traditional GUI app. Just like a windows app has GetMessage/TranslateMessage/DispatchMessage at its heart, you could do similar with a console app where you have one component that is responsible for waiting, reading and writing to the actual console and dispatches the different console input depending on its type ( windows size changes, keyboard input, signals, mouse movements and clicks). I notice that if you just run a script by itself then PSReadLine is not loaded until it is needed, and an interactive PowerShell loads it straight away. So you could say that once PSReadLine is loaded it owns the console and other components need to read the content and write their output through it. So nobody needs to read the console input directly or peek ahead because the PSReadLine message loop would process all that and dispatch the input to the various handlers, eg updating size of the window or location of the cursor. Just like a GUI app, different threads would need to effectively get the focus for input. If a line was being input and edited for a given Cmdlet invocation and that was stopped/cancelled then the entire line could be thrown away because the purpose for the entry has now gone. Each new request of a line starts from scratch, it does not need to get previously typed ahead data that was entered before the current readline request is made. Just a thought. |
This issue has not had any activity in 6 months, if this is a bug please try to reproduce on the latest version of PowerShell and reopen a new issue and reference this issue if this is still a blocker for you. |
1 similar comment
This issue has not had any activity in 6 months, if this is a bug please try to reproduce on the latest version of PowerShell and reopen a new issue and reference this issue if this is still a blocker for you. |
This issue has been marked as "No Activity" as there has been no activity for 6 months. It has been closed for housekeeping purposes. |
Summary of the new feature / enhancement
If the user input isn't strictly required and some default can be used, it may make sense to have
Read-Host
have a timeout so that the script isn't blocked indefinitely.Proposed technical implementation details (optional)
Would need to show the timeout, default, and countdown.
The text was updated successfully, but these errors were encountered: