Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/powershell/11.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Validation PowerShell:GetNewClosure()和带有验证的cmdlet_Validation_Powershell_Closures_Powershell 2.0_Cmdlet - Fatal编程技术网

Validation PowerShell:GetNewClosure()和带有验证的cmdlet

Validation PowerShell:GetNewClosure()和带有验证的cmdlet,validation,powershell,closures,powershell-2.0,cmdlet,Validation,Powershell,Closures,Powershell 2.0,Cmdlet,我试图了解.GetNewClosure()如何在PowerShell 2中的脚本cmdlet上下文中工作 本质上,我有一个函数,它返回如下对象: function Get-AnObject { param( [CmdletBinding()] [Parameter(....)] [String[]]$Id .. [ValidateSet('Option1','Option2')] [String[]]$Options ) ... $T

我试图了解.GetNewClosure()如何在PowerShell 2中的脚本cmdlet上下文中工作

本质上,我有一个函数,它返回如下对象:

function Get-AnObject {
param(
    [CmdletBinding()]
    [Parameter(....)]
    [String[]]$Id
    ..
    [ValidateSet('Option1','Option2')]
    [String[]]$Options
)

...

    $T = New-Object PSCustomObject -Property @{ ..... } 
    $T | Add-Member -MemberType ScriptProperty -Name ExpensiveScriptProperty -Value {
        $this | Get-ExpensiveStuff
    }.GetNewClosure() 

..
}
如果我没有“验证集”选项,则闭包似乎可以正常工作。但是,如果包含它,则新闭包将失败,并出现以下错误

使用“0”参数调用“GetNewClosure”时出现异常:“无法添加属性,因为这将导致具有值的变量选项无效。”

可能闭包试图捕获Cmdlet调用的上下文。由于参数“Options”根本没有绑定,这与参数验证不符


我认为可以通过将验证作为代码放在Cmdlet主体中而不是使用[Validate*()]装饰器来避免这种情况——但这似乎很讨厌,也很模糊。有没有办法融合这两种思想

我相信这可能有效:

function Get-AnObject {
param(
      [CmdletBinding()]
      [Parameter(....)]
      [String[]]$Id
      ..
      [ValidateSet('Option1','Option2')]
      [String[]]$Options
    )

...
$sb = [scriptblock]::create('$this | Get-ExpensiveStuff')
$T = New-Object PSCustomObject -Property @{ ..... } 
$T | Add-Member -MemberType ScriptProperty -Name ExpensiveScriptProperty -Value $sb 

.. }
这会将脚本块的创建延迟到运行时。

此“无法添加属性”消息是(或曾经是)PowerShell错误,我已将其提交给Microsoft。这个特定的问题似乎已经解决了(可能是在V5.1左右)。但是任何对Powershell闭包感兴趣的人都可能会发现下面的信息很有趣

在早期版本中有一种解决方法,但首先这里有一个简化的复制案例,它会产生相同的错误:

function Test-ClosureWithValidation {
    [CmdletBinding()]
    param(
        [Parameter()]
        [ValidateSet('Option1','Option2')]
        [String[]]$Options
    )
    [scriptblock] $closure = {"OK"}.GetNewClosure();
    $closure.Invoke()
}

Test-ClosureWithValidation -Options Option1
解决方法取决于以下事实:GetNewClosure()通过迭代调用脚本上下文中的局部变量,将这些局部变量绑定到脚本上下文中来解决此问题。出现此错误是因为它复制了$Options变量(包括验证属性)。您可以通过创建仅包含所需局部变量的新上下文来解决此错误。在e简单的重新编程,这是一个单线解决方案:

    [scriptblock] $closure = &{ {"OK"}.GetNewClosure();}
上面的一行现在创建了一个没有局部变量的作用域。这对于您的情况可能太简单了;如果您需要外部作用域中的一些值,您可以将它们复制到新作用域中的局部变量中,例如:

    [scriptblock] $closure = &{ 
        $options = $options; 
        {"OK $options"}.GetNewClosure();
    }
注意,上面的第二行创建了一个新的$options变量,将外部变量的值赋给它,属性不会传播

最后,我不确定在您的示例中为什么需要调用GetNewClosure。变量$this不是普通的局部变量,无论是否创建闭包,它都将在脚本属性中可用。示例:

function Test-ScriptPropertyWithoutClosure {
    [CmdletBinding()]
    param(
        [Parameter()]
        [ValidateSet('Option1','Option2')]
        [String[]]$Options
    )
    [pscustomobject]@{ Timestamp= Get-Date} | 
        Add-Member ScriptProperty ExpensiveScriptProperty { 
            $this | get-member -MemberType Properties| % Name 
        } -PassThru
}

Test-ScriptPropertyWithoutClosure -Options Option1 | fl

伟大的侦察;我已经更新了错误报告的链接,指向它在windowsserver.uservoice.com的新家-不幸的是,它被错误地标记为“已完成”尽管问题在PowerShell v5.1.14393.693/PowerShell Core v6.0.0-alpha.15中仍然存在。因此,在撰写本文时,您无法对错误报告进行投票;您只能留下评论。感谢@mklement0,很高兴您发现这一点很有帮助。我在5.1.14393.693下运行了为错误报告编写的测试用例教育结果(“OK”)was输出,没有错误,这可能就是它被标记为已完成的原因。如果PowerShell Core 6对此有错误恢复,最好打开一个新问题,而不是回收旧问题。是的,您的测试用例通过了,但我希望它始终通过,因为它通过了一个有效的
-Options
值问题-当你根本没有在Windows PowerShell和PowerShell Core中传递任何
-选项
值时,这个bug就会出现。但是我明白你关于打开一个新问题的观点:你认为在哪里发布它更有意义:windowsserver.uservoice.com或开源GitHub项目?好吧,听起来我的bug修复程序没有c改变GetNewClosure()只捕获局部变量(而不是参数)的事实。如果是这样的话,我提到的另一个解决方法[将GetNewClosure()放入脚本块中,并将参数重新分配给局部变量]可能仍然是需要的。我想归档它的任何一个地方都可以工作,但在内部它可以作为“按设计”,所以使用解决方案可能是你最好的选择。更改它可能会破坏现有的脚本。如果我误解了,可能最好编写一个新的测试用例和stackoverflow线程。我不再为Microsoft工作,但如果你在文中@提到我,我会查看它。