Skip to content
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

New-PSSession throws a black window named 'c:\windows\system32\wsmprovhost.exe' #85

Closed
5 tasks done
LqkUWp opened this issue Jan 17, 2022 · 14 comments · Fixed by #86
Closed
5 tasks done

New-PSSession throws a black window named 'c:\windows\system32\wsmprovhost.exe' #85

LqkUWp opened this issue Jan 17, 2022 · 14 comments · Fixed by #86

Comments

@LqkUWp
Copy link

LqkUWp commented Jan 17, 2022

Prerequisites

Steps to reproduce

  1. run Enable-PSRemoting in pwsh v7.2.0 and config winrm to listen to HTTPS.
  2. update pwsh from 7.2.0 to 7.2.1 manually, i.e. installing pwsh v7.2.1 to overwrite v7.2.0
  3. delete directory 'C:\Windows\System32\PowerShell\7.2.0' manually
  4. run Unregister-PSSessionConfiguration PowerShell.7
  5. run winrm invoke Restore http://schemas.microsoft.com/wbem/wsman/1/config/plugin '@{}'
  6. run Enable-PSRemoting in pwsh v7.2.1 and re-config winrm to listen to HTTPS.
  7. run
    New-PSSession -cn . -Port xxx -UseSSL -ConfigurationName Powershell.7
    

p.s.

  1. sorry for that i've forgotten the order between step 3&4.
  2. everything is fine before pwsh v7.2.1. after updating to v7.2.1, step 3-4 messed up winrm. i tried to repair that via step 5 according to error info of Get-PSSessionConfiguration.

Expected behavior

all pssession stuff runs in background and no black window pops up.

Actual behavior

1. a black window named 'c:\windows\system32\wsmprovhost.exe' pops up.
2. there are wsmprovhost and conhost foreground processes in task manager. 
3. black window is auto closed after running `Remove-PSSession xxx`.

Error details

No response

Environment data

Name                           Value
----                           -----
PSVersion                      7.2.1
PSEdition                      Core
GitCommitId                    7.2.1
OS                             Microsoft Windows 10.0.19043
Platform                       Win32NT
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0…}
PSRemotingProtocolVersion      2.3
SerializationVersion           1.1.0.1
WSManStackVersion              3.0

Visuals

  1. snapshot of task manager after all procedure in 'Steps to reproduce'
    image
  2. snapshot of the pop-up black window
    image
@LqkUWp LqkUWp changed the title New-Pssession throws a black window named 'c:\windows\system32\wsmprovhost.exe' New-PSSession throws a black window named 'c:\windows\system32\wsmprovhost.exe' Jan 17, 2022
@jborean93
Copy link

Looks like this is an unintended consequence of #70. The fact that it appears on your interactive desktop would indicate you also have -EnableNetworkAccess are you able to confirm that by checking $PSDefaultParameterValues? I'm only able to replicate it myself with -EnableNetworkAccess and not without.

The reason why this is happening is because -EnableNetworkAccess will spawn the wsmprovhost.exe process on the session the WinRM plugin is starting on. Without -EnableNetworkAccess the session used to spawn the remote process is session 0 which is hidden from the user but when you set -EnableNetworkAccess it will spawn it on the same interactive session as the caller as it's using the same access token for network access. Since the PR mentioned it will also now explicitly call AllocConsole to spawn a new console and because it's in the same session as the caller this console appears in the form of a new conhost that is blank.

This essentially means that we either need to

  • Revert the change
  • Don't create the console if not on session 0
    • Would require a check on the access token to see what session it is in and conditionally spawn the console if in session 0
    • This means the issue above will affect -EnableNetworkAccess sessions but normal ones are still unaffected
  • Explicitly hide the console
    • Simplest method will result in a flash on the screen when the conhost appears when allocated but before it is hidden
    • A more complex method to avoid this flash is to call CreateProcess to spawn a new console app (like cmd.exe in a hidden state) and attach that hidden console to wsmprovhost.exe
    • The latter has performance implications as now a new connection needs to start up an extra process
  • Do nothing
    • AFAIK this will only affect -EnableNetworkAccess and cannot see how it could affect anything else as they would all be spawned in session 0

@SteveL-MSFT @PaulHigin do you have any thoughts on the matter? Personally I think the console should be explicitly hidden and I don't really think we should go out of our way to avoid the flash due to the limited use case where it will appear.

@tbakerweb
Copy link

Hello,
I found this in trying to identify this exact behavior.

I felt it worth weighing in on this since the Do nothing option would break functionality in our product's usage.

I'm the architect and lead developer on an Enterprise grade automation tool which leverages PSSessions, Runspaces, etc to properly scope execution assignments. Our inherent process requires the -EnableNetworkAccess switch while simultaneously hiding the wsmprovhost.exe window.

Having read through the PowerShell/PowerShell#15128 and understanding as much of it as I could without a deep dive, I wonder if there's a more elegant solution to solve this, considering that 'EnableNetworkAccess' isn't even present in the linked comments.

@PaulHigin
Copy link
Contributor

@jborean93 Thanks for your analysis on this. I agree that the AllocConsole() change should be reverted or modified so that it is only called when in a non-interactive session. Is there any other way to set the .NET code page correctly?

/cc: @SteveL-MSFT

@jborean93
Copy link

I felt it worth weighing in on this since the Do nothing option would break functionality in our product's usage.

Thanks for sharing your use case, I personally don't think it's a viable option as there are some nice low hanging fruit to try and reduce the impact here.

One question I do, is there a reason why you are using -EnableNetworkAccess at all? This essentially uses the WSMan API to spawn a process using the same access token as the caller. You can achieve the same thing with a NamedPipeConnectionInfo or even just a new Runspace in a separate thread. Jobs are also essentially the same thing but might be a bit hard if you are relying on the Invoke-Command/Enter-PSSession interfaces.

Having read through the PowerShell/PowerShell#15128 and understanding as much of it as I could without a deep dive, I wonder if there's a more elegant solution to solve this, considering that 'EnableNetworkAccess' isn't even present in the linked comments.

An alternative solution IIRC was to try and fix .NET so that Console.OutputEncoding looked up the value but there's no real way of doing this without first spawning the console anyway. I personally see 3 viable options here (in no particular order and really juse psuedo code)

Option 1 - Hide the Console After Spawning

AllocConsole();
ShowWindow(GetConsoleWindow(), SW_HIDE);

Only downside here is that there will still be a flash that occurs after it is spawned but before it is hidden. Advantages is that it's very simple and doesn't have much of an overhead.

Option 2 - Hide the Console Before Spawning

STARTUPINFO startupInfo;
startupInfo.cb = sizeof(startupInfo);
startupInfo.dwFlags = STARTF_USESHOWWINDOW;
startupInfo.wShowWindow = SW_HIDE;

PROCESS_INFORMATION processInfo;

if (CreateProcess(NULL, "cmd.exe", NULL, NULL, FALSE, 
    CREATE_NEW_CONSOLE, NULL, NULL, &startupInfo, &processInfo))
{
    AttachConsole(processInfo.dwProcessId);
    TerminateProcess(processInfo.hProcess, 0);
}

This spawns a new console app (cmd.exe in this case) that is hidden and then attaches it's console to the wsmprovhost process. The Advantages here is that there shouldn't be any flash as it is spawned as a hidden window but the disadvantage is that there's now the overhead of spawning cmd everytime a new connection is made.

Option 3 - Do not spawn a console for -EnableNetworkAccess

HANDLE token
DWORD length = 0;
DWORD sessionId = 0;

OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &token);
if (GetTokenInformation(token, TokenSessionId, &sessionId, sizeof(sessionId), &length))
{
    if (sessionId == 0)
    {
        AllocConsole();
    }
}

This only spawns the console when running in session 0 (not -EnableNetworkAccess). Advantages is that it solves the original issue it tried to fix but the disadvantage is now -EnableNetworkAccess suffers from that same problem when processing non-ASCII output from native applications.

@tbakerweb do you find option 1 (with the brief flash) an acceptable middle ground here?

@jborean93
Copy link

Is there any other way to set the .NET code page correctly?

Not that I'm aware of, PowerShell could just assume a code page but then it will have the same problem when it spawns a new process which creates the conhost and is set to a different code page. It could add some heuristics to try and find the correct default but even then that's not a guarantee it will be correct, you essentially need to have a console attached to get the actual value. PowerShell could delay the initialization of the conhost (what's in option 2) until it spawns it's first process but that doesn't help code that might call [Console]::OutputEncoding beforehand.

@iSazonov
Copy link
Contributor

Notice, we already have internal static bool AllocateHiddenConsole() in native process run code. I guess it is more correctly for PowerShell always have a console whether it is started as CUI or no. Perhaps we could find right place in Engine to do that.

@LqkUWp
Copy link
Author

LqkUWp commented Jan 19, 2022

hi @jborean93 , $PSDefaultParameterValues outputs nothing

@jborean93
Copy link

hi @jborean93 , $PSDefaultParameterValues outputs nothing

Hmm I have no idea why it appears for you then, without -EnableNetworkAccess the spawned session should happen in session 0 which is hidden from the user. SOmething else might be at play but I'm fairly certain your issue is due to the changes introduced with PowerShell/PowerShell#15128.

@kasini3000
Copy link

kasini3000 commented Jan 20, 2022

hi @tbakerweb
have a look my powershell project 《kasini3000》
Welcome use , questions are welcome.
It is currently being translated into English, and you are also welcome to help translate.


kasini3000
win,linux devops automation batch script framework.(It is similar to Puppet,Ansible,pipeline)
Open source, free, cross-platform
English manual: https://gitee.com/chuanjiao10/kasini3000/blob/master/docs/kasini3000_manual.xlsx

kasini3000_agent_linux Shell script,one click install powershell on linux,modify sshd_config for PsRemote.

Gitee
类似于Puppet,Ansible,pipeline。号称比ansible好10倍,具有批量远程推送脚本,执行脚本,远程传递代码块,定时执行的,devops运维工具。

@PaulHigin
Copy link
Contributor

@WG-Remoting
Remoting working group agrees that this is likely due to this change:
#70

Removing WG-Remoting label since this is not a remoting issue, but instead a PowerShell console issue.

@PaulHigin
Copy link
Contributor

@SteveL-MSFT This issue may be causing another recent remoting problem with GMSA accounts (#17367). I feel this change should be reverted.

@metablaster
Copy link

metablaster commented Dec 2, 2022

I experience this issue as well but I do not use EnableNetworkAccess anywhere in my code.
In my case the black console window doesn't have a title bar and wsmprovhost.exe is spawned in task manager.

Once a session is removed the ghost window disappears.

I hope you guys don't give up from this as it's really annoying to minimize the window since it spawns over the PS console on which we work, is at least there a workaround to minimize the ghost window within a script?

@PaulHigin
Copy link
Contributor

I feel this should be fixed and will bring it up with the review committee.

@SteveL-MSFT
Copy link
Member

@PowerShell/powershell-committee discussed this. We propose a short term fix of simply hiding the window as this will be least risky and will improve the current experience. Longer term, we should figure out a more ideal solution.

@SteveL-MSFT SteveL-MSFT removed their assignment Dec 14, 2022
@SteveL-MSFT SteveL-MSFT transferred this issue from PowerShell/PowerShell Dec 14, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

8 participants