From a powershell script (with nuget
installed and on the path), I'm trying to execute an executable (.net, if that matters) ... but for some reason, I can't get the STDOUT to display in the command window.
nuget install mdoc -OutputDirectory packages -ExcludeVersion
start-process "packages/mdoc/tools/mdoc.exe" "--version"
echo "done"
This should output mdoc 5.7.2
(at the time of this post, current version). But you'll see the nuget output, then done
.
Any thoughts on why this is not showing up?
As Ansgar's comment implies: On Windows, Start-Process
runs console programs in a new console window by default, asynchronously.
If that program completes quickly, you may see the new console window flash only briefly, as it opens and closes soon thereafter, or you may miss the flash altogether - either way, its output will not show in the caller's console window.
Adding -Wait
to the Start-Process
call would make the invocation synchronous, and adding -NoNewWindow
would make it run in the same console, yet the calling PowerShell session wouldn't be able to capture or redirect the invoked program's output - see below.
Taking a step back: Do NOT use Start-Process
[1] if you want to run a console program synchronously, with its standard streams connected to PowerShell's streams - just invoke such a program directly:
packages/mdoc/tools/mdoc.exe --version
If the external program's path / name must be quoted (because its path contains spaces) and/or it is stored in a variable, simply use &
, the call operator, to invoke it:
# Via a quoted string:
& "packages/mdoc/tools/mdoc.exe" --version
# Via a variable:
$exePath = "packages/mdoc/tools/mdoc.exe"
& $exePath --version
Using the direct-invocation approach gives you:
$LASTEXITCODE
variable.To put it all together (based on your later comments):
nuget install mdoc -OutputDirectory packages -ExcludeVersion
$exePath = "packages/mdoc/tools/mdoc.exe"
& $exePath --version
"done"
This prints the version number - mdoc 5.7.2
as of this writing - just before printing done
(verified on Windows PowerShell v5.1.17134.48 on Microsoft Windows 10 Pro (64-bit; Version 1709, OS Build: 16299.371)).
Optional reading: capturing stdout / stderr output from external programs:
To capture stdout output, simply assign the call to a variable:
$version = & $exePath --version # $version receives stdout output as an *array of lines*
$version
receives either a string scalar (single string) if there was only 1 line of output, or an array of strings representing the output lines.
To also capture stderr output, use redirection 2>&1
:
[string[]] $allOutput = & $exePath --version 2>&1
Note the cast to [string[]]
, which ensures that the stderr lines are captured as strings too.
By default, they are captured as [System.Management.Automation.ErrorRecord]
instances, which in Windows PowerShell will somewhat confusingly print them as if they were PowerShell errors - this problem has been fixed in PowerShell Core.
Conversely, however, if you don't convert the type of the elements of the array that is returned to strings, you can examine each element with -is [System.Management.Automation.ErrorRecord]
to determine whether it originated from stdout or stderr.
2>&1
, so that they can be saved to separate files (which with >
in Windows PowerShell requires explicitly stringifying the [System.Management.Automation.ErrorRecord]
instances).Note: When PowerShell communicates with external programs, character-encoding issues come into play: see this answer for details.
[1] Or the underlying .NET API, System.Diagnostics.Process
.
For guidance on when Start-Process
is or isn't appropriate, see GitHub docs issue #6239
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With