Search code examples
powershellget-childitem

How to change default view of FileInfo and DirectoryInfo?


I want to set a default strategy for displaying FileInfo and DirectoryInfo objects in Powershell to display only file paths.

Default behaviour

PS C:\Users\user> gci

    Directory: C:\Users\user

Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
d----          2023-04-05     1:29                .cache
d----          2023-03-30    22:41                .dbus-keyrings
d----          2023-04-15    22:32                .docker
d----          2023-07-12    15:22                .gfclient
d----          2023-04-04     4:41                .gradle
d----          2023-04-16     0:30                .keras
-a---          2023-09-08    14:36          10629 _viminfo
-a---          2023-02-09    21:03              2 --help
-a---          2023-07-21    14:57          13675 .bash_history

Desired behaviour

PS C:\Users\user> gci
C:\Users\user\.cache
C:\Users\user\.dbus-keyrings
C:\Users\user\.docker
C:\Users\user\.gfclient
C:\Users\user\.gradle
C:\Users\user\.keras
C:\Users\user\_viminfo
C:\Users\user\--help
C:\Users\user\.bash_history

Desired behaviour can be achieved through appending | % fullname to command, which will print fullname property of every object in a pipe, but I need a powershell custom view which will do it every time objects of these types will end up in the end of pipe.

What I've tried

I assume my question is to be solved by creating custom view for appropriate object types and assigning this view as default.

  • This is official help on this matter: get-help about_format.ps1xml
  • This command creates xml file with default format settings for desired type: Get-FormatData -TypeName system.io.fileinfo | Export-FormatData -Path formatOrigFile.ps1xml

This is format file I've created by changing default file:

<?xml version="1.0" encoding="utf-8"?>
<Configuration>
  <ViewDefinitions>
    <View>
      <Name>children</Name>
      <ViewSelectedBy>
        <TypeName>System.IO.DirectoryInfo</TypeName>
      </ViewSelectedBy>
      <!-- <GroupBy>
        <PropertyName>PSParentPath</PropertyName>
      </GroupBy> -->
      <TableControl>
        <TableHeaders>
          <TableColumnHeader />
        </TableHeaders>
        <TableRowEntries>
          <TableRowEntry>
            <Wrap />
            <TableColumnItems>
              <TableColumnItem>
                    <ScriptBlock>$_ | Resolve-Path -Relative</ScriptBlock>
                </TableColumnItem>
            </TableColumnItems>
          </TableRowEntry>
        </TableRowEntries>
        <HideTableHeaders>true</HideTableHeaders>
      </TableControl>
    </View>
    
    
    <View>
      <Name>childrenWithHardlink</Name>
      <ViewSelectedBy>
        <TypeName>System.IO.DirectoryInfo</TypeName>
      </ViewSelectedBy>
      <!-- <GroupBy>
        <PropertyName>PSParentPath</PropertyName>
      </GroupBy> -->
      <TableControl>
        <TableHeaders>
          <TableColumnHeader />
        </TableHeaders>
        <TableRowEntries>
          <TableRowEntry>
            <Wrap />
            <TableColumnItems>
              <TableColumnItem>
                <ScriptBlock>$_ | Resolve-Path -Relative</ScriptBlock>
              </TableColumnItem>
            </TableColumnItems>
          </TableRowEntry>
        </TableRowEntries>
        <HideTableHeaders>true</HideTableHeaders>
      </TableControl>
    </View>
    
    
    <View>
      <Name>children</Name>
      <ViewSelectedBy>
        <TypeName>System.IO.DirectoryInfo</TypeName>
      </ViewSelectedBy>
      <!-- <GroupBy>
        <PropertyName>PSParentPath</PropertyName>
      </GroupBy> -->
      <ListControl>
        <ListEntries>
          <ListEntry>
            <ListItems>
              <ListItem>
                <ScriptBlock>$_ | Resolve-Path -Relative</ScriptBlock>
              </ListItem>
            </ListItems>
          </ListEntry>
          <ListEntry>
            <EntrySelectedBy>
              <TypeName>System.IO.FileInfo</TypeName>
            </EntrySelectedBy>
            <ListItems>
              <ListItem>
                <ScriptBlock>$_ | Resolve-Path -Relative</ScriptBlock>
              </ListItem>
            </ListItems>
          </ListEntry>
        </ListEntries>
        <!-- <HideTableHeaders>true</HideTableHeaders> -->
      </ListControl>
    </View>
    <View>
      <Name>children</Name>
      <ViewSelectedBy>
        <TypeName>System.IO.DirectoryInfo</TypeName>
      </ViewSelectedBy>
      <!-- <GroupBy>
        <PropertyName>PSParentPath</PropertyName>
      </GroupBy> -->
      <WideControl>
        <WideEntries>
          <WideEntry>
            <WideItem>
              <ScriptBlock>$_ | Resolve-Path -Relative</ScriptBlock>
            </WideItem>
          </WideEntry>
          <WideEntry>
            <EntrySelectedBy>
              <TypeName>System.IO.DirectoryInfo</TypeName>
            </EntrySelectedBy>
            <WideItem>
              <ScriptBlock>$_ | Resolve-Path -Relative</ScriptBlock>
            </WideItem>
          </WideEntry>
        </WideEntries>
        <!-- <HideTableHeaders>true</HideTableHeaders> -->
      </WideControl>
    </View>
  </ViewDefinitions>
</Configuration>

This is how it is loaded: Update-FormatData -PrependPath C:\Users\user\Desktop\format.ps1xml

After that, instead of desired behavior, gci produces this:

PS C:\Users\user> gci

..\.cache
..\.dbus-keyrings
..\.docker
..\.gfclient
..\.gradle
..\.keras

LastWriteTime : 2023-09-08 14:36:29
Length        : 10629
Name          : _viminfo


LastWriteTime : 2023-07-21 14:57:46
Length        : 13675
Name          : .bash_history


LastWriteTime : 2023-07-20 13:15:58
Length        : 101
Name          : .gitconfig


LastWriteTime : 2023-07-05 19:27:42
Length        : 2200
Name          : .h2.server.properties

It applies new view settings only for directories, not for files.

How should I change format.ps1xml? Or how do I get what I need in different way?


Solution

  • As @santiago-squarzon pointed out, answer to another question on SO has a better template for a format.ps1xml file. This is my final version:

    <?xml version="1.0" encoding="utf-8"?>
    <Configuration>
      <ViewDefinitions>
        <View>
          <Name>CustomIODisplay</Name>
          <ViewSelectedBy>
            <TypeName>System.IO.DirectoryInfo</TypeName>
            <TypeName>System.IO.FileInfo</TypeName>
          </ViewSelectedBy>
          <TableControl>
            <TableHeaders>
                <TableColumnHeader>
                    <Label>Path</Label>
                </TableColumnHeader>
                <!-- <TableColumnHeader>
                    <Label>Length</Label>
                </TableColumnHeader> -->
            </TableHeaders>
            <TableRowEntries>
              <TableRowEntry>
                <Wrap />
                <TableColumnItems>
                  <TableColumnItem>
                        <ScriptBlock>
                        # text colors: https://learn.microsoft.com/en-us/windows/console/console-virtual-terminal-sequences#text-formatting
                        if ($_.PSIsContainer) {
                            $colors = @()
                            # $colors += '32'   #greenFg
                            $colors += '44' #blueBg
                            $colors = $colors -join ';'
                            
                        }
                        $e = [char]27
                       "$e[${colors}m$($_.FullName)${e}[0m"
                        </ScriptBlock>
                    </TableColumnItem>
                    <!-- <TableColumnItem>
                        <ScriptBlock>$_.length</ScriptBlock>
                    </TableColumnItem> -->
                </TableColumnItems>
              </TableRowEntry>
            </TableRowEntries>
            <HideTableHeaders>true</HideTableHeaders>
          </TableControl>
        </View>
      </ViewDefinitions>
    </Configuration>
    

    Import it: Update-FormatData -PrependPath .\formatGci2.ps1xml (it changes view only for current session, add it to pwsh profile if auto-load is needed).

    It achieves desired behavior (prints only fullnames), but also changes bg color for directories to blue color, as it is in default view. Also it has commented-out columnHeader and columnItem so it would be easy to add a new column if needed.