2010-10-24 9 views
7

Estoy utilizando los cmdlets de TFS PowerTools en PowerShell para tratar de obtener cierta información sobre los conjuntos de cambios y los artículos de trabajo relacionados de mi servidor. He reducido el problema a un comportamiento que no entiendo y espero que no sea TFS específico (para que alguien allí pueda explicarme el problema :))PowerShell ForEach/Piping confusion

Este es el único comando que puedo llegar al trabajo:

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

hace lo espero - obtener-TfsItemHistory devuelve una lista de 5 conjuntos de cambios, y esos tubos a un foreach que imprime el título de la primera WorkItem asociado. Entonces, ¿cuál es mi problema? Intento escribir una secuencia de comandos grande, y prefiero codificar las cosas para que se parezcan más a un programa C# (la sintaxis de PowerShell me hace llorar). Cada vez que intento hacer lo anterior escrito de otra manera, la colección WorkItems es nula.

Los siguientes comandos (que interpreto a ser lógicamente equivalente) no funcionan (La colección WorkItems es nulo):

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

El que yo realmente preferiría:

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

leo un artículo sobre la diferencia entre el operador 'foreach' y el cmdlet ForEach-Object, pero parece ser más un debate sobre el rendimiento. Esto realmente parece ser un problema sobre cuándo se está utilizando la tubería.

No estoy seguro de por qué los tres enfoques no funcionan. Cualquier idea es apreciada.

+3

No estoy seguro de cuál es el problema, pero definitivamente es específico de los cmdlets TFS (son bastante horribles, imo). Parece que el cmdlet estaba realizando una carga diferida, y una vez que finaliza la interconexión, el contexto de datos se ha ido y es demasiado tarde para cargar los datos, pero el diseño de los cmdlets es tan intrincado que no pude rastrearlo tan lejos en el reflector . – Jaykul

Respuesta

8

Esto es ciertamente confuso. Por ahora una solución alternativa consiste en agarrar los objetos de esta manera:

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

Este acceso a la colección WorkItems que parece causar esta propiedad a ser poblada (sé - WTF?). Tiendo a usar @() para generar una matriz en los casos en que deseo usar la palabra clave foreach. Lo que pasa con la palabra clave foreach es que iterará un valor escalar que incluye $ null. Entonces, si la consulta no devuelve nada, $items se asigna $ null y el foreach iterará el ciclo una vez con $item establecido en nulo. Ahora PowerShell generalmente se ocupa de nulos muy bien. Sin embargo, si devuelve ese valor a .NET Framework, generalmente no es tan indulgente. El @() garantizará una matriz con 0, 1 o N elementos en ella. Si es 0, entonces el bucle foreach no ejecutará su cuerpo en absoluto.

Por cierto su último enfoque - foreach ($item in $items) { ... } - debería funcionar bien.

+0

Gracias, eso funciona. Estoy de vuelta en la pista y no estoy loco! Eso es raro, seguro, sería bueno saber de qué se trata todo esto, pero en este punto, estoy listo para añadir una más a los gremlins. – Hexate