1+ function ConvertTo-MarkdownTable {
2+ <#
3+ . SYNOPSIS
4+ Converts a collection of objects into a markdown-formatted table.
5+
6+ . DESCRIPTION
7+ The `ConvertTo-MarkdownTable` function converts a collection of objects into a markdown-formatted table. The names
8+ of all properties on the first object are used as column names in the order they are defined. If subsequent objects
9+ define properties that were not present on the first item processed, those additional properties will be ignored
10+ and columns will not be created for them.
11+
12+ Optionally, a maximum width can be specified for one, or all columns using MaxColumnWidth. However, if the length
13+ of the name column header is greater than the specified MaxColumnWidth, the MaxColumnWidth value used for that
14+ column will be the length of the column header. Rows with column values longer than MaxColumnWidth will be truncated
15+ and the Ellipsis string will be appended to the end with the length of the resulting string, plus ellipsis characters,
16+ equaling the MaxColumnWidth value for that column.
17+
18+ By default, all columns will be padded with a space between any column header or value and the "|" characters on
19+ either side. Values shorter than the longest value in the column will be right-padded so that all "|" characters
20+ align vertically throughout the table.
21+
22+ If the additional white space is not desired, use of the `Compress` switch will omit any unnecessary white space.
23+
24+ . PARAMETER InputObject
25+ Specified the object, or a collection of objects to represent in the resulting markdown data table. All properties
26+ of InputObject will be used to define the resulting columns. Consider using `Select-Object` first to select which
27+ properties on the source object should be passed to this function.
28+
29+ . PARAMETER MaxColumnWidth
30+ Specifies the maximum length of all columns if one value is provided, or the maximum length of each individual column
31+ if more than one value is provided. When providing more than one value, you must provide a value for every column. Columns
32+ with values longer than MaxColumnWidth will be truncated, and the Ellipsis characters will be appended. The length
33+ of the resulting string with ellipsis will match the MaxColumnWidth value.
34+
35+ The default value is `[int]::MaxValue` so effectively no columns will be truncated. And the minimum value is the length
36+ of Ellipsis + 1, or 4 by default.
37+
38+ . PARAMETER Ellipsis
39+ Specifies the characters to use as an ellipsis. By default, the ellipsis value is "...", but this can be overridden
40+ to be an empty string, or some other value. The minimum value for MaxColumnWidth is defined as 1 + the length of Ellipsis.
41+
42+ . PARAMETER Compress
43+ Specifies that no extra padding should be added to make the "|" symbols align vertically.
44+
45+ . EXAMPLE
46+ Get-Process | Select-Object Name, Id, VirtualMemorySize | ConvertTo-MarkdownTable -MaxColumnWidth 16
47+
48+ Gets a list of processes, selects the Name, Id, and VirtualMemorySize properties, and returns a markdown-formatted
49+ table representing all properties with a maximum column width of 16 characters.
50+
51+ . EXAMPLE
52+ Get-Service | Select-Object DisplayName, Name, Status | ConvertTo-MarkdownTable
53+
54+ Generates a markdown-formatted table with the DisplayName, Name, and Status properties of all services.
55+
56+ . EXAMPLE
57+ Get-Service | Select-Object DisplayName, Name, Status | ConvertTo-MarkdownTable -Compress
58+
59+ Generates a markdown-formatted table with the DisplayName, Name, and Status properties of all services, without any
60+ unnecessary padding, resulting in a much shorter string for large sets of data.
61+
62+ . NOTES
63+ Based on gist at https://gist.github.com/joshooaj/ef9b5ac769dd0f824c01497bf3e771dc
64+ #> #
65+ [CmdletBinding ()]
66+ [OutputType ([string ])]
67+ param (
68+ [Parameter (Mandatory , ValueFromPipeline , Position = 0 )]
69+ [psobject []]
70+ $InputObject ,
71+
72+ [Parameter ()]
73+ [ValidateRange (1 , [int ]::MaxValue)]
74+ [int []]
75+ $MaxColumnWidth = ([int ]::MaxValue),
76+
77+ [Parameter ()]
78+ [string ]
79+ $Ellipsis = ' ...' ,
80+
81+ [Parameter ()]
82+ [switch ]
83+ $Compress
84+ )
85+
86+ begin {
87+ $MaxColumnWidth | ForEach-Object {
88+ if ($_ -le $Ellipsis.Length ) {
89+ throw " MaxColumnWidth values must be greater than $ ( $Ellipsis.Length ) which is the length of the Ellipsis parameter. $_ "
90+ }
91+ }
92+ $items = [system.collections.generic.list [object ]]::new()
93+ $columns = [ordered ]@ {}
94+ $firstRecordProcessed = $false
95+ }
96+
97+ process {
98+ foreach ($item in $InputObject ) {
99+ $items.Add ($item )
100+ $columnNumber = 0
101+ foreach ($property in $item.PSObject.Properties ) {
102+ if ($MaxColumnWidth.Count -gt 1 -and $MaxColumnWidth.Count -lt ($columnNumber + 1 )) {
103+ throw " No MaxColumnWidth value defined for column $ ( $columnNumber + 1 ) . MaxColumnWidth must define a single value for all columns, or one value for each column."
104+ }
105+
106+ $maxLength = $MaxColumnWidth [0 ]
107+ if ($MaxColumnWidth.Count -gt 1 ) {
108+ $maxLength = $MaxColumnWidth [$columnNumber ]
109+ }
110+
111+ if (-not $columns.Contains ($property.Name )) {
112+ if ($firstRecordProcessed ) {
113+ Write-Warning " Ignoring property '$ ( $property.Name ) ' on $item because the property was not present in the first item processed."
114+ continue
115+ } else {
116+ $columns [$property.Name ] = $property.Name.Length
117+ if ($property.Name.Length -gt $maxLength ) {
118+ $maxLength = $property.Name.Length
119+ Write-Warning " The header for column $columnNumber , '$ ( $property.Name ) ', is longer than the MaxColumnWidth value provided. The MaxColumnWidth value for this column is now $maxLength ."
120+ }
121+ }
122+ }
123+
124+ $length = 0
125+ if ($null -ne $property.Value ) {
126+ $length = [math ]::Min($maxLength , $property.Value.ToString ().Length)
127+ }
128+
129+ if ($columns [$property.Name ] -lt $length ) {
130+ $columns [$property.Name ] = $length
131+ }
132+ $columnNumber ++
133+ }
134+ $firstRecordProcessed = $true
135+ }
136+ }
137+
138+ end {
139+ function Shorten {
140+ param (
141+ [Parameter (ValueFromPipeline )]
142+ [string ]
143+ $InputObject ,
144+
145+ [Parameter (Mandatory )]
146+ [ValidateRange (1 , [int ]::MaxValue)]
147+ [int ]
148+ $MaxLength ,
149+
150+ [Parameter ()]
151+ [string ]
152+ $Ellipsis = ' ...'
153+ )
154+
155+ process {
156+ if ($InputObject.Length -gt $MaxLength ) {
157+ ' {0}{1}' -f $InputObject.Substring (0 , ($MaxLength - $Ellipsis.Length )), $Ellipsis
158+ } else {
159+ $InputObject
160+ }
161+ }
162+ }
163+
164+ $sb = [text.stringbuilder ]::new()
165+
166+ # Header
167+ $paddedColumnNames = $columns.GetEnumerator () | ForEach-Object {
168+ $text = $_.Key | Shorten - MaxLength $_.Value - Ellipsis $Ellipsis
169+ if ($Compress ) {
170+ ' {0} ' -f $text
171+ } else {
172+ ' {0} ' -f ($text.PadRight ($_.Value ))
173+ }
174+ }
175+ $null = $sb.AppendLine (' |' + ($paddedColumnNames -join ' |' ) + ' |' )
176+ $null = $sb.AppendLine (' |' + (($paddedColumnNames | ForEach-Object { ' -' * $_.Length } ) -join ' |' ) + ' |' )
177+
178+ foreach ($item in $items ) {
179+ $paddedRowValues = $columns.GetEnumerator () | ForEach-Object {
180+ $text = [string ]::Empty
181+ if ($null -ne $item .($_.Key )) {
182+ $text = $item .($_.Key ) | Shorten - MaxLength $_.Value - Ellipsis $Ellipsis
183+ }
184+ if ($Compress ) {
185+ ' {0} ' -f $text
186+ } else {
187+ ' {0} ' -f $text.PadRight ($_.Value )
188+ }
189+ }
190+
191+ $null = $sb.AppendLine (' |' + ($paddedRowValues -join ' |' ) + ' |' )
192+ }
193+ $sb.ToString ()
194+ }
195+ }
0 commit comments