【问题标题】:Clear captured output/return value in a Powershell function在 Powershell 函数中清除捕获的输出/返回值
【发布时间】:2014-07-03 08:31:41
【问题描述】:

有没有办法清除函数内部的返回值,这样我就可以保证返回值是我想要的?或者也许关闭函数的这种行为?

在这个例子中,我希望返回值是一个包含 ("Hello", "World") 的 ArrayList

function GetArray() 
{
    # $AutoOutputCapture = "Off" ?
    $myArray = New-Object System.Collections.ArrayList
    $myArray.Add("Hello")
    $myArray.Add("World")

    # Clear return value before returning exactly what I want?
    return $myArray
}

$x = GetArray
$x

但是,输出包含从添加操作中捕获的值。

0
1
Hello
World

我觉得 Powershell 的这个“特性”很烦人,因为它很容易通过调用另一个函数来破坏你的函数,而你不知道它返回了一个值。

更新

我了解有一些方法可以防止输出被捕获(如下面的答案之一所述),但这需要您知道函数实际上返回一个值。如果您正在调用另一个 Powershell 函数,将来可能有人更改此函数以返回一个值,这将破坏您的代码。

【问题讨论】:

  • 你是如何处理这个问题的。这是 powershell 的一个非常烦人的特性,不允许控制返回值。
  • 我只是在所有地方都使用了 [void]。我还决定用 C# 做复杂的事情更容易,然后使用 powershell 将它们粘合在一起。

标签: powershell


【解决方案1】:

我遇到了同样的问题。在 PS 中,函数将返回所有输出管道信息。 | Out-Null 函数中的其余代码变得棘手。 我通过将返回变量作为参考参数 [ref] 来解决这个问题。这始终有效。检查下面的示例代码。 注意:一些语法对于避免错误很重要。例如参数必须在括号中传递([ref]$result)

function DoSomethingWithFile( [ref]$result, [string]$file )
{
    # Other code writing to output
    # ....

    # Initialize result
    if (Test-Path $file){
        $result.value = $true
    } else {
        $result.value = $false
    }
}
$result = $null
DoSomethingWithFile ([ref]$result) "C:\test.txt" 

【讨论】:

  • 我认为这是任何阅读代码的人最清楚的解决方案。它还避免了重定向使您的代码混乱(例如| Out-Null
  • 希望有更好的方法……但这最像“编程”。不幸的是,我必须使用 Write-Output 才能显示日志...
【解决方案2】:

使用来自 user1654962 的信息,这是我解决此 PowerShell 问题的方法。因为,如果有输出信息,PowerShell 会将其作为数组返回,我决定确保函数输出始终是数组。然后调用行可以使用 [-1] 获取数组的最后一个元素,我们会得到一个一致的返回值。

function DoSomething()
{
  # Code that could create output
  Write-Output "Random output that we don't need to return"
  Write-Output "More random output"

  # Create the return value. It can be a string, object, etc.
  $MyReturnString = "ImportantValue"

  # Other code

  # Make sure the return value is an array by preceding it with a comma
  return ,$MyReturnString
}

$CleanReturnValue = ( DoSomething() )[-1]

【讨论】:

    【解决方案3】:

    管道输出到Out-Null,将输出重定向到$null,或者在函数调用前加上[void]

    $myArray.Add("Hello") | Out-Null
    

    $myArray.Add("Hello") >$null
    

    [void]$myArray.Add("Hello")
    

    【讨论】:

    • 是的,我知道这一点,但这意味着我必须将每个函数调用的输出传递给 null 以保证我的输出没有损坏,这是一个巨大的痛苦。如果我忘记这样做,并且代码可以工作,那么将来可能有人更改了 Powershell 函数并破坏了另一个函数。
    • 看来这个问题的答案是没有办法解决这个问题,除了让每个函数调用都作废,这很烦人。
    • 不幸的是,这适用于 Write-Output,除了没有输出输出。 Runbooks 不会将门户日志写入除 Write-Output 之外的任何内容,所以我很烦。
    【解决方案4】:

    我也有同样的挫败感!我有一个函数,变量应该向上计数 $<variablename>++

    除了。我在一次迭代中忘记了最后的“++”。这导致变量的值被发送到输出缓冲区。找到它是非常痛苦和耗时的! MS 至少应该提供在用户分配所需返回值之前刷新输出缓冲区的能力。无论如何...我相信我有办法解决。

    由于我在函数末尾分配了一个返回值,我想要的值将始终是输出缓冲区数组的最后一个条目。所以我改变了调用函数的方式:

    If (FunctionName (parameters)) {}
    

    收件人:

    If ((FunctionName (parameters))[-1]) {}
    

    当我试图捕获函数 $False 返回时,我的特殊情况让我很不爽。由于我上面的错字,我的 IF 语句认为它是真的,因为输出中有垃圾,即使我的最后一个函数输出是“Return $False”。该函数分配的最后一个输出是 $False 值,因为错误导致计算错误。 所以将我的函数返回评估更改为:

    If (!((FunctionName (parameters))[-1])) {#something went wrong!}
    

    让我只计算输出数组的最后一个元素,从而达到了目的。我希望这对其他人有所帮助。

    【讨论】:

    • 如果您期望单个返回值,这是一个不错的技巧。我会记住这一点。
    • 请注意,当您有一个作为哈希表的单个返回值时,这不起作用 - 您会尝试对其进行索引。解决方案:在函数调用前加上array,如[array](FunctionName(parameters)),以强制结果为返回值数组。然后,这将在预期索引处包含您的哈希表。
    【解决方案5】:

    只是想发布这个以防万一。我有多个要调用的函数。每个函数都返回 0 或 1。我用它来查看是否一切正常。

    所以基本上...

    function Funct1
    {
       # Do some things
       return 1
    }
    
    $myResult += Funct1
    $myResult += Funct2
    $myResult += Funct3
    if ($myResult -eq 3) { "All is good" }
    

    一切都很顺利,直到我添加了一个包含一些 Copy-Item 和此类命令的函数。

    长话短说,一两个小时我再也回不来了,我发现这个该死的管道问题也有同样的问题。无论如何,在这样的网站的帮助下,我找到了确保您获得“退货”的最干净的方法。

    $myResult += Funct1 -split " " | Select-Object -Last 1
    $myResult += Funct2 -split " " | Select-Object -Last 1
    $myResult += Funct3 -split " " | Select-Object -Last 1
    

    【讨论】:

      【解决方案6】:

      这是一个让我在使用更大的功能时遇到一些麻烦的问题。

      人们可以将第一个答案“管道输出到 Out-Null”更进一步。我们在函数中获取代码并将其嵌入到脚本块中,然后我们将其输出通过管道传输到 Out-Null。

      现在我们不需要遍历函数中的所有代码......就像这样:

      function GetArray() 
      {
          .{
              # $AutoOutputCapture = "Off" ?
              $myArray = New-Object System.Collections.ArrayList
              $myArray.Add("Hello")
              $myArray.Add("World")
      
          } | Out-Null
      
          # Clear return value before returning exactly what I want?
          return $myArray
      }
      
      $x = GetArray
      $x
      

      【讨论】:

        【解决方案7】:

        为什么不使用 Powershell Array 对象,而不是 .Net arrayList ?

        你可以这样做:

        function GetArray() {
          # set $myArray as a powershell array   
          $myArray = @()
          $myArray+="Hello"
          $myArray+="World"
          # $myArray=@("Hello", "World") would work as well
        
          return $myArray
        }
        

        这将返回一个“干净”的数组,正如预期的那样。

        如果你真的需要一个 System.collections.ArrayList,你可以分两步完成:

        • 如上所述创建一个 powershell 数组
        • 以这种方式在 .Net arrayList 中转换你的 powershell 数组:

          # Get the powershellArray 
          $x = getArray
          # Create a .Net ArrayList
          $myArrayList = New-Object System.Collections.ArrayList
          # Fill your arraylist with the powershell array
          $myArrayList.AddRange($x)
          

        希望这会有所帮助。

        【讨论】:

        • 问题中的代码只是不良行为的一个例子。一般来说,我问的是如何处理这种情况。
        【解决方案8】:

        将变量范围设置为脚本或全局。

        function Get-Greeting {
            'Hello Everyone'
            $greeting = 'Hello World'
            'Ladies and Gentlemen'
            $script:greeting = $greeting
        }
        
        Get-Greeting
        $greeting <== 'Hello World'
        

        【讨论】:

          猜你喜欢
          • 2013-01-21
          • 2021-11-16
          • 2011-10-15
          • 2018-12-13
          • 2010-10-29
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多