ChatGPT解决这个技术问题 Extra ChatGPT

How to output something in PowerShell

I am running a PowerShell script from within a batch file. The script fetches a web page and checks whether the page's content is the string "OK".

The PowerShell script returns an error level to the batch script.

The batch script is executed by ScriptFTP, an FTP automation program. If an error occurs, I can have ScriptFTP send the full console output to the administrator via E-Mail.

In the PowerShell script, I would like to output the return value from the web site if it is not "OK", so the error message gets included in the console output, and thus in the status mail.

I am new to PowerShell and not sure which output function to use for this. I can see three:

Write-Host

Write-Output

Write-Error

What would be the right thing to use to write to the Windows equivalent of stdout?


P
Pure.Krome

Simply outputting something is PowerShell is a thing of beauty - and one its greatest strengths. For example, the common Hello, World! application is reduced to a single line:

"Hello, World!"

It creates a string object, assigns the aforementioned value, and being the last item on the command pipeline it calls the .toString() method and outputs the result to STDOUT (by default). A thing of beauty.

The other Write-* commands are specific to outputting the text to their associated streams, and have their place as such.


That's not really what happens. It's a string literal expression and the only thing in its pipeline. Thus it's equivalent to "Hello, World!" | Out-Host. Out-Host on the other hand sends objects to the PowerShell host for display and its implementation is dependent on the host. The console host sends them to the standard output handle (passing through Out-Default along the way), indeed. PowerShell ISE displays them in its output pane, however, and other hosts may do yet other things entirely.
Objects also don't get blindly converted to string, but pass through a formatter which decides on what to do with them. That's why you see Get-ChildItem's output coming in a table form, for example, and results with many properties (e.g. WMI) default to Format-List instead.
C
Community

I think in this case you will need Write-Output.

If you have a script like

Write-Output "test1";
Write-Host "test2";
"test3";

then, if you call the script with redirected output, something like yourscript.ps1 > out.txt, you will get test2 on the screen test1\ntest3\n in the "out.txt".

Note that "test3" and the Write-Output line will always append a new line to your text and there is no way in PowerShell to stop this (that is, echo -n is impossible in PowerShell with the native commands). If you want (the somewhat basic and easy in Bash) functionality of echo -n then see samthebest's answer.

If a batch file runs a PowerShell command, it will most likely capture the Write-Output command. I have had "long discussions" with system administrators about what should be written to the console and what should not. We have now agreed that the only information if the script executed successfully or died has to be Write-Host'ed, and everything that is the script's author might need to know about the execution (what items were updated, what fields were set, et cetera) goes to Write-Output. This way, when you submit a script to the system administrator, he can easily runthescript.ps1 >someredirectedoutput.txt and see on the screen, if everything is OK. Then send the "someredirectedoutput.txt" back to the developers.


P
Peter Mortensen

I think the following is a good exhibit of Echo vs. Write-Host. Notice how test() actually returns an array of ints, not a single int as one could easily be led to believe.

function test {
    Write-Host 123
    echo 456 # AKA 'Write-Output'
    return 789
}

$x = test

Write-Host "x of type '$($x.GetType().name)' = $x"

Write-Host "`$x[0] = $($x[0])"
Write-Host "`$x[1] = $($x[1])"

Terminal output of the above:

123
x of type 'Object[]' = 456 789
$x[0] = 456
$x[1] = 789

I can look at this all day... But why is $x = test only printing 123 and not also 456?
Write-Output (or echo) writes the specified objects to the pipeline. If Write-Output is the last command in the pipeline, the objects are displayed in the console. Here it is the 2nd last and is there being piped down to the return statement and added the array docs.microsoft.com/en-us/powershell/module/…
S
Sara J

You can use any of these in your scenario since they write to the default streams (output and error). If you were piping output to another commandlet you would want to use Write-Output, which will eventually terminate in Write-Host.

This article describes the different output options: PowerShell O is for Output


Thanks for the link. Goodness, this is complicated. If Write-host is some sort of endpoint or flushing function, I will try and go with that and report back.
m
mklement0

What would be the right thing to use to write to the Windows equivalent of stdout?

In effect, but very unfortunately, both Windows PowerShell and PowerShell Core as of v7.2, send all of their 6(!) output streams to stdout when called from the outside, via PowerShell's CLI.

See GitHub issue #7989 for a discussion of this problematic behavior, which likely won't get fixed, so as to preserve backward compatibility.

In practice, this means that whatever PowerShell stream you send output to will be seen as stdout output by an external caller: E.g., if you run the following from cmd.exe, you'll see no output, because the stdout redirection to NUL applies equally to all PowerShell streams: C:\>powershell -noprofile -command "Write-Error error!" >NUL However - curiously - if you redirect stderr, PowerShell does send its error stream to stderr, so that with 2> you can capture the error-stream output selectively; the following outputs just 'hi' - the success-stream output - while capturing the error-stream output in file err.txt: C:\>powershell -noprofile -command "'hi'; Write-Error error!" 2>err.txt

E.g., if you run the following from cmd.exe, you'll see no output, because the stdout redirection to NUL applies equally to all PowerShell streams: C:\>powershell -noprofile -command "Write-Error error!" >NUL

C:\>powershell -noprofile -command "Write-Error error!" >NUL

However - curiously - if you redirect stderr, PowerShell does send its error stream to stderr, so that with 2> you can capture the error-stream output selectively; the following outputs just 'hi' - the success-stream output - while capturing the error-stream output in file err.txt: C:\>powershell -noprofile -command "'hi'; Write-Error error!" 2>err.txt

C:\>powershell -noprofile -command "'hi'; Write-Error error!" 2>err.txt

The desirable behavior is:

Send PowerShell's success output stream (number 1) to stdout.

Send output from all other streams to stderr, which is the only option, given that between processes only 2 output streams exist - stdout (standard output) for data, and stderr (standard error) for error messages and all other types of messages - such as status information - that aren't data.

It's advisable to make this distinction in your code, even though it currently isn't being respected.

Inside PowerShell:

Write-Host is for display output, and bypasses the success output stream - as such, its output can neither be (directly) captured in a variable nor suppressed nor redirected. Its original intent was simply to create user feedback and create simple, console-based user interfaces (colored output). Due to the prior inability to be captured or redirected, PowerShell version 5 made Write-Host write to the newly introduced information stream (number 6), so since then it is possible to capture and redirect Write-Host output.

Its original intent was simply to create user feedback and create simple, console-based user interfaces (colored output).

Due to the prior inability to be captured or redirected, PowerShell version 5 made Write-Host write to the newly introduced information stream (number 6), so since then it is possible to capture and redirect Write-Host output.

Write-Error is meant for writing non-terminating errors to the error stream (number 2); conceptually, the error stream is the equivalent of stderr.

Write-Output writes to the success [output] stream (number 1), which is conceptually equivalent to stdout; it is the stream to write data (results) to. However, explicit use of Write-Output is rarely needed due to PowerShell's implicit output feature: Output from any command or expression that isn't explicitly captured, suppressed or redirected is automatically sent to the success stream; e.g., Write-Output "Honey, I'm $HOME" and "Honey, I'm $HOME" are equivalent, with the latter not only being more concise, but also faster. See this answer for more information.

However, explicit use of Write-Output is rarely needed due to PowerShell's implicit output feature: Output from any command or expression that isn't explicitly captured, suppressed or redirected is automatically sent to the success stream; e.g., Write-Output "Honey, I'm $HOME" and "Honey, I'm $HOME" are equivalent, with the latter not only being more concise, but also faster. See this answer for more information.

Output from any command or expression that isn't explicitly captured, suppressed or redirected is automatically sent to the success stream; e.g., Write-Output "Honey, I'm $HOME" and "Honey, I'm $HOME" are equivalent, with the latter not only being more concise, but also faster.

See this answer for more information.


j
jordan
Write-Host "Found file - " + $File.FullName -ForegroundColor Magenta

Magenta can be one of the "System.ConsoleColor" enumerator values - Black, DarkBlue, DarkGreen, DarkCyan, DarkRed, DarkMagenta, DarkYellow, Gray, DarkGray, Blue, Green, Cyan, Red, Magenta, Yellow, White.

The + $File.FullName is optional, and shows how to put a variable into the string.


U
Uwe Keim

You simply cannot get PowerShell to ommit those pesky newlines. There is no script or cmdlet that does this.

Of course Write-Host is absolute nonsense because you can't redirect/pipe from it! You simply have to write your own:

using System;

namespace WriteToStdout
{
    class Program
    {
        static void Main(string[] args)
        {
            if (args != null)
            {
                Console.Write(string.Join(" ", args));
            }
        }
    }
}

E.g.

PS C:\> writetostdout finally I can write to stdout like echo -n
finally I can write to stdout like echo -nPS C:\>

You could do this in powershell itself. [System.Console]::Write("stringy") However you won't be able to redirect it at all in powershell.
Sure you can. See this question