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.
<#
.Synopsis
Resets the size of the current console window
.Description
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.
.Example
Set-myConSize
Restores the console window to 120x40
.Example
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
.Inputs
[int]
[int]
.Notes
Author: Charlie Russel
Copyright: 2017 by Charlie Russel
: Permission to use is granted but attribution is appreciated
Initial: 28 April, 2017 (cpr)
ModHist:
:
#>
[CmdletBinding()]
Param(
[Parameter(Mandatory=$False,Position=0)]
[int]
$Height = 40,
[Parameter(Mandatory=$False,Position=1)]
[int]
$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