How can I display output in a variable from an external process in Powershell?

I want to start an external process and output its command output to a variable in Powershell. I am currently using this:

$params = "/verify $pc /domain:hosp.uhhg.org" start-process "netdom.exe" $params -WindowStyle Hidden -Wait 

I confirmed that the command is executing, but I need to write the output to a variable. This means that I cannot use -RedirectOutput because it is only a redirect to the file.

+138
process powershell
Nov 11 '11 at 16:59
source share
8 answers

You tried:

$OutputVariable = (Shell command) | Out-String

+137
Nov 11 '11 at 17:11
source share
β€” -

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> # captures the command success stream / stdout 

To capture the output in a variable and print on the screen :

 <command> | Tee-Object -Variable cmdOutput # Note how the var. name is NOT $-prefixed 

To capture the output from multiple commands , use either a subexpression ( $(...) ) or a call ( & or . ) To the script block ( { ... } ):

 $cmdOutput = $(<command>; ...) # subexpression $cmdOutput = & {<command>; ...} # or: script block with &; creates child scope for vars. $cmdOutput = . {<command>; ...} # or: script block with .; no child scope 

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 # redirect error stream (2) to success stream (1) 

However, for external teams, it is more likely that the work will work as follows:

 $cmdOutput = cmd /c <command> '2>&1' # Let cmd.exe handle redirection - see below. 

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 { $_ } } 
+133
Mar 14 '16 at 6:15
source share

If you also want to redirect the error output, follow these steps:

 $cmdOutput = command 2>&1 

or if there are spaces in the program name:

 $cmdOutput = & "command with spaces" 2>&1 
+21
Nov 18 '11 at 16:49
source share

Or try this one. It will output the output to the $ scriptOutput variable:

 & "netdom.exe" $params | Tee-Object -Variable scriptOutput | Out-Null $scriptOutput 
+11
Mar 07 '13 at 8:24
source share

Another real life example:

 $result = & "$env:cust_tls_store\Tools\WDK\x64\devcon.exe" enable $strHwid 2>&1 | Out-String 

Note that this example includes a path (which starts with an environment variable). Note that quotation marks must surround the path and exe , but not the parameters!

Note: Do not forget the character before the command, but outside the quotation marks.

Error output is also output.

It took me a while to get this combination to work, so although I would share it.

+10
Sep 01 '14 at 12:33
source share

I tried the answers, but in my case I did not get the original result. Instead, it was converted to a Powershell exception.

The original result that I got:

 $rawOutput = (cmd /c <command> 2`>`&1) 
+5
Nov 06 '15 at 10:54
source share

If all you are trying to do is capture output from a command, then this will work well. I use it to change the system time, since [timezoneinfo]::local always produces the same information, even after making changes to the system. This is the only way to check and record the change in the time zone:

 $NewTime = (powershell.exe -command [timezoneinfo]::local) $NewTime | Tee-Object -FilePath $strLFpath\$strLFName -Append 

means I need to open a new powershell session to reload system variables

0
Jul 28 '16 at 19:45
source share

I am trying to execute git commands (and write the output to variables) in a powershell script using the information in this thread. I can very easily execute commands simply by using:

 # Make sure we're in the correct folder cd myGitRepo # Fetch sha1 of a specific commit into a Powershell variable - works fine without variable assignment git log --grep='My specific commit message here' --format=%H # This does not work, git reports 'not a git repository' $myVar = git log.... # git fatal: not a git repo 

It looks like the variable assignment function somehow ignores the current path and forces the command to execute in the root folder (which is not a git repo). Does anyone know why this is happening, and how can I fix it?

Update 2 : cd is an alias for Set-Location, so I should get something completely wrong.

Update . Oddly enough, by doing Set-Location (instead of cd), myGitRepo seems to fix the problem, i.e. this works:

 Set-Location '.\myGitRepo' $myVar = git log ..... 
0
Dec 01 '16 at 9:02
source share



All Articles