清除Powershell函数中捕获的输出/返回值



是否有一种方法可以清除函数内部的返回值,以便我可以保证返回值是我想要的?或者关闭函数的这种行为?

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

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

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

0
1
Hello
World

我发现Powershell的这个"特性"非常烦人,因为它使你很容易通过调用另一个你不知道返回值的函数来破坏你的函数。

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

我遇到了同样的问题。在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,将输出重定向到$null,或在函数调用前加上[void]:

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

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

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

使用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]

我也有同样的沮丧!我有一个函数,其中变量应该计数$ <variablename>++

除外。在一次迭代中,我忘记了末尾的"++"。这导致变量的值被发送到输出缓冲区。这是非常恼人和耗时的寻找!MS至少应该提供在用户分配期望的返回值之前刷新输出缓冲区的能力。Anywhew……我想我有一个解决办法。

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

If (FunctionName (parameters)) {}

:

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

当我试图捕获函数$False返回时,我的特定场景咬了我。由于我上面的打字错误,由于输出中的垃圾,我的IF语句将其视为true,即使我的最后一个函数输出是"Return $False"。该函数分配的最后一个输出是$False值,这是由于输入错误导致的错误计算所导致的问题。所以改变我的函数返回值为:

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

通过允许我只计算输出数组的最后一个元素实现了这一功能。我希望这对其他人有所帮助。

这是一个给我带来一些麻烦的大函数。

可以将第一个答案"Pipe输出为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

只是想张贴这个,以防它有帮助。我调用了多个函数。每个函数返回一个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

为什么不使用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
}

这将返回一个"clean"数组,如预期的那样。

如果你真的需要一个System.collections. .数组列表,你可以分两步完成

  • 创建一个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)
    

希望这能有所帮助。

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

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

有一种方法来从一个方法返回一个100%干净的对象,你不必做任何空赋值或输出任何东西(即Write-Information)!唯一的问题是必须定义一个类。在PowerShell 5.0中,他们引入了正式的类。如果你想静态调用多个方法,而不必创建类的实例,那么你可以使用static关键字静态调用这些方法,并将它们包装在"UtilityMethods"类;否则,创建类实例就有意义了。

这是一个定义了静态方法以及如何调用它的类。

class UtilityMethods {
        static [HashSet[int]] GetCleanHashSet(){
        $hs = New-Object System.Collections.Generic.HashSet[int];
        $null = $hs.Add(1);
        $null = $hs.Add(2);
        #Here is some code doing something completely unrelated to $hs. 
        #Notice how the return object and output are unnaffected by this and I don't need to do null assignments or Write-Information or anything like that.
        $hs2 = New-Object System.Collections.Generic.HashSet[int];
        $hs2.Add(99);
        return $hs; #This will return a clean HashSet, as you would expect.
    }
}
$cleanHS = [UtilityMethods]::GetCleanHashSet();
Write-Host "cleanHS = $cleanHS" #output: cleanHS = 1 2

您还可以在方法中添加任何您想要输出到控制台或日志记录的内容,它不会影响返回对象。对我来说,在大多数情况下,这是编写函数的最佳解决方案,它将返回您所期望的结果,而不会出现垃圾管道。如果你选择使用null赋值,那么你将不得不在函数的管道输出的每一行代码上都这样做,即使它与你要返回的对象完全无关。

最新更新