Цветные слова в формате сценария powershell-вывод таблицы

можно ли окрашивать только определенные слова (не полные строки) для вывода powershell с помощью format-table. Например, этот скрипт рекурсивно сканирует папку для строки, а затем выводит результат с помощью format-table.

dir -r -i *.* | Select-String $args[0] |
format-table -Property @{label="Line #"; Expression={$_.LineNumber}; width=6},
Path, Line -wrap

было бы неплохо иметь возможность форматировать слово, которое мы ищем, определенным цветом, чтобы вы могли точно видеть, где оно было найдено в строке.

4 ответов


вы могли бы трубу таблицы в Out-String, затем напишите строку по частям, используя Write-Host С -NoNewLine переключатель.

что-то вроде этого:

filter ColorWord {
    param(
        [string] $word,
        [string] $color
    )
    $line = $_
    $index = $line.IndexOf($word, [System.StringComparison]::InvariantCultureIgnoreCase)
    while($index -ge 0){
        Write-Host $line.Substring(0,$index) -NoNewline
        Write-Host $line.Substring($index, $word.Length) -NoNewline -ForegroundColor $color
        $used = $word.Length + $index
        $remain = $line.Length - $used
        $line = $line.Substring($used, $remain)
        $index = $line.IndexOf($word, [System.StringComparison]::InvariantCultureIgnoreCase)
    }
    Write-Host $line
}

Get-Process| Format-Table| Out-String| ColorWord -word 1 -color magenta

мне нравится Rynant'ы подход. Вот альтернативная реализация, использующая -split вместо IndexOf:

filter ColorWord( [string]$word, [ConsoleColor]$color ) {
    $later = $false
    $_ -split [regex]::Escape( $word ) | foreach {
      if( $later ) { Write-Host "$word" -NoNewline -ForegroundColor $color }
      else { $later = $true }
      Write-Host $_ -NoNewline
    }
    Write-Host
}

Split включает пустые строки, если строка начинается или заканчивается данным словом, следовательно, дополнительная логика" если не первая".


Edit: следуя комментарию Райнанта, вот еще одна реализация, которая поддерживает как простые, так и регулярные выражения:

filter ColorPattern( [string]$Pattern, [ConsoleColor]$Color, [switch]$SimpleMatch ) {
  if( $SimpleMatch ) { $Pattern = [regex]::Escape( $Pattern ) }

  $split = $_ -split $Pattern
  $found = [regex]::Matches( $_, $Pattern, 'IgnoreCase' )
  for( $i = 0; $i -lt $split.Count; ++$i ) {
    Write-Host $split[$i] -NoNewline
    Write-Host $found[$i] -NoNewline -ForegroundColor $Color
  }

  Write-Host
}

в вывод из следующих примеров показывает разницу:

PS> '\d00\d!' | ColorPattern '\d' 'Magenta' -Simple
\d00\d!

PS> '\d00\d!' | ColorPattern '\d' 'Magenta'
\d00\d!


Я люблю ответ @Ryant дал. У меня есть модифицированная версия, которая может использоваться для окрашивания нескольких слов в выходе, передавая массивы или слова и цвета. Фокус в том, что вы должны разделить входной текст на строки на основе разделителя новой строки.

filter ColorWord2 {
param(
    [string[]] $word,
    [string[]] $color
)
$all = $_
$lines = ($_ -split '\r\n')

$lines | % {
    $line = $_      
    $x = -1

    $word | % {
        $x++
        $item = $_      

        $index = $line.IndexOf($item, [System.StringComparison]::InvariantCultureIgnoreCase)                            
            while($index -ge 0){
                Write-Host $line.Substring(0,$index) -NoNewline                 
                Write-Host $line.Substring($index, $item.Length) -NoNewline -ForegroundColor $color[$x]
                $used =$item.Length + $index
                $remain = $line.Length - $used
                $line =$line.Substring($used, $remain)
                $index = $line.IndexOf($item, [System.StringComparison]::InvariantCultureIgnoreCase)
            }
        }

    Write-Host $line
} }

и будет выполняться следующим образом

Get-Service | Format-Table| Out-String| ColorWord2 -word 'Running','Stopped' -color 'Green','Red'

#$VerbosePreference = 'continue'
$VerbosePreference = 'silent'

filter ColorPattern {
    param ([object]$colors, [switch]$SimpleMatch)
    [string]$line = $_

    $collection = New-Object 'System.Collections.Generic.SortedDictionary[int, pscustomobject]'
    $RegexOptions = [Text.RegularExpressions.RegexOptions]::IgnoreCase.value__ + [Text.RegularExpressions.RegexOptions]::Singleline.value__

    if ($SimpleMatch){
        $patternMatches = $colors.keys | % {[regex]::Escape($_)}
        $reference = 'Value'
    } else {
        $patternMatches = $colors.keys
        $reference = 'Pattern'
    }

    # detect RegEx matches and add to collection object
    Write-Verbose "'$line'"

    $measureparsing