2010-10-24 73 views
7

我在PowerShell中使用TFS PowerTools Cmdlet尝试从我的服务器获取有关Changesets和相关WorkItems的一些信息。我已经把问题归结为行为我不明白,我希望它不是特定于TFS(所以有人可能能够向我解释问题:))PowerShell ForEach /管道混淆

这是唯一的命令,我可以得到工作:

 
Get-TfsItemHistory C:\myDir -recurse -stopafter 5 | % { Write-Host $_.WorkItems[0]["Title"] } 

它做什么,我期待 - 获取-TfsItemHistory返回5次变更的列表,它管那些打印出的第一个关联工作项的标题一个foreach。那么我的问题是什么?我正在尝试编写一个大脚本,我更愿意将代码看起来更像C#程序(powershell语法让我哭了)。每当我尝试以任何其他方式完成上述操作时,WorkItems集合都为null。

下面的命令(我解释在逻辑上等同)不工作(工作项的集合为null):

 
$items = Get-TfsItemHistory C:\myDir -recurse -stopafter 5 
$items | ForEach-Object { Write-Host $_.WorkItems[0]["Title"] } 

的一个,我真的很喜欢:

 
$items = Get-TfsItemHistory C:\myDir -recurse -stopafter 5 
foreach ($item in $items) 
{ 
    $item.WorkItems[0]["Title"] 
    # do lots of other stuff 
} 

我读一篇关于'foreach'操作符和ForEach-Object Cmdlet之间区别的文章,但这似乎更像是一场性能辩论。这似乎是一个关于何时使用管道的问题。

我不确定为什么这三种方法都不起作用。任何见解都会被赞赏。

+3

我不确定问题是什么,但它绝对特定于TFS Cmdlet(它们相当可怕,imo)。看起来cmdlet正在进行延迟加载,一旦管道结束,数据上下文就消失了,加载数据也为时已晚,但是cmdlet的设计过于复杂,以至于我无法在反射器上追踪它。 – Jaykul 2010-10-25 13:44:02

回答

8

这确实令人困惑。对于现在的解决办法是抢项目,像这样:

$items = @(Get-TfsItemHistory . -r -Stopafter 25 | 
      Foreach {$_.WorkItems.Count > $null; $_}) 

该项访问工作项集合,这似乎导致填充这个属性(我知道 - 跆拳道?)。在我想使用foreach关键字的情况下,我倾向于使用@()来生成数组。 foreach关键字的含义是它会迭代包含$ null的标量值。因此,如果查询不返回任何内容,$items被赋值为$ null,并且foreach将使用$item设置为null来迭代循环一次。现在PowerShell通常非常好地处理空值。但是,如果您将该值重新提交给.NET Framework,通常不会宽容。 @()将保证阵列中有0,1或N个元素。如果它是0,那么foreach循环根本不会执行它的主体。

顺便说一句,你最后的做法 - foreach ($item in $items) { ... } - 应该工作得很好。

+0

谢谢,这是有效的。我回到了正轨,我并不疯狂!这太奇怪了,很高兴知道这是什么,但在这一点上,我已经准备好再次粉饰一堆。 – Hexate 2010-10-25 15:34:58