55

How can I modify the default ls (Get-ChildItem) in PowerShell so that it displays human-readable file sizes, like ls -h on a *nix machine?

ls -lh does simple logic with the file size, so that it shows bytes for really small files, kilobytes for files over 1K (with one decimal place if it's under 10K), and megabytes for files over 1M (with one decimal place if it's under 10MB).

Tom Mayfield
  • 1,597

9 Answers9

25

Something like the following for listing just file sizes. Yes it is a bit sore on the eyes but it manages to get the job done.

For converting to KB:

ls | Select-Object Name, @{Name="KiloBytes";Expression={$_.Length / 1KB}}

For converting to MB:

ls | Select-Object Name, @{Name="MegaBytes";Expression={$_.Length / 1MB}}
jmreicha
  • 2,267
22

First, create the following function:

Function Format-FileSize() {
    Param ([int64]$size)
    If     ($size -gt 1TB) {[string]::Format("{0:0.00} TB", $size / 1TB)}
    ElseIf ($size -gt 1GB) {[string]::Format("{0:0.00} GB", $size / 1GB)}
    ElseIf ($size -gt 1MB) {[string]::Format("{0:0.00} MB", $size / 1MB)}
    ElseIf ($size -gt 1KB) {[string]::Format("{0:0.00} kB", $size / 1KB)}
    ElseIf ($size -gt 0)   {[string]::Format("{0:0.00} B", $size)}
    Else                   {""}
}

You can then pipe the output of Get-ChildItem through Select-Object and use a calculated property to format the filesize:

Get-ChildItem | Select-Object Name, @{Name="Size";Expression={Format-FileSize($_.Length)}}

The function could of course be improved to account for sizes in the PB range and more, or to vary the number of decimal points as necessary.

Indrek
  • 24,874
20

Here's a bit of an orthogonal answer to this quite-old question. It's not an answer to the question as literally asked, but more about the "spirit" of the question. It's also not an answer that was even possible for years after the question was asked. But now, it may be useful for some subset of folks who come looking for this information (as I did).

There are now several ways to get a more improved file listing in PowerShell that includes human-readable file sizes:

Windows Subsystem for Linux

Since the original question pointed out how easy this is in *nix, I realized that with WSL (Windows Subsystem for Linux) installed, it's a no-brainer to just use the Linux ls -lh from PowerShell:

PS> wsl ls -lh

... gives me the results I want (and it sounds like the OP did) on the current directory from within PowerShell. Better yet, if you have exa installed in your WSL instance, wsl exa -l is much prettier (and defaults to -h).

Note that if you want a different directory, there's a bit of a "trick" when using the wsl command. Since utilities running inside a WSL instance (such as ls) only understand Linux paths, you can't do something like:

PS> wsl ls -lh C:\

Instead, there are two options. First, you can use the WSL equivalent of the Windows path. E.g.:

PS> wsl ls -lh /mnt/c
PS> wsl eza -l /mnt/c

Or, just set the directory for the WSL instance with the --cd option, like so:

PS> wsl --cd C:\ ls -lh # or
PS> wsl --cd C:\ eza -l

This also works with relative directory paths:

PS> wsl --cd .. ls -lh # or
PS> wsl --cd .. eza -l

Don't worry (if you were) -- it's not going to change the current directory in PowerShell. When the WSL instance exits after running ls command, PowerShell will retain its current environment; just like running a subshell (in either PowerShell or a Linux shell like Bash).

PowerShell and WSL are each great on their own, but putting the two together gives you something even more powerful.

P.S. This works with either WSL1 or WSL2, but if you are going to be handling a lot of Windows files in WSL, version 1 is (currently) an order of magnitude faster. WSL2 is faster when using the virtualized ext4 filesystem.

Nushell for Windows

Like WSL, you may already have Nushell for Windows installed for one reason or another. If so, you can use a similar method as above to call Nushell's ls command, which is by far my person favorite for style/formatting:

PS> nu -c ls <optional_path>
╭─────────────────────────┬──────┬──────────┬──────────────╮
│          name           │ type │   size   │   modified   │
├─────────────────────────┼──────┼──────────┼──────────────┤
│ C:\Windows\AppReadiness │ dir  │      0 B │ 21 hours ago │
│ C:\Windows\BRPP2KA.INI  │ file │     26 B │ 3 years ago  │
│ C:\Windows\BRWMARK.INI  │ file │    448 B │ 2 years ago  │
│ C:\Windows\Boot         │ dir  │  4.0 KiB │ 2 days ago   │
│ C:\Windows\Branding     │ dir  │      0 B │ 2 years ago  │
│ ...                     │ ...  │ ...      │ ...          │
│ C:\Windows\twain_32     │ dir  │      0 B │ 2 years ago  │
│ C:\Windows\twain_32.dll │ file │ 67.5 KiB │ 2 years ago  │
│ C:\Windows\win.ini      │ file │     92 B │ 4 years ago  │
│ C:\Windows\winhlp32.exe │ file │ 12.0 KiB │ 2 years ago  │
│ C:\Windows\write.exe    │ file │ 28.0 KiB │ 2 years ago  │
╰─────────────────────────┴──────┴──────────┴──────────────╯

This is a bit simpler than the WSL alternative, since you don't need to worry about handling Windows <-> Linux conversion of path formats.

Bonus: Nushell includes a built in "data explorer" that will allow you to (among other things) page the results:

nu -c 'ls | explore'

LSDeluxe (et. al.)

The eza (f.k.a. exa) mentioned in my WSL notes above is written-in-Rust, but doesn't yet seem to be ported to Windows. However, a nice (also Rust-based) alternative appears to be lsd which is natively available for Windows and (while I have not installed or tested it personally) should run in PowerShell without issue.

This is probably the smallest and lightest solution of the three.

NotTheDr01ds
  • 28,025
18

try this

PS> gc c:\scripts\type\shrf.ps1xml

<Types>
<Type>
  <Name>System.IO.FileInfo</Name>
   <Members>
      <ScriptProperty>
          <Name>FileSize</Name>
          <GetScriptBlock>
             switch($this.length) {
               { $_ -gt 1tb } 
                      { "{0:n2} TB" -f ($_ / 1tb) }
               { $_ -gt 1gb } 
                      { "{0:n2} GB" -f ($_ / 1gb) }
               { $_ -gt 1mb } 
                      { "{0:n2} MB " -f ($_ / 1mb) }
               { $_ -gt 1kb } 
                      { "{0:n2} KB " -f ($_ / 1Kb) }
               default  
                      { "{0} B " -f $_} 
             }      
          </GetScriptBlock>
     </ScriptProperty>   
  </Members>
</Type>
</Types>

PS> Update-TypeData -AppendPath c:\scripts\type\shrf.ps1xml -verbose
PS> get-childItem $env:windir  | select Name,FileSize,length
PS> # you can paste this in your profile
PS> 

you can also use dynamic type data with PS3:

   PS> Update-TypeData -TypeName System.IO.FileInfo -MemberName FileSize -MemberType ScriptProperty -Value { 

    switch($this.length) {
               { $_ -gt 1tb } 
                      { "{0:n2} TB" -f ($_ / 1tb) }
               { $_ -gt 1gb } 
                      { "{0:n2} GB" -f ($_ / 1gb) }
               { $_ -gt 1mb } 
                      { "{0:n2} MB " -f ($_ / 1mb) }
               { $_ -gt 1kb } 
                      { "{0:n2} KB " -f ($_ / 1Kb) }
               default  
                      { "{0} B " -f $_} 
             }      

 } -DefaultDisplayPropertySet Mode,LastWriteTime,FileSize,Name
7

based on the answer by walid toumi:

Steps to do:

  • Create your own Type-file with the new FileSize-Property
  • Change the standard output format for FileInfo
  • load the changes in $PROFILE

Create your own Type-file with the new FileSize-Property

  • Create your own Type-file: MyTypes.ps1xml
    (I put it in $Env:USERPROFILE\Documents\WindowsPowershell, so right next to my $PROFILE)

    <?xml version="1.0" encoding="utf-8" ?>
    <Types>
        <Type>
            <Name>System.IO.FileInfo</Name>
            <Members>
                <ScriptProperty>
                    <!-- Filesize converts the length to a human readable
                        format (kb, mb, gb, tb) -->
                    <Name>FileSize</Name>
                    <GetScriptBlock>
                        switch($this.length) {
                            { $_ -gt 1tb } 
                                { "{0:n2} TB" -f ($_ / 1tb) ; break }
                            { $_ -gt 1gb } 
                                { "{0:n2} GB" -f ($_ / 1gb) ; break }
                            { $_ -gt 1mb } 
                                { "{0:n2} MB " -f ($_ / 1mb) ; break }
                            { $_ -gt 1kb } 
                                { "{0:n2} KB " -f ($_ / 1Kb) ; break }
                            default
                                { "{0}  B " -f $_}
                        }
                    </GetScriptBlock>
                </ScriptProperty>
            </Members>
        </Type>
    </Types>
    
  • load the new property in a powershell-session:

    • Update-TypeData -PrependPath $Env:USERPROFILE\Documents\WindowsPowershell\MyTypes.ps1xml
  • try the new property
    • Get-ChildItem | Format-Table -Property Name, Length, FileSize

Change the standard output format for FileInfo

  • create your own Fileformat-file: MyFileFormat.format.ps1xml (Again in $Env:USERPROFILE\Documents\WindowsPowershell\)

    <?xml version="1.0" encoding="utf-8" ?> 
    <Configuration>
        <SelectionSets>
            <SelectionSet>
                <Name>FileSystemTypes</Name>
                <Types>
                    <TypeName>System.IO.DirectoryInfo</TypeName>
                    <TypeName>System.IO.FileInfo</TypeName>
                </Types>
            </SelectionSet>
        </SelectionSets>
    
        <!-- ################ GLOBAL CONTROL DEFINITIONS ################ -->
        <Controls>
            <Control>
                <Name>FileSystemTypes-GroupingFormat</Name>
                        <CustomControl>
                            <CustomEntries>
                                <CustomEntry>
                                    <CustomItem>
                                        <Frame>
                                            <LeftIndent>4</LeftIndent>
                                            <CustomItem>
                                                <Text AssemblyName="System.Management.Automation" BaseName="FileSystemProviderStrings" ResourceId="DirectoryDisplayGrouping"/>
                                                <ExpressionBinding>
                                                  <ScriptBlock>
                                                      $_.PSParentPath.Replace("Microsoft.PowerShell.Core\FileSystem::", "")                                                  
                                                  </ScriptBlock>
                                                </ExpressionBinding>
                                                <NewLine/>
                                            </CustomItem> 
                                        </Frame>
                                    </CustomItem>
                                </CustomEntry>
                            </CustomEntries>
                </CustomControl>
            </Control>
        </Controls>
    
        <!-- ################ VIEW DEFINITIONS ################ -->
    
        <ViewDefinitions>
           <View>
                <Name>children</Name>
                <ViewSelectedBy>
                    <SelectionSetName>FileSystemTypes</SelectionSetName>
                </ViewSelectedBy>
                <GroupBy>
                    <PropertyName>PSParentPath</PropertyName> 
                    <CustomControlName>FileSystemTypes-GroupingFormat</CustomControlName>  
                </GroupBy>
                <TableControl>
                    <TableHeaders>
                       <TableColumnHeader>
                          <Label>Mode</Label>
                          <Width>7</Width>
                          <Alignment>left</Alignment>
                       </TableColumnHeader>
                        <TableColumnHeader>
                            <Label>LastWriteTime</Label>
                            <Width>25</Width>
                            <Alignment>right</Alignment>
                        </TableColumnHeader>
                        <TableColumnHeader>
                            <Label>FileSize</Label>
                            <Width>14</Width>
                            <Alignment>right</Alignment>
                        </TableColumnHeader>
                        <TableColumnHeader/>
                    </TableHeaders>
                    <TableRowEntries>
                        <TableRowEntry>
                            <Wrap/>
                            <TableColumnItems>
                                <TableColumnItem>
                                    <PropertyName>Mode</PropertyName>
                                </TableColumnItem>
                                <TableColumnItem>
                                    <ScriptBlock>
                                        [String]::Format("{0,10}  {1,8}", $_.LastWriteTime.ToString("d"), $_.LastWriteTime.ToString("t"))
                                    </ScriptBlock>
                                </TableColumnItem>
                                <TableColumnItem>
                                <PropertyName>FileSize</PropertyName>
                                </TableColumnItem>
                                <TableColumnItem>
                                    <PropertyName>Name</PropertyName>
                                </TableColumnItem>
                            </TableColumnItems>
                        </TableRowEntry>
                    </TableRowEntries>
                </TableControl>
            </View>
            <View>
                <Name>children</Name>
                <ViewSelectedBy>
                    <SelectionSetName>FileSystemTypes</SelectionSetName>
                </ViewSelectedBy>
                <GroupBy>
                    <PropertyName>PSParentPath</PropertyName> 
                    <CustomControlName>FileSystemTypes-GroupingFormat</CustomControlName>  
                </GroupBy>
                <ListControl>
                    <ListEntries>
                        <ListEntry>
                            <EntrySelectedBy>
                                <TypeName>System.IO.FileInfo</TypeName>
                            </EntrySelectedBy>
                            <ListItems>
                                <ListItem>
                                    <PropertyName>Name</PropertyName>
                                </ListItem>
                                <ListItem>
                                    <PropertyName>FileSize</PropertyName>
                                </ListItem>
                               <ListItem>
                                    <PropertyName>CreationTime</PropertyName>
                                </ListItem>
                                <ListItem>
                                    <PropertyName>LastWriteTime</PropertyName>
                                </ListItem>
                                <ListItem>
                                    <PropertyName>LastAccessTime</PropertyName>
                                </ListItem>
                                <ListItem>
                                    <PropertyName>Mode</PropertyName>
                                </ListItem>
                                <ListItem>
                                    <PropertyName>LinkType</PropertyName>
                                </ListItem>
                                <ListItem>
                                    <PropertyName>Target</PropertyName>
                                </ListItem>                        
                                <ListItem>
                                    <PropertyName>VersionInfo</PropertyName>
                                </ListItem>
                            </ListItems>
                        </ListEntry>
                        <ListEntry>
                            <ListItems>
                                <ListItem>
                                    <PropertyName>Name</PropertyName>
                                </ListItem>
                                <ListItem>
                                    <PropertyName>CreationTime</PropertyName>
                                </ListItem>
                                <ListItem>
                                    <PropertyName>LastWriteTime</PropertyName>
                                </ListItem>
                                <ListItem>
                                    <PropertyName>LastAccessTime</PropertyName>
                                </ListItem>
                              <ListItem>
                                <PropertyName>Mode</PropertyName>
                              </ListItem>
                              <ListItem>
                                <PropertyName>LinkType</PropertyName>
                              </ListItem>
                              <ListItem>
                                <PropertyName>Target</PropertyName>
                              </ListItem>
                            </ListItems>
                        </ListEntry>
                    </ListEntries>
                </ListControl>
            </View>
            <View>
                <Name>children</Name>
                <ViewSelectedBy>
                    <SelectionSetName>FileSystemTypes</SelectionSetName>
                </ViewSelectedBy>
                <GroupBy>
                    <PropertyName>PSParentPath</PropertyName> 
                    <CustomControlName>FileSystemTypes-GroupingFormat</CustomControlName>  
                </GroupBy>
                <WideControl>
                    <WideEntries>
                        <WideEntry>
                            <WideItem>
                                <PropertyName>Name</PropertyName>
                            </WideItem>
                        </WideEntry>
                        <WideEntry>
                            <EntrySelectedBy>
                                <TypeName>System.IO.DirectoryInfo</TypeName>
                            </EntrySelectedBy>
                            <WideItem>
                                <PropertyName>Name</PropertyName>
                                <FormatString>[{0}]</FormatString>
                            </WideItem>
                        </WideEntry>
                    </WideEntries>
                </WideControl>
            </View>
            <View>
                <Name>FileSecurityTable</Name>
                <ViewSelectedBy>
                    <TypeName>System.Security.AccessControl.FileSystemSecurity</TypeName>
                </ViewSelectedBy>
                <GroupBy>
                    <PropertyName>PSParentPath</PropertyName> 
                    <CustomControlName>FileSystemTypes-GroupingFormat</CustomControlName>  
                </GroupBy>
                <TableControl>
                    <TableHeaders>
                       <TableColumnHeader>
                          <Label>Path</Label>
                       </TableColumnHeader>
                       <TableColumnHeader />
                       <TableColumnHeader>
                          <Label>Access</Label>
                       </TableColumnHeader>
                    </TableHeaders>
                    <TableRowEntries>
                        <TableRowEntry>
                            <TableColumnItems>
                                <TableColumnItem>
                                    <ScriptBlock>
                                        split-path $_.Path -leaf
                                    </ScriptBlock>
                                </TableColumnItem>
                                <TableColumnItem>
                                <PropertyName>Owner</PropertyName>
                                </TableColumnItem>
                                <TableColumnItem>
                                    <ScriptBlock>
                                        $_.AccessToString
                                    </ScriptBlock>
                                </TableColumnItem>
                            </TableColumnItems>
                        </TableRowEntry>
                    </TableRowEntries>
                </TableControl>
            </View>
           <View>
                <Name>FileSystemStream</Name>
                <ViewSelectedBy>
                    <TypeName>Microsoft.PowerShell.Commands.AlternateStreamData</TypeName>
                </ViewSelectedBy>
                <GroupBy>
                    <PropertyName>Filename</PropertyName> 
                </GroupBy>
                <TableControl>
                    <TableHeaders>
                       <TableColumnHeader>
                          <Width>20</Width>
                          <Alignment>left</Alignment>
                       </TableColumnHeader>
                        <TableColumnHeader>
                            <Width>10</Width>
                            <Alignment>right</Alignment>
                        </TableColumnHeader>
                    </TableHeaders>
                    <TableRowEntries>
                        <TableRowEntry>
                            <TableColumnItems>
                                <TableColumnItem>
                                    <PropertyName>Stream</PropertyName>
                                </TableColumnItem>
                                <TableColumnItem>
                                    <PropertyName>Length</PropertyName>
                                </TableColumnItem>
                            </TableColumnItems>
                        </TableRowEntry>
                    </TableRowEntries>
                </TableControl>
            </View>          
        </ViewDefinitions>
    </Configuration>
    

    (It's allmost a direct copy of the original $PSHOME\FileFormat.format.ps1xml. I only changed Length to FileSize a few times)

  • load the new format in our powershell session:

    • Update-FormatData -PrependPath $Env:USERPROFILE\Documents\WindowsPowershell\MyFileFormat.format.ps1xml
  • try the new property
    • Get-ChildItem

load the changes in $PROFILE

  • copy these lines to $PROFILE to load the changes in every new session

    # local path to use in this script
    $scriptpath = Split-Path -parent $MyInvocation.MyCommand.Definition
    
    # custom types and formats
    # currently only System.IO.FileInfo is changed
    update-TypeData -PrependPath $scriptpath\MyTypes.ps1xml
    update-FormatData -PrependPath $scriptpath\MyFileFormat.format.ps1xml
    
egolus
  • 475
4

I used jmreicha's solution with an alias in my $profile:

function Get-ChildItem-MegaBytes {
  ls $args | Select-Object Name, @{Name="MegaBytes";Expression={$_.Length / 1MB}}
}

Set-Alias -name megs -val Get-ChildItem-MegaBytes

Now I just type: megs [whatever]

0

You can use a unixy ls by installing a BusyBox port. Scoop.sh has the package.

Then in Powershell, you can define a function to do ll in your $PROFILE:

function ll() {
  ls.exe -lah $args
}
moshen
  • 1,810
0

A simple function without having to hack the type system:

function lh {
    <#
    .SYNOPSIS
        Replicate the behaviour of `ls -lah` in Linux.
    .DESCRIPTION
        Lists file sizes output by `Get-ChildItem` in human-readable format.
    .PARAMETER Path
        The directory path containing files and/or directories to list.
    #>
    [OutputType()]
    param(
        [Parameter()]
        [String]$Path = "$PWD"
    )
    [Int64]$MaxFileSize = (Get-ChildItem -Path $Path | Measure-Object -Property Length -Maximum).Maximum
    [Double]$NumTrailingDecimals = [Math]::Log10($MaxFileSize)
    # Conditionally select the correct human-readable size format
    if ($NumTrailingDecimals -ge 12) {
        Get-ChildItem -Path $Path | Select-Object Mode, LastWriteTime, @{Name="Length (TB)";Expression={$_.Length / 1TB}}, Name
    } elseif ($NumTrailingDecimals -ge 9) {
        Get-ChildItem -Path $Path | Select-Object Mode, LastWriteTime, @{Name="Length (GB)";Expression={$_.Length / 1GB}}, Name
    } elseif ($NumTrailingDecimals -ge 6) {
        Get-ChildItem -Path $Path | Select-Object Mode, LastWriteTime, @{Name="Length (MB)";Expression={$_.Length / 1MB}}, Name
    } elseif ($NumTrailingDecimals -ge 3) {
        Get-ChildItem -Path $Path | Select-Object Mode, LastWriteTime, @{Name="Length (KB)";Expression={$_.Length / 1KB}}, Name
    } else {
        Get-ChildItem -Path $Path | Select-Object Mode, LastWriteTime, @{Name="Length (Bytes)";Expression={$_.Length}}, Name
    }
}
0
Function ll {
    ls -Force $args | select *, @{ Name = 'HRLength'; Expression = {
        if ($_.PSobject.Properties.Name -contains "Length") {
            $k = 0; while ($_.Length -shr 10 * ++$k -and $k -le 6) {}
            "{0:N3} {1}" -f ($_.Length / ([Int64]1 -shl 10 * --$k)),
                @('B','KB','MB','GB','TB','PB','EB')[$k]
    }}} | select name, hrlength, mode, lastwritetime
}

Note:

  • Copy this and paste it into PowerShell to give it a try.
  • [Math]::Log and numeric literals (e.g. 1kb,1mb...) are fine, but I'm using bitwise shifting here.
  • You can modify the last select name, ... line to focus on other properties. Possible properties of File type can be looked up with:
    ls 'C:\Windows\notepad.exe' | select *
    The first column of output is the PSobject.Properties.Name. Alternatively, you can run this command:
    (ls 'C:\Windows\notepad.exe').PSobject.Properties.Name
    to get the property names.

Explanation:

Function ll {
    Get-ChildItem -Force -Path $args | `
    ## The '-Force' parameter here has an effect similar to the 'ls -a'.
    ## You can remove it if you don't like it.
    ##
    Select-Object *, @{ Name = 'HRLength'; Expression = {
    ## Adding a new property named 'HRLength' (Human-Readable Length)
    ## as a 'calculated property'
    ## to the objects passed from the Get-ChildItem cmdlet.
    ##
        if ($_.PSobject.Properties.Name -contains "Length") {
        ## Checking the existence of 'Length' property,
        ## if not, you will see that each folder is 1 byte size.
        ## Because folder doesn't have a 'Length' property at all.
        ##
            $k = 0; while ($_.Length -shr 10 * ++$k -and $k -le 6) {}
            ## - Determining the order of magnitude
            ##   of file size through a while loop
            ##
            ## - For example, if file size is 10'000 bytes
            ##       before loop, $k = 0
            ##          1st loop, $k = 1, 10'000 -shr (10 * 1) = 9, 9 != 0
            ##          2nd loop, $k = 2, 10'000 -shr (10 * 2) = 0, stop looping
            ##   To get the order of magnitude, we need to subtract one from $k
            ##   Then, we know that the order of magnitude is 2^10 bytes, namely 'KB'
            ##
            ## - If file size is zero, when we enter the loop, $k is incremented first.
            ##   $k = 1, then 0 -shr 10 * 1 is still 0, then loop stopped.
            ##   And the order of magnitude of zero is 2^0 = 1, namely 'B'
            ##
            ## - If file size is [Int64]::MaxValue = 9223372036854775807 byte.
            ##   We will overflow the Int64 integer type after the 7th right-shift operation,
            ##   which will result in an infinite loop, so setting a boundary is necessary.
            ##   '-and $k -le 6' here break the loop when $k = 7
            ##
            ##   The following shows the overflow process for the Int64 type
            ##
            ##     k = 1 -> [Int64]::MaxValue -shr 10 * 1 = 9007199254740991
            ##     k = 2 -> [Int64]::MaxValue -shr 10 * 2 = 8796093022207
            ##     k = 3 -> [Int64]::MaxValue -shr 10 * 3 = 8589934591
            ##     k = 4 -> [Int64]::MaxValue -shr 10 * 4 = 8388607
            ##     k = 5 -> [Int64]::MaxValue -shr 10 * 5 = 8191
            ##     k = 6 -> [Int64]::MaxValue -shr 10 * 6 = 7
            ##     k = 7 -> [Int64]::MaxValue -shr 10 * 7 = 144115188075855871
            ##
            "{0:N3} {1}" -f ($_.Length / ([Int64]1 -shl 10 * --$k)),
                @('B','KB','MB','GB','TB','PB','EB')[$k]
            ## - We format the result by '-f' format operator
            ##   1. The file length set by its unit is placed in the first position,
            ##      and "{0:N3}" means to display to 3 decimal places.
            ##   2. The unit is placed in the second position.
            ##
            ## - First, we encounter ($_.Length / ([Int64]1 -shl 10 * --$k))
            ##   $k is decremented first to get the order of magnitude,
            ##   and the file size is calculated by its unit.
            ##   For example, if the file size is 10'000 bytes,
            ##   the order of magnitude $k after its decrement is 1
            ##   then (10'000 / (1 -shl 10 * 1)) = (10'000 / 1024) = 9.766
            ##
            ## - Second, we choose the literal unit from an array with $k.
            ##   It was interesting to note that the maximum length of
            ##   the 'Length' property is [Int64]::MaxValue = 9223372036854775807
            ##   which is 8 EB. Therefore the maximum order of magnitude is $k = 6,
            ##   that is ([Int64]1 -shl 10 * 6) = 1 EB
            ##
    }}} | `
    Select-Object Name, HRLength, Mode, LastWriteTime
    ## Finally, we format the output by columns.
    ##
}