💾 Archived View for pwshnotes.flounder.online › gemlog › 2022-04-21-format-ps1xml.gmi captured on 2024-08-31 at 11:38:17. Gemini links have been rewritten to link to archived content

View Raw

More Information

⬅️ Previous capture (2022-04-28)

-=-=-=-=-=-=-

Fix the Get-ChildItem Output in a Smaller Shell

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
...

My Format.ps1xml File

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.

What Changes Did I Make? / Tutorial

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.

Change View Name

I changed the name of my view from "childrenWithUnixStat" to "LinuxFileSystem".

      <!-- Before -->
      <Name>childrenWithUnixStat</Name>

      <!-- After -->
      <Name>LinuxFileSystem</Name>

Add a Reference to the FileInfo Type

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>

Delete Other Views

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>

Remove <Width/> Tags

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.

Update <GroupBy/> Tag

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

Test Tutorial File

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
...

References

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

Visual Studio Code

RedHat XML Extension | Visual Studio Code Marketplace

Created: Thursday, April 21, 2022

Updated: Thursday, April 21, 2022