2010-10-24 4 views
7

Я использую командлеты TFS PowerTools в PowerShell, чтобы попытаться получить некоторую информацию о серверах и связанных с ними WorkItems. Я откинул проблему до поведения, которое я не понимаю, и я надеюсь, что это не спецификация TFS (так что кто-то там может объяснить мне эту проблему :))PowerShell ForEach/Piping confusion

Вот единственная команда, которую я могу приступить к работе:

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

Это то, что я ожидал - Get-TfsItemHistory возвращает список из 5 ревизий, и это трубы тех к Еогеасп, который выводит название первого связанный WorkItem. Так в чем моя проблема? Я пытаюсь написать большой скрипт, и я предпочитаю кодировать вещи, чтобы больше походить на программу C# (синтаксис powershell заставляет меня плакать). Всякий раз, когда я пытаюсь сделать написанное выше любым другим способом, коллекция WorkItems имеет значение null.

следующие команды (которые я интерпретируют быть логически эквивалентными) не работают (сбор 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, но это, по-видимому, больше связано с дебатами по производительности. По-видимому, это проблема о том, когда используется трубопровод.

Я не уверен, почему все три из этих подходов не работают. Любое понимание очень ценится.

+3

Я не уверен, в чем проблема, но это определенно специфично для команд TFS (они довольно ужасные, imo). Похоже, что командлет выполнял ленивую загрузку, и как только конвейер заканчивается, контекст данных ушел, и слишком поздно загружать данные, но дизайн командлетов настолько запутан, что я не мог отследить его, что далеко в отражателе , – Jaykul

ответ

8

Это действительно сбивает с толку. В настоящее время работы вокруг, чтобы захватить предметы, как так:

$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) { ... } - должен работать нормально.

+0

Спасибо, что работает. Я снова на ходу, и я не сумасшедший! Конечно, это странно, было бы неплохо узнать, что это значит, но на данный момент я готов залить еще до гремлинов. – Hexate