【问题标题】:Unable to modify function argument in Powershell无法在 Powershell 中修改函数参数
【发布时间】:2011-11-10 14:16:49
【问题描述】:

我有一个类似这样的功能:

function A-Function{
  [CmdletBinding(SupportsShouldProcess=$True)]
param (
    [Parameter(Position=0, HelpMessage="A Test string", Mandatory=$true)]
    [string]$Path,

    [Parameter(Position=1, HelpMessage="The list of file names to download.", ValueFromPipeline=$True)]
    [string[]]$testVar,

    [Parameter(HelpMessage= "The username")]
    [string]$User,

    [Parameter(HelpMessage= "The password")]
    [string]$Password,

    [Parameter(HelpMessage= "The credentials used.")]
    [Net.NetworkCredential]$Credential = (New-Object Net.NetworkCredential("Anonymous", ""))
)

Begin {         
    $Path = "TEST_" + $Path

    if ($User) {
        if ($Password) {
            $Credential = New-Object Net.NetworkCredential($User, $Password)
        }
    }
}

Process {
    $Path
    $Credential
}

End {

}

}

如果我运行“A-Function test -User test -Password -test”,我会得到输出:

TEST_test

用户名密码 SecurePassword 域
-------- -------- -------------- ------
测试测试 System.Security.SecureString

这是我预期的输出。但是,如果我改为运行此命令:

“测试”| A-功能测试-用户测试-密码-测试

我得到了这个输出:

TEST_test

用户名密码 SecurePassword 域
-------- -------- -------------- ------
匿名 System.Security.SecureString

换句话说,在第二种情况下,它没有改变 Begin 部分中的 Credential 参数的值,但在第一种情况下,它改变了。我不明白这是为什么,有人可以解释一下吗?

问候

【问题讨论】:

    标签: function powershell arguments


    【解决方案1】:

    如果你做一个

    trace-command parameterbinding {"Test" | A-Function test -User test -Password test} -pshost
    

    您将看到 $credential,因为它没有作为参数传递给函数,所以每次在 process 期间它都与默认值绑定。另一方面,Path 只绑定一次,因为您将它传递给函数,因此您在 begin 中所做的更改在进程中可用。

    这绝对是一个错误/不是真正优化的东西,因为这没有在 Powershell v3 中重现。在 v3 中,您将获得所需的凭证输出,即测试而不是匿名。

    当然,您现在可以通过在 begin 中使用局部变量或使用 $script:Path 等限定现有变量来解决此问题:

    function A-Function{
      [CmdletBinding(SupportsShouldProcess=$True)]
    param (
        [Parameter(Position=0, HelpMessage="A Test string", Mandatory=$true)]
        [string]$Path,
    
        [Parameter(Position=1, HelpMessage="The list of file names to download.", ValueFromPipeline=$True)]
        [string[]]$testVar,
    
        [Parameter(HelpMessage= "The username")]
        [string]$User,
    
        [Parameter(HelpMessage= "The password")]
        [string]$Password,
    
        [Parameter(HelpMessage= "The credentials used.")]
        [Net.NetworkCredential]$Credential = (New-Object Net.NetworkCredential("Anonymous", ""))
    )
    
    Begin {         
        $script:Path = "TEST_" + $Path
    
        if ($User) {
            if ($Password) {
                $script:Credential = New-Object Net.NetworkCredential($User, $Password)
            }
        }
    }
    
    Process {
        $script:Path
        $script:Credential
    }
    
    End {
    
    }
    }
    
    "Test" | A-Function test -User test -Password test
    

    【讨论】:

      【解决方案2】:

      是的,我被这个咬过。函数参数在 Process 块的每次迭代中都会被重置。只需在 Begin 块中设置一个局部变量,然后在 Process 块中使用该局部变量,而不是使用参数变量。

      编辑:

      我必须承认,我并没有仔细查看您的示例代码,因为我立即从您的问题标题和您在 Begin 块中设置 $Path 的事实的组合中发现了一个问题。更加努力地查看您的函数,让我想知道为什么您在不处理任何管道输入时会有一个 Process 块。

      我记得您对 Begin 块中的函数参数所做的更改将在 Process 块的第一次迭代中继续存在。它们只会在后续迭代(或者,也许在第一次迭代结束时)被重置。

      【讨论】:

      • 我认为这是我将不得不求助的方法,是的,而且它似乎在流程块的每次迭代中都会被重置。但是,正如上面的测试所示,它只对 $Credential 参数执行此操作,而不是对 $Path 参数执行此操作,这令人困惑!
      • 嗨,OldFart,这个函数只是一个更长的函数的摘录——一个对管道输入进行适当处理的函数。它适用于简单/可读性。从这个例子看来,字符串分配在修改后仍然存在,但凭证分配没有。我无法在网上找到任何关于此的信息,所以想知道是否有人可以告知。
      • 好吧,不管怎样,修​​改函数参数只会让人伤心。
      猜你喜欢
      • 2017-12-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-01-12
      • 2013-10-24
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多