21

In doing some Powershell automation, I'm having trouble with the way that data written to stdout by a .cmd file is automatically captured. I have two functions that do something like the following:

function a {
    & external.cmd # prints "foo"
    return "bar"
}

function b {
    $val = a
    echo $val # prints "foobar", rather than just "bar"
}

Basically, data that external.cmd sends to stdout is added to the return value of a, even though all I really want to return from a is the string that I specified. How can I prevent this?

JSBձոգչ
  • 40,684
  • 18
  • 101
  • 169

3 Answers3

24

Here are a few different approaches for handling this:

  • capture the output of the .cmd script:

      $output = & external.cmd # saves foo to $output so it isn't returned from the function
    
  • redirect the output to null (throw it away)

      & external.cmd | Out-Null # throws stdout away
    
  • redirect it to a file

      & external.cmd | Out-File filename.txt
    
  • ignore it in the caller by skipping it in the array of objects that's returned from the function

      $val = a
      echo $val[1] #prints second object returned from function a (foo is object 1... $val[0])
    

In PowerShell, any output value your code does not capture, is returning the "caller" object (including stdout, stderr, etc). So you have to capture or pipe it to something that doesn't return a value, or you'll end up with the object[] itself as your return value from the function.

The return keyword is really just for clarity, with the exact same effect as just writing the variable alone (as shown), but with an immediate exit of a script block in PowerShell. Something like this would even work (not verbatim but just to give you the idea):

function foo()
{
    "a"
    "b"
    "c"
}

PS> $bar = foo
PS> $bar.gettype()
System.Object[]
PS> $bar
a
b
c

function foobar()
{
    "a"
    return "b"
    "c"
}

PS> $myVar = foobar
PS> $myVar
a
b
not2qubit
  • 14,531
  • 8
  • 95
  • 135
Robert S Ciaccio
  • 2,675
  • 1
  • 19
  • 21
17

I generally prefer to use one of the following two techniques which, in my opinion, make the code more readable:

  • Cast an expression to void in order to suppress the return value:

    [void] (expression)

  • Assign the output value to the $null variable:

    $null = expression

For example:

function foo
{
    # do some work
    return "success"
}

function bar
{
    [void] (foo)  # no output
    $null = foo   # no output
    return "bar"
}

bar # outputs bar
Community
  • 1
  • 1
Adrian Theodorescu
  • 11,664
  • 2
  • 23
  • 30
7

If you want the output from the command to still print to the powershell command line, you can do a variant of the accepted answer:

& external.cmd | Out-Host
nickwesselman
  • 6,845
  • 2
  • 27
  • 46