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

simple powershell installation scripts for macos

If you’re playing with Powershell under Mac (see https://github.com/PowerShell/PowerShell ) you reach a point where you want to quickly install and uninstall Powershell from the command line. Thus, the following two scripts.

First to install;

#!/usr/bin/env bash

file=`ls powershell*`
[ -z "$file" ] && echo "Cannot find powershell installer" || sudo installer -pkg ${file} -target /

Then to uninstall;

#!/usr/bin/env bash

sudo rm -rf /usr/local/bin/powershell /usr/local/microsoft/powershell

You can name these whatever you want (I chose install-powershell.sh and uninstall-powershell.sh respectively) and remember to set their permissions respectively. Make sure the install script is in the same directory with the the Powershell dmg file, otherwise you can run the uninstall script from anywhere.