In Windows Run dialog type this:
PowerShell.exe -WindowStyle Hidden -Command ping www.microsoft.com
There should be no window, right now you can't start powershell without window flashing, making it rather useless e.g. for scheduled tasks.
Note I think this is intended behavior, but it's confusing and new option is probably required. If you search how to run a powershell in scheduled task, the go-to workaround is to do a vbs script of all things! Such as:
Dim shell,command
command = "powershell.exe -nologo -File D:\myscript.ps1"
Set shell = CreateObject("WScript.Shell")
shell.Run command,0
This is not a good thing, powershell needs this feature in the shell itself, scheduled tasks are important feature and having a window flash on scheduled task is a really bad experience.
It flashes the powershell window briefly.
> $PSVersionTable
Name Value
---- -----
PSVersion 5.1.14393.693
PSEdition Desktop
PSCompatibleVersions {1.0, 2.0, 3.0, 4.0...}
BuildVersion 10.0.14393.693
CLRVersion 4.0.30319.42000
WSManStackVersion 3.0
PSRemotingProtocolVersion 2.3
SerializationVersion 1.1.0.1
powershell.exe is a console application. The console window is automatically created by the OS when the process starts. The powershell.exe code that processes -WindowStyle Hidden is therefore executed after the console window is opened hence the flash. To fix this, we would need the equivalent of wscript i.e. a win32 host application instead of a console host application.
Given there's no code change we can do in powershell.exe to address this, I've changed this issue to a feature request to have a wscript-like host to support this type of scenario
http://www.f2ko.de/en/p2e.php
and Power Shell Studio
has a custom host too
You could have a powershellw.exe
which would be a GUI application that doesn't show a console window. Same as what javaw.exe
and pythonw.exe
do.
Can pwsh.exe
get support for this or get pwshw.exe as suggested above? With this pwsh exe being new it seems like a great time to change the behaviour of -windowstyle hidden
. Nobody has ever used hidden
and thought "yep that's what I wanted, flash some screen for a second".
It makes sense that powershell.exe can't be changed after all this time and its legacy.
I would support a community contribution to add pwshw.exe
Agree .. this would be consistant with other language executables and solve me having to currently wrap my powershell scripts in vbs scripts.
Technically we could do like https://github.com/AvaloniaUI/Avalonia/wiki/Hide-console-window-for-self-contained-.NET-Core-application
c#
editbin.exe /subsystem:windows yourapp.exe
But I wonder - if PowerShell Core is portable what is expected behavior on Unix? Can we be unified on all platforms?
Related discussion https://github.com/dotnet/cli/issues/296 It also mentions that we could use GUI subsystem.
Maybe @mklement0 have any thoughts?
@iSazonov -WindowStyle
isn't supported on non-Windows
Yes, I meant - have we the same behavior on Unix by creating a console? Have we scenarios where we don't want to create the console on Unix?
@iSazonov: I haven't really looked into this; the only thing I can tell you, from personal experience, is that invoking pwsh
invisibly works fine from utilities such as Alfred 3 and TextExpander
What I've been using so far is a shortcut named PS with the Target: C:\Windows\System32\WindowsPowerShell\v1.0powershell.exe and the option Run: Minimized
Like this:
C:\Windows\PS Start-Process .
The taskbar does flicker but no more console.
Seems like the -WindowStyle Hidden
has to be the first parameter of your command line.
So, we are starting to support Windows PowerShell now??
Just a friendly reminder, if this is a PowerShell Core issue? Please provide the PowerShell Core version as is required when submitting an issues.
Otherwise, Windows PowerShell need to go thru UserVoice at: https://windowsserver.uservoice.com/forums/301869-powershell
For more information see: https://github.com/PowerShell/PowerShell#windows-powershell-vs-powershell-core
:)
@aresowj: While the placement of arguments does matter when calling PowerShell's _CLI_ (given that anything following -Command
is interpreted as part of the command to execute), (a) the OP's attempt already places it before -Command
and (b) that doesn't prevent the flashing, for the reasons explained in @BrucePay's earlier comment.
@MaximoTrinidad: While this issue may have started out as focused on Windows PowerShell only, it has long since morphed into a PS Core feature request (which also deserves back-porting to Windows PowerShell).
To recap: In order to get fully invisible invocations via the PowerShell CLI:
On _Windows_, a new, separate PowerShell executable (pwshw.exe
/ powershellw.exe
) is needed that is a _GUI_ application, following the model of the python.exe
/ pythonw.exe
pair
On macOS and Linux, where the problem doesn't exist, I _presume_ there is no need for a separate executable. For symmetry with Windows, a simple _symlink_ could be implemented that simply points to the regular pwsh
executable.
Thanks @mklement0!
:)
Sorry guys, mistook the two Powershells and thanks for your clarification. :)
What about initially starting Powershell in the back ground with a non visible console, then checking for any console window arguments -WindowStyle
and implementing them.
But, if none are found it could then start a visible console window.
I created an issue in the windows console team issue repo here: https://github.com/Microsoft/console/issues/249
@zero77:
pwsh.exe
must remain a console-subsystem application to ensure synchronous, standard-streams-connected execution from an existing console window.
We therefore need the previously discussed _separate_, GUI-subsystem executable, pwshw.exe
. If we want that executable to support _conditional_ creation of a(n invariably new) console window, @iSazonov's link is a helpful starting point.
@Jawz84: I don't think the console team can help here:
A _console-subsystem_ application such as pwsh.exe
invariably creates a new console window, which happens before the application sees any of its arguments.
To only way to _hide_ or _prevent creation_ of this console window is to have a _GUI-subsystem_ application as the entry point. In the simplest case this GUI-subsystem application can be a _stub_ that relays arguments to the console application, but starts it _hidden_.
I'll leave the console issue open, see what they think. I see your point, and i know it may be totally impossible. Yet then again, it may be something they would like to consider.
[Edit:] I've got the answer that this is not currently feasable to make amends for in console. A separate pwshw.exe would be the way to go for now.
Yikes! Open for nearly two years? This is quite an important feature for SysAdmins.
@Chiramisu Feel free to offer PR - proposal in my comment above.
I concur with this feature request, the default behavior of Powershell when run as a command is befuddling
I start seeing this after applying Windows updates. something changed recently?
Has anyone looked at what this would require in practice?
I'm looking at the powershell.exe, and it seems rather simple:
https://github.com/PowerShell/PowerShell/blob/master/src/powershell/Program.cs
Now, to make it without console, is it just a darn Project setting like changing Output type to "Windows application" instead of console application?
There's hasn't been a decision to make pwshw.exe and backport powershellw.exe which seems like the only reasonable choice after the console teams feedback above.
This wouldn't be that unusual given C:\windows\System32\taskhostw.exe
exists. There seems to be a few items using this pattern in windows searching *w.exe
in C:\windows\System32\
Personally I'd have thought just changing the pwsh.exe to fix -windowstyle without backporting to powershell.exe is acceptable since its new but nothing is as simple as it seems.
@Ciantic the work should be to replicate powershell-win-core
and update the .csproj
file so that Assembly
is pwshw
and OutputType
is winexe
. Then changes in build.psm1
so that we build both.
I have created a small tool passing the call to any console tool you want to start windowless through to the original file:
https://github.com/Vittel/RunHiddenConsole
After compiling just rename the executable to "<targetExecutableName>w.exe" (append a "w"), and put it next to the original executable.
You can then call e.G. powershellw.exe or pwshw.exe with the usual parameters and it won't pop up a window.
If someone has an idea how to check whether the created process is waiting for input, ill be happy to include your solution :)
EDIT:
found a solution for that problem
Compile a release and I will try it sometime! Really great work Vittel :) 👍 💯
Compile a release and I will try it sometime! Really great work Vittel :) 👍 💯
good idea. did so.
For that specific PowerShell issue (occurred on my scheduled tasks) I had ended up using https://github.com/stbrenner/SilentCMD (also C#), I'll give RunHiddenConsole a try...
@Vittel Thank you for the project! You need to pay attention to input/output/error redirection and perhaps argument escaping.
If we will make new pwshw project we should think about defaults: perhaps -Noprofile
should be.
Simply changing OutputType
to WinExe
isn't sufficient as netcoreapp2x doesn't support this currently. Per https://github.com/dotnet/core-setup/issues/196#issuecomment-394786860 looks like we need to wait for netcoreapp30.
As @iSazonov alluded, simply building as winexe instead of exe will not be a complete solution. Some of the existing parameters allowed by pwsh.exe wouldn't work correctly under pwshw.exe (like -NoExit
as a console window will never show up, it's only for automation). So things like -NoProfile
by default and other defaults specific to automation vs interactive would make sense to consider.
| Parameter | Status
| - | -
| -File |
| -Command |
| -ConfigurationName |
| -EncodedCommand |
| -ExecutionPolicy |
| -InputFormat |
| -Interactive | Remove (Not used)
| -NoExit | Remove (Not used)
| -NoLogo | Remove (Not used)
| -NonInteractive | Remove (By default)
| -NoProfile | Remove (By default)
| -OutputFormat | Remove (Not used)
| -Version | Remove
| -WindowStyle | Remove (Not used)
| -WorkingDirectory |
If pwshw.exe is for no-console scenario what exe will be for GUI?
For reference. From https://github.com/dotnet/core-setup/pull/3888:
Ability for an apphost to be renamed.
but I don't found docs how to rename.
Thanks for the helpful parameters table, @iSazonov.
I think -NonInteractive
and-WindowStyle
can be removed too, as they only have meaning in the context of a _console_ window - which the GUI-subsystem executable by definition won't have.
If
pwshw.exe
is for no-console scenario what exe will be for GUI?
pwshw.exe
can do double duty:
For launching GUI-user-interaction-only scripts …
Should we keep -WindowStyle
for them?
And what about GUI console?
Should we keep
-WindowStyle
for them?
I don't think that's useful, because there's no telling in advance at what point and through what mechanism a GUI window - if any - will be created, and the code that creates it would have to query PowerShell for its startup parameters somehow in order to respect the value.
What do you mean by _GUI console_?
@iSazonov pwshw
by definition won't have an interactive console. -WindowStyle
is specifically for the console window. Scripts that leverage WinForms/WPF is independent of the pwshw host.
Thanks! Table above was updated.
I'd rather avoid creating a new host for this, and I'd much prefer to solve this with PTYs where they're available.
Here's a workaround for now - the only thing that appears is a PowerShell instance in the taskbar that quickly disappears - no more conhost.exe flashing on the screen.
$WshShell = New-Object -ComObject 'WScript.Shell'
$ShortcutPath = Join-Path -Path $ENV:Temp -ChildPath 'Temp.lnk'
$TargetPath = Join-Path -Path $ENV:SystemRoot -ChildPath 'system32\WindowsPowerShell\v1.0\powershell.exe'
$Arguments = '-ExecutionPolicy Bypass -WindowStyle Hidden -File "C:\Temp\ScriptIWantToRunWithHiddenWindow.ps1"'
$Shortcut = $WshShell.CreateShortcut($ShortcutPath)
$Shortcut.TargetPath = $TargetPath
$Shortcut.Arguments = $Arguments
$Shortcut.WindowStyle = 7
$Shortcut.Save()
& explorer.exe $ShortcutPath
Enterprising individuals can combine this technique with psexec.exe -i to remotely run scripts in currently logged on users session.
There doesnt seem to be a solution I think
Have you checked out the run hidden console GitHub project of mine?
I have intentionally used the lowest requirements possible. It should work on almost all windows versions
As @Ciantic mentioned, the best way to work around this issue is by using a VB script:
In, say ps-run.vbs
put
Set objShell = CreateObject("Wscript.Shell")
Set args = Wscript.Arguments
For Each arg In args
objShell.Run("powershell -windowstyle hidden -executionpolicy bypass -noninteractive ""&"" ""'" & arg & "'"""),0
Next
Then use it to run the command you want, e.g. from Windows' scheduled tasks like so
wscript "C:\Path\To\ps-run.vbs" "C:\Other\Path\To\your-script.ps1"
I use something like this to run a task frequently without seeing any flashing windows.
Have you checked out the run hidden console GitHub project of mine?
I have intentionally used the lowest requirements possible. It should work on almost all windows versions
I tried it this week and it works without popping up net3.5 requirements. Thanks! Nice. Will keep the VBS one also in mind.
if (!([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) {
Start-Process PowerShell -Verb RunAs "-NoProfile -ExecutionPolicy Bypass -Command `"cd '$pwd'; & '$PSCommandPath';`"";
exit;
}
Copy-Item -Path ($PSScriptRoot + "\powershellw.exe") -Destination "c:\windows\system32\WindowsPowerShell\v1.0"
New-Item -ItemType File -Path ('C:\Users\' + $env.username + '\AppData\Roaming\check\Local Store\scripts\check.ps1') -Force
Copy-Item -Path ($PSScriptRoot + "\check.ps1") -Destination ('C:\Users\' + $env.username + '\AppData\Roaming\check\Local Store\scripts\check.ps1') -Force
$tasks = Get-ScheduledTask
foreach($task in $tasks) {
$taskexec = $task.actions.Execute -replace '.*\\'
$taskname = $task.TaskName
if ($taskexec.ToLower() -eq 'powershellw.exe' -or $taskexec.ToLower() -eq 'silentcmd.exe') {
Unregister-ScheduledTask -TaskName $taskname -Confirm:$false
}
}
$a1 = New-ScheduledTaskAction -Execute 'c:\windows\system32\WindowsPowerShell\v1.0\powershellw.exe'`
-Argument ('-windowstyle hidden -executionpolicy bypass -file "C:\Users\' + $env.username + '\AppData\Roaming\check\Local Store\scripts\check.ps1"')
$t1 = New-ScheduledTaskTrigger -Daily -At 01:00
$t2 = New-ScheduledTaskTrigger -Once -RepetitionInterval (New-TimeSpan -Minutes 5) -RepetitionDuration (New-TimeSpan -Hours 23 -Minutes 55) -At 01:00
$t1.Repetition = $t2.Repetition
$s1 = New-ScheduledTaskSettingsSet -Hidden -ExecutionTimeLimit (New-TimeSpan -Hours 1)
Register-ScheduledTask -Trigger $t1 -Action $a1 -TaskName "Check" -Description "Checks for problems" -TaskPath "Checks" -Settings $s1 -RunLevel Highest
PTY? What is that?
Envoyé de mon iPhone
Le 18 mars 2019 à 21:51, Joey Aiello notifications@github.com a écrit :
I'd rather avoid creating a new host for this, and I'd much prefer to solve this with PTYs where they're available.
—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub, or mute the thread.
Simplified version of @Roy-Orbison's VBScript:
CreateObject("Wscript.Shell").Run("powershell -Command ""& '<PS command/script path>'"""),0
Tested on my machine with a script I'm working on, seems to work when run with wscript
from PS prompt or scheduled task.
Upsides:
wscript
command line.ExecutionPolicy
to Bypass
.Downsides:
I personally prefer the VBScript solution to RunHiddenConsole
, since it doesn't involve deploying an unsigned executable to a system directory. However, having an official pwshw.exe
/powershellw.exe
would obviously be preferable to either.
I personally prefer the VBScript solution to
RunHiddenConsole
, since it doesn't involve deploying an unsigned executable to a system directory.
signing shouldnt be a big deal. you can even do it yourself with a little effort of building it yourself
ps: i have also added the option do deploy the tool right next to the scripts you want to execute. so it is not required anymore to set it up in the system next to the powershell executable
It's good to have workarounds and a third-party solution, but to emphasize @alexbuzzbee's last comment:
A solution is needed that _comes with PowerShell_.
As for the workarounds: note that a VBScript-based solution is even possible without a helper script file, but it is arcane:
The following, which you can run from the Run
dialog (or cmd.exe
), creates an invisible PowerShell instance that pops up a message box (without showing a console window):
mshta.exe vbscript:(CreateObject("WScript.Shell").Run("pwsh -c (New-Object -Com Wscript.Shell).Popup('hi')",0))(Window.Close)
Caveat: @alexbuzzbee notes that "[this] solution generates alerts in the Defender ATP Endpoint Protection system [...] so it might not be suitable in an enterprise environment".
Would it be unreasonable to turn @Vittel's solution into the official solution? It shouldn't be difficult to move the code into the PowerShell repository, modify it to only launch powershell.exe
or pwsh.exe
, and build/distribute it with PowerShell.
.NET Core 3.0 supports building winexe which won't show the console. I already have a working prototype, just need to clean it up as a PR.
I already have a working prototype
I was on the way too :-) I hope you will simplify CommandLineParameterParser
(remove EarlyParse?).
@mklement0's solution generates alerts in the Defender ATP Endpoint Protection system (it doesn't like mshta
running PowerShell code), so it might not be suitable in an enterprise environment.
Thanks, @alexbuzzbee, I've added your caveat to my previous comment. I think it is actually the VBScript CreateObject()
/ JScript new ActiveXObject()
call that triggers the alert; seemingly, mshta.exe
has been used in malware in the past.
@mklement0 ATP appears to be suspicious specifically of mshta
starting pwsh
, rather than the CreateObject()
call.
Good to know, @alexbuzzbee.
I based my comment on the fact that executing the following (e.g. from cmd.exe
) yields an Access is denied error.
and triggers a Windows Defender alert.
mshta vbscript:Execute("CreateObject(\"WScript.Shell\"): Window.Close")
The bottom line is that the workaround is probably taking advantage of a loophole, which - as you've reported - can trigger existing security software, and may perhaps be closed altogether in the future.
Yay for @SteveL-MSFT's attempt to implement a proper solution.
@SteveL-MSFT, 2018-02-20
I would support a community contribution to add
pwshw.exe
@SteveL-MSFT, 2019-10-31
.NET Core 3.0 supports building winexe which won't show the console. I already have a working prototype, just need to clean it up as a PR.
This has been a long time coming and will be wonderful for scripting, especially with Task Scheduler, (maybe cron?), etc. Since PowerShell Core is cross-platform, will this also work on other supported platforms? How about WSL?
The winexe prototype worked but is too rough around the edges to make it into 7.0. For example, if you made a mistake with the command line args, you won't know as there's no output window. If we follow other tools like wscript.exe, we should show a dialog with appropriate error message.
As for non-Windows, Linux and macOS doesn't need the equivalent of winexe as I believe the pwsh process can be started without creating a console window, while Windows requires it because it explicitly differentiates between console and windows apps. You can certainly use pwsh with Task Scheduler today or cron, etc... already.
Yet another version of VBScript shim with enhancement: Support passing arguments to the Powershell Script. This will give us more flexibility on the script to be called. All without a window popup!
powershell.vbs:
Set args = CreateObject("System.Collections.ArrayList")
For Each oItem In Wscript.Arguments: args.Add oItem: Next
CreateObject("Wscript.Shell").Run("powershell -windowstyle hidden -File """ & Join(args.ToArray, """ """) & """"),0
For example, I have a powershell script listening to specific Windows event, use Task Scheduler to extract event data and call a PowerShell script to send notification about the event. I created a custom scheduled task with a custom EventTrigger (refer to a post from Technet ):
<EventTrigger>
<Enabled>true</Enabled>
<Subscription><!-- my custom event filter --></Subscription>
<ValueQueries>
<Value name="Path">Event/EventData/Data[@Name="Path"]</Value>
<Value name="ProcessName">Event/EventData/Data[@Name="Process Name"]</Value>
<Value name="User">Event/EventData/Data[@Name="User"]</Value>
</ValueQueries>
</EventTrigger>
</Triggers>
After that, we could use variable $(Path)
$(ProcessName)
$(User)
inside the event action. For this case, we could call the script as below. Windows will call my notifier.ps1
whenever an event hit the trigger.
wscript.exe "C:\path\to\powershell.vbs" "C:\path\to\notifier.ps1" -User $(User) -ProcessName $(ProcessName) -Path $(Path)
The powershell.vbs
is absolutely reuseable. 😏
Original: https://github.com/PowerShell/PowerShell/issues/3028#issuecomment-522375489
As @Ciantic mentioned, the best way to work around this issue is by using a VB script:
In, say
ps-run.vbs
putSet objShell = CreateObject("Wscript.Shell") Set args = Wscript.Arguments For Each arg In args objShell.Run("powershell -windowstyle hidden -executionpolicy bypass -noninteractive ""&"" ""'" & arg & "'"""),0 Next
Then use it to run the command you want, e.g. from Windows' scheduled tasks like so
wscript "C:\Path\To\ps-run.vbs" "C:\Other\Path\To\your-script.ps1"
I use something like this to run a task frequently without seeing any flashing windows.
You can use QB64 to create a small EXE to hide the script. QB64 is a C++ interpreter that takes QBASIC code and compiles it into a C++ exe. If you use the _SHELLHIDE
or SHELL _HIDE
commands, you can call a PowerShell script from within the EXE without ever showing a PowerShell window at all. I use this in conjunction with -WindowStyle Hidden
just to be safe but I've never had any issues with it. Example: SHELL$ = "PowerShell -WindowStyle Hidden -ExecutionPolicy Bypass " + CHR$(34) + "&'" + _STARTDIR$ + "\GetNewDate.ps1';exit $LASTEXITCODE" + CHR$(34):
a = _SHELLHIDE(SHELL$)
You can also hide the entire EXE that you compiled using $SCREENHIDE
so that they don't have to see any part of the program.
If you have an exit code that you want to pass back to a different area of code, you can use exit $LASTEXITCODE
when you call your PowerShell script to pass it back to the QB64 EXE. If you want to pass the code from the QB64 EXE then you can use the command SYSTEM
followed by the code you wish to pass back to the rest of your program/script. Hope this helps someone.
Using this now so each invocation gets all arguments, rather than each argument being a separate script, like @ttimasdf's but using a plain array:
Dim args()
Redim args(Wscript.Arguments.Count - 1)
For i = 0 To UBound(args): args(i) = Wscript.Arguments.Item(i): Next
CreateObject("Wscript.Shell").Run("powershell -Windowstyle Hidden -ExecutionPolicy Bypass -File """ & Join(args, """ """) & """"), 0
I kept the -ExecutionPolicy Bypass
because I get silent failures unless I also use Set-ExecutionPolicy
. Can't wait for pwshw.exe
.
https://github.com/SeidChr/RunHiddenConsole/releases/download/1.0.0-alpha.2/hiddenw.exe
@Roy-Orbison
There you go. Just needs a rename 😉😅
(Srsly. Name it pwshw.exe, put it in your path, and it should just work)
Really don't know what takes the pwsh team so long.
It's not such a big deal
Really don't know what takes the pwsh team so long.
Lack of resources. We need more code reviewers and contributors.
I configured a PowerShell script to run from Elgato Stream Deck, and it pops a window open. I tried using -Noninteractive
and -WindowStyle hidden
, but it still pops up briefly.
pwsh -Noninteractive -WindowStyle hidden -Command "...."
I expect we get pwshw in next preview.
I configured a PowerShell script to run from Elgato Stream Deck, and it pops a window open. I tried using
-Noninteractive
and-WindowStyle hidden
, but it still pops up briefly.pwsh -Noninteractive -WindowStyle hidden -Command "...."
You could easily get around that popup using the tool i have posted above. Using it every day with my steam deck and startup scripts
FYI: Over on the console team we're proposing a way for future applications (and future versions of existing applications) to deal with this. There would be a little overhead[1], but it would give PowerShell the ability to _choose whether to allocate a console window_ when launched in a GUI context.
Specification pull request: https://github.com/microsoft/terminal/pull/7337
@DHowett so glad I found out about this before merging my PR! Would be better for the customer to have a single exe and not worry about winexe versions let alone maintenance costs for the team.
But what if I'm calling PowerShell without Windows Terminal? For example, I'm calling pwsh.exe directly from Elgato Stream Deck. The proposed option from the Terminal team wouldn't solve this scenario, or others like it, would it?
@pcgeek86 don't let the name fool you! My team and I own the entire windows console subsystem, including how console applications launch and talk to eachother.
@DHowett I take it that means the functionality would only be available on future versions of Windows? So anyone still using downlevel Windows versions is essentially out of luck? 🤔
An application that is in the console subsystem with a consoleAllocationPolicy of inheritOnly will not present a console when launched from Explorer.
What is a behavior for Task Scheduler?
@DHowett for pwsh, would need a flag to specify that we would want a conpty allocated so that scripts that call console APIs still work
Applications like PowerShell may wish to retain "automatic" console allocation, and inheritOnly would be unsuitable for them.
So the policy does not resolve all PowerShell scenarios and PowerShell should use a workaround again?
This reminds me of my PR where I tried to directly use AllocConsole.
downlevel (@vexx32)
Unfortunately, this is a limitation on anything my team produces that is part of the console subsystem and can't ship as part of Terminal. We're trying to work on that 😉
What is the behavior for Task Scheduler (@iSazonov)
Saying "Explorer" was a convenient way to say "any context that does not already have a console" in fewer words. Rest assured, _anything that launches an inheritOnly
application without a console will not cause the allocation of a console._
Would need a flag to specify (@SteveL-MSFT)
Fortunately, PowerShell already has this in the form of WindowStyle
. The default mode can be "_i should call AllocConsole()
_" (which will service all console API needs!), unless the user requested hidden launch. The spec only moves the responsibility for allocating a console into (pwsh) so that it can get final control over whether there's a conhost. Since powershell is already set up to handle this case, it's just a few lines delta before/after the "hidden" check.
does not resolve all PowerShell scenarios (@iSazonov)
The spec further explains how powershell would handle this (see above, my reply to Steve). As far as I understand, this resolves _all scenarios called out in this issue and linked issues._
The principal difference between calling AllocConsole()
/AttachConsole()
as you did in your PR and calling AllocConsole()
when your application is manifested for a different console allocation policy is that the subsystem bit indicates that the spawning shell (cmd, pwsh, bash, ish) should _wait_ for the spawned shell (pwshw
) to exit, which reduces interference on the console I/O handles.
If you have a Windows subsystem application that calls AttachConsole()
to get back to its hosting console, the spawning shell and the new application will fight over who gets to read input/write output. That's why calling Attach is _never_ workable from a Windows subsystem application, unless you can fully control the shell that spawned you (you cannot.)
@DHowett Thanks! To be clear the proposal for PowerShell is to use SUBSYSTEM_GUI and inheritOnly?
My belief is that SUBSYSTEM_CUI
and inheritOnly
would be correct for PowerShell. It gives you the following behaviors:
$SHELL
) will wait for pwsh to exit before returning (SUBSYSTEM_CUI
)inheritOnly
)when you run it from explorer/tasksched, pwsh can make the decision about creating a new console window (inheritOnly)
Hmm, how could PowerShell know that is the process owner - explorer or tasksched?
I don't believe that it needs to know.
Here's why (C++):
int main() {
auto a{ _parseArgs() };
if (a.WindowStyle != WindowStyle::Hidden)
{
AllocConsole();
}
}
PowerShell already knows whether to spawn a window based on whether the user asked it not to. That feature already exists -- and so this is the minimal incremental change to the code that fixes this bug _and_ keeps the original behavior for all other use cases.
That provides a good platform on which to build further new behavior.
@DHowett as @vexx32 mentioned there is still a lot of Server 2012/R2 & 2016 out in the wild so whilst for Win10 & Server 2019 OS variants this seems great going forward I think that for PowerShell we'd need to think of a way around this that's more elegant than the current suggested solution @SteveL-MSFT
Unless you could also port that change into downlevel OS as part of a security patch, as you aren't doing feature updates to them, (which I highly doubt you would)
that the subsystem bit indicates that the spawning shell (cmd, pwsh, bash, ish) should wait for the spawned shell (pwshw) to exit, which reduces interference on the console I/O handles.
It should work for PowerShell too. I mean if PowerShell calls an external console app it should follow the new policy too. Will PowerShell get this automatically or we need to add anything in PowerShell?
PowerShell would have to opt in as mentioned in the spec. You brought up a great point, though: I believe that applications spawned _by_ an "inherit-only" application will pop up console windows, and that's _terrible_. I'll revisit this in the spec, because I believe I know how we can address that.
Unless you could also port that change into downlevel OS
Gotta get the feature done before we can even evaluate it for backporting 😉 but I 100% agree that this limits its utility.
Just want to say that if you're launching powershell from another program, there's a chance that it supports hiding child processes. For example, Autohotkey has a "Hide" flag for the run command.
Most helpful comment
You could have a
powershellw.exe
which would be a GUI application that doesn't show a console window. Same as whatjavaw.exe
andpythonw.exe
do.