22

I want to collect all output from my script in a log file and must use Write-Output instead of Write-Host.

Write-Output "Server:" $a looks like:

Server: foo 

Do I really have to write to write Write-Output $("sfdghk:" + $a) to get Server:Foo?

1

4 Answers 4

17

I found this somewhere on the Internet:

Write-Output "Server: $($a)" 

It works great in my code.

Sign up to request clarification or add additional context in comments.

2 Comments

For this example, the $(...) construct is redundant, as it says to treat everything inside the parentheses as script rather than text. Since the $a is already interpreted and inserted in quoted strings, the wrapper doesn't need to be added. Write-Output "Server: $a" ...will work fine. Use the wrapper $() when you are trying to access methods or properties of variables. $a = "I like eggs." Write-Output "Character count: $($a.length)" would print out I like eggs..length without the $(...) wrapper.
thank you, you save me a day! I think this is powershell design problem, it shouldn't make the way so different then another script lang.
11

There's good information in the existing answers, but let me attempt a pragmatic summary:

  • When printing to the console or redirecting to a file, Write-Output separates multiple arguments by a newline each.

  • Therefore, in order to produce single-line output, you must "preassemble" the parts to output into a single string that you pass as a single argument.

  • Except to suppress enumeration of collections, you generally do not need to use Write-Output explicitly, because PowerShell by default sends anything that is not captured in a variable or redirected elsewhere or sent through the pipeline to the [success] output stream (which Write-Output also writes to); thus, in the case at hand, the following is sufficient:

     "Server: $a" # What this expandable string expands to is *implicitly* output 

What may be confusing is that the Write-Host cmdlet acts differently, but it's important to note that it has a different purpose.

# IMPORTANT: Do not use Write-Host to output *data*; only use it to write # directly to the host (console). PS> Write-Host "Server:" $a # multiple spaces used on purpose Server: srv1 

Write-Host, unlike Write-Output, separates multiple arguments by a single space each. There are other important differences, which are summarized in this answer.


Given the generic title of the question, let's also address how to suppress a trailing newline:

  • For printing to the console only, you can use Write-Host -NoNewline.

  • With data output, be it via Write-Output, implicit output, or from another command:

    • You cannot prevent a trailing newline when the output is sent to the console.

    • Unfortunately, in Windows PowerShell and in PowerShell (Core) 7 as of v7.4.x, you cannot prevent a trailing newline when sending text to external programs via the pipeline—see GitHub issue #5974.

    • In Windows PowerShell v5+ and all versions of PowerShell 7, however, you can prevent a trailing newline when capturing output in a file, by using Out-File -NoNewline or Set-Content -NoNewline (in PowerShell v4-, you must use the .NET Framework directly); by contrast, redirecting to a file with > always appends a trailing newline.

    • Caveat: If you're outputting multiple objects, -NoNewline not only suppresses a trailing newline, but also newlines between these objects.

    • For the differences between Out-File and Set-Content and when to choose which, see this answer.

2 Comments

In case you need to use args[n] you can't use the "$args[-1]" but have to use the formatted form, like this: Write-Output ("{0} `t{1}" -f $args[-1],$PWD) | Out-File -Append $HOME/.somefile.
@not2qubit: As an isolated command argument, you can use $args[-1] as-is: & { Write-Output $args[-1] } one two. To embed it in a larger string, you need $(...): & { Write-Output "$($args[-1])!" } one two - see PowerShell's string interpolation rules.
9

9 hours ... I start an answer.

In Powershell everything you manipulate is an object.

so "Server:" is an object, $a is an object

PS> "server :".gettype() IsPublic IsSerial Name BaseType -------- -------- ---- -------- True True String System.Object 

Write-output is a CmdLet that put object in a kind of list (a pipe) to be used by other CmdLets or scripts. So there is not a really a newline between "Server:" and "foo". It's the way the console show you a list (an array) of objects. As you can see here under :

PS> $a = "foo" PS> (Write-Output "Server :" $a).gettype() IsPublic IsSerial Name BaseType -------- -------- ---- -------- True True Object[] System.Array 

Clearly it's an abstract here, but I hope it can make you understand.

Comments

8

Consider:

Write-Output "Server: $a" Write-Output ("Server: {0}" -f $a) Write-Output ("Server: " + $a) 

If you want to collect the output from a script into a log file, consider using Start-Transcript. It logs every command and all PowerShell output to a file. It doesn't log anything sent to standard output. However, so if you're using any legacy commands, you'll have to pipe their output to Write-Host:

Start-Transcript C:\logs\mylog.txt Write-Host "Server: " $a ping | Write-Host 

1 Comment

PowerShell's equivalent to stdout is its success output stream and things sent there do get logged. Write-Host in the past didn't write to stdout but rather printed directly to the console, which is why such output didn't show up in transcripts. In PSv5+, however, Write-Host / Out-Host now write to the newly introduced information stream (as does the new Write-Information cmdlet), which now does get logged. You can either use $null = ... to suppress output completely, or, to emulate PSv4- Write-Host behavior in this context, use $host.ui.WriteLine().

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.