views:

79

answers:

1

I got this colored dir script from http://tasteofpowershell.blogspot.com/2009/02/get-childitem-dir-results-color-coded.html:

function ls {
  $regex_opts = ([System.Text.RegularExpressions.RegexOptions]::IgnoreCase -bor [System.Text.RegularExpressions.RegexOptions]::Compiled)

  $fore = $Host.UI.RawUI.ForegroundColor
  $compressed = New-Object System.Text.RegularExpressions.Regex('\.(zip|tar|gz|rar)$', $regex_opts)
  $executable = New-Object System.Text.RegularExpressions.Regex('\.(exe|bat|cmd|ps1|psm1|vbs|rb|reg|dll|o|lib)$', $regex_opts)
  $executable = New-Object System.Text.RegularExpressions.Regex('\.(exe|bat|cmd|ps1|psm1|vbs|rb|reg|dll|o|lib)$', $regex_opts)
  $source = New-Object System.Text.RegularExpressions.Regex('\.(py|pl|cs|rb|h|cpp)$', $regex_opts)
  $text = New-Object System.Text.RegularExpressions.Regex('\.(txt|cfg|conf|ini|csv|log|xml)$', $regex_opts)

  Invoke-Expression ("Get-ChildItem $args") |
    %{
      if ($_.GetType().Name -eq 'DirectoryInfo') {
        $Host.UI.RawUI.ForegroundColor = 'DarkCyan'
        $_
        $Host.UI.RawUI.ForegroundColor = $fore
      } elseif ($compressed.IsMatch($_.Name)) {
        $Host.UI.RawUI.ForegroundColor = 'Yellow'
        $_
        $Host.UI.RawUI.ForegroundColor = $fore
      } elseif ($executable.IsMatch($_.Name)) {
        $Host.UI.RawUI.ForegroundColor = 'Red'
        $_
        $Host.UI.RawUI.ForegroundColor = $fore
      } elseif ($text.IsMatch($_.Name)) {
        $Host.UI.RawUI.ForegroundColor = 'Green'
        $_
        $Host.UI.RawUI.ForegroundColor = $fore
      } elseif ($source.IsMatch($_.Name)) {
        $Host.UI.RawUI.ForegroundColor = 'Cyan'
        $_
        $Host.UI.RawUI.ForegroundColor = $fore
      } else {
        $_
      }
    }
}

It works great, but I most of the time I want only the file names, in wide format. So after the invoke-expression call, I added

  Invoke-Expression ("Get-ChildItem $args") |
    %{
      if ($_.GetType().Name -eq 'DirectoryInfo') {
  :
  :
  :
        $_
      }
    } | format-wide -property Name
}

Now I have a bug. Only the colour of the second column is correct; the first item in each column takes the colour of the item in the second column. For example, if I have

> ls

Directory     Program.exe

Then both Directory and Program.exe will be red, even though Directory is supposed to be DarkCyan. How can I correct this?

+2  A: 

Rather than twiddling the foreground/background colors of the host in between displaying text to the screen, why don't you use Write-Host which gives you a bit more control over the displayed text (you can control when newlines are output) e.g.:

$_ | Out-String -stream | Write-Host -Fore Red

And for the wide listing use, you will need to handle the column formatting yourself unless you want to update the format data XML for the DirectoryInfo/FileInfo types. If you don't want to do that, then you can write out each name - padded out appropriately - with the desired color. On the last column, set the -NoNewLine param to $false:

$width =  $host.UI.RawUI.WindowSize.Width
$cols = 3   
ls | % {$i=0; $pad = [int]($width/$cols) - 1} `
       {$nnl = ++$i % $cols -ne 0; `
        Write-Host ("{0,-$pad}" -f $_) -Fore Green -NoNewLine:$nnl}
Keith Hill
This works great _unless_ $pad is not an integer (and 80/3 - 1 is not). I edited your example to include an int conversion.
Nathan Sanders
Thx. To really flesh it out you should also find the max length of each name and then determine how many columns you can display rather than hardcoding it to 3. :-)
Keith Hill
@Keith: could you please tell me what I need to do so that this script can color my output inside PowerShell? Take a look at my comment in the question.
Leniel Macaferi