PowerShell PipelineVariable参数仅包含PSCustomObject集合中的第一个值 [英] PowerShell PipelineVariable parameter contains only first value in a collection of PSCustomObject

查看:152
本文介绍了PowerShell PipelineVariable参数仅包含PSCustomObject集合中的第一个值的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

问题

我只能得到类型为PSCustomObject的数组中一个文件的代码行数.其余的数组错误中的所有条目都显示以下消息-

I get count for lines of code for only one file in the array of type PSCustomObject. Rest all entries in the array error out with following message -

Get-Content:由于参数'null'为空,因此无法将其绑定到参数'Path'.

Get-Content : Cannot bind argument to parameter 'Path' because it is null.

在线:42个字符:100

At line:42 char:100

... -Content -Path $ files.UncommentedFileName)|测量对象线| Select-Objec ...

... -Content -Path $files.UncommentedFileName) | Measure-Object -Line | Select-Objec ...

如何克服此错误并显示数组中所有文件的代码行?

How do I overcome this error and display the lines of code for all the files in the array?

约束

  1. 我打算在必须处理VB6文件的其他情况下重新使用功能Remove-VBComments.因此,我无法避免定义和使用Remove-VBComments
  2. 我打算让函数Remove-VBComments接受管道输入,因为它将是管道友好的,以便在其他cmdlet可以在管道中Remove-VBComments之后运行的情况下使用
  3. 我必须在客户环境中使用PowerShell 4.0版本.
  1. I intend to re-use the function Remove-VBComments for other scenarios where I have to process VB6 files. Thus, I cannot avoid defining and using Remove-VBComments
  2. I intend to have the function Remove-VBComments accept pipelined input as will be pipeline friendly to be useable in the scenarios where other cmdlets could operate after Remove-VBComments in the pipeline
  3. I am constrained in the customer environment to use PowerShell version 4.0.

详细信息-

意图

我的代码的摘要是总结从注释中剥离的VB6代码文件的代码行.注释始终是single ',没有多行注释.我尝试遵循PowerShell脚本来实现此目的.

Of my code is to summarize the Lines of Code for a VB6 code file which is stripped off from comments. Comments are always a single ' with no provision for multi-line comments. Following PowerShell script is my attempt to fulfill this intent.

PowerShell代码

$filesToStripComment = @([PSCustomObject]@{
"SourceFileName" = ".\vb6-master\ClassTemplate\ClassBuilder\App.cls";
"UncommentedFileName" = ".\vb6-master\ClassTemplate\ClassBuilder\App.cls.uncommented"
},[PSCustomObject]@{
"SourceFileName" = ".\vb6-master\ClassTemplate\ClassBuilder\Class1.cls";
"UncommentedFileName" = ".\vb6-master\ClassTemplate\ClassBuilder\Class1.cls.uncommented"
},[PSCustomObject]@{
"SourceFileName" = ".\vb6-master\ClassTemplate\ClassBuilder\IFilterReporter.cls";
"UncommentedFileName" = ".\vb6-master\ClassTemplate\ClassBuilder\IFilterReporter.cls.uncommented"
},[PSCustomObject]@{
"SourceFileName" = ".\vb6-master\ClassTemplate\ClassBuilder\ITemplateFilter.cls";
"UncommentedFileName" = ".\vb6-master\ClassTemplate\ClassBuilder\ITemplateFilter.cls.uncommented"
});

Function Remove-VBComments {
    [CmdletBinding()]
    Param(
        [Parameter(
            Mandatory = $True,
            ValueFromPipelineByPropertyName=$True
        )]
        [String]
        $SourceFileName,

        [Parameter(
            Mandatory = $True,
            ValueFromPipelineByPropertyName=$True
        )]
        [String]
        $UncommentedFileName
    )
    Process {
        (Get-Content -LiteralPath $SourceFileName) `
            -replace "\'.*$",$ReplaceString -notmatch "^\s*$" `
        | Out-File -LiteralPath     $UncommentedFileName;
        $result =  [PSCustomObject]@{
                        SourceFileName=$($SourceFileName); 
                        UncommentedFileName=$($UncommentedFileName)
                    };
        Write-Output $result;
    }
}

$filesToStripComment | `
    Remove-VBComments -PipelineVariable "files" | `
    &{Process{ `
               (Get-Content -Path $files.UncommentedFileName) `
                  | Measure-Object -Line `
                  | Select-Object -Property `
                      @{n="FileName";e={$files.UncommentedFileName}}, ` 
                      @{n="LoC";e={$_.Lines}} `
     } }

cls文件是我从 github 复制的文件项目.

The cls files are the ones I copied from a github project.

上述代码的输出

FileName                                                          LoC
-------------                                                     -------
.\vb6-master\ClassTemplate\ClassBuilder\App.cls.uncommented       29

Get-Content : Cannot bind argument to parameter 'Path' because it is null.
At line:42 char:100
...... 
# The above error repeats for all other entries in the array $filesToStripComment.

观察#1

如果在调用Cmdlet Remove-VBComments之后进行了一些小的更改,我将获得数组$filesToStripComment中所有文件的LoC计数.

If I make following small change after the call to Cmdlet Remove-VBComments, I get the LoC count for all files in the array $filesToStripComment.

... | Remove-VBComments | Select-Object -PipelineVariable "files" | `
& { Process { (Get-Content -Path $files.UncommentedFileName) | `
Measure-Object -Line | `
Select-Object -Property @{n="FileName",e={$files.UncommentedFileName} ...

现在,我不明白为什么管道Select-Object的这种细微变化会为我带来所需的结果,但是在Cmdlet Remove-VBComments上使用PipelineVariable却无法得到结果吗?!

Now I do not understand why does this subtle change of piping Select-Object gets me the desired result but using the PipelineVariable on Cmdlet Remove-VBComments does not get me the result?!

观察#2

我没有通过传递PSCustomObject的数组,而是通过引入新的Cmdlet Get-ClsFilesRecursively改进了代码.函数看起来像这样-

Instead of passing an array of PSCustomObject I have improvised the code in the meanwhile by introducing a new Cmdlet Get-ClsFilesRecursively. The function looks like this -

Function Get-ClsFilesRecursively{
[CmdletBinding()]
Param(
      [Parameter(
        Mandatory=$True,
        ValueFromPipelineByPropertyName=$True,
      )]
      [String]
      $SourceCodePath
)
  Process{
    Write-Output (Get-ChildItem -Path $SourceCodePath `
                              -Filter "*.cls" `
                              -Recurse | `
               Select-Object -Property `
                    @{n="LiteralPath";e={$_.FullName}});
  }
}

要使用此功能,我要打这样的电话

To put this function to use I make a call like this

Get-ClsFilesRecursively -SourceCodePath . -PipelineVariable "files" | `
& { Process { `
   Get-Content -LiteralPath $files.LiteralPath | `
   Measure-Object -Line | `
   Select-Object -Property @{n="File name";e={$files.LiteralPath}} `
                        @{n="LoC"; e={$_.Lines}}
}}

现在,这为目录中的所有文件提供了代码行;没有任何例外.但是,此调用在文件中包括注释.现在,如果按上述调用顺序传送Remove-VBCommments,我会得到上面问题中提到的问题. 我对导致Remove-VBComments无法与PipelineVariable正常工作而导致其他Cmdlet与PipelineVariable正常运行的原因感到困惑!

Now this gives the me the Lines of Code for all the files in the directory; without any exception. However, this call includes comments in the files. Now if I pipe the Remove-VBCommments in the above call sequence I get back the problem I mentioned in the question above. I am perplexed with what causes Remove-VBComments to fail in working properly with PipelineVariable whereas other Cmdlets behave properly with PipelineVariable!

请帮助!

推荐答案

不幸的是,-PipelineVariable不适用于Remove-VBComments之类的脚本cmdlet.这就是为什么将Select-Object运行成功的原因-这是C#cmdlet.但是您实际上并不需要它,因为foreach循环中的$_具有$files变量中应包含的所有信息.更新代码看起来像

Unfortunately -PipelineVariable doesn't work with script cmdlets like Remove-VBComments. That's why moving if to Select-Object worked - it's a C# cmdlet. But you don't actually need it since $_ in the foreach loop has all of the information that would have been in the $files variable. The update code would look something like

$filesToStripComment |
    Remove-VBComments |
    &{Process{
                $UncommentedFileName = $_.UncommentedFileName
                Get-Content -Path $UncommentedFileName |
                    Measure-Object -Line |
                        Select-Object -Property `
                            @{n="FileName";e={$UncommentedFileName}}, 
                            @{n="LoC";e={$_.Lines}} `
     } }

这篇关于PowerShell PipelineVariable参数仅包含PSCustomObject集合中的第一个值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆