💾 Archived View for pwshnotes.flounder.online › gemlog › 2022-04-21-format-ps1xml.gmi captured on 2024-02-05 at 09:38:27. Gemini links have been rewritten to link to archived content
⬅️ Previous capture (2022-04-28)
-=-=-=-=-=-=-
I am using PowerShell on Linux. And I prefer a shell that is 80 characters wide instead of the 120 characters typical for PowerShell.
One problem I have is that, when I use Get-ChildItem, the output is truncated because of the smaller window. For example, there is no Name column in the output below:
# Output from a Linux terminal that is 80 characters wide. # There is no Name column. Get-ChildItem Directory: /data/Michael UnixMode User Group LastWriteTime Size -------- ---- ----- ------------- ---- drwxr-xr-x michael michael 4/9/2022 04:20 4096 drwxr-xr-x michael michael 4/12/2022 04:56 4096 drwxr-xr-x michael michael 4/20/2022 05:40 4096 ...
This can be temporarily fixed by piping to Format-Table -AutoSize:
# Use Format-Table -AutoSize. # This requires a lot of extra typing. Get-ChildItem | Format-Table -AutoSize Directory: /data/Michael UnixMode User Group LastWriteTime Size Name -------- ---- ----- ------------- ---- ---- drwxr-xr-x michael michael 4/9/2022 04:20 4096 Background Images drwxr-xr-x michael michael 4/12/2022 04:56 4096 Bookmarklets drwxr-xr-x michael michael 4/20/2022 05:40 4096 Drafts ...
But the permanent solution is to use a Format.ps1xml file. This will change the default output when Get-ChildItem is used alone.
# Install a custom Format.ps1xml file. # Using Get-ChildItem alone produces autosized output. Get-ChildItem Directory: /data/Michael UnixMode User Group LastWriteTime Size Name -------- ---- ----- ------------- ---- ---- drwxr-xr-x michael michael 4/9/2022 04:20 4096 Background Images drwxr-xr-x michael michael 4/12/2022 04:56 4096 Bookmarklets drwxr-xr-x michael michael 4/20/2022 05:40 4096 Drafts ...
Below is the formatting file I used to autosize the Get-ChildItem output.
File Name:
~/PowerShell Formatting/FileSystem.Format.ps1xml
File Contents:
<?xml version="1.0" encoding="utf-8"?> <Configuration> <ViewDefinitions> <View> <Name>LinuxFileSystem</Name> <ViewSelectedBy> <TypeName>System.IO.DirectoryInfo</TypeName> <TypeName>System.IO.FileInfo</TypeName> </ViewSelectedBy> <GroupBy> <Label>Directory</Label> <ScriptBlock>$_.PSParentPath.Replace('Microsoft.PowerShell.Core\FileSystem::','')</ScriptBlock> </GroupBy> <TableControl> <TableHeaders> <TableColumnHeader> <Label>UnixMode</Label> <Alignment>Left</Alignment> </TableColumnHeader> <TableColumnHeader> <Label>User</Label> <Alignment>Left</Alignment> </TableColumnHeader> <TableColumnHeader> <Label>Group</Label> <Alignment>Left</Alignment> </TableColumnHeader> <TableColumnHeader> <Label>LastWriteTime</Label> <Alignment>Right</Alignment> </TableColumnHeader> <TableColumnHeader> <Label>Size</Label> <Alignment>Right</Alignment> </TableColumnHeader> <TableColumnHeader> <Label>Name</Label> <Alignment>Left</Alignment> </TableColumnHeader> </TableHeaders> <TableRowEntries> <TableRowEntry> <Wrap /> <TableColumnItems> <TableColumnItem> <PropertyName>UnixMode</PropertyName> </TableColumnItem> <TableColumnItem> <PropertyName>User</PropertyName> </TableColumnItem> <TableColumnItem> <PropertyName>Group</PropertyName> </TableColumnItem> <TableColumnItem> <ScriptBlock>'{0:d} {0:HH}:{0:mm}' -f $_.LastWriteTime</ScriptBlock> </TableColumnItem> <TableColumnItem> <PropertyName>Size</PropertyName> </TableColumnItem> <TableColumnItem> <PropertyName>NameString</PropertyName> </TableColumnItem> </TableColumnItems> </TableRowEntry> </TableRowEntries> </TableControl> </View> </ViewDefinitions> </Configuration>
Once saved, the file will have to be imported into the current session.
Update-FormatData -PrependPath "~/PowerShell Formatting/FileSystem.Format.ps1xml"
After importing, you can run Get-ChildItem to show the autosized output.
Get-ChildItem Directory: /data/Michael UnixMode User Group LastWriteTime Size Name -------- ---- ----- ------------- ---- ---- drwxr-xr-x michael michael 4/9/2022 04:20 4096 Background Images drwxr-xr-x michael michael 4/12/2022 04:56 4096 Bookmarklets drwxr-xr-x michael michael 4/20/2022 05:40 4096 Drafts ...
If you want to automatically apply these changes to every PowerShell session, save the command in your PowerShell profile. See the References section below for all my links including the about_Profiles article.
I exported the default views relating to the Get-ChildItem cmdlet with the command below. And I used that as the basis for creating my Format.ps1xml file.
Get-FormatData -PowerShellVersion $PSVersionTable.PSVersion -TypeName System.IO.DirectoryInfo | Export-FormatData -Path "~/Desktop/Export.Format.ps1xml" -IncludeScriptBlock
Note that if you already imported my customized Format.ps1xml, you can launch a new PowerShell session by using the -NoProfile parameter. This will allow you to get a fresh export.
pwsh -NoProfile PowerShell 7.2.2 Copyright (c) Microsoft Corporation. https://aka.ms/powershell Type 'help' to get help. Get-FormatData -PowerShellVersion $PSVersionTable.PSVersion -TypeName System.IO.DirectoryInfo | Export-FormatData -Path "~/Desktop/Export.Format.ps1xml" -IncludeScriptBlock
After exporting the default views, I customized the file in the following ways.
I changed the name of my view from "childrenWithUnixStat" to "LinuxFileSystem".
<!-- Before --> <Name>childrenWithUnixStat</Name> <!-- After --> <Name>LinuxFileSystem</Name>
The export only refers to the System.IO.DirectoryInfo type. But the Get-ChildItem cmdlet outputs DirectoryInfo and FileInfo types. Including only the DirectoryInfo type in my Format.ps1xml did not work. So, I added the FileInfo type to my Formatl.ps1xml file.
<!-- Before --> <ViewSelectedBy> <TypeName>System.IO.DirectoryInfo</TypeName> </ViewSelectedBy> <!-- After --> <ViewSelectedBy> <TypeName>System.IO.DirectoryInfo</TypeName> <TypeName>System.IO.FileInfo</TypeName> </ViewSelectedBy>
There are multiple views in the exported file. I deleted everything below the top view.
Here is what that looks like at a high level:
<!-- Before --> <?xml version="1.0" encoding="utf-8"?> <Configuration> <ViewDefinitions> <View> <Name>LinuxFileSystem</Name> <!-- ... --> </View> <View> <Name>children</Name> <!-- ... --> </View> <View> <Name>childrenWithHardlink</Name> <!-- ... --> </View> <View> <Name>children</Name> <!-- ... --> </View> <View> <Name>children</Name> <!-- ... --> </View> </ViewDefinitions> </Configuration> <!-- After --> <?xml version="1.0" encoding="utf-8"?> <Configuration> <ViewDefinitions> <View> <Name>LinuxFileSystem</Name> <!-- ... --> </View> </ViewDefinitions> </Configuration>
I removed all the <Width/> XML tags from the view. Below is one example. Remember to do this for every <TableColumnHeader/>.
<!-- Before --> <TableColumnHeader> <Label>UnixMode</Label> <Width>10</Width> <Alignment>Left</Alignment> </TableColumnHeader> <!-- After --> <TableColumnHeader> <Label>UnixMode</Label> <Alignment>Left</Alignment> </TableColumnHeader>
If you check the XML schema (Format.xsd), you will see a comment that says the <Width/> tag is required. But note that one of the default <TableColumnHeader/> tags omits its child <Width/> tag. And removing the <Width/> tags did not cause any problems in my testing.
I updated the <GroupBy/> tag to match the stock Get-ChildItem output.
Normally, Get-ChildItem groups items by directory and uses this output format:
> Get-ChildItem Directory: /data/Michael ...
But the export uses <PropertyName>PSParentPath</PropertyName> which produces this output:
> Get-ChildItem PSParentPath: Microsoft.PowerShell.Core\FileSystem::/data/Michael ...
I was able to address this issue with the changes below. Namely, I explicitly set the label to "Directory". And I used the .NET String method Replace(String, String) to strip off the provider.
<!-- Before --> <GroupBy> <PropertyName>PSParentPath</PropertyName> </GroupBy> <!-- After --> <GroupBy> <Label>Directory</Label> <ScriptBlock>$_.PSParentPath.Replace('Microsoft.PowerShell.Core\FileSystem::','')</ScriptBlock> </GroupBy>
You can safely skip to the next section.
Note I tried to use the Directory property which I found in some of my testing. But that property is only available on the FileInfo object and does not exist on the DirectoryInfo object. Remember that Get-ChildItem emits a mix of both types of objects. So, the formatting has to use a property common to both. By choosing the PSParentPath property and modifying the resulting string, I was able to get consistent behavior.
Note that the customized label has three spaces in front of it versus the standard four. This might cause a problem if you are parsing the text output instead of consuming PowerShell objects.
# Stock PowerShell produces a "Directory:" label with four leading spaces. # Using the <PropertyName/> tag produces three leading spaces. # Using <Label/> also produces three spaces. Directory: /data/Michael PSParentPath: Microsoft.PowerShell.Core\FileSystem::/data/Michael Directory: /data/Michael
If you add a leading space to the tag value, that will be reproduced in the shell. So, you can remove this discrepancy.
# <Label>Directory</Label> versus # <Label> Directory</Label> Directory: /data/Michael Directory: /data/Michael
Modifying <GroupBy/> is the last change I made to my Format.ps1xml file.
If you have been following along and making edits to a clean export, try importing that file to see if Get-ChildItem is autosizing its output now.
Remember to save your Format.ps1xml file before importing.
# Start a clean PowerShell session. pwsh -NoProfile # Import the tutorial file. Update-FormatData -PrependPath "~/Desktop/Export.Format.ps1xml" # Test Get-ChildItem. Get-ChildItem Directory: /home/michael UnixMode User Group LastWriteTime Size Name -------- ---- ----- ------------- ---- ---- drwxr-xr-x michael michael 4/21/2022 04:46 4096 Desktop drwxr-xr-x michael michael 12/23/2021 07:14 4096 Documents drwxr-xr-x michael michael 4/19/2022 11:58 4096 Downloads ...
about_Format.ps1xml | Microsoft Docs
Get-FormatData | Microsoft Docs
Export-FormatData | Microsoft Docs
Update-FormatData | Microsoft Docs
Format.xsd (Raw) | PowerShell | GitHub
Examples | Format-Table | Microsoft Docs
about_Providers | Microsoft Docs
Replace(String, String) | String | Microsoft Docs
about_Profiles | Microsoft Docs
RedHat XML Extension | Visual Studio Code Marketplace
Created: Thursday, April 21, 2022
Updated: Thursday, April 21, 2022