有没有办法在使用write-output时指定字体颜色

时间:2011-01-10 14:23:57

标签: powershell

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

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

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

任何想法如何解决这个问题?

6 个答案:

答案 0 :(得分:10)

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

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

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

答案 1 :(得分:7)

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

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

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
}

我还建议你使用以下cmdlet之一而不是write-host来输出脚本中的状态消息:

  • write-debug
  • 写错误
  • write-verbose
  • 写入警告

这些状态消息的外观将根据使用的cmdlet而有所不同。此外,用户可以使用$(warning | error | verbose | debug)首选项变量禁用特定级别的状态,或使用 - (warning | error | verbose | debug)变量常用cmdlet参数捕获特定状态消息。

答案 2 :(得分:1)

我遇到了同样的问题,所以我分享了我认为非常有效的解决方案:

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
}

答案 3 :(得分:1)

这种方式:

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

enter image description here

答案 4 :(得分:0)

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

我想改变颜色,接受的答案不是最佳解决方案。在我看来,以下代码是更好的解决方案,因为它利用了本机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

答案 5 :(得分:0)

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

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

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"