Allow user to force the default implicit formatting to use AutoSize (#28018)

When `$PSStyle.AutoSizeDefaultFormatting = $true`, the default implicit formatting applied by PowerShell (via `Out-Default`) will enforce `AutoSize` when the chosen formatting view is `table` or `wide`, similar to running `Format-Table -AutoSize` and `Format-Wide -AutoSize` explicitly. The `List` and `Complex` views formatting won't be buffered though -- they will continue to be streamed.

This allows PowerShell to generate less verbose output when used by an agent. It also makes PowerShell works better with small-window terminal.
This commit is contained in:
Dongbo Wang authored and GitHub committed 2026-09-17 14:27:16 -07:00
1 parent a049fa38ef
commit 2179219c84
5 files changed
+194

No files matched your search

@@ -2157,6 +2157,7 @@ namespace System.Management.Automation.Runspaces
.AddItemScriptBlock(@"""$($_.StrikethroughOff)$($_.StrikethroughOff.Replace(""""`e"""",'`e'))$($_.Reset)""", label: "StrikethroughOff")
.AddItemScriptBlock(@"""$($_.Strikethrough)$($_.Strikethrough.Replace(""""`e"""",'`e'))$($_.Reset)""", label: "Strikethrough")
.AddItemProperty(@"OutputRendering")
.AddItemProperty(@"AutoSizeDefaultFormatting")
.AddItemScriptBlock(@"""$($_.Formatting.FormatAccent)$($_.Formatting.FormatAccent.Replace(""""`e"""",'`e'))$($PSStyle.Reset)""", label: "Formatting.FormatAccent")
.AddItemScriptBlock(@"""$($_.Formatting.ErrorAccent)$($_.Formatting.ErrorAccent.Replace(""""`e"""",'`e'))$($PSStyle.Reset)""", label: "Formatting.ErrorAccent")
.AddItemScriptBlock(@"""$($_.Formatting.Error)$($_.Formatting.Error.Replace(""""`e"""",'`e'))$($PSStyle.Reset)""", label: "Formatting.Error")
@@ -135,6 +135,12 @@ namespace Microsoft.PowerShell.Commands.Internal.Format
private void InitializeAutoSize()
{
// Only Table and Wide views support autosize.
if (this is not (TableViewGenerator or WideViewGenerator))
{
return;
}
// check the autosize flag first
if (parameters != null && parameters.autosize.HasValue)
{
@@ -641,6 +641,11 @@ namespace System.Management.Automation
/// </summary>
public OutputRendering OutputRendering { get; set; } = OutputRendering.Host;
/// <summary>
/// Gets or sets whether to force the default implicit formatting to use 'AutoSize'.
/// </summary>
public bool AutoSizeDefaultFormatting { get; set; }
/// <summary>
/// Gets value to turn off all attributes.
/// </summary>
@@ -20,5 +20,20 @@ namespace Microsoft.PowerShell.Commands
{
this.implementation = new InnerFormatShapeCommand(FormatShape.Undefined);
}
/// <summary>
/// Hook up the AutoSize override, if requested, before handing off to the
/// implementation.
/// </summary>
protected override void BeginProcessing()
{
if (PSStyle.Instance.AutoSizeDefaultFormatting)
{
var parameters = new FormattingCommandLineParameters { autosize = true };
((InnerFormatShapeCommand)this.implementation).SetCommandLineParameters(parameters);
}
base.BeginProcessing();
}
}
}
@@ -89,6 +89,10 @@ Describe 'Tests for $PSStyle automatic variable' -Tag 'CI' {
$PSStyle.OutputRendering | Should -BeExactly 'Host'
}
It '$PSStyle default view includes AutoSizeDefaultFormatting' {
$PSStyle | Out-String | Should -Match 'AutoSizeDefaultFormatting'
}
It '$PSStyle has correct defaults for style <key>' -TestCases (Get-TestCases $styleDefaults) {
param($key, $value)
@@ -603,3 +607,166 @@ Billy Bob… Senior DevOps … 13
$text.Trim().Replace("`r", "") | Should -BeExactly $expected.Replace("`r", "")
}
}
Describe 'Default formatting AutoSize override' -Tag 'CI' {
BeforeAll {
$formatFile = Join-Path $TestDrive 'AutoSizeDefaultFormatting.format.ps1xml'
@'
<Configuration>
<ViewDefinitions>
<View>
<Name>AutoSizeWide</Name>
<ViewSelectedBy>
<TypeName>Test.AutoSizeWide</TypeName>
</ViewSelectedBy>
<WideControl>
<WideEntries>
<WideEntry>
<WideItem>
<PropertyName>Name</PropertyName>
</WideItem>
</WideEntry>
</WideEntries>
</WideControl>
</View>
<View>
<Name>AutoSizeComplex</Name>
<ViewSelectedBy>
<TypeName>Test.AutoSizeComplex</TypeName>
</ViewSelectedBy>
<CustomControl>
<CustomEntries>
<CustomEntry>
<CustomItem>
<Text>Item</Text>
<NewLine />
</CustomItem>
</CustomEntry>
</CustomEntries>
</CustomControl>
</View>
</ViewDefinitions>
</Configuration>
'@ | Set-Content -Path $formatFile
}
It "Forces default table formatting to use 'AutoSize'" {
$oldOutputRendering = $PSStyle.OutputRendering
$oldAutoSizeDefaultFormatting = $PSStyle.AutoSizeDefaultFormatting
try {
$PSStyle.OutputRendering = 'PlainText'
$PSStyle.AutoSizeDefaultFormatting = $false
$defaultOutput = Get-Command Import-Module | Out-String
$PSStyle.AutoSizeDefaultFormatting = $true
$autoSizedOutput = Get-Command Import-Module | Out-String
$defaultOutput = $defaultOutput.Trim().Split("`n")
$autoSizedOutput = $autoSizedOutput.Trim().Split("`n")
$defaultOutput.Count | Should -BeExactly $autoSizedOutput.Count
for ($i = 0; $i -lt $defaultOutput.Count; $i++) {
$defaultOutput[$i].Length | Should -BeGreaterThan $autoSizedOutput[$i].Length
$elements_1 = $defaultOutput[$i].Split(' ', [System.StringSplitOptions]::RemoveEmptyEntries)
$elements_2 = $autoSizedOutput[$i].Split(' ', [System.StringSplitOptions]::RemoveEmptyEntries)
$elements_1 -join ' ' | Should -BeExactly ($elements_2 -join ' ')
}
}
finally {
$PSStyle.AutoSizeDefaultFormatting = $oldAutoSizeDefaultFormatting
$PSStyle.OutputRendering = $oldOutputRendering
}
}
It "Forces default wide formatting to use 'AutoSize'" {
$powerShell = [PowerShell]::Create()
try {
$result = $powerShell.AddScript({
param($Path)
Update-FormatData -PrependPath $Path
$oldOutputRendering = $PSStyle.OutputRendering
$oldAutoSizeDefaultFormatting = $PSStyle.AutoSizeDefaultFormatting
try {
$PSStyle.OutputRendering = 'PlainText'
$items = 1..6 | ForEach-Object {
[pscustomobject]@{ PSTypeName = 'Test.AutoSizeWide'; Name = "Item$_" }
}
$PSStyle.AutoSizeDefaultFormatting = $false
$defaultOutput = $items | Out-String -Width 40
$PSStyle.AutoSizeDefaultFormatting = $true
$autoSizedOutput = $items | Out-String -Width 40
[pscustomobject]@{
DefaultOutput = $defaultOutput
AutoSizedOutput = $autoSizedOutput
}
}
finally {
$PSStyle.AutoSizeDefaultFormatting = $oldAutoSizeDefaultFormatting
$PSStyle.OutputRendering = $oldOutputRendering
}
}).AddArgument($formatFile).Invoke()
$powerShell.HadErrors | Should -BeFalse
$defaultLines = $result.DefaultOutput.Trim().Split("`n")
$autoSizedLines = $result.AutoSizedOutput.Trim().Split("`n")
$defaultLines | Should -HaveCount 3
$autoSizedLines | Should -HaveCount 1
$autoSizedLines[0].Split(' ', [System.StringSplitOptions]::RemoveEmptyEntries) | Should -HaveCount 6
}
finally {
$powerShell.Dispose()
}
}
It 'Does not buffer default <ViewType> formatting until pipeline completion' -TestCases @(
@{ ViewType = 'List' }
@{ ViewType = 'Complex' }
) {
param($ViewType)
$powerShell = [PowerShell]::Create()
try {
$producerFinished = $powerShell.AddScript({
param($Path, $ViewType)
Update-FormatData -PrependPath $Path
$oldAutoSizeDefaultFormatting = $PSStyle.AutoSizeDefaultFormatting
try {
$PSStyle.AutoSizeDefaultFormatting = $true
$inputObject = $ViewType -eq 'List' ? $PSStyle : [pscustomobject]@{ PSTypeName = 'Test.AutoSizeComplex'; Name = 'Item' }
$script:producerFinished = $false
& {
$inputObject
$script:producerFinished = $true
} |
Out-String -Stream |
Where-Object { -not [string]::IsNullOrWhiteSpace($_) } | ## Ignore the newline written out by 'Out-String'
Select-Object -First 1 |
Out-Null
$script:producerFinished
}
finally {
$PSStyle.AutoSizeDefaultFormatting = $oldAutoSizeDefaultFormatting
}
}).AddArgument($formatFile).AddArgument($ViewType).Invoke()
$powerShell.HadErrors | Should -BeFalse
# When rendering streams, the first non-whitespace string reaches 'Select-Object' before '$script:producerFinished = $true' runs. 'Select-Object -First 1' then stops
# the upstream script, so that assignment is never evaluated and '$producerFinished' remains false.
# If rendering is buffered, 'Out-String' emits no non-whitespace payload until the upstream script finishes and the assignment runs, making '$producerFinished' true.
$producerFinished | Should -BeFalse
}
finally {
$powerShell.Dispose()
}
}
}