Now that I have my custom type I can use cmdlets such as Format-Table
or Format-List
to format its output while at the console, but it would be nice if I did not have to remember to usem the every time. Powershell uses Format.ps1xml
to define how types should be formatted when their output is sent to the console and this technique can come to our rescue.
If an output object exposes up to 4 properties, by default Powershell formats it as a table while objects with 5+ displayed properties are formatted as list for better readability; for example, in this first example I am selecting only four properties and Powershell prints data in a table format, while in the second example I am selecting five properties and Powershell presents then in a list:
λ 16 carlo@CARLOCXPS 21:36:08 carlo >_ dir | select Name, Exists, Mode, CreationTime Name Exists Mode CreationTime ---- ------ ---- ------------ .atom True d----- 4/18/2018 8:04:37 AM .azure True d----- 3/23/2018 7:48:42 PM .azure-shell True d----- 12/30/2018 1:40:08 PM .config True d----- 4/27/2018 8:35:53 PM .dotnet True d----- 3/15/2018 1:48:02 PM .electron True d----- 8/23/2018 5:17:56 PM .hyper_plugins True d----- 6/4/2018 8:58:08 AM .mume True d----- 1/30/2019 8:26:59 PM .nuget True d----- 9/20/2018 9:55:27 AM .omnisharp True d----- 1/30/2019 7:10:26 AM .rest-client True d----- 8/3/2018 9:59:46 PM .templateengine True d----- 4/6/2018 9:09:33 PM .VirtualBox True d----- 5/24/2018 9:36:28 PM .vscode True d----- 10/9/2018 11:24:33 AM .vscode-exploration True d----- 2/1/2019 6:05:52 AM .vscode-insiders True d----- 1/30/2019 5:48:11 AM λ 18 carlo@CARLOCXPS 21:40:04 carlo >_ dir | select Name, Exists, Mode, CreationTime, LastWriteTime Name : .atom Exists : True Mode : d----- CreationTime : 4/18/2018 8:04:37 AM LastWriteTime : 12/13/2018 7:16:48 PM Name : .azure Exists : True Mode : d----- CreationTime : 3/23/2018 7:48:42 PM LastWriteTime : 1/1/2019 2:05:17 PM Name : .azure-shell Exists : True Mode : d----- CreationTime : 12/30/2018 1:40:08 PM LastWriteTime : 12/30/2018 1:40:51 PM Name : .config Exists : True Mode : d----- CreationTime : 4/27/2018 8:35:53 PM LastWriteTime : 4/27/2018 8:35:53 PM
This is not always true though, for example Get-Process
returns a table with 6 columns:
λ 19 carlo@CARLOCXPS 21:40:26 carlo >_ Get-Process NPM(K) PM(M) WS(M) CPU(s) Id SI ProcessName ------ ----- ----- ------ -- -- ----------- 64 107.13 143.16 297.45 16932 1 1Password 10 17.79 9.43 0.00 5560 0 AdminService 10 1.49 6.03 0.00 5496 0 AdobeUpdateService 13 2.48 9.09 0.00 5528 0 AGMService 16 4.20 13.95 0.00 5544 0 AGSService 20 3.42 11.35 15.22 15356 1 AppleMobileDeviceProcess 40 12.23 30.09 7.61 18688 1 ApplePhotoStreams 31 21.56 34.46 10.39 19580 1 ApplicationFrameHost 8 1.80 5.80 0.00 14972 0 AppVShNotify 12 2.88 7.41 0.02 14984 1 AppVShNotify 26 6.65 16.61 2.92 18708 1 APSDaemon 9 1.37 5.71 0.00 5484 0 armsvc 25 19.39 3.07 2.20 21136 1 Calculator
This is because Get-Process
returns a type that happens to have a custom format defined; which type is that?
λ 20 carlo@CARLOCXPS 21:42:01 carlo >_ Get-Process | Get-Member TypeName: System.Diagnostics.Process Name MemberType Definition ---- ---------- ---------- Handles AliasProperty Handles = Handlecount Name AliasProperty Name = ProcessName NPM AliasProperty NPM = NonpagedSystemMemorySize64 PM AliasProperty PM = PagedMemorySize64 SI AliasProperty SI = SessionId VM AliasProperty VM = VirtualMemorySize64 WS AliasProperty WS = WorkingSet64
System.Diagnostic.Process
. If we check $PSHOME
and search the *.format.ps1xml
files we can find that C:\Windows\System32\WindowsPowerShell\v1.0\DotNetTypes.format.ps1xml
contains a definition for this .NET type:
<View> <Name>process</Name> <ViewSelectedBy> <TypeName>System.Diagnostics.Process</TypeName> </ViewSelectedBy> <TableControl> <TableHeaders> <TableColumnHeader> <Label>Handles</Label> <Width>7</Width> <Alignment>right</Alignment> </TableColumnHeader> <TableColumnHeader> <Label>NPM(K)</Label> <Width>7</Width> <Alignment>right</Alignment> </TableColumnHeader> <TableColumnHeader> <Label>PM(K)</Label> <Width>8</Width> <Alignment>right</Alignment> </TableColumnHeader> <TableColumnHeader> <Label>WS(K)</Label> <Width>10</Width> <Alignment>right</Alignment> </TableColumnHeader> <TableColumnHeader> <Label>VM(M)</Label> <Width>5</Width> <Alignment>right</Alignment> </TableColumnHeader> <TableColumnHeader> <Label>CPU(s)</Label> <Width>8</Width> <Alignment>right</Alignment> </TableColumnHeader> <TableColumnHeader> <Width>6</Width> <Alignment>right</Alignment> </TableColumnHeader> <TableColumnHeader> <Width>3</Width> <Alignment>right</Alignment> </TableColumnHeader> <TableColumnHeader /> </TableHeaders> <TableRowEntries> <TableRowEntry> <TableColumnItems> <TableColumnItem> <PropertyName>HandleCount</PropertyName> </TableColumnItem> <TableColumnItem> <ScriptBlock>[long]($_.NPM / 1024)</ScriptBlock> </TableColumnItem> <TableColumnItem> <ScriptBlock>[long]($_.PM / 1024)</ScriptBlock> </TableColumnItem> <TableColumnItem> <ScriptBlock>[long]($_.WS / 1024)</ScriptBlock> </TableColumnItem> <TableColumnItem> <ScriptBlock>[long]($_.VM / 1048576)</ScriptBlock> </TableColumnItem> <TableColumnItem> <ScriptBlock> if ($_.CPU -ne $()) { $_.CPU.ToString("N") } </ScriptBlock> </TableColumnItem> <TableColumnItem> <PropertyName>Id</PropertyName> </TableColumnItem> <TableColumnItem> <PropertyName>SI</PropertyName> </TableColumnItem> <TableColumnItem> <PropertyName>ProcessName</PropertyName> </TableColumnItem> </TableColumnItems> </TableRowEntry> </TableRowEntries> </TableControl> </View>
This is a relatively complex View definition with custom column size and ScriptBlock for calculated fields I did not use in my AzSqlDatabaseSize
example, but it still provides a bases to create my own. These files are signed to prevent tampering so we cannot modify them directly, but as for Types.ps1xml
I created new .ps1xml
file in my module’s folder (I usually use these with modules) and customize it as needed.
This is the simple view I created for my AzSqlDatabaseSize
type:
<View> <Name>AzSqlDatabaseSize</Name> <ViewSelectedBy> <TypeName>AzSqlDatabaseSize</TypeName> </ViewSelectedBy> <TableControl> <TableHeaders> <TableColumnHeader> <Label>ServerName</Label> <Width>15</Width> </TableColumnHeader> <TableColumnHeader> <Label>DatabaseName</Label> <Width>15</Width> </TableColumnHeader> <TableColumnHeader> <Label>Sku</Label> <Width>5</Width> </TableColumnHeader> <TableColumnHeader> <Label>CurrentSizeGb</Label> <Width>15</Width> <Alignment>Right</Alignment> </TableColumnHeader> <TableColumnHeader> <Label>MaxSizeGb</Label> <Width>10</Width> <Alignment>Right</Alignment> </TableColumnHeader> <TableColumnHeader> <Label>%-Used</Label> <Width>8</Width> <Alignment>Right</Alignment> </TableColumnHeader> </TableHeaders> <TableRowEntries> <TableRowEntry> <TableColumnItems> <TableColumnItem> <PropertyName>ServerName</PropertyName> </TableColumnItem> <TableColumnItem> <PropertyName>DatabaseName</PropertyName> </TableColumnItem> <TableColumnItem> <PropertyName>Sku</PropertyName> </TableColumnItem> <TableColumnItem> <PropertyName>CurrentSizeGb</PropertyName> </TableColumnItem> <TableColumnItem> <PropertyName>MaxSizeGb</PropertyName> </TableColumnItem> <TableColumnItem> <PropertyName>%-Used</PropertyName> </TableColumnItem> </TableColumnItems> </TableRowEntry> </TableRowEntries> </TableControl> </View>
It is a simpler View than the process
one (I did not specify column width nor I used ScriptBlock for calculated fields) but it nicely format my output
λ 35 carlo@CARLOCXPS 14:13:56 carlo >_ Get-AzSqlDatabaseSize -ServerName MySqlServer -ResourceGroupName Default-SQL-EastUS2 -DatabaseName MySqlDatabase ServerName DatabaseName Sku CurrentSizeGb MaxSizeGb %-Used ---------- ------------ --- ------------- --------- ------ MySqlServer MySqlDatabase P1 50.63 500 10.13
As for custom types, custom format can be referenced in a module Data File and loaded automatically when importing the module into the session:
# Format files (.ps1xml) to be loaded when importing this module FormatsToProcess = 'Format.ps1xml'
When you were born, you cried and the world rejoiced. Live your life in such a manner that when you die the world cries and you rejoice. – Indian Proverb |