2013-09-26 28 views
0

作为此问题的附件:How do I force declared parameters to require explicit naming?我正在努力处理管道。假设我想要的行为,这种声明:参数列表和管道

param(
    $installdir, 
    $compilemode, 
    [Parameter(Position=0, ValueFromRemainingArguments=$true)] $files 
    ) 

即,我可以把我的脚本是这样的:

c:\> MyScript -installdir c:\ file-1.txt file-2.txt file-3.txt 

,但现在我也想能够做到这样说:

c:\> gi file-*.txt |MyScript -installdir c:\ 

我可能会想增加一个装饰的参数是这样的:

param(
    $installdir, 
    $compilemode, 
    [Parameter(
     Position=0, 
     ValueFromRemainingArguments=$true, 
     ValueFromPipeline=$true 
    )] $files 
    ) 

但实际发生的是我只有1个参数到我的参数,而不是获得一个数组与gi产生的所有文件,我只得到列表中的第一个。

我试图这样的第二种方式是通过使用$input变量(而不是使用ValueFromPipeline装饰),但随后在试图调用脚本我得到的错误:

The input object cannot be bound to any parameters for the command either because the command does not take pipeline input or the input and its properties do not match any of the parameters that take pipeline input.

在那里我可以从去这里?

回答

3

你可以声明它没有ValueFromRemainingArguments:

param(
    [Parameter(
     Position=0, 
     ValueFromPipeline=$true, 
     ValueFromPipelineByPropertyName=$true)] 
    [Alias('PSPath')] 
    [string[]] 
    $files, 
    $installdir, 
    $compilemode 
    ) 

然后在多个文件中使用逗号操作符如传递一个数组:

MyScript -installdir c:\ file-1.txt,file-2.txt,file-3.txt 

注:为了接受类似的命令输入Get-Item和Get-ChildItem,使用ValueFromPipelineByPropertyName并添加一个参数别名“PSPath”,它将在由Get-Item/Get-ChildItem输出的对象上查找PSPath属性。

我有测试此在ISE和正常工作:

function foo 
{ 
    param(
     [Parameter(
      Position=0, 
      ValueFromPipeline=$true, 
      ValueFromPipelineByPropertyName=$true)] 
     [Alias('PSPath')] 
     [string[]] 
     $files, 
     $installdir, 
     $compilemode 
     ) 

    process { 
     foreach ($file in $files) { 
      "File is $file, installdir: $installdir, compilemode: $compilemode" 
     } 
    } 
} 

foo a,b,c -installdir c:\temp -compilemode x64 
ls $home -file | foo -installdir c:\bin -compilemode x86 

仅供参考,这是一个模板,我用所有的时间来创建能够利用管道输入或数组输入,以及通配符路径命令:

function Verb-PathLiteralPath 
{ 
    [CmdletBinding(DefaultParameterSetName="Path", 
        SupportsShouldProcess=$true)] 
    #[OutputType([output_type_here])] # Uncomment this line and specify the output type of this 
             # function to enable Intellisense for its output. 
    param(
     [Parameter(Mandatory=$true, 
        Position=0, 
        ParameterSetName="Path", 
        ValueFromPipeline=$true, 
        ValueFromPipelineByPropertyName=$true, 
        HelpMessage="Path to one or more locations.")] 
     [ValidateNotNullOrEmpty()] 
     [SupportsWildcards()] 
     [string[]] 
     $Path, 

     [Alias("PSPath")] 
     [Parameter(Mandatory=$true, 
        Position=0, 
        ParameterSetName="LiteralPath", 
        ValueFromPipelineByPropertyName=$true, 
        HelpMessage="Literal path to one or more locations.")] 
     [ValidateNotNullOrEmpty()] 
     [string[]] 
     $LiteralPath 
    ) 

    Begin 
    { 
     Set-StrictMode -Version Latest 
    } 

    Process 
    { 
     if ($psCmdlet.ParameterSetName -eq "Path") 
     { 
      if (!(Test-Path $Path)) { 
       $ex = new-object System.Management.Automation.ItemNotFoundException "Cannot find path '$Path' because it does not exist." 
       $category = [System.Management.Automation.ErrorCategory]::ObjectNotFound 
       $errRecord = new-object System.Management.Automation.ErrorRecord $ex, "PathNotFound", $category, $Path 
       $psCmdlet.WriteError($errRecord) 
      } 

      # In the -Path (non-literal) case, resolve any wildcards in path 
      $resolvedPaths = $Path | Resolve-Path | Convert-Path 
     } 
     else 
     { 
      if (!(Test-Path $LiteralPath)) { 
       $ex = new-object System.Management.Automation.ItemNotFoundException "Cannot find path '$LiteralPath' because it does not exist." 
       $category = [System.Management.Automation.ErrorCategory]::ObjectNotFound 
       $errRecord = new-object System.Management.Automation.ErrorRecord $ex, "PathNotFound", $category, $LiteralPath 
       $psCmdlet.WriteError($errRecord) 
      } 

      # Must be -LiteralPath 
      $resolvedPaths = $LiteralPath | Convert-Path 
     } 

     foreach ($rpath in $resolvedPaths) 
     { 
      if ($pscmdlet.ShouldProcess($rpath, "Operation")) 
      { 
       # .. process rpath 
      } 
     } 
    } 

    End 
    { 
    } 
} 
+0

是的。我可能必须这样做。我不喜欢它,因为本能说你用空格分隔列表。或者,也许我可以运行$ args变量,但它仍然让我不得不声明至少有一个参数与一个位置,以便其他名称是必需的。叹...... perl在这方面好得多 – ekkis

+0

我想这里真正困扰我的是似乎在参数和管道对象之间存在混淆。管道输入到我的脚本中的东西还不是我的参数,当我尝试输入管道时我的param()声明失败了,我不明白为什么......并且特别是当我声明参数的位置为0时 – ekkis

+0

在任何情况下,你的解决方案不起作用,因为只要我声明一个带有位置值的参数,我似乎无法将任何东西传入脚本(我不明白为什么) – ekkis