试图理解这段代码用$ PSBoundParameters对象做了什么

时间:2016-06-02 16:40:12

标签: .net powershell

我正在玩代理功能,我想完全理解我正在查看的所有代码。

鉴于此:

$MetaData = New-Object System.Management.Automation.CommandMetaData
    (Get-Command Get-ChildItem)
[System.Management.Automation.ProxyCommand]::Create($MetaData)

以下是我不明白的输出代码片段:

begin
{
    try {

        $outBuffer = $null

        if ($PSBoundParameters.TryGetValue('OutBuffer', [ref]$outBuffer)) {
            $PSBoundParameters['OutBuffer'] = 1
        }

我只是好奇PSBoundParameters在这里发生了什么。它只是测试它是否可以获得outbuffer的句柄?为什么呢?

编辑:我不能解决的其他问题是它调用TryGetValue的方式,因为查看定义:

($PSBoundParameters | gm -Name trygetvalue).definition

bool TryGetValue(string key, [ref] System.Object value),
bool IDictionary[string,Object].TryGetValue(string key, [ref] System.Object value),
bool IReadOnlyDictionary[string,Object].TryGetValue(string key, [ref] System.Object value)

看起来它需要第三个参数:(string key, [ref]System.Object valueToBeStored)

它只是传递一个字符串和一个[ref] $对象,但是#34;值"没有字符串。 "值"我相信你用它来检索从字典查找中找到的值。

1 个答案:

答案 0 :(得分:1)

什么是OutBuffer

运行:OutBuffer @MathiasR.Jessen可以在Get-Help about_CommonParameters的评论文档中按^获取{p}}。

  

-OutBuffer

     

别名:ob

     

确定之前在缓冲区中累积的对象数      任何对象都通过管道发送。如果省略此参数,      对象在生成时发送。

     

此资源管理参数专为高级用户设计。      使用此参数时,Windows PowerShell不会调用      管道中的下一个cmdlet,直到生成的对象数      等于OutBuffer + 1.此后,它按原样发送所有对象      生成。

-OutBuffer vs $ PSBoundParameters [' OutBuffer']

关于$PSBoundParameters['OutBuffer']与参数OutBuffer之间的差异;空无一人。 $PSBoundParameters是一个字典,其中包含通过值传递到当前函数/ cmdlet的所有参数。您可以通过运行Get-Help about_Automatic_Variables ^

找到有关此变量的更多信息
  

$ PSBoundParameters

     

包含传递给脚本的参数字典      或功能及其当前值。此变量仅具有值      在声明参数的范围内,例如脚本或函数。      您可以使用它来显示或更改参数的当前值      或者将参数值传递给另一个脚本或函数。

     

例如:

function Test {
    param($a, $b)

    # Display the parameters in dictionary format.
    $PSBoundParameters

    # Call the Test1 function with $a and $b.
    test1 @PSBoundParameters
}

有关此方案的更多信息

您显示的代码看起来像proxy function。因此,您可能会在代码中进一步查看以下行:

$scriptCmd = {& $wrappedCmd @PSBoundParameters }

这里将$PSBoundParameters哈希表/字典传递给变量$wrappedCmd中定义的命令,所有命名值都作为该函数的参数值传递(即每个字典条目映射其值)到具有相同名称的命令参数)。这称为Splatting(通过运行Get-Help about_splatting更多信息):

  

Splatting是一种将参数值集合传递给a的方法   命令为单位。 Windows PowerShell关联了每个值   使用命令参数进行集合。 Splatted参数值是   存储在命名的splatting变量中,看起来像标准的   变量,但以At符号(@)而不是美元符号开头   ($)。 At符号告诉Windows PowerShell您正在传递   值的集合,而不是单个值。

     

Splatting使您的命令更短,更容易阅读。您可以   在不同的命令调用中重用splatting值并使用   splatting从$ PSBoundParameters传递参数值   自动变量到其他脚本和函数。

     

从Windows PowerShell 3.0开始,您还可以使用splatting   代表命令的所有参数。

回到OutBuffer ...你为什么要使用它?

这里有一篇很好的文章:https://mcpmag.com/articles/2013/07/16/common-parameter-part-4.aspx。我也在下面尝试了自己的解释:

通常,它用于提高性能。通常,PowerShell通过获取单个行/对象并在获取下一个对象/行之前将其一直传递到管道,就像foreach / iterator循环一样。 e.g。

Import-CSV 'abc.csv' | Export-CSV '123.csv'

有点像这样(伪代码):

$reader = New-Object 'PseudoCode.CSVReader' -ArgumentList 'abc.csv'
$writer = New-Object 'PseudoCode.CSVReader' -ArgumentList '123.csv'
while ($data = $reader.ReadLine())
{
    $writer.WriteLine($data)
}

在某些情况下这很好;它意味着你不会在内存中(通常)保留太多内容,因为你一点一点地抓住并使用数据。但是,有时候你可以通过处理更大的块来获得更好的性能。我经常使用的类比是用手填充沙坑。鉴于这个过程:

  1. 从源桩中取出沙子
  2. 把它带到沙坑里
  3. 将它放入沙坑中
  4. 返回源桩/重复直到沙坑已满
  5. 考虑一次移动1个谷物,一次移动1个桶,每次移动1个沙坑。

    • 一次一粒,使每次单独行程变得容易,但由于往返次数的原因,需要很长时间才能完成。
    • 每次旅行时,一次一桶仍然很容易携带;它仍然涉及多次旅行,但更可行/将在100次左右旅行后完成;所以会更有效率。
    • 一次性拿起整个沙坑的价值(没有机械装置)需要的力量比普通人的能力更强;所以会失败。

    现在的问题是:什么是最佳的铲斗尺寸。

    这里我们的水桶是我们的外出手。

    TryGetValue的第三个参数怎么样?

    你说:

      

    看起来它需要第三个参数:(字符串键,[ref] System.Object valueToBeStored)

    没有第三个参数;参数是:

    • string key
    • [ref]System.Object valueToBeStored

    Key定义要获取的值的名称。

    valueToBeStored是我们提取的价值。它作为引用传递,因为如果存在这样的值,则该值将填充给定键的值(在这种情况下,函数TryGetValue返回true以及分配值)。如果字典中不存在这样的键,则函数返回false,并且传递给参数valueToBeStored的变量保持其原始值(在这种情况下为$null)。有关详情,请参阅documentation on TryGetValue

    如果[ref]使您感到困惑,则会导致该参数用作参考变量。您可以通过get-help about_ref ^

    了解相关信息
      

    TOPIC

         

    about_Ref

         

    简短说明

         

    描述如何创建和使用引用变量类型。

         

    详细说明

         

    您可以使用引用变量类型来允许方法更改   传递给它的变量的值。

         

    当[ref]类型与对象关联时,它返回一个引用   到那个对象。如果引用与方法一起使用,则该方法可以   引用传递给它的对象。如果在其中更改了对象   该方法,更改显示为变量值的更改   当控制返回到调用方法时。

         

    要使用引用,参数必须是引用变量。如果是   不,抛出InvalidArgument异常。

         

    方法调用中使用的参数必须与所需类型匹配   按方法。