Resizing the PowerShell Console

Windows 10's support for high DPI displays is much better than previous iterations of Windows, but there are still some times it gets a bit confused. One such problem occurs when you have multiple high DPI displays or two displays of different sizes. If you move PowerShell console windows between displays or log back in after being logged out for a while, you can end up with a scrunched up PowerShell window. Nothing I had to deal with when all I had was a pair of standard FullHD monitors, but ever since I got my Surface Book, and connected it to a 28 inch 4k monitor, I've had periodic problems. Very annoying when your PowerShell window changes to 37 characters wide and 7 lines long!


The fix is to reset the window size. Now I can do this graphically (right click on the title bar, select Properties, and then the Layout tab), but that's a nuisance at best, and besides, the whole idea of using the GUI to fix a console just isn't right. The answer is to leverage the built-in $host variable:

$host | Get-Member

   TypeName: System.Management.Automation.Internal.Host.InternalHost

Name                   MemberType Definition
----                   ---------- ----------
EnterNestedPrompt      Method     void EnterNestedPrompt()
Equals                 Method     bool Equals(System.Object obj)
ExitNestedPrompt       Method     void ExitNestedPrompt()
GetHashCode            Method     int GetHashCode()
GetType                Method     type GetType()
NotifyBeginApplication Method     void NotifyBeginApplication()
NotifyEndApplication   Method     void NotifyEndApplication()
PopRunspace            Method     void PopRunspace(), void IHostSupportsInteractiveSession.PopRunspace()
PushRunspace           Method     void PushRunspace(runspace runspace), void IHostSupportsInteractiveSession.PushRunspace(runspace runspace)
SetShouldExit          Method     void SetShouldExit(int exitCode)
ToString               Method     string ToString()
CurrentCulture         Property   cultureinfo CurrentCulture {get;}
CurrentUICulture       Property   cultureinfo CurrentUICulture {get;}
DebuggerEnabled        Property   bool DebuggerEnabled {get;set;}
InstanceId             Property   guid InstanceId {get;}
IsRunspacePushed       Property   bool IsRunspacePushed {get;}
Name                   Property   string Name {get;}
PrivateData            Property   psobject PrivateData {get;}
Runspace               Property   runspace Runspace {get;}
UI                     Property   System.Management.Automation.Host.PSHostUserInterface UI {get;}
Version                Property   version Version {get;}

OK, there's some interesting bits there, but the one that looks most promising is UI. So:

 $host.UI | Get-Member

   TypeName: System.Management.Automation.Internal.Host.InternalHostUserInterface

Name                    MemberType Definition
----                    ---------- ----------
Equals                  Method     bool Equals(System.Object obj)
GetHashCode             Method     int GetHashCode()
GetType                 Method     type GetType()
Prompt                  Method     System.Collections.Generic.Dictionary[string,psobject] Prompt(string caption, string message, System.Collection...
PromptForChoice         Method     int PromptForChoice(string caption, string message, System.Collections.ObjectModel.Collection[System.Management...
PromptForCredential     Method     pscredential PromptForCredential(string caption, string message, string userName, string targetName), pscredent...
ReadLine                Method     string ReadLine()
ReadLineAsSecureString  Method     securestring ReadLineAsSecureString()
ToString                Method     string ToString()
Write                   Method     void Write(string value), void Write(System.ConsoleColor foregroundColor, System.ConsoleColor backgroundColor, ...
WriteDebugLine          Method     void WriteDebugLine(string message)
WriteErrorLine          Method     void WriteErrorLine(string value)
WriteInformation        Method     void WriteInformation(System.Management.Automation.InformationRecord record)
WriteLine               Method     void WriteLine(), void WriteLine(string value), void WriteLine(System.ConsoleColor foregroundColor, System.Cons...
WriteProgress           Method     void WriteProgress(long sourceId, System.Management.Automation.ProgressRecord record)
WriteVerboseLine        Method     void WriteVerboseLine(string message)
WriteWarningLine        Method     void WriteWarningLine(string message)
RawUI                   Property   System.Management.Automation.Host.PSHostRawUserInterface RawUI {get;}
SupportsVirtualTerminal Property   bool SupportsVirtualTerminal {get;}

Hmmm. Even more interesting stuff. I can tell I'm going to be doing some poking around in here! But, for our purposes, let's take a look at RawUI.

That looks the most promising:

$host.UI.RawUI | Get-Member

   TypeName: System.Management.Automation.Internal.Host.InternalHostRawUserInterface

Name                  MemberType Definition
----                  ---------- ----------
Equals                Method     bool Equals(System.Object obj)
FlushInputBuffer      Method     void FlushInputBuffer()
GetBufferContents     Method     System.Management.Automation.Host.BufferCell[,] GetBufferContents(System.Management.Automation.Host.Rectangle r)
GetHashCode           Method     int GetHashCode()
GetType               Method     type GetType()
LengthInBufferCells   Method     int LengthInBufferCells(string str), int LengthInBufferCells(string str, int offset), int LengthInBufferCells(cha...
NewBufferCellArray    Method     System.Management.Automation.Host.BufferCell[,] NewBufferCellArray(string[] contents, System.ConsoleColor foregro...
ReadKey               Method     System.Management.Automation.Host.KeyInfo ReadKey(System.Management.Automation.Host.ReadKeyOptions options), Syst...
ScrollBufferContents  Method     void ScrollBufferContents(System.Management.Automation.Host.Rectangle source, System.Management.Automation.Host.C...
SetBufferContents     Method     void SetBufferContents(System.Management.Automation.Host.Coordinates origin, System.Management.Automation.Host.Bu...
ToString              Method     string ToString()
BackgroundColor       Property   System.ConsoleColor BackgroundColor {get;set;}
BufferSize            Property   System.Management.Automation.Host.Size BufferSize {get;set;}
CursorPosition        Property   System.Management.Automation.Host.Coordinates CursorPosition {get;set;}
CursorSize            Property   int CursorSize {get;set;}
ForegroundColor       Property   System.ConsoleColor ForegroundColor {get;set;}
KeyAvailable          Property   bool KeyAvailable {get;}
MaxPhysicalWindowSize Property   System.Management.Automation.Host.Size MaxPhysicalWindowSize {get;}
MaxWindowSize         Property   System.Management.Automation.Host.Size MaxWindowSize {get;}
WindowPosition        Property   System.Management.Automation.Host.Coordinates WindowPosition {get;set;}
WindowSize            Property   System.Management.Automation.Host.Size WindowSize {get;set;}
WindowTitle           Property   string WindowTitle {get;set;}

BINGO! I see BufferSize and WindowSize, and I know from the GUI Properties page that those are the relevant settings, but just to verify:

$host.UI.RawUI.BufferSize | Get-Member

   TypeName: System.Management.Automation.Host.Size

Name        MemberType Definition
----        ---------- ----------
Equals      Method     bool Equals(System.Object obj)
GetHashCode Method     int GetHashCode()
GetType     Method     type GetType()
ToString    Method     string ToString()
Height      Property   int Height {get;set;}
Width       Property   int Width {get;set;}

$host.UI.RawUI.WindowSize | Get-Member

   TypeName: System.Management.Automation.Host.Size

Name        MemberType Definition
----        ---------- ----------
Equals      Method     bool Equals(System.Object obj)
GetHashCode Method     int GetHashCode()
GetType     Method     type GetType()
ToString    Method     string ToString()
Height      Property   int Height {get;set;}
Width       Property   int Width {get;set;}

And there we have it.  Both of them can be retrieved and set.  So, I came up with a little script, Set-myConSize, that lets me restore the window to its default size, or set it to a new size if I'm doing something that needs a bit of window size tweaking.

Resets the size of the current console window
Set-myConSize resets the size of the current console window. By default, it
sets the windows to a height of 40 lines, with a 3000 line buffer, and sets the 
the width and width buffer to 120 characters. 
Restores the console window to 120x40
Set-myConSize -Height 30 -Width 180
Changes the current console to a height of 30 lines and a width of 180 characters. 
.Parameter Height
The number of lines to which to set the current console. The default is 40 lines. 
.Parameter Width
The number of characters to which to set the current console. Default is 120. Also sets the buffer to the same value
    Author: Charlie Russel
 Copyright: 2017 by Charlie Russel
          : Permission to use is granted but attribution is appreciated
   Initial: 28 April, 2017 (cpr)
     $Height = 40,
     $Width = 120
$Console = $host.ui.rawui
$Buffer  = $Console.BufferSize
$ConSize = $Console.WindowSize

# If the Buffer is wider than the new console setting, first reduce the buffer, then do the resize
If ($Buffer.Width -gt $Width ) {
   $ConSize.Width = $Width
   $Console.WindowSize = $ConSize
$Buffer.Width = $Width
$ConSize.Width = $Width
$Buffer.Height = 3000
$Console.BufferSize = $Buffer
$ConSize = $Console.WindowSize
$ConSize.Width = $Width
$ConSize.Height = $Height
$Console.WindowSize = $ConSize

One quick comment on this script -- you can't set the BufferSize to smaller than the current WindowSize. With a Height buffer set to 3,000, that's not likely to be a problem, but if you don't want scroll bars on the bottom of your console windows (and you do NOT, trust me!), then you need the console WindowSize.Width to be the same as the BufferSize.Width. So if your reducing, you need to change the WindowSize first, then you can reduce the BufferSize. If you're increasing width, you need to do the buffer first.


Finally, I set an alias in my $Profile:

Set-Alias -Name Resize -Value Set-myConSize