19

I want to collect all output from my script in a log file and must use write-output instaed 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

Thanks -jt

Emiliano Poggi
  • 24,390
  • 8
  • 55
  • 67
ithyme
  • 201
  • 1
  • 2
  • 6

4 Answers4

15

Found somewhere on the Internet:

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

Works great in my code.

Piotr S.
  • 159
  • 1
  • 4
  • 6
    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. – HipCzeck Jan 15 '15 at 17:19
  • 1
    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. – ariso Apr 20 '17 at 16:10
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.

JPBlanc
  • 70,406
  • 17
  • 130
  • 175
8
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 stdout, 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
mklement0
  • 382,024
  • 64
  • 607
  • 775
Aaron Jensen
  • 25,861
  • 15
  • 82
  • 91
  • 3
    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()`. – mklement0 Jan 22 '18 at 18:08
7

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 "pre-assemble" 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 of mine.


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, as of Windows PowerShell v5.1 / PowerShell Core v6.0.0, you cannot prevent a trailing newline when sending text to external programs via the pipeline - see this GitHub issue.

    • In PSv5+, however, you can prevent a trailing newline when capturing output in a file, by using Out-File -NoNewline or Set-Content -NoNewline (in PSv4-, you must use the .NET Framework directly); by contrast, redirecting to a file with > does append 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 of mine.
mklement0
  • 382,024
  • 64
  • 607
  • 775
  • 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 Oct 25 '20 at 22:28
  • 2
    @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](https://stackoverflow.com/a/40445998/45375). – mklement0 Oct 25 '20 at 22:43