2010-10-24 19 views
7

J'utilise les applets de commande TFS PowerTools dans PowerShell pour essayer d'obtenir des informations sur les modifications et les éléments de travail connexes de mon serveur. J'ai fait bouillir le problème à un comportement que je ne comprends pas et j'espère que ce n'est pas spécifique à TFS (donc quelqu'un pourrait m'expliquer le problème :) :)Confusion PowerShell ForEach/Piping

Voici la seule commande que je peux se rendre au travail:

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

Il fait ce que je pense - Get-TfsItemHistory retourne une liste de 5 changesets, et tuyaux ceux foreach qui imprime le titre du premier WorkItem associé. Alors quel est mon problème? J'essaye d'écrire un grand script, et je préfère coder les choses pour ressembler plus à un programme C# (la syntaxe PowerShell me fait pleurer). Chaque fois que j'essaie de faire ce qui est écrit d'une autre manière, la collection WorkItems est nulle.

Les commandes suivantes (que j'interprète d'être logiquement équivalent) ne fonctionnent pas (La collection WorkItems est null):

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

Celui que je préférerais vraiment:

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

Je lis un article sur la différence entre l'opérateur 'foreach' et la Cmdlet ForEach-Object, mais cela semble être davantage un débat sur la performance. Cela semble vraiment être un problème concernant le moment où la tuyauterie est utilisée. Je ne sais pas pourquoi ces trois approches ne fonctionnent pas. Toute idée est appréciée.

+3

Je ne suis pas sûr de savoir quel est le problème, mais il est certainement spécifique aux Cmdlets TFS (ils sont plutôt horribles, imo). Il semble que l'applet de commande effectuait un chargement paresseux et une fois le pipeline terminé, le contexte de données est parti et il est trop tard pour charger les données, mais la conception des applets de commande est tellement compliquée que je ne pouvais pas la repérer aussi loin dans le réflecteur. . – Jaykul

Répondre

8

Ceci est en effet déroutant. Pour l'instant, une autre solution consiste à saisir les articles comme ceci:

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

Cette collection accède à la WorkItems qui semble causer cette propriété à être rempli (je sais - WTF?). J'ai tendance à utiliser @() pour générer un tableau dans les cas où je veux utiliser le mot-clé foreach. La chose avec le mot-clé foreach est qu'il va itérer une valeur scalaire incluant $ null. Ainsi, si la requête ne renvoie rien, $items reçoit assigné $ null et foreach va répéter la boucle une fois avec $item mis à null. Maintenant, PowerShell traite généralement très bien les valeurs nulles. Toutefois, si vous remettez cette valeur à .NET Framework, elle n'est généralement pas aussi tolérante. Le @() garantira un tableau contenant soit 0, 1 ou N éléments. Si c'est 0 alors la boucle foreach n'exécutera pas son corps du tout.

BTW votre dernière approche - foreach ($item in $items) { ... } - devrait fonctionner très bien.

+0

Merci, ça fonctionne. Je suis de retour sur la bonne voie et je ne suis pas folle! C'est bizarre à coup sûr, ce serait bien de savoir de quoi il s'agit, mais à ce stade, je suis prêt à m'en remettre aux gremlins. – Hexate