usar tutorial script como commands comandos powershell

tutorial - Seleccione los valores de una propiedad en todos los objetos de una matriz en PowerShell



powershell tutorial (3)

Como una solución aún más fácil, puedes usar:

$results = $objects.Name

Que debería llenar $results con una matriz de todos los valores de propiedad ''Nombre'' de los elementos en $objects .

Digamos que tenemos una matriz de objetos $ objetos. Digamos que estos objetos tienen una propiedad de "Nombre".

Esto es lo que quiero hacer

$results = @() $objects | %{ $results += $_.Name }

Esto funciona, pero ¿se puede hacer de una mejor manera?

Si hago algo como:

$results = objects | select Name

$results es una matriz de objetos que tienen una propiedad Name. Quiero $ resultados para contener una matriz de nombres.

¿Hay una mejor manera?


Creo que es posible que pueda usar el parámetro ExpandProperty de Select-Object .

Por ejemplo, para obtener la lista del directorio actual y simplemente mostrar la propiedad Nombre, uno haría lo siguiente:

ls | select -Property Name

Esto sigue devolviendo objetos DirectoryInfo o FileInfo. Siempre puede inspeccionar el tipo que llega a través de la tubería por tuberías a Get-Member (alias gm ).

ls | select -Property Name | gm

Entonces, para expandir el objeto para que sea del tipo de propiedad que está mirando, puede hacer lo siguiente:

ls | select -ExpandProperty Name

En su caso, puede hacer lo siguiente para que una variable sea una matriz de cadenas, donde las cadenas son la propiedad Nombre:

$objects = ls | select -ExpandProperty Name


Para complementar las respuestas preexistentes y útiles con orientación de cuándo usar qué enfoque y una comparación de rendimiento .

  • Fuera de una tubería, use:

    $objects.Name (PSv3 +), como se demostró en la respuesta de rageandqq , que es sintácticamente más simple y mucho más rápido .

    • Acceder a una propiedad en el nivel de colección para obtener los valores de sus miembros como una matriz se denomina enumeración de miembros y es una función de PSv3 + ;
    • Compensaciones :
      • Tanto la matriz de entrada como la de salida deben caber en la memoria como un todo .
      • Si la colección de entrada es en sí misma el resultado de un comando (canalización) (por ejemplo, (Get-ChildItem).Name ), ese comando primero debe ejecutarse hasta su finalización antes de que se pueda acceder a los elementos de la matriz resultante.
  • En una tubería donde el resultado debe procesarse más a fondo o los resultados no encajan en la memoria como un todo, use:

    $objects | Select-Object -ExpandProperty Name

    • La necesidad de -ExpandProperty se explica en la respuesta de Scott Saad .
    • Obtendrá los beneficios normales de la línea de procesamiento uno por uno, que normalmente produce la salida de inmediato y mantiene el uso de la memoria constante (a menos que finalmente recopile los resultados en la memoria de todos modos).
    • Tradeoff :
      • El uso de la tubería es comparativamente lento .

Para pequeñas colecciones de entrada (matrices), probablemente no notará la diferencia , y, especialmente en la línea de comandos, a veces es más importante poder escribir el comando fácilmente.

Aquí hay una alternativa fácil de escribir , que, sin embargo, es el enfoque más lento ; usa una sintaxis ForEach-Object simplificada llamada una instrucción de operación (nuevamente, PSv3 +):; por ejemplo, la siguiente solución PSv3 + es fácil de agregar a un comando existente:

$objects | % Name # short for: $objects | ForEach-Object -Process { $_.Name }

En aras de la exhaustividad: el operador de recopilación de PSv4 + .ForEach() poco conocido es otra alternativa :

# By property name (string): $objects.ForEach(''Name'') # By script block (much slower): $objects.ForEach({ $_.Name })

  • Este enfoque es similar a la enumeración de miembros (los mismos intercambios), excepto más lento (aunque aún notablemente más rápido que la interconexión).

  • Para extraer un único valor de propiedad por nombre (argumento de cadena ), esta solución está a la par con la enumeración de miembros (aunque la última es sintácticamente más simple).

  • La variante script-block , aunque mucho más lenta, permite transformaciones arbitrarias; es una alternativa más rápida, todo en memoria a la vez, al cmdlet ForEach-Object basado en ForEach-Object .

Comparando el desempeño de los diferentes enfoques

Aquí están los tiempos de muestreo para los diversos enfoques, basados ​​en una colección de entrada de 100,000 objetos ; los números absolutos no son importantes y varían en función de muchos factores, pero deberían proporcionarle una sensación de rendimiento relativo :

Approach Seconds -------- ------- $objects.ForEach(''Number'') 0.060 $objects.Number 0.065 $objects | Select-Object -ExpandProperty Number 0.859 $objects.ForEach({ $_.Number }) 1.008 $objects | % Number 4.380

  • La solución más rápida basada en canalización es más de 10 veces más lenta que las soluciones de operador de recopilación basadas en enumeración / nombre de propiedad.

  • El uso de un bloque de scripts en cada iteración ralentiza las cosas dramáticamente, de modo que la solución más rápida basada en canalización ( Select-Object -Expand ) supera a la collection-operativa basada en bloques de scripts

  • % Number es lo peor de ambos mundos: una canalización que usa un bloque de script en cada iteración (como se indica, % Number es el equivalente de % { $_.Number } ).

Nota: Curiosamente, ejecutar la misma prueba en PowerShell Core v6.0.2 en macOS produce una clasificación diferente (aunque la observación básica acerca de las canalizaciones es mucho más lenta): la enumeración de miembros es más rápida e incluso la .ForEach() basada en bloques de secuencias de .ForEach() solución es notablemente más rápida que Select-Object -ExpandProperty .

Código fuente para las pruebas :

# Number of input objects to create. $count = 1e5 # 100,000 # Create sample input objects. $objects = 1..$count | % { [pscustomobject] @{ Number = $_ } } # An array of script blocks with the various approaches. $approaches = { $objects | Select-Object -ExpandProperty Number }, { $objects | % Number }, { $objects.ForEach(''Number'') }, { $objects.ForEach({ $_.Number }) }, { $objects.Number } # Time the approaches and sort them by execution time (fastest first): $approaches | % { $scriptBlock = $_ Measure-Command $scriptBlock | Select-Object @{ n=''Approach''; e = { $scriptBlock.ToString() } } , Ticks } | Sort-Object Ticks | Format-Table Approach, @{ n = ''Seconds''; e = { ''{0:N3}'' -f ($_.Ticks / 1e7) } }