powershell colored directory listing


I still continue to fiddle about with PowerShell scripting on Windows 10. With PowerShell Core, PowerShell is also available for Linux and macOS. With that kind of cross-platform availability I’ve been trying to write code that works across Windows 10 Desktop as well as the Core implementations. This post is about a colored directory lister written in PowerShell that does that.

If you’re a Linux user, then you’re probably used to the colorization abilities of Gnu ls. I wanted that basic capability for Windows 10 and I wanted it to operate the same across all platforms. One feature I wanted was for this colored directory to show soft links, that is, identify a soft link and show what it pointed to. I managed to get that to work. The code follows.

function Get-ColoredDir {
    $regex_opts =
        ([System.Text.RegularExpressions.RegexOptions]::IgnoreCase `
          -bor [System.Text.RegularExpressions.RegexOptions]::Compiled)
    # Save the foreground and background colors. We'll restore when finished.
    $fore = $Host.UI.RawUI.ForegroundColor
    $back = $Host.UI.RawUI.BackgroundColor
    # Create regular expressions for finding compressed, executable, and text files.
    # We'll use these distinctions for our coloration below.
    $compressed =
        New-Object System.Text.RegularExpressions.Regex('\.(zip|tar|gz|rar|jar|war)$', $regex_opts)
    $executable =
        New-Object System.Text.RegularExpressions.Regex('\.(exe|bat|cmd|py|pl|ps1|psm1|vbs|rb|reg|msi|sh)$', $regex_opts)
    $text_files =
        New-Object System.Text.RegularExpressions.Regex('\.(txt|cfg|conf|ini|csv|log|xml|html|java|c|cpp|cs)$', $regex_opts)

    Invoke-Expression ("Get-ChildItem $args -Force") | ForEach-Object {

        $timestamp =
            '{0,2}/{1,2}/{2:D4} {3:D2}:{4:D2}:{5:D2}' -f
                $_.LastWriteTime.Month,
                $_.LastWriteTime.Day,
                $_.LastWriteTime.Year,
                $_.LastWriteTime.Hour,
                $_.LastWriteTime.Minute,
                $_.LastWriteTime.Second;

        $foretext = '{0, -10} {1} {2, 10} ' -f $_.Mode, $timestamp, $_.Length

        # Look to see if any of the objects found is a soft link.
        # Microsoft's term for a soft link is ReparsePoint.
        # Note the use of -Force to pick up hidden files, or files that start
        # with a period (.)
        $linkedItem = ''
        if ($_.Attributes -match "ReparsePoint") {
            $linkedItem = Get-Item -Force $_ | select-object -expandproperty Target
        }

        if ($_.GetType().Name -eq 'DirectoryInfo') {
            $Host.UI.RawUI.ForegroundColor = 'Cyan'
            if ($_.Attributes -match "ReparsePoint") {
                $Host.UI.RawUI.ForegroundColor = 'Magenta'
            }
        }
        elseif ($compressed.IsMatch($_.Name)) {
            $Host.UI.RawUI.ForegroundColor = 'Yellow'
        }
        elseif ($executable.IsMatch($_.Name)) {
            $Host.UI.RawUI.ForegroundColor = 'Red'
        }
        elseif ($text_files.IsMatch($_.Name)) {
            $Host.UI.RawUI.ForegroundColor = 'White'
        }
        else {
            $Host.UI.RawUI.ForegroundColor = $fore
        }

        if ($linkedItem.length -gt 0) {
            '{0}{1} -> {2}' -f $foretext, $_.Name, $linkedItem
        } else {
            '{0}{1}' -f $foretext, $_.Name
        }

    }

    $Host.UI.RawUI.ForegroundColor = $fore
    $Host.UI.RawUI.BackgroundColor = $back
}

I wouldn’t call this particularly exciting PowerShell code. I’m quite certain that a real PowerShell scripting guru would come up with something far more elegant. But it works, and it has examples of how to extract information for directory objects in a PowerShell environment, especially when determining soft links and what they resolve to. I hope you find it useful.

If you’re interested in PowerShell Core, you can find it on GitHub here: https://github.com/PowerShell/PowerShell