In principle, capturing output from external utilities works the same way as with your own PowerShell commands (you may need to update how to make external tools run ):
$cmdOutput = <command>
To capture the output in a variable and print on the screen :
<command> | Tee-Object -Variable cmdOutput
To capture the output from multiple commands , use either a subexpression ( $(...) ) or a call ( & or . ) To the script block ( { ... } ):
$cmdOutput = $(<command>; ...)
Please note that the general need for a prefix with & (call operator) is a separate command whose name / path is quoted - for example, $cmdOutput = & 'netdom.exe' ... - does not apply to external programs as such (this is equally refers to PowerShell scripts), but this is a syntax requirement : PowerShell parses an instruction that starts with the quoted string in the default expression mode, while the argument mode is required, which is & provides.
Redirects also work the same way (mostly below):
$cmdOutput = <command> 2>&1
However, for external teams, it is more likely that the work will work as follows:
$cmdOutput = cmd /c <command> '2>&1'
External Program Considerations:
External programs , since they run outside of a system like PowerShell, only return strings through their success stream (stdout).
If the output contains more than 1 line , PowerShell by default splits it into an array of lines . More precisely, the output lines are stored in an array of the type [System.Object[]] , whose elements are strings ( [System.String] ).
If you want the output to be a single, potentially multi-line string , to an Out-String :
$cmdOutput = <command> | Out-String
Redirecting stderr to stdout using 2>&1 to also capture it as part of the success stream contains caveats :
To make 2>&1 merge stdout and stderr in the source , let cmd.exe handle the redirection using the following idioms:
$cmdOutput = cmd /c <command> '2>&1' # *array* of strings (typically)
$cmdOutput = cmd /c <command> '2>&1' | Out-String # single string
cmd /c calls cmd.exe with the <command> and exits after completing <command> .- Note the single quotes around
2>&1 , which ensures that the redirection is passed to cmd.exe and not interpreted by PowerShell. Note that the inclusion of cmd.exe means that its rules for escaping characters and expanding environment variables come into play by default in addition to PowerShell's own requirements; in PS v3 +, you can use the special parameter --% (the so-called stop symbol) to disable the interpretation of other parameters using PowerShell, with the exception of cmd.exe -line references to environment variables, for example %PATH% .
Note that since you combine stdout and stderr in the source with this approach , you wonβt be able to distinguish between lines created with stdout and stderr in PowerShell; if you need this distinction, use your own PowerShell 2>&1 redirection - see below.
Use the 2>&1 PowerShell redirection to find out which lines came from the stream :
Stderr output is written as error records ( [System.Management.Automation.ErrorRecord] ) rather than strings, so the output array can contain a combination of strings (each row represents a stdout string) and error records (each record represents a stderr string) . Note that for query 2>&1 both strings and error records are received through the PowerShell success output stream).
In the console, an error writes a red print, and the first one by default produces a multi-line display in the same format as the displayed cmdlet interrupt error; subsequent error records are also printed in red, but only print their error message on one line.
When outputting to the console, the lines usually appear first in the output array, followed by error records (at least from the stdout / stderr series of output lines at the same time), but, fortunately , when you write the output, it is correctly interleaved using the same the output order you get without 2>&1 ; in other words: when outputting to the console, the captured output does NOT reflect the order in which the stdout and stderr lines were generated by an external command.
If you capture all the output in one line using Out-String , PowerShell will add additional lines , since the string representation of the error record contains additional information, such as location ( At line:... ) and category ( + CategoryInfo ... ) ; Curiously, this only applies to the first error record.
- To work around this problem, apply the
.ToString() method to each output object, and not to the Out-String channel:
$cmdOutput = <command> 2>&1 | % { $_.ToString() } $cmdOutput = <command> 2>&1 | % { $_.ToString() } ;
in PS v3 + you can simplify:
$cmdOutput = <command> 2>&1 | % ToString
(As a bonus, if the output was not captured, it produces correctly interleaved output even when printing to the console.)
As an alternative, filter error records and send them to the PowerShell error stream using Write-Error (as a bonus, if the output was not captured, this will result in correctly alternating output when printing to the console):
$cmdOutput = <command> 2>&1 | ForEach-Object { if ($_ -is [System.Management.Automation.ErrorRecord]) { Write-Error $_ } else { $_ } }
mklement0 Mar 14 '16 at 6:15 2016-03-14 06:15
source share