Can powershell let you determine if output is being printed to the screen, vs piped to variable / file?

I know this type feels like moving a state in the "wrong direction" in the pipeline, but there are a few circumstances where it might be convenient.

Is this piece of code possible?

if (Directed-To-Screen) {
    Write-Host "Error!" -ForegroundColor Red 
} else {
    Write-Output "Error!"
}    

      

Where Directed-To-Screen

will return $ false if the current code / script is passed to a variable or file, etc. (I know [Console]::ForegroundColor

\ $host.UI.RawUI.ForegroundColor

can be used for colored write-output in some consoles).

In fact, quite a lot can be done to improve the formatting if printed on the screen, whereas the output from the utility functions should be structured in such a way that separate fields can be used. Being able to tell them apart can be very helpful. (Is there no way to force PSObject to override the ToString formatting to look pretty nice when printed on screen?)

It may not even be possible to determine if it comes out on screen or not. Can anyone confirm any method?

+3


source to share


1 answer


I think you are approaching this the wrong way. Instead of using Write-Host

and forcing the foreground color to red, you should output an object that appears in red on the terminal, but just looks like plain text when written to a file.

There is already an object that does this: any object of the type System.Management.Automation.ErrorRecord

will display in red if it reaches the end of the pipeline, but can be written to a file. Unfortunately for your purposes it is usually formatted with CategoryId

and fields FullyQualifiedErrorId

, but it won't do that if the error object was created with its own command. We can fake this behavior like this:

function Write-RedText
{
    [CmdletBinding()]
    [OutputType([int])]
    Param
    (
        [Parameter(Mandatory=$true,
                   ValueFromPipelineByPropertyName=$true,
                   Position=0)]
        $Text
    )

    Begin
    {
    }
    Process
    {
       foreach ($s in $Text)
       {
           #Wr$o = (Write-Error $s -ErrorId NativeCommandErrorMessage -TargetObject $None) 2>&1
           $o = new-object -TypeName "System.Management.Automation.ErrorRecord" -ArgumentList ($s, "NativeCommandErrorMessage", [System.Management.Automation.ErrorCategory]::FromStdErr, "c")
           $o | Add-Member -NotePropertyName writeErrorStream -NotePropertyValue $True
          Write-Output $o
       }
    }
    End
    {
    }
}

      

Now you can simply do:

Write-RedText "Error!"

      



and it will appear in red if it reaches the host, but will just appear as plain text if it ends up in the file.

NB It's a property writeErrorStream

on an object that actually renders it in red, so you can make other objects red just by adding this property. eg.

$out = ls
$out | Add-Member -NotePropertyName writeErrorStream -NotePropertyValue $True
$out

      

will give you a list of directories, red on the console, or if you'd rather use the property WriteWarningStream

for orange text.

As for the rest of your question, I'm sure there is no way to tell where the exit will end. There is an implicit one at the end of the outermost pipeline | Out-Default

. Out-Default

formats the objects and sends them to the console, but there is no way to know if any of the objects have reached this final command, or if they do, have you overridden Out-Default

something completely different.

+3


source







All Articles