Launching a process with a different user identity invariably launches the process in a new window on Windows, which means that you cannot directly capture that process' output.
You have two options:
Use the System.Diagnostics.Process API directly, which allows you to capture the process' output in memory, as text, via the .RedirectStandardOutput (and .RedirectStandardError) properties of the System.Diagnostics.ProcessStartInfo class.
This approach is nontrivial, especially if you want to also capture stderr output without the risk of deadlocks; a stdout-output-only-capturing solution can be found in this answer.
It precludes running the process hidden, because the use of another user's credentials (.UserName and .PassWord properties) requires that .UseShellExecute be $false, which in turn means that the .WindowStyle property is ignored.
Use Start-Process if you want (the option) to run the process hidden, although that requires the use of a temporary file to capture the output:
Pitfalls: You must ensure that the target user has permission:
- to access the working directory of the newly launched process, which requires passing a suitable directory to
-WorkingDirectory
- to write to the (temporary) file path passed to
-RedirectStandardOutput / -RedirectStandardError.
Note that -RedirectStandardOutput / -RedirectStandardError capture the output from the named streams separately, and must be separate files. If you want to merge the streams and capture them interleaved in a single file, you must launch your process via a shell (such as PowerShell or cmd.exe) and use its stream-merging features, typically 2>&1.
The following Start-Process-based solution shows how to run the process hidden and capture stdout output (only):
# Prompt for the target user's credentials.
$cred = Get-Credential
# Determine the working directory and temporary file path.
# IMPORTANT: THE TARGET USER MUST HAVE PERMISSION TO
# * ACCESS the working directory
# * access and WRITE TO the temp file.
$workingDir = "$env:SystemRoot\Temp"
$tmpFile = Join-Path "$env:SystemRoot\Temp" "~$PID.tmp"
# Launch the process as the target user, hidden, save its stdout
# to the temporary file, and wait for it to terminate.
(Start-Process -WindowStyle Hidden -PassThru -WorkingDirectory $workingDir -RedirectStandardOutput $tmpFile -Credential $cred powershell.exe @'
-noprofile -command
"[array] (wsl -- ip -o -4 -json addr list eth0 | ConvertFrom-Json).addr_info.local -ne ''"
'@).WaitForExit()
# Get the captured output and remove the temp. file.
$output = Get-Content $tmpFile; Remove-Item $tmpFile
# Print the captured result
$output
Note:
The powershell.exe CLI call above uses a streamlined version of the command in your question.
While Start-Process has a dedicated -Wait switch to await the launched process' termination, as of PowerShell Core 7.2 it appears to be incompatible with -Credential, i.e. with running as a different user (resulting in an Access denied error while still launching the process, albeit asynchronously).
- The workaround is to use
-PassThru, in order to make the normally output-less Start-Process emit a System.Diagnostics.Process instance describing the launched process, and call .WaitForExit() on that instance.