PowerShell中的函数返回值

时间:2012-04-23 18:28:39

标签: powershell

我开发了一个PowerShell函数,它执行了许多涉及配置SharePoint团队网站的操作。最终,我希望函数将配置站点的URL作为String返回,所以在我的函数结束时,我有以下代码:

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

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

$returnURL = MyFunction -param 1 ...

所以我期待一个String,但事实并非如此。相反,它是System.Management.Automation.PSMethod类型的对象。为什么它返回该类型而不是String类型?

10 个答案:

答案 0 :(得分:237)

PowerShell具有非常古怪的返回语义 - 至少从更传统的编程角度来看。有两个主要想法可以解决这个问题:

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

因此,以下两个脚本块将完全相同:

$a = "Hello, World"
return $a

$a = "Hello, World"
$a
return

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

如果没有更多的函数定义,我不能说你为什么要获得PSMethod对象。我的猜测是你可能有几行没有被捕获并被放置在输出管道上。

值得注意的是,可能不需要那些分号 - 除非您在一行上嵌套多个表达式。

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

答案 1 :(得分:41)

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

所以,我所做的是从原始函数调用中删除赋值,以便输出最终显示在屏幕上,然后逐步执行直到我不打算在调试器窗口中弹出的内容(使用PS ISE)

即使在外部作用域中保留变量之类的东西也会导致输出,比如[boolean]$isEnabled会导致输出False,除非你将它[boolean]$isEnabled = $false。{/ p>

另一个好的是$someCollection.Add("thing"),它会吐出新的收集计数。

答案 2 :(得分:30)

使用PowerShell 5,我们现在可以创建类。将函数更改为类不仅可以键入它,而且只返回它之前的对象。这是一个非常简单的例子。

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

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

Hello World
808979

但是作为一个类,唯一返回的是INT 808979.一个类就像保证它只返回声明的类型或void。

答案 3 :(得分:22)

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

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

$b = someFunction
$b = $b[($b.count - 1)]  # or 
$b = $b[-1]              # simpler

答案 4 :(得分:5)

我使用单个结果成员传递一个简单的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 project unpackTunes

中查看真实的示例用法

答案 5 :(得分:4)

如果不看代码,很难说。确保您的函数不会返回多个对象,并且您可以捕获从其他调用中获得的任何结果。你得到了什么:

@($returnURL).count

无论如何,有两点建议:

将对象转换为字符串:

...
return [string]$rs

或者只是用双引号将其括起来,与上面相同但是更短以输入:

...
return "$rs"

答案 6 :(得分:4)

卢克对这些情景中的功能结果的描述似乎正确。只希望了解根本原因并且PowerShell产品团队会对这种行为采取一些措施,这似乎很常见并且调试时间太长。

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

这是使用全局变量的另一个主题: Setting a global PowerShell variable from a function where the global variable name is a variable passed to the function

答案 7 :(得分:4)

现有答案是正确的,但是有时您实际上并没有使用df <- data.frame(number = c(1, 2), textEmoji = c("Test ?", "Test ?")) write.csv(df, file="df.csv", row.names = FALSE, fileEncoding = "UTF-8") Write-Output显式返回某些内容,但是函数结果中仍有一些神秘之处。这可能是诸如return

之类的内置函数的输出
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 语句的末尾添加| Out-Null,或者可以将结果分配给变量,而不必使用该变量。看起来像这样...

New-Item

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*()方法。

答案 8 :(得分:3)

以下简单地返回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”是什么。

我希望它有所帮助。

答案 9 :(得分:0)

作为return的替代方案,我建议使用Write-Output

Write-Output可以从管道中获取输入,然后将其转发到管道中,或者将其打印到控制台(如果这是最后一条命令)。

但是,Write-Output不会像return那样结束脚本,如果应该在循环中使用,转发输出等,这可能是一个优势。