函数在PowerShell中的返回值

我已经开发了一个PowerShell函数,它执行许多涉及提供SharePoint Team站点的操作。最终,我想函数返回的URL提供的网站作为字符串,所以在我的函数结束,我有以下代码:

$rs = $url.ToString();
return $rs;

调用这个函数的代码如下所示:

$returnURL = MyFunction -param 1 ...

我期待的是一个字符串,但它不是。相反,它是System.Management.Automation.PSMethod类型的对象。为什么它返回的是那个类型而不是String类型?

656907 次浏览

PowerShell有非常古怪的返回语义——至少从更传统的编程角度来看是这样。这里有两个值得你思考的观点:

  • 捕获并返回所有输出
  • return关键字实际上只是指示了一个逻辑退出点

因此,下面两个脚本块将有效地完成完全相同的事情:

$a = "Hello, World"
return $a

 

$a = "Hello, World"
$a
return

第二个示例中的$a变量被保留为管道上的输出,并且如前所述,将返回所有输出。事实上,在第二个示例中,您可以完全省略返回,并且您将得到相同的行为(返回将在函数自然完成和退出时隐含)。

没有更多的函数定义,我不能说为什么你得到一个PSMethod对象。我的猜测是,您可能有一些未被捕获的内容,它们被放置在输出管道中。

同样值得注意的是,可能不需要这些分号——除非你在一行中嵌套多个表达式。

你可以在TechNet的about_Return页面上阅读更多关于返回语义的信息,或者从PowerShell本身调用help return命令。

如果不查看代码,就很难说。确保函数不返回一个以上的对象,并且捕获其他调用产生的任何结果。你得到了什么:

@($returnURL).count

总之,我有两个建议:

将对象转换为字符串:

...
return [string]$rs

或者用双引号括起来,和上面一样,但是要短一点:

...
return "$rs"

PowerShell的这一部分可能是最愚蠢的方面。函数期间产生的任何无关输出都会污染结果。有时没有任何输出,然后在某些情况下,除了您计划的返回值之外,还会有其他一些计划外的输出。

因此,我从原始函数调用中删除赋值,因此输出最终出现在屏幕上,然后逐步执行,直到调试器窗口中弹出我没有计划的内容(使用PowerShell伊势)。

甚至像在外部作用域保留变量这样的事情也会导致输出,比如[boolean]$isEnabled,它会烦人地吐出一个False,除非你把它设置为[boolean]$isEnabled = $false

另一个很好的方法是$someCollection.Add("thing"),它吐出新的集合计数。

Luke对函数结果的描述在这些情况下似乎是正确的。我只想了解根本原因,PowerShell产品团队会对这种行为采取一些措施。这似乎很常见,并且花费了我太多的调试时间。

为了解决这个问题,我一直在使用全局变量,而不是返回和使用函数调用的值。

下面是另一个关于全局变量使用的问题: 从函数设置全局PowerShell变量,其中全局变量名是传递给该函数的变量 < / em >

作为一种变通方法,我一直在返回数组中的最后一个对象,你从函数中返回…这不是一个很好的解决方案,但总比什么都没有好:

someFunction {
$a = "hello"
"Function is running"
return $a
}


$b = someFunction
$b = $b[($b.count - 1)]  # Or
$b = $b[-1]              # Simpler

总而言之,写同一件事的一种更简洁的方式是:

$b = (someFunction $someParameter $andAnotherOne)[-1]

下面的函数简单地返回4作为答案。当你替换字符串的add表达式时,它会返回第一个字符串。

Function StartingMain {
$a = 1 + 3
$b = 2 + 5
$c = 3 + 7
Return $a
}


Function StartingEnd($b) {
Write-Host $b
}


StartingEnd(StartingMain)

这也可以用于数组。下面的例子将返回"Text 2"

Function StartingMain {
$a = ,@("Text 1","Text 2","Text 3")
Return $a
}


Function StartingEnd($b) {
Write-Host $b[1]
}


StartingEnd(StartingMain)

注意,必须调用函数本身下面的函数。否则,它第一次运行时将返回一个错误,它不知道“StartingMain”是什么。

我传递了一个简单的Hashtable对象和一个结果成员,以避免返回的疯狂,因为我也想输出到控制台。它通过引用传递起作用。

function sample-loop($returnObj) {
for($i = 0; $i -lt 10; $i++) {
Write-Host "loop counter: $i"
$returnObj.result++
}
}


function main-sample() {
$countObj = @{ result = 0 }
sample-loop -returnObj $countObj
Write-Host "_____________"
Write-Host "Total = " ($countObj.result)
}


main-sample

你可以在我的GitHub项目unpackTunes中看到实际的使用示例。

在PowerShell 5中,我们现在能够创建类。将函数更改为类,return将只有返回紧挨着它前面的对象。这里有一个简单的例子。

class test_class {
[int]return_what() {
Write-Output "Hello, World!"
return 808979
}
}
$tc = New-Object -TypeName test_class
$tc.return_what()

如果这是一个函数,期望输出将是

Hello World
808979

但是作为一个类,唯一返回的是整数808979。类有点像一个保证,它只返回声明的类型或void。

现有的答案是正确的,但有时你实际上并没有用Write-Outputreturn显式返回一些东西,但函数结果中有一些神秘的值。这可以是内置函数的输出,比如New-Item

PS C:\temp> function ContrivedFolderMakerFunction {
>>    $folderName = [DateTime]::Now.ToFileTime()
>>    $folderPath = Join-Path -Path . -ChildPath $folderName
>>    New-Item -Path $folderPath -ItemType Directory
>>    return $true
>> }
PS C:\temp> $result = ContrivedFolderMakerFunction
PS C:\temp> $result




Directory: C:\temp




Mode                LastWriteTime         Length Name
----                -------------         ------ ----
d-----         2/9/2020   4:32 PM                132257575335253136
True

所有创建目录的额外噪音都被收集并在输出中发出。减轻这种情况的简单方法是在New-Item语句的末尾添加| Out-Null,或者你可以将结果赋值给一个变量,而不使用该变量。它看起来是这样的……

PS C:\temp> function ContrivedFolderMakerFunction {
>>    $folderName = [DateTime]::Now.ToFileTime()
>>    $folderPath = Join-Path -Path . -ChildPath $folderName
>>    New-Item -Path $folderPath -ItemType Directory | Out-Null
>>    # -or-
>>    $throwaway = New-Item -Path $folderPath -ItemType Directory
>>    return $true
>> }
PS C:\temp> $result = ContrivedFolderMakerFunction
PS C:\temp> $result
True

New-Item可能是这些方法中更著名的,但其他方法包括所有StringBuilder.Append*()方法,以及SqlDataAdapter.Fill()方法。

您需要在返回之前清除输出。尝试使用Out-Null。这就是powershell return的工作方式。它返回的不是你想要的变量,而是整个函数的输出。你的例子是:

function Return-Url
{
param([string] $url)


. {
$rs = $url.ToString();
return
} | Out-Null
   

return $rs
}


$result = Return-Url -url "https://stackoverflow.com/questions/10286164/function-return-value-in-powershell"


Write-Host $result
Write-Host $result.GetType()

结果是:

https://stackoverflow.com/questions/10286164/function-return-value-in-powershell
System.String

感谢https://riptutorial.com/powershell/example/27037/how-to-work-with-functions-returns