Powershell: Powershell -WindowStyle Hidden still shows a window briefly

Created on 22 Jan 2017  ·  90Comments  ·  Source: PowerShell/PowerShell

Steps to reproduce

In Windows Run dialog type this:
PowerShell.exe -WindowStyle Hidden -Command ping www.microsoft.com

Expected behavior

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.

Actual behavior

It flashes the powershell window briefly.

Environment data

> $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
Issue-Enhancement OS-Windows WG-Interactive-Console

Most helpful comment

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.

All 90 comments

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 automation (run hidden from a scheduled task, for instance)
  • For launching GUI-user-interaction-only scripts without an unwanted console window (e.g., scripts that create WinForms UIs).

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.

  • This still bring up a quick visible flash window on my systems
  • I tried the silentCMD above but this requires net3.5 which is not installed on some of the 3rd party systems i run this on

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:

  • Don't need to put the script path on the wscript command line.
  • Doesn't set ExecutionPolicy to Bypass.

Downsides:

  • Need separate VBScript scripts for each PowerShell command.

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 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.

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:

  1. cmd ($SHELL) will wait for pwsh to exit before returning (SUBSYSTEM_CUI)
  2. when you run it from explorer/tasksched, pwsh can make the decision about creating a new console window (inheritOnly)
  3. when you run it from cmd/pwsh/(a console shell), pwsh will automatically receive a console window

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.

Was this page helpful?
0 / 5 - 0 ratings