11

I am having to run a Microsoft cmdlet, and the important bit of information is written to console using a Write-Host line within the cmdlet.

It is NOT returned, so I cannot do $result = Commandlet ... A different value is returned that is not of use to me, what I actually need is printed to console within the commandlet is there anyway I can 'sniff' or 'scrape' the console to get the information I want?

$result = Test-Cluser

Test-Cluster will print stuff like: 'HadUnselectedTests', 'ClusterConditionallyApproved', etc. But the value it returns in the path to the .htm report file. And the .htm report file does not contain one of those status codes unfortunately so I cannot just parse the .htm file for it either.

Any suggestions?

3 Answers 3

23

Note: As for why you should never use Write-Host to output data, see this answer.

In PSv5+:

$result = Test-Cluster 6>&1

Since version 5, Write-Host writes to the newly introduced information stream, whose number is 6.

6>&1 redirects that stream to the success output stream (number 1), so that it too can be captured in $result.

Caveat: The related Out-Host cmdlet does not write to the information stream; its output cannot be captured - see this answer for the differences between Write-Host and Out-Host.


In PSv4-:

There is no way to capture Write-Host output in-session.

The only workaround is to launch another instance of Powershell with the target command specified as a string.
Caveats:

  • Such an invocation is slow,
  • prevents passing of arguments with their original data type
  • invariably only returns string data (lines of text)
  • returns output from all output streams, including error output
$result = powershell -noprofile -command 'Test-Cluster'

Note that using a script block to pass the command (-command { Test-Cluster }) would not work, because PowerShell then uses serialization and deserialization to emulate the in-session behavior.


Optional reading: output streams in PowerShell and how to redirect them:

Get-Help about_Redirection discusses a list of all output streams, which can be targeted by their numbers; since PSv5, these are:

1 ... success output stream (implicit output and Write-Output output)
2 ... error output stream (Write-Error and unhandled errors)
3 ... warnings (Write-Warning)
4 ... verbose output (Write-Verbose)
5 ... debug output (Write-Debug)
6 ... (v5+) Write-Information and Write-Host output

Note that some streams are silent by default and require opt-in to produce output, either via a preference variable (e.g., $VerbosePreference) or a common parameter (e.g., -Verbose)

  • {n}> allows redirecting the number {n} stream; if {n} is omitted, 1 is implied:

    • to a file (e.g., 3> c:/tmp/warnings.txt
    • to "nowhere", i.e suppressing the output (e.g., 3> $null)
    • to the success output stream (e.g., 3>&1); note: only stream 1 can be targeted this way.
  • *> targets all output streams.

Note: Unlike in POSIX-like shells (e.g., bash), the order of multiple redirection expression does not matter.

Therefore, the following POSIX-like shell idiom - which redirects error output to the success stream and silences only the original success output - does NOT work:

... 2>&1 1>$null # !! NO output in PowerShell

To achieve this in PowerShell, you mustn't redirect 1 and instead filter the objects in the success by their stream of origin.

Case in point: In the end, the OP wanted the following: capture only warning output, without the regular (success) output:

Test-Cluster 3>&1 | Where-Object { $_ -is [System.Management.Automation.WarningRecord] }

Objects that came from the warning stream have type [System.Management.Automation.WarningRecord], which is what enables the filtering above.

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

5 Comments

Nice! The PSv5+ part should be documented in about_Redirection
$result = SomeFunction 6>&1 turns newlines into spaces by default. To keep newlines: $result = SomeFunction 6>&1 | Out-String or set preference variable before the command to be redirected: $OFS = "`n"
@zett42: I think you're seeing the behavior of Write-Host, not effects of the 6>&1 redirection. When you pass an array to Write-Host, it is stringified the way you describe. That 6>&1 isn't to blame can be verified as follows: function SomeFunction { 1, 2, 3 | Write-Host }; $result = SomeFunction 6>&1 - $result will contain each number on its own line.
@mklement0 Correct! When just writing $result, I see the separate lines, while I see the "newlines turned into spaces" only with Write-Host $result.
@pico, I'v added a note re Out-Host to the answer. If you have further questions, please create a new question post.
1

I use *> instead of > to redirect all outputs from console to a file.

Comments

0

Example of redirecting text and a variable to a file:

"The "+$set_groups+"ADGroup set!" | Out-File -FilePath $log_path -Append

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.