How to return one and only one value from a PowerShell function?

前端 未结 10 845
暖寄归人
暖寄归人 2020-12-24 01:17

I\'ve learned from this Stack Overflow question, that PowerShell return semantics are different, let\'s say, from C#\'s return semantics. Quote from the aforementioned quest

相关标签:
10条回答
  • 2020-12-24 01:47

    Several answers already given do not fully answer your question because they do not account for other cmdlets you might call--as you point out--that might "pollute" your output. The answer from @Laezylion is essentially correct but I believe bears further elaboration.

    It is clear that you appreciate that your current workaround--forcing every function to return an array then taking the last element--is not a very robust solution. (In fact, I think it is safe to call that a kludge. :-) The correct approach--and a direct answer to your question--is clear... though at first glance it sounds like a tautology:

    Question: How do you ensure a function returns only one thing?
    Answer: By ensuring that it returns only one thing.
    

    Let me elucidate. There are really two kinds of functions/cmdlets in PowerShell: (A) those that return data and (B) those that do not return data but may instead report progress or diagnostic messages. Problems arise, as you have seen, when you try to mix the two. And this may easily happen inadvertently. Thus, it is your responsibility, as the function author, to understand each function/cmdlet call within your function: specifically, does it return anything, be it a true return value or just diagnostic output? You are expecting output from type A functions, but you need to be wary of any type B functions. For any one that does return something you must either assign it to a variable, feed it into a pipeline, or... make it go away. (There are several ways to make it go away: pipe it to Out-Null, cast it to void, redirect it to $null, or assign it to $null. See Jason Archer’s Stack Overflow post that evaluates the performance of each of these flavors, suggesting you shy away from Out-Null.)

    Yes, this approach takes more effort, but you get a more robust solution by doing so. For a bit more discussion on this very issue, these A/B functions, etc. see Question 1 on A Plethora of PowerShell Pitfalls recently published on Simple-Talk.com.

    0 讨论(0)
  • 2020-12-24 01:48

    The use of parenthesis seems critical when calling a function that accepts parameters. This example fills a DataTable from SQL Server, and returns an [int] from the first row, fourth column. Note the parenthesis around the actual function call assigned to the variable [int]$tt1

        function InvokeSQL-GetOneCount { param( [string]$cn, [string]$prj )
            $sql = "SELECT * FROM [dbo].[dummytable] WHERE ProjectNumber = '$prj' ORDER BY FormID, PartID;"
    
            $handler = [System.Data.SqlClient.SqlInfoMessageEventHandler] { param($sender, $event) Handle-Message -message $event.Message -fcolor "yellow" -bcolor "black"; };
            $conn = new-Object System.Data.SqlClient.SqlConnection($cn)
            $conn.add_InfoMessage($handler); 
            $conn.FireInfoMessageEventOnUserErrors = $true;
    
            $cmd = New-Object System.Data.SqlClient.SqlCommand;
            $cmd.Connection = $conn;
            $cmd.CommandType = [System.Data.CommandType]::Text;
            $cmd.CommandText = $sql;
            $cmd.CommandTimeout = 0;
    
            $sa = New-Object System.Data.SqlClient.SqlDataAdapter($cmd);
            $dt = New-Object System.Data.DataTable("AllCounts");
            $sa.Fill($dt) | Out-Null;
    
            [int]$rval = $dt.Rows[0][3];
    
            $conn.Close();
            return $rval;
        }
        clear-host;
        [int]$tt1 = (InvokeSQL-GetOneCount -cn "Server=[your server];DataBase=[your catalog];Integrated Security=SSPI" -prj "MS1904");
        write-host $tt1;
    
    0 讨论(0)
  • 2020-12-24 01:53

    You can also just assign everything to null, and then return just the variable you want:

    Function TestReturn {
    
        $Null = @(
            Write-Output "Hi there!"
            1 + 1
            $host
            $ReturnVar = 5
        )
        return $ReturnVar
    }
    
    0 讨论(0)
  • 2020-12-24 01:54

    Don't use echo to write information, use Write-Host, Write-Verbose or Write-Debug depending on the message.

    Echo is an alias for Write-Output which will send it as an Object through the pipeline. Write-Host/Verbose/Debug however is only console-messages.

    PS P:\> alias echo
    
    CommandType Name                 ModuleName
    ----------- ----                 ----------
    Alias       echo -> Write-Output               
    

    Sample:

    function test {
        Write-Host calc
        return 11
    }
    
    $t = test
    "Objects returned: $($t.count)"
    $t
    
    #Output
    calc
    Objects returned: 1
    11
    

    Also, if you return the value on the last line in your function, then you don't need to use return. Writing the Object/value by itself is enough.

    function test {
        Write-Host calc
        11
    }
    

    The difference is that return 11 would skip the lines after it you use it in the middle of a function.

    function test {
        return 11
        12
    }
    
    test
    
    #Output
    11
    
    0 讨论(0)
  • 2020-12-24 02:05

    You could replace echo (alias of Write-Output) with Write-Host:

    PS> function test{ Write-Host "foo";"bar"} 
    PS> $a = test                                    
    test                                          
    PS >$a                                         
    bar
    
    0 讨论(0)
  • 2020-12-24 02:05

    I ended up using the following to make sure only one value is returned:

    • write-host 'some console message'
    • invoke-some-utility arg1 arg2 | write-host
    • functionCall arg1 arg2 | out-null # suppress any output
    • return theDesiredValue
    0 讨论(0)
提交回复
热议问题