Search code examples
powershellwindows-11windows-terminal

Hide the Windows Terminal console window with PowerShell


Background

  • I want to hide the console window in a PowerShell script.

    • EDIT: I am making this script stay resident with the system tray icon and hide from the taskbar. This script uses OneDrive to store screenshots. When you run this script, you have to authenticate to OneDrive, so first you can't run this script with -WindowStyle Hidden option (the window for authentication should be shown). After authentication, I want to hide the terminal from the taskbar and show the system tray icon.
  • On Windows 11, when you set Windows Console Host as the "Default terminal application" in the Startup setting of Windows Terminal, you can hide the console windows like this:

$windowcode = '[DllImport("user32.dll")] public static extern bool ShowWindowAsync(IntPtr hWnd, int nCmdShow);'
$asyncwindow = Add-Type -MemberDefinition $windowcode -name Win32ShowWindowAsync -namespace Win32Functions -PassThru
$hwnd = (Get-Process -PID $pid).MainWindowHandle
if ($hwnd -ne [System.IntPtr]::Zero) {
  $hidden = $asyncwindow::ShowWindowAsync($hwnd, 0)
}

Problem

On Windows 11, when you set Windows Terminal as the "Default terminal application" in the Startup setting of Windows Terminal, you can't get the window handle of console windows with the code above.

Instead of the code above, you can get the window handle like this:

Add-Type -Name ConsoleAPI -Namespace Win32Util -MemberDefinition '[DllImport("Kernel32.dll")] public static extern IntPtr GetConsoleWindow();'
$hwnd = [Win32Util.ConsoleAPI]::GetConsoleWindow()
$hidden = $asyncwindow::ShowWindowAsync($hwnd, 0)

But in this code, ShowWindowAsync($hwnd, 0) doesn't work properly. According to the document of ShowWindowAsync, it hides the windows when you pass 0 as the 2nd parameter. When I ran the code above, the Windows Terminal window is minimized rather than hidden.

Question

How can I hide the console window with PowerShell when you set Windows Terminal as the "Default terminal application" in the Startup setting of Windows Terminal on Windows 11?


Solution

  • Based on @postanote and @Luuk's answers, I made a function to hide the console window like this:

    function Hide-ConsoleWindow() {
      $ShowWindowAsyncCode = '[DllImport("user32.dll")] public static extern bool ShowWindowAsync(IntPtr hWnd, int nCmdShow);'
      $ShowWindowAsync = Add-Type -MemberDefinition $ShowWindowAsyncCode -name Win32ShowWindowAsync -namespace Win32Functions -PassThru
    
      $hwnd = (Get-Process -PID $pid).MainWindowHandle
      if ($hwnd -ne [System.IntPtr]::Zero) {
        # When you got HWND of the console window:
        # (It would appear that Windows Console Host is the default terminal application)
        $ShowWindowAsync::ShowWindowAsync($hwnd, 0)
      } else {
        # When you failed to get HWND of the console window:
        # (It would appear that Windows Terminal is the default terminal application)
    
        # Mark the current console window with a unique string.
        $UniqueWindowTitle = New-Guid
        $Host.UI.RawUI.WindowTitle = $UniqueWindowTitle
        $StringBuilder = New-Object System.Text.StringBuilder 1024
    
        # Search the process that has the window title generated above.
        $TerminalProcess = (Get-Process | Where-Object { $_.MainWindowTitle -eq $UniqueWindowTitle })
        # Get the window handle of the terminal process.
        # Note that GetConsoleWindow() in Win32 API returns the HWND of
        # powershell.exe itself rather than the terminal process.
        # When you call ShowWindowAsync(HWND, 0) with the HWND from GetConsoleWindow(),
        # the Windows Terminal window will be just minimized rather than hidden.
        $hwnd = $TerminalProcess.MainWindowHandle
        if ($hwnd -ne [System.IntPtr]::Zero) {
          $ShowWindowAsync::ShowWindowAsync($hwnd, 0)
        } else {
          Write-Host "Failed to hide the console window."
        }
      }
    }