Is there a way to specify a font color when using

2020-05-31 04:34发布

问题:

I have a powershell script that gives some status output via write-output. I am intentionally not using write-host because the output may be captured and written to a logfile like this:

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

But if the output is not redirected it would be nice to have colored output on the console, because the script is producing a lot of different status messages. I know that colored output is possible with write-host but the status messages should be pipeable.

Any ideas how to solve this?

回答1:

I have tried this extra function and it basically works fine:

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

The result of this particular test is a little bit funny though: we really get lines in red, green and yellow but the table header is in red, i.e. the color of the the first call of the function.



回答2:

Separate the results on the pipeline from the status messages in the console.

E.g., use a function like this in your script:

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
}

I would also recommend you use one of the following cmdlets over write-host for outputting status messages from your scripts:

  • write-debug
  • write-error
  • write-verbose
  • write-warning

The appearance of these status messages will vary depending on the cmdlet used. In addition, the user can disable specific levels of status using the $(warning|error|verbose|debug)preference variables, or capture specific status messages using the -(warning|error|verbose|debug)variable common cmdlet parameters.



回答3:

This way:

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



回答4:

I had the same problem, so I share my solution which I think works quite well:

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

This is the Cmdlet to use it

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:

I know this post is ancient, but this could come handy to someone out there.

I wanted to change colors and the accepted answer was not the best solution. In my eyes, the following code is better solution as it takes advantage of the native PowerShell functionality:

EDIT:

# 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


标签: powershell