none
Write-output inside a function

    Question

  • Hello,

    I am trying to achieve something that I wonder how I can do.

    Here is a sample of code:

    function test{
    $t=$true
    Write-Output "test"
    return $t
    }
    
    function main{
    $e=test 
    Write-Output "Main $e" 
    }
    
    main

    So I would expect to have on my output:

    test

    Main true

    Because the test function is first executed, so it should write on the ouput (i.e. the ps console) the string test, then write "Main" and the return of my test function.

    Instead I have

    Main test true

    This is because I think that the output of the function named test is redirected in the variable $e

    I don't want to use Write-Host in the test function because I want the end-user of my script to be able to redirect the full output of the script in a file using a >

    Do you have an idea on how I could achieve that?

    Thanks,

    Sevan

    Thursday, November 20, 2014 3:56 PM

Answers

  • Make sense, real option would be to add a parameter to the script (like -outputfile) rather than let the user redirect the output through >
    • Marked as answer by Sevan Thursday, November 27, 2014 9:00 AM
    Wednesday, November 26, 2014 5:10 PM

All replies

  • Hi Sevan,

    when returning from a function, powershell will return all objects in the output queue in the order they were added to it. This includes:

    • All output from a single command row that wasn't stored in a variable or nulled.
    • All output written by Write-Output
    • All objects behind the return statement (last object in queue)

    This is why in your example "test" is written before "true".
    Your main function collects all output from test ("test" and $true) and writes it to the output stream as part of a string. Which is how you get the results you're getting.

    If you want to affect the order output is outputted from main, you have to handle the output from test, not just pass it along.

    Cheers,
    Fred

    Ps.: Here an example that will return what you expected:

    function test
    {
    	$t = $true
    	$props = @{
    		Name = "Test"
    		Value = $t
    	}
    	return (New-Object PSObject -Property $props)
    }
    
    function main
    {
    	$e = test
    	$output = @()
    	$output += $e.Name
    	$output += "Main " + $e.Value
    	return $output
    }
    
    main


    There's no place like 127.0.0.1

    Thursday, November 20, 2014 4:24 PM
  • function test{
    $t=$true
    Write-Output "test"
    Return $t
    }
    
    function main{
    $e=test 
    Write-Output "Main $e" 
    }
    
    Function Piped
    {
        Param([Parameter(ValueFromPipeline=$true)]
              [Object]$Object
        )
        Process 
        { 
            Write-output "Piped $Object"
        }
     }
    
    main
    Test | Piped

    Gives this

    Main test True
    Piped test
    Piped True


    Thursday, November 20, 2014 7:09 PM
  • Write-Output inside of a function does not write to the host screen.  It just contributes to the output of the function:  Try this instead:

    function test{
    $t=$true
    Write-Output "test"
    return $t
    }
    
    function main{
    $e=test 
    Write-Output "$($e[0])`nMain $($e[1])" 
    }
    
    main
    

    Thursday, November 20, 2014 9:21 PM
  • Write-Output inside of a function does not write to the host screen.  It just contributes to the output of the function:  Try this instead:

    function test{
    $t=$true
    Write-Output "test"
    return $t
    }
    
    function main{
    $e=test 
    Write-Output "$($e[0])`nMain $($e[1])" 
    }
    
    main

    Contrary:  Write-Output anywhere always writes to teh current pipeline.  If there is no assignment it displlayss on the screen.

    So you are right - almost - it only writes to the screen when there is no assignment.

    function main{
         $e='test' 
         Write-Output $e
    }
    
    # output to file
    main > test.txt
    
    # receive to variable
    $x=main
    
    # default to screen
    main
    
    #these functions are equivalent.
    
    function main{
         $e='test' 
         $e
    }
    function main{
         $e='test' 
         return $e
    }
    function main{
      'test'
    }


    ¯\_(ツ)_/¯


    Friday, November 21, 2014 1:58 AM
    Moderator
  • Hello,

    Thank you all for your answers,

    Is it possible to flush the current pipeline to have something like:

    function test{
    $t=$true
    Write-Output "test"
    #Flush current pipeline so it will display "test" on the screen
    return $t
    }
    
    function main{
    $e=test 
    Write-Output "Main $e" 
    }
    
    main

    Thanks,

    Monday, November 24, 2014 1:51 PM
  • To understand how this works try this function alone

    function NewTest{
         $t=$true
        Write-Output "test"
        sleep 10
        #Flush current pipeline so it will display "test" on the screen
        return $t
    }

    NewTest


    ¯\_(ツ)_/¯

    Monday, November 24, 2014 2:35 PM
    Moderator
  • To understand how this works try this function alone

    function NewTest{
         $t=$true
        Write-Output "test"
        sleep 10
        #Flush current pipeline so it will display "test" on the screen
        return $t
    }

    NewTest


    ¯\_(ツ)_/¯

    And also execute it as

    $t = NewTest; $t

    and note the difference.



    • Edited by Larry Weiss Monday, November 24, 2014 4:05 PM
    Monday, November 24, 2014 4:03 PM
  • Hello,

    Thanks for your reply, I am not really sure about what you want to make me understand here, the question was more if it's possible to flush the current pipeline to standard output of the script, instead of flashing it in the "return" of the function?

    What is not what I expected, it's that I was expecting to use Write-Ouput to write in the output of the script and not the output of the function where it's called.

    Is there a way to do that (Write-Host would do that more or less, but in that case I won't be able to redirect the script's output to a file for example)?

    Thanks

    Monday, November 24, 2014 4:35 PM
  • Hello,

    Thanks for your reply, I am not really sure about what you want to make me understand here, the question was more if it's possible to flush the current pipeline to standard output of the script, instead of flashing it in the "return" of the function?

    What is not what I expected, it's that I was expecting to use Write-Ouput to write in the output of the script and not the output of the function where it's called.

    Is there a way to do that (Write-Host would do that more or less, but in that case I won't be able to redirect the script's output to a file for example)?

    Thanks

    If you want dual output use tee-object.  WHat you are asking is not really sennsible.  YOU can do direct output:

    'Some message' | Out-File myfile.txt -Append


    ¯\_(ツ)_/¯

    Monday, November 24, 2014 4:54 PM
    Moderator
  • I guess I can decide wether I should make my script write in a file or not, but my purpose here is to let the end-user of the script be able to choose wether he wants the output displayed on his screen or on a file (using the >).

    It seems that it is not really possible that way, and I need to have only one function using the write-output function, not various.

    Is that right?

    Thanks,

    Sevan

    Wednesday, November 26, 2014 10:07 AM
  • I guess I can decide wether I should make my script write in a file or not, but my purpose here is to let the end-user of the script be able to choose wether he wants the output displayed on his screen or on a file (using the >).

    It seems that it is not really possible that way, and I need to have only one function using the write-output function, not various.

    Is that right?

    Thanks,

    Sevan

    Typically, you want to write functions to output to the pipeline.  This makes the function re-usable and lets you save the output to variable or pipe it directly into other cmdlets or functions for further processing.

    If you want a script that lets the user choose console or file output, then write the script to let the user choose that via a parameter or prompt.  The script should run the function (which outputs to the pipeline) and use that output as input to Write-Host if the user wants console output, or to Out-File, Set-Content, or Add-Content if they want to save it to a file, or possible both using Tee-Object based on what the user chose for output.

     

    [string](0..33|%{[char][int](46+("686552495351636652556262185355647068516270555358646562655775 0645570").substring(($_*2),2))})-replace " "


    • Edited by mjolinor Wednesday, November 26, 2014 5:20 PM
    Wednesday, November 26, 2014 12:41 PM
  • Make sense, real option would be to add a parameter to the script (like -outputfile) rather than let the user redirect the output through >
    • Marked as answer by Sevan Thursday, November 27, 2014 9:00 AM
    Wednesday, November 26, 2014 5:10 PM
  • I know this is an old post, but here is another solution just in case anyone else is interested.  since the returned value is an array you can always rely on the [-1] to get the last result from the array. This even works for non-array objects. See the example below. 

    function test{
    $t=$true
    Write-Output "test"
    return $t
    }
    
    function main{
    $e=test 
    Write-Output "Main $($e[-1])" 
    }
    
    main

    Friday, November 10, 2017 11:55 PM