PowerShell ForEach / Piping混乱

时间:2010-10-24 16:33:14

标签: powershell foreach tfs2010 piping

我在PowerShell中使用TFS PowerTools Cmdlet尝试从我的服务器获取有关Changeset和相关WorkItem的一些信息。我已将问题归结为我不理解的行为,我希望它不是TFS特定的(所以有人可能会向我解释这个问题:))

这是我可以开始工作的唯一命令:

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

它做了我所期望的 - Get-TfsItemHistory返回一个包含5个ChangeSet的列表,并将它们传递给foreach,它打印出第一个关联WorkItem的Title。那我的问题是什么?我正在尝试编写一个大型脚本,我更喜欢将事物编写为更像C#程序(powershell语法让我哭泣)。每当我尝试以任何其他方式编写上述内容时,WorkItems集合都为空。

以下命令(我认为在逻辑上等效)不起作用(WorkItems集合为空):

$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之间差异的文章,但这似乎更像是一场性能争论。这似乎是关于何时使用管道的问题。

我不确定为什么所有这三种方法都不起作用。任何见解都表示赞赏。

1 个答案:

答案 0 :(得分:11)

这确实令人困惑。现在,解决方法就是抓住这样的项目:

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

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

BTW你最后的方法 - foreach ($item in $items) { ... } - 应该可以正常工作。