Skip to content

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

Closed

Description

@LqkUWp

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

Activity

  1. 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'[/+] on Jan 17, 2022
  2. jborean93 commented on Jan 18, 2022

    @jborean93

    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

    Steve Lee (@SteveL-MSFT) Paul Higinbotham (@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.

  3. tbakerweb commented on Jan 18, 2022

    @tbakerweb

    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.

  4. PaulHigin commented on Jan 18, 2022

    @PaulHigin
    Contributor

    Jordan Borean (@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: Steve Lee (@SteveL-MSFT)

  5. jborean93 commented on Jan 18, 2022

    @jborean93

    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.

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

  6. jborean93 commented on Jan 18, 2022

    @jborean93

    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.

  7. iSazonov commented on Jan 19, 2022

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

  8. LqkUWp commented on Jan 19, 2022

    @LqkUWp
    Author

    hi Jordan Borean (@jborean93) , $PSDefaultParameterValues outputs nothing

  9. jborean93 commented on Jan 20, 2022

    @jborean93

    hi Jordan Borean (@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.

  10. kasini3000 commented on Jan 20, 2022

    @kasini3000

    hi Tony Baker (@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运维工具。
  11. PaulHigin commented on Apr 7, 2022

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

  12. PaulHigin commented on May 25, 2022

    @PaulHigin
    Contributor

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

  13. metablaster commented on Dec 2, 2022

    @metablaster

    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?

  14. PaulHigin commented on Dec 2, 2022

    @PaulHigin
    Contributor

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

  15. SteveL-MSFT commented on Dec 14, 2022

    @SteveL-MSFT
    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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions