【问题标题】:Is there a way to specify a font color when using write-output使用写输出时有没有办法指定字体颜色
【发布时间】:2011-06-06 13:46:03
【问题描述】:

我有一个 powershell 脚本,它通过 write-output 提供一些状态输出。我故意不使用 write-host 因为输出可能会被捕获并写入这样的日志文件:

./myscript.ps1 | out-file log.txt

但是如果输出没有被重定向,那么在控制台上有彩色输出会很好,因为脚本会产生很多不同的状态消息。我知道使用 write-host 可以进行彩色输出,但状态消息应该是可传输的。

有什么办法解决这个问题吗?

【问题讨论】:

  • MS 建议使用write-host technet.microsoft.com/en-us/library/ff406264.aspx,但我理解您的担心
  • 这很糟糕,因为Write-Host 有一个-ForegroundColor 参数,但Write-Output 没有。
  • @DennisG 问题是当你使用Write-Host 显示Psobject 时,它看起来像@{test=test; test1=test1; test2=test2},看起来很可怕

标签: powershell


【解决方案1】:

我已经尝试过这个额外的功能,它基本上可以正常工作:

function Write-ColorOutput($ForegroundColor)
{
    # save the current color
    $fc = $host.UI.RawUI.ForegroundColor

    # set the new color
    $host.UI.RawUI.ForegroundColor = $ForegroundColor

    # output
    if ($args) {
        Write-Output $args
    }
    else {
        $input | Write-Output
    }

    # restore the original color
    $host.UI.RawUI.ForegroundColor = $fc
}

# test
Write-ColorOutput red (ls)
Write-ColorOutput green (ls)
ls | Write-ColorOutput yellow

这个特殊测试的结果有点有趣:我们确实得到了红色、绿色和黄色的线条,但表格标题是红色的,即第一次调用函数的颜色。

【讨论】:

  • 这在 ISE 或其他非基于控制台的主机中效果不佳。 :-) 你可以试试$host.UI.RawUI.ForegroundColor
  • @Keith,你绝对是对的(即使作者询问控制台)。我已经更新了代码。
  • [Console]::ForegroundColor 实际上更好,因为 $host.UI.RawUI.ForegroundColor 确实做你在 powershell_ise 中所期望的。
【解决方案2】:

这样:

function Green
{
    process { Write-Host $_ -ForegroundColor Green }
}

function Red
{
    process { Write-Host $_ -ForegroundColor Red }
}

Write-Output "this is a test" | Green
Write-Output "this is a test" | Red

【讨论】:

  • 这只是将输出重定向到Write-Host,因此效果与您首先使用Write-Host的效果相同,并且关键不能解决输出被重定向到的问题一份文件。使用此方法,如果您将脚本的输出重定向到文件,则使用此方法返回的任何文本都会显示在屏幕上,而不是输出到文件。
【解决方案3】:

将管道上的结果与控制台中的状态消息分开。

例如,在你的脚本中使用这样的函数:

function write-status( $status ){
   $status | write-host -fore green -back red;  #send a status msg to the console
   $status | write-output; #send a status object down the pipe
}

我还建议您在 write-host 上使用以下 cmdlet 之一从脚本输出状态消息:

  • 写调试
  • 写入错误
  • 写详细
  • 写警告

这些状态消息的外观会因使用的 cmdlet 而异。此外,用户可以使用 $(warning|error|verbose|debug) 首选项变量禁用特定级别的状态,或使用 -(warning|error|verbose|debug) 变量通用 cmdlet 参数捕获特定状态消息。

【讨论】:

  • 不是很好,因为当输出未通过管道传输到文件时,所有消息都会显示两次。
  • 我同意,任何使用它的功能都将不适合交互使用。捕获您编写托管的任何内容的唯一不错的方法是 Start-Transcript。
【解决方案4】:

我遇到了同样的问题,所以我分享了我认为效果很好的解决方案:

Write-ColorOutput "Hello" Green Black -NoNewLine
Write-ColorOutput " World" Red

这是使用它的 Cmdlet

function Write-ColorOutput
{
    [CmdletBinding()]
    Param(
         [Parameter(Mandatory=$False,Position=1,ValueFromPipeline=$True,ValueFromPipelinebyPropertyName=$True)][Object] $Object,
         [Parameter(Mandatory=$False,Position=2,ValueFromPipeline=$True,ValueFromPipelinebyPropertyName=$True)][ConsoleColor] $ForegroundColor,
         [Parameter(Mandatory=$False,Position=3,ValueFromPipeline=$True,ValueFromPipelinebyPropertyName=$True)][ConsoleColor] $BackgroundColor,
         [Switch]$NoNewline
    )    

    # Save previous colors
    $previousForegroundColor = $host.UI.RawUI.ForegroundColor
    $previousBackgroundColor = $host.UI.RawUI.BackgroundColor

    # Set BackgroundColor if available
    if($BackgroundColor -ne $null)
    { 
       $host.UI.RawUI.BackgroundColor = $BackgroundColor
    }

    # Set $ForegroundColor if available
    if($ForegroundColor -ne $null)
    {
        $host.UI.RawUI.ForegroundColor = $ForegroundColor
    }

    # Always write (if we want just a NewLine)
    if($Object -eq $null)
    {
        $Object = ""
    }

    if($NoNewline)
    {
        [Console]::Write($Object)
    }
    else
    {
        Write-Output $Object
    }

    # Restore previous colors
    $host.UI.RawUI.ForegroundColor = $previousForegroundColor
    $host.UI.RawUI.BackgroundColor = $previousBackgroundColor
}

【讨论】:

    【解决方案5】:

    我知道这篇文章很古老,但这对那里的人来说可能会派上用场。

    我想更改颜色,但接受的答案不是最佳解决方案。在我看来,以下代码是更好的解决方案,因为它利用了本机 PowerShell 功能:

    编辑:

    # Print User message using String Array $message
    function PrintMessageToUser {
        param(
            [Parameter( `
                Mandatory=$True, `
                Valuefrompipeline = $true)]
            [String]$message
        )
        begin {
            $window_private_data = (Get-Host).PrivateData;
            # saving the original colors
            $saved_background_color = $window_private_data.VerboseBackgroundColor
            $saved_foreground_color = $window_private_data.VerboseForegroundColor
            # setting the new colors
            $window_private_data.VerboseBackgroundColor = 'Black';
            $window_private_data.VerboseForegroundColor = 'Red';
        }
        process {
            foreach ($Message in $Message) {
                # Write-Host Considered Harmful - see http://www.jsnover.com/blog/2013/12/07/write-host-considered-harmful/
                # first way how to correctly write it
                #Write-host $message;
                Write-Verbose -Message $message -Verbose;
                # second correct way how to write it
                #$VerbosePreference = "Continue"
                #Write-Verbose $Message;
            }
        }
        end {
          $window_private_data.VerboseBackgroundColor = $saved_background_color;
          $window_private_data.VerboseForegroundColor = $saved_foreground_color;
        }
    
    } # end PrintMessageToUser
    

    【讨论】:

      【解决方案6】:

      我有同样的问题,我需要以交互方式用颜色记录屏幕输出,并以自动方式将该输出发送到文件。

      我的解决方案是用一个参数来表示输出类型('Screen'或'File'),然后函数可以决定如何渲染de输出。

      function Write-Color([String[]]$Text, [ConsoleColor[]]$Color, [ConsoleColor]$BackgroundColor = ([console]::BackgroundColor), $OutputType='Screen') {
          switch ($OutputType) {
              'Screen' { 
                  for ($i = 0; $i -lt $Text.Length; $i++) {
                      Write-Host $Text[$i] -Foreground $Color[$i] -NoNewLine -BackgroundColor $BackgroundColor
                  }
                  Write-Host
                  break
              }
              'File' {
                  # Assuming $OFS built-in Variable is an space
                  write-output "$Text"
                  break
              }
              Default {
                  throw '$OutputType must be "Screen" or "File".'
              }
          }
      }
      
      $CodeBlock = {
          param ($OutputType)
          Write-Color -T "=== STARTING ===" -C Cyan -B Gray -O $OutputType
          Write-Color -T 'Date: ', (Get-Date).ToString('yyyy-MM-dd hh:mm:ss') -C Green, Yellow -O $OutputType
          Write-Color -T 'Processing..' -C Cyan -O $OutputType
          Write-Color -T 'Date: ', (Get-Date).AddSeconds(3).ToString('yyyy-MM-dd hh:mm:ss') -C Green, Yellow -O $OutputType
          Write-Color -T "=== ENDING ===" -C Cyan -B Gray -O $OutputType
      }
      
      $Dir = 'D:\Tmp'  # Set your output directory
      
      #### Screen Test ####
      
      & $CodeBlock -OutputType 'Screen'
      & $CodeBlock -OutputType 'File'
      
      ### File Test ####
      
      # This file have unwanted newlines, notice the IO redirection with "*>"
      & $CodeBlock -OutputType 'Screen' *> "$Dir\Screen.log"
      
      & $CodeBlock -OutputType 'File' > "$Dir\File.log"
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-08-05
        • 1970-01-01
        • 2020-06-15
        • 1970-01-01
        • 2011-12-13
        • 2021-03-09
        相关资源
        最近更新 更多