Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PowerShell Capture Write-Host output

Tags:

powershell

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?

like image 229
Dylan Holmes Avatar asked Jun 19 '18 21:06

Dylan Holmes


2 Answers

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
    • for a list of all output streams, see Get-Help about_Redirection
$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.

like image 195
mklement0 Avatar answered Sep 27 '22 22:09

mklement0


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

like image 33
pseca Avatar answered Sep 27 '22 23:09

pseca