Skip to content
ConsoleMonster

Tables that fit the window

ConsoleMonster tables negotiate their width instead of overflowing it. Pick a width to see exactly what a console of that width prints.

Priority, overflow and a footer for what is hidden

DnsClientX-style records. The key column never hides; the SPF value wraps at its separators; the cache path is shortened in the middle; low-priority columns hide first and the footer names them.

  • Priority, MinWidth and MaxWidth per column
  • Wrap with MaxLines, Truncate, TruncateMiddle or Never
  • A footer such as +2 columns (TTL, Cache file)
TableShowcases.DnsRecords() 100×1924-bitFull
 evotec.xyz · DNS records via Cloudflare DoH
╭────────────────────────────┬───────┬──────────┬────────────────────────────────────────┬─────────╮
│ Name                       │ Type  │      TTL │ Data                                   │ Latency │
├────────────────────────────┼───────┼──────────┼────────────────────────────────────────┼─────────┤
│ evotec.xyz                 │ A     │ 5 m 00 s │ 104.21.48.12                           │   12 ms │
│ evotec.xyz                 │ AAAA  │ 5 m 00 s │ 2606:4700:3036::6815:300c              │   14 ms │
│ evotec.xyz                 │ MX    │ 1 h 00 m │ 10                                     │   18 ms │
│                            │       │          │ evotec-xyz.mail.protection.outlook.com │         │
│ evotec.xyz                 │ TXT   │ 1 h 00 m │ v=spf1                                 │   21 ms │
│                            │       │          │ include:spf.protection.outlook.com     │         │
│                            │       │          │ include:_spf.google.com…               │         │
│ _dmarc.evotec.xyz          │ TXT   │ 1 h 00 m │ v=DMARC1; p=reject;                    │  133 ms │
│                            │       │          │ rua=mailto:dmarc@evotec.xyz;           │         │
│                            │       │          │ ruf=mailto:forensic@evotec.xyz; fo=1   │         │
│ selector1._do…y.evotec.xyz │ CNAME │ 1 h 00 m │ selector1-evotec-xyz._domainkey.       │   16 ms │
│                            │       │          │ evotecpl.onmicrosoft.com               │         │
│ evotec.xyz                 │ CAA   │ 1 h 00 m │ 0 issue "letsencrypt.org"              │   15 ms │
╰────────────────────────────┴───────┴──────────┴────────────────────────────────────────┴─────────╯
 +1 column (Cache file)

Every table here is a showcase from ConsoleMonster.Examples, rendered by the site tool at 120, 100, 80, 64, 48 and 36 columns. The data is synthetic and the clock is fixed, so relative dates read the same in every render. From PowerShell, Format-ConsoleTable, Format-ConsoleList and Format-ConsoleTree build the same widgets from pipeline input; the PowerShell page shows them beside Format-Table.

Status, durations and tone rules

DomainDetective-style mail checks. Status presenters show a symbol and a word, so the result reads without colour; durations use the presenter's units.

Status, durations and tone rules 100×1424-bitFull
 evotec.xyz · DomainDetective checks
╭─────────┬────────┬───────────────────────────────────────────────────────────────┬────────┬──────╮
│ Check   │ Status │ Detail                                                        │   Took │ RFC  │
├─────────┼────────┼───────────────────────────────────────────────────────────────┼────────┼──────┤
│ SPF     │ ✓ PASS │ 9 DNS lookups (limit 10); ends with -all                      │  84 ms │ 7208 │
│ DMARC   │ ✓ PASS │ p=reject, aggregate and forensic reports configured           │  41 ms │ 7489 │
│ DKIM    │ ▴ WARN │ selector2 key is 1024-bit; selector1 is 2048-bit. Rotate      │ 212 ms │ 6376 │
│         │        │ selector2 to a 2048-bit key                                   │        │      │
│ MTA-STS │ ✗ FAIL │ policy file returns 404 at                                    │  1.4 s │ 8461 │
│         │        │ https://mta-sts.evotec.xyz/.well-known/mta-sts.txt            │        │      │
│ TLS-RPT │ – SKIP │ not published                                                 │  22 ms │ 8460 │
│ DNSSEC  │ ▴ WARN │ zone is not signed                                            │  95 ms │ 4033 │
│ BIMI    │ ◆ INFO │ no record; optional                                           │  19 ms │      │
╰─────────┴────────┴───────────────────────────────────────────────────────────────┴────────┴──────╯
 evotec.xyz · DomainDetective checks
╭─────────┬────────┬───────────────────────────────────────────────────────────────┬────────┬──────╮
│ Check   │ Status │ Detail                                                        │   Took │ RFC  │
├─────────┼────────┼───────────────────────────────────────────────────────────────┼────────┼──────┤
│ SPF     │ ✓ PASS │ 9 DNS lookups (limit 10); ends with -all                      │  84 ms │ 7208 │
│ DMARC   │ ✓ PASS │ p=reject, aggregate and forensic reports configured           │  41 ms │ 7489 │
│ DKIM    │ ▴ WARN │ selector2 key is 1024-bit; selector1 is 2048-bit. Rotate      │ 212 ms │ 6376 │
│         │        │ selector2 to a 2048-bit key                                   │        │      │
│ MTA-STS │ ✗ FAIL │ policy file returns 404 at                                    │  1.4 s │ 8461 │
│         │        │ https://mta-sts.evotec.xyz/.well-known/mta-sts.txt            │        │      │
│ TLS-RPT │ – SKIP │ not published                                                 │  22 ms │ 8460 │
│ DNSSEC  │ ▴ WARN │ zone is not signed                                            │  95 ms │ 4033 │
│ BIMI    │ ◆ INFO │ no record; optional                                           │  19 ms │      │
╰─────────┴────────┴───────────────────────────────────────────────────────────────┴────────┴──────╯
  • Cell presenters shared by tables, cards, key/value lists and trees
  • A tone rule colours a value by threshold
  • Below 60 cells the rows become cards
C# source
C#ConsoleMonster.Examples/Showcases/TableShowcases.cs
public static Table DomainChecks() {
    Table table = new Table { Title = "[bold]evotec.xyz[/] [muted]· DomainDetective checks[/]" };
    table.AddColumn(new TableColumn("Check") { IsKey = true, Overflow = ColumnOverflow.Never });
    table.AddColumn(new TableColumn("Status") { Priority = 10, Presenter = CellPresenters.Status });
    table.AddColumn(new TableColumn("Detail") { Priority = 5, Overflow = ColumnOverflow.Wrap, MaxLines = 2, Flexible = true, MinWidth = 18 });
    table.AddColumn(new TableColumn("Took") { Priority = 1, Presenter = CellPresenters.Duration });
    table.AddColumn(new TableColumn("RFC") { Priority = 0, Overflow = ColumnOverflow.Never });
    table.AddValues("SPF", StatusKind.Pass, "9 DNS lookups (limit 10); ends with -all", TimeSpan.FromMilliseconds(84), "7208");
    table.AddValues("DMARC", StatusKind.Pass, "p=reject, aggregate and forensic reports configured", TimeSpan.FromMilliseconds(41), "7489");
    table.AddValues("DKIM", StatusKind.Warn, "selector2 key is 1024-bit; selector1 is 2048-bit. Rotate selector2 to a 2048-bit key", TimeSpan.FromMilliseconds(212), "6376");
    table.AddValues("MTA-STS", StatusKind.Fail, "policy file returns 404 at https://mta-sts.evotec.xyz/.well-known/mta-sts.txt", TimeSpan.FromSeconds(1.4), "8461");
    table.AddValues("TLS-RPT", StatusKind.Skip, "not published", TimeSpan.FromMilliseconds(22), "8460");
    table.AddValues("DNSSEC", StatusKind.Warn, "zone is not signed", TimeSpan.FromMilliseconds(95), "4033");
    table.AddValues("BIMI", StatusKind.Info, "no record; optional", TimeSpan.FromMilliseconds(19), null);
    return table;
}

Groups, subtotals and totals

A TestimoX run summary grouped by target type, with subtotals, a totals row and a score drawn as a data bar inside the cell.

Groups, subtotals and totals 100×1824-bitFull
 TestimoX · ad.evotec.xyz run summary
╭───────────────────────┬────────┬────────┬────────┬──────────┬──────────┬──────────────────╮
│ Target                │ Result │ Passed │ Failed │ Warnings │ Duration │            Score │
├───────────────────────┼────────┼────────┼────────┼──────────┼──────────┼──────────────────┤
│ Domains  2                                                                                │
│ ad.evotec.xyz         │ ✗ FAIL │      9 │      2 │        5 │     24 s │ ▆▆▆▆▆▆      56 % │
│ eu.ad.evotec.xyz      │ ✗ FAIL │     13 │      1 │        1 │     16 s │ ▆▆▆▆▆▆▆▆▆   87 % │
│ Subtotal              │        │     22 │      3 │        6 │     40 s │           71.5 % │
│ Domain controllers  5                                                                     │
│ DC01.ad.evotec.xyz    │ ▴ WARN │     26 │      0 │        3 │     17 s │ ▆▆▆▆▆▆▆▆▆   90 % │
│ DC02.ad.evotec.xyz    │ ▴ WARN │     23 │      0 │        6 │     17 s │ ▆▆▆▆▆▆▆▆    79 % │
│ DC03.ad.evotec.xyz    │ ✗ FAIL │     23 │      3 │        4 │     19 s │ ▆▆▆▆▆▆▆▆    77 % │
│ DC07.eu.ad.evotec.xyz │ ✗ FAIL │     21 │      4 │        4 │     16 s │ ▆▆▆▆▆▆▆     72 % │
│ DC09.eu.ad.evotec.xyz │ ✓ PASS │     30 │      0 │        0 │     15 s │ ▆▆▆▆▆▆▆▆▆▆ 100 % │
│ Subtotal              │        │    123 │      7 │       17 │ 1 m 24 s │           83.6 % │
├───────────────────────┼────────┼────────┼────────┼──────────┼──────────┼──────────────────┤
│ Total                 │        │    145 │     10 │       23 │ 2 m 04 s │          80.14 % │
╰───────────────────────┴────────┴────────┴────────┴──────────┴──────────┴──────────────────╯
 TestimoX · ad.evotec.xyz run summary
╭───────────────────────┬────────┬────────┬────────┬──────────┬──────────┬──────────────────╮
│ Target                │ Result │ Passed │ Failed │ Warnings │ Duration │            Score │
├───────────────────────┼────────┼────────┼────────┼──────────┼──────────┼──────────────────┤
│ Domains  2                                                                                │
│ ad.evotec.xyz         │ ✗ FAIL │      9 │      2 │        5 │     24 s │ ▆▆▆▆▆▆      56 % │
│ eu.ad.evotec.xyz      │ ✗ FAIL │     13 │      1 │        1 │     16 s │ ▆▆▆▆▆▆▆▆▆   87 % │
│ Subtotal              │        │     22 │      3 │        6 │     40 s │           71.5 % │
│ Domain controllers  5                                                                     │
│ DC01.ad.evotec.xyz    │ ▴ WARN │     26 │      0 │        3 │     17 s │ ▆▆▆▆▆▆▆▆▆   90 % │
│ DC02.ad.evotec.xyz    │ ▴ WARN │     23 │      0 │        6 │     17 s │ ▆▆▆▆▆▆▆▆    79 % │
│ DC03.ad.evotec.xyz    │ ✗ FAIL │     23 │      3 │        4 │     19 s │ ▆▆▆▆▆▆▆▆    77 % │
│ DC07.eu.ad.evotec.xyz │ ✗ FAIL │     21 │      4 │        4 │     16 s │ ▆▆▆▆▆▆▆     72 % │
│ DC09.eu.ad.evotec.xyz │ ✓ PASS │     30 │      0 │        0 │     15 s │ ▆▆▆▆▆▆▆▆▆▆ 100 % │
│ Subtotal              │        │    123 │      7 │       17 │ 1 m 24 s │           83.6 % │
├───────────────────────┼────────┼────────┼────────┼──────────┼──────────┼──────────────────┤
│ Total                 │        │    145 │     10 │       23 │ 2 m 04 s │          80.14 % │
╰───────────────────────┴────────┴────────┴────────┴──────────┴──────────┴──────────────────╯
  • AddGroup with ShowSubtotals
  • Sum, Count, Average, Min and Max per column
  • A data bar presenter in a cell
C# source
C#ConsoleMonster.Examples/Showcases/TableShowcases.cs
public static Table TestimoXSummary() {
    Table table = new Table { Title = "[bold]TestimoX[/] [muted]· ad.evotec.xyz run summary[/]", ShowSubtotals = true, ShowTotals = true };
    table.AddColumn(new TableColumn("Target") { IsKey = true, Overflow = ColumnOverflow.TruncateMiddle, MinWidth = 12 });
    table.AddColumn(new TableColumn("Result") { Priority = 10, Presenter = CellPresenters.Status });
    table.AddColumn(new TableColumn("Passed") { Priority = 8, Presenter = CellPresenters.Number, Aggregate = ColumnAggregate.Sum });
    table.AddColumn(new TableColumn("Failed") { Priority = 9, Presenter = CellPresenters.Number, Aggregate = ColumnAggregate.Sum, ToneRules = { ToneRule.Above(0, ThemeToken.Fail) } });
    table.AddColumn(new TableColumn("Warnings") { Priority = 6, Presenter = CellPresenters.Number, Aggregate = ColumnAggregate.Sum, ToneRules = { ToneRule.Above(0, ThemeToken.Warn) } });
    table.AddColumn(new TableColumn("Duration") { Priority = 4, Presenter = CellPresenters.Duration, Aggregate = ColumnAggregate.Sum });
    table.AddColumn(new TableColumn("Score") { Priority = 2, Presenter = new DataBarPresenter(100, new NumberPresenter("%")), Aggregate = ColumnAggregate.Average });
    table.AddGroup("Domains");
    table.AddValues("ad.evotec.xyz", StatusKind.Fail, 9, 2, 5, TimeSpan.FromSeconds(24), 56);
    table.AddValues("eu.ad.evotec.xyz", StatusKind.Fail, 13, 1, 1, TimeSpan.FromSeconds(16), 87);
    table.AddGroup("Domain controllers");
    table.AddValues("DC01.ad.evotec.xyz", StatusKind.Warn, 26, 0, 3, TimeSpan.FromSeconds(17), 90);
    table.AddValues("DC02.ad.evotec.xyz", StatusKind.Warn, 23, 0, 6, TimeSpan.FromSeconds(17), 79);
    table.AddValues("DC03.ad.evotec.xyz", StatusKind.Fail, 23, 3, 4, TimeSpan.FromSeconds(19), 77);
    table.AddValues("DC07.eu.ad.evotec.xyz", StatusKind.Fail, 21, 4, 4, TimeSpan.FromSeconds(16), 72);
    table.AddValues("DC09.eu.ad.evotec.xyz", StatusKind.Pass, 30, 0, 0, TimeSpan.FromSeconds(15), 100);
    return table;
}

Bytes, relative dates and top N

PSPublishModule-style build artifacts: sizes in bytes, build times, relative dates against a fixed clock, and the first five of 1,234 rows.

Bytes, relative dates and top N 100×1424-bitFull
 PSPublishModule · ConsoleMonster 2.0.0 artifacts
╭───────────────────────────────┬─────────┬─────────┬──────────┬──────────┬────────────────────────╮
│ Artifact                      │ Kind    │    Size │ Built in │ Created  │ Path                   │
├───────────────────────────────┼─────────┼─────────┼──────────┼──────────┼────────────────────────┤
│ ConsoleMonster.2.0.0.nupkg    │ NuGet   │ 1.41 MB │     48 s │ 12 m ago │ C:\Support\….0.0.nupkg │
│ ConsoleMonster.2.0.0.snupkg   │ Symbols │  393 KB │    3.1 s │ 12 m ago │ C:\Support\…0.0.snupkg │
│ ConsoleMonster-2.0.0.zip      │ Module  │ 2.77 MB │     12 s │ 11 m ago │ C:\Support\…-2.0.0.zip │
│ ConsoleMonster.PowerShell.dll │ Binary  │  184 KB │     23 s │ 3 h ago  │ C:\Support\…rShell.dll │
│ en-US\ConsoleMonster-help.xml │ Help    │   94 KB │    6.4 s │ 2 d ago  │ C:\Support\…r-help.xml │
├───────────────────────────────┼─────────┼─────────┼──────────┼──────────┼────────────────────────┤
│ Total                         │         │ 4.89 MB │ 1 m 33 s │          │                        │
╰───────────────────────────────┴─────────┴─────────┴──────────┴──────────┴────────────────────────╯
 +1 column (SHA256)
 Showing 5 of 1,234
 PSPublishModule · ConsoleMonster 2.0.0 artifacts
╭───────────────────────────────┬─────────┬─────────┬──────────┬──────────┬────────────────────────╮
│ Artifact                      │ Kind    │    Size │ Built in │ Created  │ Path                   │
├───────────────────────────────┼─────────┼─────────┼──────────┼──────────┼────────────────────────┤
│ ConsoleMonster.2.0.0.nupkg    │ NuGet   │ 1.41 MB │     48 s │ 12 m ago │ C:\Support\….0.0.nupkg │
│ ConsoleMonster.2.0.0.snupkg   │ Symbols │  393 KB │    3.1 s │ 12 m ago │ C:\Support\…0.0.snupkg │
│ ConsoleMonster-2.0.0.zip      │ Module  │ 2.77 MB │     12 s │ 11 m ago │ C:\Support\…-2.0.0.zip │
│ ConsoleMonster.PowerShell.dll │ Binary  │  184 KB │     23 s │ 3 h ago  │ C:\Support\…rShell.dll │
│ en-US\ConsoleMonster-help.xml │ Help    │   94 KB │    6.4 s │ 2 d ago  │ C:\Support\…r-help.xml │
├───────────────────────────────┼─────────┼─────────┼──────────┼──────────┼────────────────────────┤
│ Total                         │         │ 4.89 MB │ 1 m 33 s │          │                        │
╰───────────────────────────────┴─────────┴─────────┴──────────┴──────────┴────────────────────────╯
 +1 column (SHA256)
 Showing 5 of 1,234
  • Bytes, Duration and Date presenters
  • MaxRows with TotalRowCount prints Showing 5 of 1,234
  • Numbers follow the culture; the site renders en-US
C# source
C#ConsoleMonster.Examples/Showcases/TableShowcases.cs
public static Table PublishArtifacts() {
    Table table = new Table { Title = "[bold]PSPublishModule[/] [muted]· ConsoleMonster 2.0.0 artifacts[/]", ShowTotals = true, MaxRows = 5, TotalRowCount = 1234 };
    table.Presentation.Now = Now;
    table.AddColumn(new TableColumn("Artifact") { IsKey = true, Overflow = ColumnOverflow.Never });
    table.AddColumn(new TableColumn("Kind") { Priority = 3 });
    table.AddColumn(new TableColumn("Size") { Priority = 9, Presenter = CellPresenters.Bytes, Aggregate = ColumnAggregate.Sum });
    table.AddColumn(new TableColumn("Built in") { Priority = 6, Presenter = CellPresenters.Duration, Aggregate = ColumnAggregate.Sum });
    table.AddColumn(new TableColumn("Created") { Priority = 4, Presenter = new DatePresenter(DateDisplay.Relative) });
    table.AddColumn(new TableColumn("Path") { Priority = 1, Overflow = ColumnOverflow.TruncateMiddle, MinWidth = 20, MaxWidth = 40 });
    table.AddColumn(new TableColumn("SHA256") { Priority = 0, Overflow = ColumnOverflow.Truncate, MaxWidth = 14 });
    const string Root = @"C:\Support\GitHub\ConsoleMonster\Artefacts\Packed\";
    table.AddValues("ConsoleMonster.2.0.0.nupkg", "NuGet", 1_482_113L, TimeSpan.FromSeconds(48.2), Now.AddMinutes(-12), Root + "ConsoleMonster.2.0.0.nupkg", "9f2c4e81a7d03b6e");
    table.AddValues("ConsoleMonster.2.0.0.snupkg", "Symbols", 402_331L, TimeSpan.FromSeconds(3.1), Now.AddMinutes(-12), Root + "ConsoleMonster.2.0.0.snupkg", "41ab09cd77e2f310");
    table.AddValues("ConsoleMonster-2.0.0.zip", "Module", 2_904_576L, TimeSpan.FromSeconds(11.7), Now.AddMinutes(-11), Root + "ConsoleMonster-2.0.0.zip", "c0ffee4251de9a07");
    table.AddValues("ConsoleMonster.PowerShell.dll", "Binary", 188_416L, TimeSpan.FromSeconds(22.9), Now.AddHours(-3), @"C:\Support\GitHub\ConsoleMonster\Sources\ConsoleMonster.PowerShell\bin\Release\net8.0\ConsoleMonster.PowerShell.dll", "77aa13f9b2c46e5d");
    table.AddValues("en-US\\ConsoleMonster-help.xml", "Help", 96_210L, TimeSpan.FromSeconds(6.4), Now.AddDays(-2), Root + @"en-US\ConsoleMonster-help.xml", "0be4d29c6a1f8873");
    table.AddValues("Docs.zip", "Docs", 51_302L, TimeSpan.FromSeconds(1.2), Now.AddDays(-9), Root + "Docs.zip", "5d6e7f8091a2b3c4");
    return table;
}

One record as a record view

A certificate as sections, fields and nested tables. Empty fields are hidden and dates show both absolute and relative forms.

One record as a record view 100×2124-bitFull
mail.evotec.xyz  ·  TLS certificate · ECDSA P-256 · Let's Encrypt

Certificate
  Subject           CN=mail.evotec.xyz
  Issuer            CN=R11, O=Let's Encrypt, C=US
  Serial            04:A1:7F:3C:9E:22:51:0B:6D:8E:F0:13:44:2A:BC:91
  Valid from (UTC)  2026-08-09 12:00 (2 mo ago)
  Valid to (UTC)    2026-11-08 12:00 (in 22 d)
  Key               ECDSA P-256
  OCSP stapling     ✓ yes
  Revoked           – no
  Subject alternative names  3
    mail.evotec.xyz
    autodiscover.evotec.xyz
    mta-sts.evotec.xyz
  Chain  3 certificates
    Subject                  Expires  Key
    ───────────────────────  ───────  ───────────
    CN=mail.evotec.xyz       in 22 d  ECDSA P-256
    CN=R11, O=Let's Encrypt  in 4 mo  RSA 2048
    CN=ISRG Root X1          in 8 y   RSA 4096
mail.evotec.xyz  ·  TLS certificate · ECDSA P-256 · Let's Encrypt

Certificate
  Subject           CN=mail.evotec.xyz
  Issuer            CN=R11, O=Let's Encrypt, C=US
  Serial            04:A1:7F:3C:9E:22:51:0B:6D:8E:F0:13:44:2A:BC:91
  Valid from (UTC)  2026-08-09 12:00 (2 mo ago)
  Valid to (UTC)    2026-11-08 12:00 (in 22 d)
  Key               ECDSA P-256
  OCSP stapling     ✓ yes
  Revoked           – no
  Subject alternative names  3
    mail.evotec.xyz
    autodiscover.evotec.xyz
    mta-sts.evotec.xyz
  Chain  3 certificates
    Subject                  Expires  Key
    ───────────────────────  ───────  ───────────
    CN=mail.evotec.xyz       in 22 d  ECDSA P-256
    CN=R11, O=Let's Encrypt  in 4 mo  RSA 2048
    CN=ISRG Root X1          in 8 y   RSA 4096
  • Sections, groups and nested widgets
  • Boolean presenters can mark either value as the problem
  • A single record from Format-ConsoleTable renders this way
C# source
C#ConsoleMonster.Examples/Showcases/TableShowcases.cs
public static RecordView Certificate() {
    RecordView view = new RecordView("[bold]mail.evotec.xyz[/]") { Summary = "TLS certificate · ECDSA P-256 · Let's Encrypt" };
    view.Presentation.Now = Now;
    view.Presentation.TimeZone = TimeZoneInfo.Utc;
    view.AddSection("Certificate");
    view.AddField("Subject", "CN=mail.evotec.xyz");
    view.AddField("Issuer", "CN=R11, O=Let's Encrypt, C=US");
    view.AddField("Serial", "04:A1:7F:3C:9E:22:51:0B:6D:8E:F0:13:44:2A:BC:91");
    view.AddField("Valid from (UTC)", new DateTimeOffset(2026, 8, 9, 12, 0, 0, TimeSpan.Zero), new DatePresenter(DateDisplay.Both));
    view.AddField("Valid to (UTC)", new DateTimeOffset(2026, 11, 8, 12, 0, 0, TimeSpan.Zero), new DatePresenter(DateDisplay.Both), new[] { ToneRule.Below(0, ThemeToken.Fail), ToneRule.Below(30, ThemeToken.Warn) });
    view.AddField("Key", "ECDSA P-256");
    view.AddField("OCSP stapling", true);
    view.AddField("Revoked", false, new BooleanPresenter(trueIsProblem: true));
    view.AddField("Notes", (object?)null);
    view.AddGroup("Subject alternative names", "3");
    Table sans = new Table { Border = TableBorder.None, ShowHeader = false, RecordViewRows = 0 };
    sans.AddColumn("Name");
    sans.AddValues("mail.evotec.xyz");
    sans.AddValues("autodiscover.evotec.xyz");
    sans.AddValues("mta-sts.evotec.xyz");
    view.AddWidget(sans);
    view.AddGroup("Chain", "3 certificates");
    Table chain = new Table { Border = TableBorder.Minimal, RecordViewRows = 0 };
    chain.Presentation.Now = Now;
    chain.Presentation.TimeZone = TimeZoneInfo.Utc;
    chain.AddColumn(new TableColumn("Subject") { IsKey = true });
    chain.AddColumn(new TableColumn("Expires") { Presenter = new DatePresenter(DateDisplay.Relative), ToneRules = { ToneRule.Below(30, ThemeToken.Warn) } });
    chain.AddColumn(new TableColumn("Key") { Priority = 1 });
    chain.AddValues("CN=mail.evotec.xyz", new DateTimeOffset(2026, 11, 8, 12, 0, 0, TimeSpan.Zero), "ECDSA P-256");
    chain.AddValues("CN=R11, O=Let's Encrypt", new DateTimeOffset(2027, 3, 12, 23, 59, 59, TimeSpan.Zero), "RSA 2048");
    chain.AddValues("CN=ISRG Root X1", new DateTimeOffset(2035, 6, 4, 11, 4, 38, TimeSpan.Zero), "RSA 4096");
    view.AddWidget(chain);
    return view;
}

The object inspector

Nested dictionaries and lists, shown as indented sections and nested tables. The inspector also reads .NET objects, PSObjects and JSON, with depth, item and node limits.

The object inspector 100×2024-bitFull
evotec.xyz zone  ·  6 members
Name    evotec.xyz
Serial  2,351,234,567
Signed  – no

Soa  Dictionary<String, Object>
  Primary  dana.ns.cloudflare.com
  Refresh  2 h 46 m
  Expire   7 d 0 h

NameServers  2 items
  Host                    Address          LatencyMs
  ──────────────────────  ───────────────  ─────────
  dana.ns.cloudflare.com  108.162.192.103         12
  kirk.ns.cloudflare.com  172.64.33.149           14

Tags  3 items
  [0]  production
  [1]  cloudflare
  [2]  doh
evotec.xyz zone  ·  6 members
Name    evotec.xyz
Serial  2,351,234,567
Signed  – no

Soa  Dictionary<String, Object>
  Primary  dana.ns.cloudflare.com
  Refresh  2 h 46 m
  Expire   7 d 0 h

NameServers  2 items
  Host                    Address          LatencyMs
  ──────────────────────  ───────────────  ─────────
  dana.ns.cloudflare.com  108.162.192.103         12
  kirk.ns.cloudflare.com  172.64.33.149           14

Tags  3 items
  [0]  production
  [1]  cloudflare
  [2]  doh
  • MaxDepth, MaxItems and MaxNodes bound one inspection
  • Cycles are detected and marked
  • Format-ConsoleTree -AsInspector in PowerShell
C# source
C#Website/tools/SiteFrames/Catalog/PageExamples.cs
Dictionary<string, object?> zone = new Dictionary<string, object?> {
    ["Name"] = "evotec.xyz",
    ["Serial"] = 2351234567L,
    ["Signed"] = false,
    ["Soa"] = new Dictionary<string, object?> {
        ["Primary"] = "dana.ns.cloudflare.com",
        ["Refresh"] = TimeSpan.FromSeconds(10000),
        ["Expire"] = TimeSpan.FromSeconds(604800)
    },
    ["NameServers"] = new List<Dictionary<string, object?>> {
        new Dictionary<string, object?> { ["Host"] = "dana.ns.cloudflare.com", ["Address"] = "108.162.192.103", ["LatencyMs"] = 12 },
        new Dictionary<string, object?> { ["Host"] = "kirk.ns.cloudflare.com", ["Address"] = "172.64.33.149", ["LatencyMs"] = 14 }
    },
    ["Tags"] = new[] { "production", "cloudflare", "doh" }
};
Terminal.Write(new InspectorView(zone, new InspectorOptions { MaxDepth = 3 }, "evotec.xyz zone"));