Home > Blockchain >  Powershell - Write-Host printing in wrong place
Powershell - Write-Host printing in wrong place

Time:07-16

My code has the following function:

function status{
    if ($args[0] -eq "Stopped"){
        Write-Host -NoNewline "Stopped" -fore red
    .....
    }
}

and the function is used as:

...
Write-Host "$($count)) $($i.DisplayName)   STATUS: $(status $i.State)"
...

The result after script execution is:

Stopped 1) XXXXXX STATUS:

Why "Stopped" is in the beginning of the line? can someone help me? The function is only to change the text color. As the example -fore red is to Stopped value.

CodePudding user response:

You could use example

CodePudding user response:

Santiago Squarzon's helpful answer provides an effective solution; let me complement it with an explanation of what you tried:

Why "Stopped" is in the beginning of the line?

The reason is that Write-Host doesn't write to PowerShell's success output stream and therefore doesn't "return" a value from your status function.

Instead, Write-Host instantly prints to the host (display; in PSv5 via the information stream), before exiting the function, and your function produces no success-stream output.

Since subexpressions (via $(...)) are evaluated first in an expandable string (or command in general):

  • the Write-Host call inside your status function executes right away and prints at the start of the line.

  • only then does the outer Write-Host call execute, which - due to the inner call's -NoNewLine switch - prints on the same line, after what the function printed, and $(status $i.State), due to the status call producing no success output, evaluates to the empty string.

A simple example can illustrate the problem:

Write-Host "foo: >>$(Write-Host bar)<<"

Output:

bar         # The inner Write-Host printed right away.
foo >><<    # $(Write-Host bar) produced no success output

Santiago's solution avoids this problem by replacing the Write-Host call inside the function with sending a string (implicitly) to the success output stream, so that it becomes the function's "return value" that subexpression $(status $i.State) expands to, and to make this string colored, ANSI / VT escape sequences are needed.

Note that while "$([char] 27)" is required in Windows PowerShell to embed an ESC character in an expanable string, PowerShell (Core) 7 now offers escape sequence "`e"

Also, PowerShell (Core) 7.2 offers the automatic $PSStyle variable, which, while more verbose, offers a more descriptive way to embed ANSI / VT escape sequences; e.g.:

# Prints only the word "green" in green.
"It ain't easy being $($PSStyle.Foreground.Green)green$($PSStyle.Reset)."

Note:

  • If you send strings with ANSI / VT sequences to the success output stream, as in the example above, colors are not automatically reset; $PSStyle.Reset is needed for a manual reset.

  • By contrast, if Write-Host prints a string, it resets colors automatically.

  • Related