PowerShell, запускайте код, если в ConHost, но не в терминале Windows

Я использую приведенные ниже функции, чтобы обойти тот невероятно раздражающий факт, что Windows открывает более 80% новых окон PowerShell с положением курсора ниже панели задач, поэтому мне приходится перемещать окно перед использованием.

Однако это приводит к ошибке в терминале Windows:

      Exception setting "BufferSize": "Cannot set the buffer size because the size
specified is too large or too small. Actual value was 120,9999."

Итак, как мне определить, работаю ли я в данный момент в ConHost или в терминале Windows (или в других терминалах? может быть, у Cmder другой тип хоста?), чтобы я мог создать условие в моем$profileне запускать эту опцию изменения размера, когда я нахожусь в терминале Windows?

      function Global:Set-ConsolePosition ($x, $y, $w, $h) {
    Add-Type -Name Window -Namespace Console -MemberDefinition '
[DllImport("Kernel32.dll")] 
public static extern IntPtr GetConsoleWindow();
[DllImport("user32.dll")]
public static extern bool MoveWindow(IntPtr hWnd, int X, int Y, int W, int H); '
    # Maybe do the Add-Type outside of the function as repeating it in a session can cause errors?
    $consoleHWND = [Console.Window]::GetConsoleWindow();
    $consoleHWND = [Console.Window]::MoveWindow($consoleHWND, $x, $y, $w, $h);
    # $consoleHWND = [Console.Window]::MoveWindow($consoleHWND,75,0,600,600);
    # $consoleHWND = [Console.Window]::MoveWindow($consoleHWND,-6,0,600,600);
}

function Global:Set-WindowState([int]$Type) {
    $Script:showWindowAsync = Add-Type -MemberDefinition @"
[DllImport("user32.dll")]
public static extern bool ShowWindowAsync(IntPtr hWnd, int nCmdShow);
"@ -Name "Win32ShowWindowAsync" -Namespace Win32Functions -PassThru
    
    $null = $showWindowAsync::ShowWindowAsync((Get-Process -Id $pid).MainWindowHandle, $Type)
}

function Set-WindowClose() { Set-WindowState 0 }
function Set-WindowNormal() { Set-WindowState 1 }
function Set-WindowMin() { Set-WindowState 2 }
function Set-WindowMax() { Set-WindowState 3 }

function Global:Set-MaxWindowSize {
    # This will open every new console in a reasonable position with cursor position visible
    # Added new restriction for ultrawide screens to cap the width to 175
    # https://gallery.technet.microsoft.com/scriptcenter/Set-the-PowerShell-Console-bd8b2ad1
    # https://stackoverflow.com/questions/5197278/how-to-go-fullscreen-in-powershell
    # "Also note: 'Mode 300' or 'Alt-Enter' to fullscreen a Conhost window`n"

    if ($Host.Name -match "console") {
        $MaxHeight = 32   # Setting to size relative to screen size: $host.UI.RawUI.MaxPhysicalWindowSize.Height - 5    # 1
        $MaxWidth = 120   # Setting to size relative to screen size: $host.UI.RawUI.MaxPhysicalWindowSize.Width - 15     # 15
        if ($MaxWidth -gt 120) { $MaxWidth = 120 }   # This is to handle ultra-wide monitors, was 175, but 100 is better
        $MyBuffer = $Host.UI.RawUI.BufferSize
        $MyWindow = $Host.UI.RawUI.WindowSize
        $MyWindow.Height = ($MaxHeight)
        $MyWindow.Width = ($MaxWidth)
        $MyBuffer.Height = (9999)
        $MyBuffer.Width = ($MaxWidth)
        # $host.UI.RawUI.set_bufferSize($MyBuffer)
        # $host.UI.RawUI.set_windowSize($MyWindow)
        $host.UI.RawUI.BufferSize = $MyBuffer
        $host.UI.RawUI.WindowSize = $MyWindow
    }
}

Set-WindowNormal
Set-ConsolePosition 75 20 500 400

2 ответа

С уважением к Ойсину Грехану в этом комментарии GitHub , простой, но не всегда правильный подход — проверить наличие$env:WT_SESSION, который доступен только в сеансах терминала Windows.

      if ($env:WT_SESSION) { 
    # yes, windows terminal
} else {
    # nope
}

Более комплексное решение , требующее PowerShell 7+, предлагает Херардо Гриньоли :

      function Get-ConsoleHostProcessId {
  
    # Save Original ConsoleHost title   
    $oldTitle=$host.ui.RawUI.WindowTitle; 
    # Set unique console title.
    $r=(New-Guid); 
    $host.ui.RawUI.WindowTitle = "$r"; 
    #Find console window by title, then find console PID.
    $result = (tasklist.exe /FO LIST /FI "WINDOWTITLE eq $r") | Select-String -Pattern  "PID:*" -Raw
    
    if ($null -ne $result) {
        $consolePid = [int]($result.SubString(5).Trim());
    } else {
        $consolePid = 0;
    }        
    # Restore original ConsoleHost title.
    $host.ui.RawUI.WindowTitle=$oldTitle;

    return [int]$consolePid;
}
  
function Test-IsWindowsTerminal {
    $consolePid = Get-ConsoleHostProcessId;
    if ($consolePid -gt 0) {
        return (Get-Process -PID (Get-ConsoleHostProcessId)).ProcessName -eq "WindowsTerminal";
    }
    return $false;
}

Просто добавьте в свой профиль код ветвления, который проверяет тип хоста, используя оператор If/Then.

      If ($Host.Name -match 'ISE')
{
    # Do ISE customizations
}

If ($Host.Name -notmatch 'ISE')
{ 
    # Do console customizations
}

Если вы используете множество других оболочек, которые могут загружать PS, то также можно использовать оператор переключения.

      switch ($host.Name)
{
    'Windows PowerShell ISE Host' {
        # Do ISE customizations
    }

    'ConsoleHost' {
        # Do console customizations
    }

    'Visual Studio Code Host' {
        # Do VSCode customizations
    }

    Default {}
}
Другие вопросы по тегам