Skip to content
ConsoleMonster

Everyday formatting

What Enable-ConsoleFormatting changes for everyday commands: files, processes, services, events, JSON, CSV, certificates and the Format commands.

Enable-ConsoleFormatting gives everyday commands a ConsoleMonster view when their output reaches the console. This page lists what each command shows, the features behind the switch and what stays as PowerShell writes it. To turn it on and keep it on, follow Everyday PowerShell output.

Windows PowerShell 5.1
PowerShell 7.6
PowerShelleveryday-commands.ps1
Enable-ConsoleFormatting

# Search text: matches highlighted, -Context lines dimmed.
$log = 'Started', 'Warning: api-02 is slow', 'Checked 12', 'Error: api-03 timed out', 'Done'
$log | Select-String -Pattern 'Warning|Error' -Context 1

# ACLs and certificate stores are Windows features.
$windows = $IsWindows -or $PSVersionTable.PSEdition -eq 'Desktop'

# Get-Acl and Cert:\ load the module behind these objects; the fixtures below load it themselves.
if ($windows) {
    Import-Module Microsoft.PowerShell.Security
}

# A folder ACL as Get-Acl returns it, built from fixed SDDL with well-known accounts.
if ($windows) {
    $acl = New-Object System.Security.AccessControl.DirectorySecurity
    $acl.SetSecurityDescriptorSddlForm(
        'O:BAG:SYD:PAI(D;;SD;;;WD)(A;OICIID;FA;;;SY)(A;OICI;FA;;;BA)(A;OICIIO;GA;;;CO)(A;OICINP;0x1200a9;;;BU)')
    $acl
}

# Three invented certificates with fixed dates: expired, expiring and valid.
if ($windows) {
    $certificates = @(
        'MIIBKjCB0KADAgECAggvcTE9RKF/bzAKBggqhkjOPQQDAjAbMRkwFwYDVQQDExB2cG4uZXhhbXBsZS50ZXN0MB4XDTI1MTAyMTEyMDAwMFoXDTI2MTAxODEyMDAwMFowGzEZMBcGA1UEAxMQdnBuLmV4YW1wbGUudGVzdDBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABKZisgRy8+IHe8o56IQPyVMExb4wQdMQopSpYo9aBg2yy6NZrQI5Mn1+bconqBWt/Qf/IhoeInAEONSwxgd0iEwwCgYIKoZIzj0EAwIDSQAwRgIhAMi0NVEH3Rdj8I9kAvrd8LAPVjBGStsH2mv89JrrsvZaAiEAlIq2VFwK7pSf09EZRZp2ISVtnE9jyBpNob7H/0CHEsQ='
        'MIIBKjCB0KADAgECAggi8amAzhXvhzAKBggqhkjOPQQDAjAbMRkwFwYDVQQDExBhcGkuZXhhbXBsZS50ZXN0MB4XDTI1MTAyMTEyMDAwMFoXDTI2MTAzMDEyMDAwMFowGzEZMBcGA1UEAxMQYXBpLmV4YW1wbGUudGVzdDBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABG5qZumktovjlNi/B8Tg2JAmDN0mOspNzMBl/tXceIpoK35Hj1Yb5g/oJuo8ZG4BDI/AfYkxiyhEsjYh2ZSZ1gIwCgYIKoZIzj0EAwIDSQAwRgIhAJ687lafA0jM9v7hnYcq3695N9WgnwmwKphsjJAqkx8nAiEA+35r9XtUFixSxhUPn8gn0rW/oKYzPfyigkA7eTa9jmc='
        'MIIBLjCB1qADAgECAghUZ3JsL9/HszAKBggqhkjOPQQDAjAeMRwwGgYDVQQDExNwb3J0YWwuZXhhbXBsZS50ZXN0MB4XDTI1MTAyMTEyMDAwMFoXDTI3MDIxNDEyMDAwMFowHjEcMBoGA1UEAxMTcG9ydGFsLmV4YW1wbGUudGVzdDBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABHKVW2PoHLpQq0yTzkqV1M8UGH81HENH6tz9seHhy5eLWTK2FM4a9G1mfcisZEZt60lmSYiM1jzy/7xbDYjAqDIwCgYIKoZIzj0EAwIDRwAwRAIgc0rww4RQjhbtDpcwyj5dC1RRG/cI1z36/n39AM5hWlwCIH9nSfnbTygb4p+mRu/h4b62fXA8cdwCzNigXR36rQWG'
    )
    foreach ($text in $certificates) {
        $bytes = [Convert]::FromBase64String($text)
        New-Object Security.Cryptography.X509Certificates.X509Certificate2 -ArgumentList (, $bytes)
    }
}

# Counts, statistics and elapsed time.
'Info', 'Warning', 'Info', 'Error', 'Info' | Group-Object | Sort-Object Count -Descending
12, 48, 7, 30 | Measure-Object -Sum -Average -Minimum -Maximum
New-TimeSpan -Start '2026-10-21 12:00' -End '2026-10-21 13:42:05'

# Windows inventory and installed modules.
Get-Volume
Get-Disk
Get-NetTCPConnection
Get-ScheduledTask
Get-LocalUser
Get-InstalledModule
Full program
Import-Module ConsoleMonster
Enable-ConsoleFormatting

# Search text: matches highlighted, -Context lines dimmed.
$log = 'Started', 'Warning: api-02 is slow', 'Checked 12', 'Error: api-03 timed out', 'Done'
$log | Select-String -Pattern 'Warning|Error' -Context 1

# ACLs and certificate stores are Windows features.
$windows = $IsWindows -or $PSVersionTable.PSEdition -eq 'Desktop'

# Get-Acl and Cert:\ load the module behind these objects; the fixtures below load it themselves.
if ($windows) {
    Import-Module Microsoft.PowerShell.Security
}

# A folder ACL as Get-Acl returns it, built from fixed SDDL with well-known accounts.
if ($windows) {
    $acl = New-Object System.Security.AccessControl.DirectorySecurity
    $acl.SetSecurityDescriptorSddlForm(
        'O:BAG:SYD:PAI(D;;SD;;;WD)(A;OICIID;FA;;;SY)(A;OICI;FA;;;BA)(A;OICIIO;GA;;;CO)(A;OICINP;0x1200a9;;;BU)')
    $acl
}

# Three invented certificates with fixed dates: expired, expiring and valid.
if ($windows) {
    $certificates = @(
        'MIIBKjCB0KADAgECAggvcTE9RKF/bzAKBggqhkjOPQQDAjAbMRkwFwYDVQQDExB2cG4uZXhhbXBsZS50ZXN0MB4XDTI1MTAyMTEyMDAwMFoXDTI2MTAxODEyMDAwMFowGzEZMBcGA1UEAxMQdnBuLmV4YW1wbGUudGVzdDBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABKZisgRy8+IHe8o56IQPyVMExb4wQdMQopSpYo9aBg2yy6NZrQI5Mn1+bconqBWt/Qf/IhoeInAEONSwxgd0iEwwCgYIKoZIzj0EAwIDSQAwRgIhAMi0NVEH3Rdj8I9kAvrd8LAPVjBGStsH2mv89JrrsvZaAiEAlIq2VFwK7pSf09EZRZp2ISVtnE9jyBpNob7H/0CHEsQ='
        'MIIBKjCB0KADAgECAggi8amAzhXvhzAKBggqhkjOPQQDAjAbMRkwFwYDVQQDExBhcGkuZXhhbXBsZS50ZXN0MB4XDTI1MTAyMTEyMDAwMFoXDTI2MTAzMDEyMDAwMFowGzEZMBcGA1UEAxMQYXBpLmV4YW1wbGUudGVzdDBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABG5qZumktovjlNi/B8Tg2JAmDN0mOspNzMBl/tXceIpoK35Hj1Yb5g/oJuo8ZG4BDI/AfYkxiyhEsjYh2ZSZ1gIwCgYIKoZIzj0EAwIDSQAwRgIhAJ687lafA0jM9v7hnYcq3695N9WgnwmwKphsjJAqkx8nAiEA+35r9XtUFixSxhUPn8gn0rW/oKYzPfyigkA7eTa9jmc='
        'MIIBLjCB1qADAgECAghUZ3JsL9/HszAKBggqhkjOPQQDAjAeMRwwGgYDVQQDExNwb3J0YWwuZXhhbXBsZS50ZXN0MB4XDTI1MTAyMTEyMDAwMFoXDTI3MDIxNDEyMDAwMFowHjEcMBoGA1UEAxMTcG9ydGFsLmV4YW1wbGUudGVzdDBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABHKVW2PoHLpQq0yTzkqV1M8UGH81HENH6tz9seHhy5eLWTK2FM4a9G1mfcisZEZt60lmSYiM1jzy/7xbDYjAqDIwCgYIKoZIzj0EAwIDRwAwRAIgc0rww4RQjhbtDpcwyj5dC1RRG/cI1z36/n39AM5hWlwCIH9nSfnbTygb4p+mRu/h4b62fXA8cdwCzNigXR36rQWG'
    )
    foreach ($text in $certificates) {
        $bytes = [Convert]::FromBase64String($text)
        New-Object Security.Cryptography.X509Certificates.X509Certificate2 -ArgumentList (, $bytes)
    }
}

# Counts, statistics and elapsed time.
'Info', 'Warning', 'Info', 'Error', 'Info' | Group-Object | Sort-Object Count -Descending
12, 48, 7, 30 | Measure-Object -Sum -Average -Minimum -Maximum
New-TimeSpan -Start '2026-10-21 12:00' -End '2026-10-21 13:42:05'

# Windows inventory and installed modules.
Get-Volume
Get-Disk
Get-NetTCPConnection
Get-ScheduledTask
Get-LocalUser
Get-InstalledModule
Formatted at a Windows PowerShell 5.1 and PowerShell 7 prompt with invented inventory records. Switch the site theme to see the light or dark run.

What changes and what stays

Only output that goes straight to the console changes. Pipelines into other commands, assignment, Out-String, Out-File, redirection, transcripts, jobs and remoting keep PowerShell's objects and text. The objects themselves are never changed.

Typed records with their own PowerShell table view keep its columns and expressions. An explicit Register-ConsoleView registration takes precedence over a built-in view, and -NoBuiltIn keeps only your own.

Features

FeatureDefaultWhat it does
OutputOnViews for registered and built-in types.
FormatCommandsOnFormat-Table, Format-List and Format-Wide drawn by ConsoleMonster; see Coming from Format-Table.
ErrorsOnThe error view.
StreamsOnTheme colours for warning, verbose, debug and native progress messages.
ReadLineOnTheme colours for the PSReadLine editor, if it is loaded.
ProgressOffWrite-Progress drawn as ConsoleMonster's progress area.
HelpOffStyled command help.
GridViewOffOut-GridView in the terminal where the desktop grid is unavailable.
PromptOffA short prompt with path, git state and the last command's duration.

-Include adds features, -Exclude leaves them out, Disable-ConsoleFormatting -Feature turns one off, and Get-ConsoleFormatting lists what is on.

Summary lines

A line under the view sums it up. Small results get no line, and only the console view has it: Show-ConsoleTable, Out-String and captured output stay as they were.

ViewThe line under it
Get-ChildItemFolders, files, their total size and the largest. With -Recurse the listing is one tree, folders first, each with the size of the files under it.
Get-ProcessHow many, their memory together and the process using the most. Memory draws a bar against the largest.
Get-ServiceRunning and stopped, and automatic services that are not running.
Get-WinEventErrors, warnings and information, the time they cover and a sparkline of when they happened.
Test-ConnectionReplies, minimum, average and maximum latency, one line per destination.
Get-HistoryCommands, failures, the time they took and the slowest.
Certificates, Select-String, Get-JobExpired and expiring certificates; matches and files; jobs by state.
PowerShell 7
PowerShelleveryday-summaries.ps1
Enable-ConsoleFormatting

# An invented release folder with fixed sizes and times.
$temp = if ($IsMacOS -or $IsLinux) { '/tmp' } else { $env:TEMP }
$root = Join-Path $temp 'release'
if (Test-Path -LiteralPath $root) { Remove-Item -LiteralPath $root -Recurse -Force }
$files = [ordered] @{
    'bin/ConsoleMonster.dll' = 1048576
    'bin/ConsoleMonster.xml' = 262144
    'bin/runtimes/libcm.so'  = 393216
    'docs/README.md'         = 15360
    'docs/CHANGELOG.md'      = 63488
    'install.ps1'            = 2048
}
foreach ($name in $files.Keys) {
    $path = Join-Path $root $name
    $null = New-Item -ItemType Directory -Path (Split-Path $path) -Force
    [System.IO.File]::WriteAllBytes($path, (New-Object byte[] $files[$name]))
}
$stamp = [datetime] '2026-10-21 12:00'
Get-ChildItem $root -Recurse -Force | ForEach-Object { $_.LastWriteTime = $stamp }
(Get-Item -LiteralPath $root).LastWriteTime = $stamp

# A recursive listing is one tree with folder sizes; the line under it sums it up.
Get-ChildItem -LiteralPath $root -Recurse

# Your own types can sum themselves up too.
$state = @{ Name = 'State'; Expression = { $_.State }; Presenter = 'StatusWord' }
$disk = @{ Name = 'Disk'; Expression = { $_.Disk }; Presenter = 'BytesBar' }
Register-ConsoleView -TypeName Contoso.Server -Property Name, $state, $disk -Summary {
    param($servers)
    @{ Value = $servers.Count; Label = 'servers' }
    $down = @($servers | Where-Object State -ne 'Running').Count
    if ($down) { @{ Value = $down; Label = 'stopped'; Role = 'Warn' } }
    $total = ($servers | Measure-Object Disk -Sum).Sum
    @{ Caption = 'disk'; Value = $total; Presenter = 'Bytes' }
}
$servers = @(
    [pscustomobject] @{ Name = 'web-01'; State = 'Running'; Disk = 120GB }
    [pscustomobject] @{ Name = 'web-02'; State = 'Running'; Disk = 96GB }
    [pscustomobject] @{ Name = 'db-01'; State = 'Stopped'; Disk = 410GB }
)
$servers | ForEach-Object { $_.PSObject.TypeNames.Insert(0, 'Contoso.Server') }
$servers
Full program
Import-Module ConsoleMonster
Enable-ConsoleFormatting

# An invented release folder with fixed sizes and times.
$temp = if ($IsMacOS -or $IsLinux) { '/tmp' } else { $env:TEMP }
$root = Join-Path $temp 'release'
if (Test-Path -LiteralPath $root) { Remove-Item -LiteralPath $root -Recurse -Force }
$files = [ordered] @{
    'bin/ConsoleMonster.dll' = 1048576
    'bin/ConsoleMonster.xml' = 262144
    'bin/runtimes/libcm.so'  = 393216
    'docs/README.md'         = 15360
    'docs/CHANGELOG.md'      = 63488
    'install.ps1'            = 2048
}
foreach ($name in $files.Keys) {
    $path = Join-Path $root $name
    $null = New-Item -ItemType Directory -Path (Split-Path $path) -Force
    [System.IO.File]::WriteAllBytes($path, (New-Object byte[] $files[$name]))
}
$stamp = [datetime] '2026-10-21 12:00'
Get-ChildItem $root -Recurse -Force | ForEach-Object { $_.LastWriteTime = $stamp }
(Get-Item -LiteralPath $root).LastWriteTime = $stamp

# A recursive listing is one tree with folder sizes; the line under it sums it up.
Get-ChildItem -LiteralPath $root -Recurse

# Your own types can sum themselves up too.
$state = @{ Name = 'State'; Expression = { $_.State }; Presenter = 'StatusWord' }
$disk = @{ Name = 'Disk'; Expression = { $_.Disk }; Presenter = 'BytesBar' }
Register-ConsoleView -TypeName Contoso.Server -Property Name, $state, $disk -Summary {
    param($servers)
    @{ Value = $servers.Count; Label = 'servers' }
    $down = @($servers | Where-Object State -ne 'Running').Count
    if ($down) { @{ Value = $down; Label = 'stopped'; Role = 'Warn' } }
    $total = ($servers | Measure-Object Disk -Sum).Sum
    @{ Caption = 'disk'; Value = $total; Presenter = 'Bytes' }
}
$servers = @(
    [pscustomobject] @{ Name = 'web-01'; State = 'Running'; Disk = 120GB }
    [pscustomobject] @{ Name = 'web-02'; State = 'Running'; Disk = 96GB }
    [pscustomobject] @{ Name = 'db-01'; State = 'Stopped'; Disk = 410GB }
)
$servers | ForEach-Object { $_.PSObject.TypeNames.Insert(0, 'Contoso.Server') }
$servers

Your own types can have a line too: Register-ConsoleView -Summary takes a script that returns facts. Restyle any command's output walks through it.

JSON and CSV

Flat objects from ConvertFrom-Json and Invoke-RestMethod become tables. Small nested objects show their fields and short arrays their values (Tags blue, ready); null shows — and empty collections (none). An API envelope such as { Total: 3, Items: [...] } shows its scalar fields first, then a table of the records.

LimitValue
Outer table50 rows, 24 fields
Nested table5 rows each, 24 nested rows per payload
Scalar array6 values
Object depthTwo levels below the root; deeper or wider than six keys shows {…} 12 keys

Omitted items show a +N more hint. CSV keeps its header order and original strings; columns whose values all look numeric or date-like align right, and 0012 stays 0012. Captured and exported data is always complete.

Commands, modules and history

ViewShows
Get-CommandName, command-type chips, version and source; aliases show their target. Twelve or more commands group by module.
Get-ModuleName, version, type, exported command count and a shortened path. Versions group under one name.
Get-HistoryId, start time, duration, status and highlighted command text.
Get-Job, Get-PSDriveJobs with state, start, duration and command; drives with used and free space and a usage bar that warns at 80% and fails at 95%.
Get-InstalledPSResource, Get-InstalledModuleName, version, repository, author and publication date, with counts by repository from five items.

Search, permissions, certificates and measurements

ViewShowsWhere
Select-StringOne table per file with line numbers, the match highlighted and -Context lines dimmedAll platforms
Get-AclPath and owner as the title, then a row per rule: allow or deny, the account, the rights in words, what it applies to and whether it is inheritedWindows
CertificatesStatus (Expired, Expiring within 30 days, Valid), subject, issuer, expiry, days left and thumbprintWindows for Cert:\; any certificate object
Group-ObjectName and count with a bar against the largest groupAll platforms
Measure-ObjectOnly the statistics you asked forAll platforms
TimeSpanA readable duration (1 h 42 m, 250 ms) beside the exact valueAll platforms

Select-String -Raw and -Quiet keep their native strings and booleans.

Windows inventory and network

CommandShows
Get-VolumeDrive, label, file system, health, capacity and a usage bar; total, free and unhealthy volumes.
Get-DiskName, bus, partition style, health, status and size; disks that need attention.
Get-NetTCPConnectionEndpoints, state, PID and process name; counts by state and listening ports.
Get-ScheduledTaskPath, name and state, with counts by state.
Get-LocalUserEnabled, last logon, password expiry and description, with enabled, disabled and never-used counts.
Test-Connection (PowerShell 7)Destination, reply, address, latency and readable failures such as Timed out. All platforms.
.NET IPAddress, Dns.GetHostEntryAddress and family; host name, addresses and aliases. All platforms.
Resolve-DnsNameName, type, TTL and the answer for A, AAAA, CNAME, MX, NS, PTR, TXT, SRV and SOA.
Get-NetIPAddress, Get-NetAdapter, Test-NetConnectionInterface and address; adapter status, MAC and speed; ping and TCP outcomes.

Unless marked, these are Windows views and register only on Windows. No view sends network requests or loads a module: the command you run supplies the objects.

Compare-Object

Compare-Object results show the counts, then each item marked - when only the reference set has it, + when only the difference set has it and = for both (-IncludeEqual). With -Property, the first property names the item. The objects still carry SideIndicator, so filters and files work as before. Compare-ConsoleObject matches by key and lists changed properties.

PowerShell 5.1
PowerShell 7
PowerShellcompare-object.ps1
$before = @(
    [pscustomobject] @{ Name = 'web01'; Port = 80 }
    [pscustomobject] @{ Name = 'web02'; Port = 443 }
    [pscustomobject] @{ Name = 'sql01'; Port = 1433 }
)
$after = @(
    [pscustomobject] @{ Name = 'web01'; Port = 443 }
    [pscustomobject] @{ Name = 'web02'; Port = 443 }
    [pscustomobject] @{ Name = 'dc01'; Port = 389 }
)

# PowerShell's own output
Compare-Object $before $after -Property Name, Port

Enable-ConsoleFormatting

# The same comparison now
Compare-Object $before $after -Property Name, Port -IncludeEqual
Full program
Import-Module ConsoleMonster

$before = @(
    [pscustomobject] @{ Name = 'web01'; Port = 80 }
    [pscustomobject] @{ Name = 'web02'; Port = 443 }
    [pscustomobject] @{ Name = 'sql01'; Port = 1433 }
)
$after = @(
    [pscustomobject] @{ Name = 'web01'; Port = 443 }
    [pscustomobject] @{ Name = 'web02'; Port = 443 }
    [pscustomobject] @{ Name = 'dc01'; Port = 389 }
)

# PowerShell's own output
Compare-Object $before $after -Property Name, Port

Enable-ConsoleFormatting

# The same comparison now
Compare-Object $before $after -Property Name, Port -IncludeEqual

Messages and the command-line editor

Streams gives warning, verbose and debug messages the theme's colours on Windows PowerShell 5.1 and PowerShell 7; their prefixes, preferences and redirection stay PowerShell's. ReadLine colours the PSReadLine editor, including selection and inline predictions; editing mode, key bindings and prediction source stay yours. Re-run Enable-ConsoleFormatting after Set-ConsoleTheme to apply a new theme.

Windows PowerShell 5.1
PowerShell 7.6
PowerShellstreams.ps1
# Show every stream for this demo.
$VerbosePreference = 'Continue'
$DebugPreference = 'Continue'

New-ConsoleRule -Title "PowerShell's own colours" | Show-Console
Write-Warning 'Certificate for mail.evotec.xyz expires in 12 days'
Write-Verbose 'Queried 4 domain controllers in 2 domains'
Write-Debug 'Cache hit for evotec.xyz'

Enable-ConsoleFormatting -Include Streams

New-ConsoleRule -Title 'With -Include Streams: the theme''s colours' | Show-Console
Write-Warning 'Certificate for mail.evotec.xyz expires in 12 days'
Write-Verbose 'Queried 4 domain controllers in 2 domains'
Write-Debug 'Cache hit for evotec.xyz'

Disable-ConsoleFormatting -Feature Streams
Full program
Import-Module ConsoleMonster

# Show every stream for this demo.
$VerbosePreference = 'Continue'
$DebugPreference = 'Continue'

New-ConsoleRule -Title "PowerShell's own colours" | Show-Console
Write-Warning 'Certificate for mail.evotec.xyz expires in 12 days'
Write-Verbose 'Queried 4 domain controllers in 2 domains'
Write-Debug 'Cache hit for evotec.xyz'

Enable-ConsoleFormatting -Include Streams

New-ConsoleRule -Title 'With -Include Streams: the theme''s colours' | Show-Console
Write-Warning 'Certificate for mail.evotec.xyz expires in 12 days'
Write-Verbose 'Queried 4 domain controllers in 2 domains'
Write-Debug 'Cache hit for evotec.xyz'

Disable-ConsoleFormatting -Feature Streams
Before and after -Include Streams; the light-theme runs show when the site is light.

Out-GridView without a desktop

Enable-ConsoleFormatting -Include GridView
Get-Process | Out-GridView -Title 'Choose processes' -OutputMode Single
Disable-ConsoleFormatting -Feature GridView

A working native Out-GridView is always kept. Where it is unavailable, Out-GridView opens Show-ConsoleGrid, with filtering, sorting and selection, and maps -Title, -PassThru, -OutputMode and -Wait. Selection returns the original objects. Without an interactive console it prints a table with a warning and returns nothing. An existing function or alias named Out-GridView is kept unless you add -Force.

Out-GridView in the terminal
Out-GridView in the terminal
PowerShellexample.ps1
# On a desktop with working Out-GridView, the native window remains in charge.
Import-Module ConsoleMonster
$previousFeatures = @((Get-ConsoleFormatting).Features)
Enable-ConsoleFormatting -Include GridView
$nodes = @(
    [pscustomobject] @{ Name = 'api-east'; Region = 'eu-west'; Version = '2.4.1' }
    [pscustomobject] @{ Name = 'worker-west'; Region = 'eu-west'; Version = '2.4.0' }
    [pscustomobject] @{ Name = 'build-north'; Region = 'eu-north'; Version = '2.4.1' }
)
try {
    $nodes | Out-GridView -Title 'Choose nodes' -OutputMode Multiple
} finally {
    $addedFeatures = @((Get-ConsoleFormatting).Features | Where-Object {
        $_ -notin $previousFeatures
    })
    if ($addedFeatures.Count -gt 0) {
        Disable-ConsoleFormatting -Feature $addedFeatures
    }
}
C#Program.cs
using ConsoleMonster;
using ConsoleMonster.Interactive;
using ConsoleMonster.Text;

Grid grid = new Grid("Choose nodes")
{
    OutputMode = GridSelection.Multiple
};
grid.AddColumn("Name").AddColumn("Region").AddColumn("Version");
grid.AddRow("api-east", "api-east", "eu-west", "2.4.1");
grid.AddRow("worker-west", "worker-west", "eu-west", "2.4.0");
grid.AddRow("build-north", "build-north", "eu-north", "2.4.1");
GridResult selected = grid.Show();
foreach (object? node in selected.Items)
{
    Terminal.WriteMarkupLine(Markup.Escape(node?.ToString() ?? string.Empty));
}
C# fluentProgram.cs
Grid grid = Ui.Grid().Title("Choose nodes").OutputMode(GridSelection.Multiple);
grid.AddColumn("Name").AddColumn("Region").AddColumn("Version");
grid.AddRow("api-east", "api-east", "eu-west", "2.4.1");
grid.AddRow("worker-west", "worker-west", "eu-west", "2.4.0");
grid.AddRow("build-north", "build-north", "eu-north", "2.4.1");
GridResult selected = grid.Show();
foreach (object? node in selected.Items)
{
    Terminal.WriteMarkupLine(Markup.Escape(node?.ToString() ?? string.Empty));
}
Full program
using ConsoleMonster;
using ConsoleMonster.Interactive;
using ConsoleMonster.Text;

Grid grid = Ui.Grid().Title("Choose nodes").OutputMode(GridSelection.Multiple);
grid.AddColumn("Name").AddColumn("Region").AddColumn("Version");
grid.AddRow("api-east", "api-east", "eu-west", "2.4.1");
grid.AddRow("worker-west", "worker-west", "eu-west", "2.4.0");
grid.AddRow("build-north", "build-north", "eu-north", "2.4.1");
GridResult selected = grid.Show();
foreach (object? node in selected.Items)
{
    Terminal.WriteMarkupLine(Markup.Escape(node?.ToString() ?? string.Empty));
}

Views that ship with a module

A module can describe its own views in a <ModuleName>.consoleviews.psd1 file beside its manifest, with no dependency on ConsoleMonster. Custom views describes the file.

Get-ContosoServer before and after its view

A module puts Contoso.Servers.consoleviews.psd1 beside its manifest: plain data naming the columns, their presenters and the grouping. The module never imports ConsoleMonster; its users get the view when they turn formatting on.

Contoso.Servers.consoleviews.psd1 85×2924-bitFull
PowerShellmodule-views.ps1View on GitHub
Import-Module ./Contoso.Servers

# Without views: PowerShell's own table
Get-ContosoServer

Enable-ConsoleFormatting

# The module's Contoso.Servers.consoleviews.psd1 picks the columns and the groups
Get-ContosoServer
Full program
Import-Module ConsoleMonster
Import-Module ./Contoso.Servers

# Without views: PowerShell's own table
Get-ContosoServer

Enable-ConsoleFormatting

# The module's Contoso.Servers.consoleviews.psd1 picks the columns and the groups
Get-ContosoServer
PowerShellContoso.Servers/Contoso.Servers.consoleviews.psd1
# Read by ConsoleMonster when it is loaded; plain data, no code. The module itself never imports ConsoleMonster.
@{
    SchemaVersion = 1
    Views         = @(
        @{
            TypeName = 'Contoso.Server'
            View     = 'Table'
            Property = @(
                'Name'
                @{ Name = 'Health'; Expression = 'State'; Presenter = 'StatusWord' }
                'Uptime'
            )
            GroupBy  = 'Site'
        }
    )
}
PowerShellContoso.Servers/Contoso.Servers.psm1
function Get-ContosoServer {
    <#
    .SYNOPSIS
    Returns the servers in the Contoso inventory as Contoso.Server objects.
    #>
    [CmdletBinding()]
    param()
    $servers = @(
        @{ Name = 'web01'; Site = 'Warsaw'; State = 'Running'; Hours = 412 }
        @{ Name = 'web02'; Site = 'Warsaw'; State = 'Running'; Hours = 9 }
        @{ Name = 'sql01'; Site = 'Warsaw'; State = 'Degraded'; Hours = 1210 }
        @{ Name = 'app01'; Site = 'Krakow'; State = 'Running'; Hours = 77 }
        @{ Name = 'app02'; Site = 'Krakow'; State = 'Stopped'; Hours = 0 }
    )
    foreach ($server in $servers) {
        [pscustomobject] @{
            PSTypeName = 'Contoso.Server'
            Name       = $server.Name
            Site       = $server.Site
            State      = $server.State
            Uptime     = New-TimeSpan -Hours $server.Hours
        }
    }
}
PowerShellContoso.Servers/Contoso.Servers.psd1
@{
    RootModule        = 'Contoso.Servers.psm1'
    ModuleVersion     = '1.0.0'
    GUID              = '5b0f7a52-6a52-4c1e-9d58-2f1f9a7c3e21'
    Author            = 'Contoso'
    Description       = 'Servers in the Contoso inventory. It knows nothing about ConsoleMonster.'
    FunctionsToExport = 'Get-ContosoServer'
}
C#module-views.host.csView on GitHub
// A compiled cmdlet: the current PowerShell runspace owns native commands and callbacks.
[Cmdlet(VerbsLifecycle.Invoke, "ModuleViewsExample") ]
public sealed class ModuleViewsExample : PSCmdlet {
    protected override void ProcessRecord() {
        InvokeCommand.InvokeScript("Import-Module ./Contoso.Servers");
        ConsoleHostViews.Import(this, "./Contoso.Servers/Contoso.Servers.consoleviews.psd1");
        using var output = new ConsoleDefaultOutput(
            this,
            new ConsoleDefaultOutputOptions { Force = true });
        foreach (var row in InvokeCommand.InvokeScript("Get-ContosoServer")) { output.Write(row); }
        output.Complete();
    }
}
Full program
using System.Management.Automation;
using ConsoleMonster.PowerShell;

// A compiled cmdlet: the current PowerShell runspace owns native commands and callbacks.
[Cmdlet(VerbsLifecycle.Invoke, "ModuleViewsExample") ]
public sealed class ModuleViewsExample : PSCmdlet {
    protected override void ProcessRecord() {
        InvokeCommand.InvokeScript("Import-Module ./Contoso.Servers");
        ConsoleHostViews.Import(this, "./Contoso.Servers/Contoso.Servers.consoleviews.psd1");
        using var output = new ConsoleDefaultOutput(
            this,
            new ConsoleDefaultOutputOptions { Force = true });
        foreach (var row in InvokeCommand.InvokeScript("Get-ContosoServer")) { output.Write(row); }
        output.Complete();
    }
}

Download HostExample.csproj beside the source file.

PowerShell 7
Import-Module ConsoleMonster
$moduleBinary = Split-Path (Get-Command Show-Console).DLL
dotnet build ./HostExample.csproj -c Release "-p:ConsoleMonsterModuleDirectory=$moduleBinary"
Import-Module ./bin/Release/net8.0/HostExample.dll
Invoke-ModuleViewsExample

This is a compiled PowerShell cmdlet class. Reference the installed module’s ConsoleMonster and ConsoleMonster.PowerShell assemblies in a PowerShell module project; ProcessRecord runs on the owning pipeline thread. Download the project beside the source file and build/run it from PowerShell 7.

C# fluentmodule-views.host.cs
// A compiled cmdlet: the current PowerShell runspace owns native commands and callbacks.
[Cmdlet(VerbsLifecycle.Invoke, "ModuleViewsExample")]
public sealed class ModuleViewsExample : PSCmdlet
{
    protected override void ProcessRecord()
    {
        InvokeCommand.InvokeScript("Import-Module ./Contoso.Servers");
        ConsoleHostViews.Import(this, "./Contoso.Servers/Contoso.Servers.consoleviews.psd1");
        using var output = new ConsoleDefaultOutput(
            this,
            new ConsoleDefaultOutputOptions().Force());
        foreach (var row in InvokeCommand.InvokeScript("Get-ContosoServer"))
        {
            output.Write(row);
        }

        output.Complete();
    }
}
Full program
using System.Management.Automation;
using ConsoleMonster.PowerShell;

// A compiled cmdlet: the current PowerShell runspace owns native commands and callbacks.
[Cmdlet(VerbsLifecycle.Invoke, "ModuleViewsExample")]
public sealed class ModuleViewsExample : PSCmdlet
{
    protected override void ProcessRecord()
    {
        InvokeCommand.InvokeScript("Import-Module ./Contoso.Servers");
        ConsoleHostViews.Import(this, "./Contoso.Servers/Contoso.Servers.consoleviews.psd1");
        using var output = new ConsoleDefaultOutput(
            this,
            new ConsoleDefaultOutputOptions().Force());
        foreach (var row in InvokeCommand.InvokeScript("Get-ContosoServer"))
        {
            output.Write(row);
        }

        output.Complete();
    }
}

Download HostExample.csproj beside the source file.

PowerShell 7
Import-Module ConsoleMonster
$moduleBinary = Split-Path (Get-Command Show-Console).DLL
dotnet build ./HostExample.csproj -c Release "-p:ConsoleMonsterModuleDirectory=$moduleBinary"
Import-Module ./bin/Release/net8.0/HostExample.dll
Invoke-ModuleViewsExample

This is a compiled PowerShell cmdlet class. Reference the installed module’s ConsoleMonster and ConsoleMonster.PowerShell assemblies in a PowerShell module project; ProcessRecord runs on the owning pipeline thread. Download the project beside the source file and build/run it from PowerShell 7.

Ship views with your module

PowerShell 5.1 and 7
# Beside YourModule.psd1:
# YourModule.consoleviews.psd1 with SchemaVersion = 1 and a Views list, as above.
# Your users:
Import-Module YourModule
Import-Module ConsoleMonster
Enable-ConsoleFormatting

See also: Register-ConsoleView

Next

Edit this page on GitHub