且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

对于PowerShell cmdlet,是否可以始终将脚本块传递给字符串参数?

更新时间:2022-11-12 15:46:35

延迟绑定脚本块参数 隐式 >功能:

Delay-bind script-block arguments are an implicit feature that:

  • 旨在接受管道输入的参数一起使用

  • only works with parameters that are designed to take pipeline input,

  • 任何类型的除了以下,在这种情况下会发生常规参数绑定 [1] :

  • [scriptblock]
  • [object](但是,[psobject]起作用,因此[pscustomobject]也起作用)
  • (未指定类型),实际上与[object]
  • 相同
  • [scriptblock]
  • [object] ([psobject], however, does work, and therefore [pscustomobject] too)
  • (no type specified), which is effectively the same as [object]

这些参数是否接受通过 value (ValueFromPipelineBy)或通过属性名称(ValueFromPipelineByPropertyName)进行的管道输入.

whether such parameters accept pipeline input by value (ValueFromPipelineBy) or by property name (ValueFromPipelineByPropertyName), is irrelevant.

通过脚本块传递的代替类型合适的自变量每个输入对象 ;将为每个管道对象评估脚本块,该脚本块通常可以在$_中以$_的形式在脚本块内部进行访问,并且假定脚本块的 output -假定其与参数类型相符-用作参数.

enables per-input-object transformations via a script block passed instead of a type-appropriate argument; the script block is evaluated for each pipeline object, which is accessible inside the script block as $_, as usual, and the script block's output - which is assumed to be type-appropriate for the parameter - is used as the argument.

  • 由于按照定义,此类临时脚本块与您要定位的参数类型不匹配,因此在传递它们时必须始终显式使用参数名称.

延迟绑定脚本块无条件提供对管道输入对象的访问,即使该参数通常受给定的管道对象绑定,如果它定义为ValueFromPipelineByPropertyName,并且该对象缺少该名称的属性.

Delay-bind script blocks unconditionally provide access to the pipeline input objects, even if the parameter would ordinarily not be bound by a given pipeline object, if it is defined as ValueFromPipelineByPropertyName and the object lacks a property by that name.

  • 这将启用诸如以下对Rename-Item的调用之类的技术,其中,通常将Get-Item的管道输入绑定到-LiteralPath参数,但是将脚本块传递给-NewName-通常仅绑定到具有.NewName属性的输入对象-启用对同一管道对象的访问,从而从输入文件名派生目标文件名:
    • Get-Item file | Rename-Item -NewName { $_.Name + '1' } # renames 'file' to 'file1';输入绑定到 -LiteralPath(隐式) -NewName脚本块.
    • This enables techniques such as the following call to Rename-Item, where the pipeline input from Get-Item is - as usual - bound to the -LiteralPath parameter, but passing a script block to -NewName - which would ordinarily only bind to input objects with a .NewName property - enables access to the same pipeline object and thus deriving the destination filename from the input filename:
      • Get-Item file | Rename-Item -NewName { $_.Name + '1' } # renames 'file' to 'file1'; input binds to both -LiteralPath (implicitly) and the -NewName script block.

      注意:例如,与传递给ForEach-ObjectWhere-Object的脚本块不同,延迟绑定脚本块在 child 变量范围内运行 [2] ,这意味着您不能直接修改调用者的变量,例如在输入对象之间增加计数器.
      解决方法是,使用在调用方作用域中声明的[ref]类型变量,并在脚本块内访问其.Value属性-请参见这个答案为例.

      Note: Unlike script blocks passed to ForEach-Object or Where-Object, for example, delay-bind script blocks run in a child variable scope[2], which means that you cannot directly modify the caller's variables, such as incrementing a counter across input objects.
      As a workaround, use a [ref]-typed variable declared in the caller's scope and access its .Value property inside the script block - see this answer for an example.

      [1]错误条件:

      • 如果您错误地尝试将脚本块传递给不是管道绑定或[scriptblock]-或[object]类型(未键入)的参数 常规参数绑定:

      • If you mistakenly attempt to pass a script block to a parameter that is either not pipeline-binding or is [scriptblock]- or [object]-typed (untyped), regular parameter-binding occurs:

      • 在流水线输入处理开始之前(如果有的话)在一次中传递脚本块.
        也就是说,脚本块作为(可能是转换的)传递,并且没有评估发生.
        • 对于类型为[object][scriptblock]的参数/可以转换为脚本块的委托类型(例如System.Func),脚本块将按原样绑定 .
        • 对于(非管道绑定)[string]类型的参数,脚本块的文字内容作为字符串值传递.
        • 对于所有其他类型,参数绑定(以及整个命令)将简单地失败,因为无法从脚本块进行转换.
        • The script block is passed once, before pipeline-input processing begins, if any.
          That is, the script block is passed as a (possibly converted) value, and no evaluation happens.
          • For parameters of type [object] or [scriptblock] / a delegate type such as System.Func that is convertible to a script block, the script block will bind as-is.
          • In the case of a (non-pipeline-binding) [string]-typed parameter, the script block's literal contents is passed as the string value.
          • For all other types, parameter binding - and therefore the command as a whole - will simply fail, since conversion from a script block is not possible.

          如果您忽略提供管道输入,而将延迟绑定脚本块传递给支持的管道绑定参数,则会得到以下错误:

          If you neglect to provide pipeline input while passing a delay-bind script block to a pipeline-binding parameter that does support them, you'll get the following error:

          • Cannot evaluate parameter '<name>' because its argument is specified as a script block and there is no input. A script block cannot be evaluated without input.

          [2]此差异正在此GitHub问题中进行讨论