powershell

PowerShell: la salida de escritura solo escribe un objeto



(3)

En general, la expectativa es que el script / funciones devuelvan un solo "tipo" de objeto, a menudo con muchas instancias. Por ejemplo, Get-Process devuelve una carga de procesos, pero todos tienen los mismos campos. Como habrá visto en los tutoriales, etc., puede pasar la salida de Get-Process largo de una tubería y procesar los datos con cmdlets posteriores.

En su caso, está devolviendo dos tipos diferentes de objeto (es decir, con dos conjuntos diferentes de propiedades). PS genera el primer objeto, pero no el segundo (que no coincide con el primero) como descubrió. Si tuviera que agregar propiedades adicionales al primer objeto que coincidan con las utilizadas en el segundo, entonces vería ambos objetos.

Write-Host no se preocupa por este tipo de cosas. El rechazo en contra de usar esto tiene que ver principalmente con (1) que es una forma perezosa de dar retroalimentación sobre el progreso del script, es decir, usar Write-Verbose o Write-Debug lugar y (2) es imperfecto cuando se trata de pasar objetos a lo largo de una tubería, etc.

Aclaración sobre el punto (2), útilmente planteada en los comentarios a esta respuesta:

Write-Host no solo es imperfecto con respecto a la captura de canalización / redirección / salida, simplemente no puede usarlo para eso en PSv4 y versiones anteriores, y en PSv5 + debe usar torpemente 6> ; también, Write-Host stringifica con .ToString() , que a menudo produce representaciones inútiles

Si su script realmente está destinado a imprimir datos en la consola, continúe y Write-Host .

Alternativamente, puede devolver múltiples objetos desde un script o función. Usando return o Write-Output , solo devuelve objetos de objetos separados por comas. Por ejemplo:

Test-WriteOutput.ps1

$object1 = [PSCustomObject]@{ OSBuild = "910ef01.2.8779" OSVersion = "CustomOS 3" BIOSSerial = "A5FT-XT2H-5A4B-X9NM" } $object2 = [PSCustomObject]@{ Site = "SQL site" Server= "SQL Server" Database="SQL Database" } Write-Output $object1,$object2

Ejecutan el script, asignando la salida en dos variables:

$a,$b = ./Test-WriteOutput.ps1

Verá que $ a es $ object1 y $ b es $ object2 .

Estoy aprendiendo PowerShell y una gran cantidad de artículos que leí desalientan el uso de host de escritura diciéndome que es una "mala práctica" y casi siempre, la salida se puede mostrar de otra manera.

Entonces, sigo el consejo y trato de evitar el uso de host de escritura. Una sugerencia que encontré fue usar escritura de salida en su lugar. Por lo que yo entiendo, esto pone todo en una tubería, y la salida se ejecuta al final del script (?).

Sin embargo, tengo problemas para generar lo que quiero. Este ejemplo demuestra el problema:

$properties = @{''OSBuild''="910ef01.2.8779"; ''OSVersion''="CustomOS 3"; ''BIOSSerial''="A5FT-XT2H-5A4B-X9NM"} $object = New-Object –TypeName PSObject –Prop $properties Write-output $object $properties = @{''Site''="SQL site"; ''Server''="SQL Server"; ''Database''="SQL Database"} $object = New-Object –TypeName PSObject –Prop $properties Write-Output $object

De esta manera obtengo una buena salida del primer objeto que muestra los datos del sistema operativo, pero el segundo objeto que contiene los datos SQL nunca se muestra. He intentado renombrar los nombres de las variables y un montón de otras cosas diferentes, pero no tuve suerte.

Mientras solucionaba este problema, encontré problemas similares con sugerencias para reemplazar la salida de escritura con host de escritura. Esto me confunde mucho. ¿Por qué algunas personas desalientan fuertemente el host de escritura, mientras que otras lo alientan?

¿Y cómo exactamente saco estos dos objetos de una manera elegante? No entiendo completamente el mecanismo de canalización de la salida de escritura.


use write-host, write-output es para canalización (y de forma predeterminada en la consola después de borrar)


  • Solo para aclarar: el problema es solo un problema de visualización :

    • Cuando se envía a la consola , si el primer objeto tiene formato de tabla (si se aplica Format-Table , que sucede implícitamente en su caso), las columnas de visualización se bloquean en función de las propiedades de ese primer objeto.
      Como su segundo objeto de salida no comparte propiedades con el primero, no contribuye en nada a la visualización de la tabla y, por lo tanto, es efectivamente invisible.
    • Por el contrario, si procesa programáticamente la salida del script, asígnela a una variable o envíe su salida a través de la tubería a otro comando, ambos objetos estarán allí.
      • Vea la respuesta de Charlie Joynt para un ejemplo útil de asignar los dos objetos de salida a variables separadas.
  • La solución más simple para el problema de visualización es formatear explícitamente para mostrar cada objeto de entrada individualmente ; consulte a continuación.

Para un solo objeto dado dentro de un script, puede forzar la salida formateada para mostrar (a host) con Out-Host :

$object | Out-Host # same as: Write-Output $object | Out-Host

Sin embargo, tenga en cuenta que esto se envía directa e invariablemente solo a la consola y el objeto no forma parte de la salida de datos del script (los objetos escritos en la secuencia de salida de éxito , la secuencia con el índice 1 ).
En otras palabras: si intenta asignar la salida del script a una variable o enviar su salida a otro comando en una tubería, ese objeto no estará allí.

Vea a continuación por qué Out-Host es preferible a Write-Host , y por qué es mejor evitar Write-Host en la mayoría de las situaciones.

Para aplicar la técnica ad hoc a la salida de un script en su conjunto, para asegurarse de que ve todos los objetos de salida , use:

./some-script.ps1 | % { $_ | Out-String } # % is the built-in alias of ForEach-Object

Tenga en cuenta que aquí también puede usar Out-Host , pero la ventaja de usar Out-String es que aún le permite capturar la representación para visualización en un archivo, si lo desea.

Aquí hay una función auxiliar simple (filtro) que puede poner en su $PROFILE :

# Once defined, you can use: ./some-script.ps1 | Format-Each Filter Format-Each { $_ | Out-String }

PetSerAl - ./some-script.ps1 | Format-List ./some-script.ps1 | Format-List : también funciona en principio, pero cambia la salida de la salida de estilo de tabla habitual a la salida de estilo de lista , con cada propiedad listada en su propia línea, que puede no ser deseada.
Sin embargo, a la inversa, Format-Each , si un objeto de salida está (implícitamente) con formato de tabla, imprime un encabezado para cada objeto.

Por qué Write-Output no ayuda:

Write-Output no ayuda, porque de todos modos escribe a dónde van los objetos de salida de forma predeterminada: el flujo de salida de éxito mencionado anteriormente, donde deben ir los datos .

Si los objetos de la secuencia de salida no se redirigen o capturan de alguna forma, se envían al host de forma predeterminada (normalmente, la consola ), donde se aplica el formato automático.

Además, el uso de Write-Output rara vez es necesario , porque simplemente no capturar o redirigir un comando o expresión escribe implícitamente en la secuencia de éxito; Otra forma de decirlo:
Write-Output está implícita .

Por lo tanto, las siguientes dos declaraciones son equivalentes:

Write-Output $object # write $object to the success output stream $object # same; *implicitly* writes $object to the success output stream

Por qué el uso de Write-Host es aconsejable, tanto aquí como a menudo en general:

Suponiendo que conozca las implicaciones del uso de Write-Host en general, vea a continuación, podría usarlo para el problema en cuestión, pero Write-Host aplica un .ToString() simple .ToString() a su entrada , lo que no le da la ventaja, formato de varias líneas que PowerShell aplica de forma predeterminada.
Por lo tanto, Out-Host (y Out-String ) se usaron anteriormente, porque aplican el mismo formato amigable.

Contraste las siguientes dos declaraciones, que imprimen un literal de [hashtable] ( [hashtable] ):

# (Optional) use of Write-Output: The friendly, multi-line default formatting is used. # ... | Out-Host and ... | Out-String would print the same. PS> Write-Output @{ foo = 1; bar = ''baz'' } Name Value ---- ----- bar baz foo 1 # Write-Host: The hashtable''s *entries* are *individually* stringified # and the result prints straight to the console. PS> Write-Host @{ foo = 1; bar = ''baz'' } System.Collections.DictionaryEntry System.Collections.DictionaryEntry

Write-Host hizo dos cosas aquí, lo que resultó en una salida casi inútil:

  • Las entradas de la instancia de [hashtable] se enumeraron y cada entrada se encadenó individualmente.

  • La .ToString() de las entradas de la tabla hash (pares clave-valor) es System.Collections.DictionaryEntry , es decir, simplemente el nombre de tipo de la instancia.

Las razones principales para evitar Write-Host en general son :

  • Sale directamente al host (consola) en lugar de a la secuencia de salida de éxito de PowerShell.

    • Como principiante, puede pensar erróneamente que Write-Host es para escribir resultados (datos), pero no lo es.
  • Al pasar por alto el sistema de secuencias de PowerShell, la salida de Write-Host no se puede redirigir , es decir, no se puede suprimir ni capturar (en un archivo o variable).

    • Dicho esto, comenzando con PowerShell v5.0, ahora puede redirigir su salida a través del flujo de información recientemente introducido (número 6 ; por ejemplo, ./some-script.ps1 6>write-host-output.txt ); sin embargo, esa secuencia se usa más correctamente con el nuevo cmdlet Write-Information .
      Por el contrario, la Out-Host todavía no se puede redirigir.

Eso deja solo los siguientes usos legítimos de Write-Host :

  • Crear avisos para el usuario final y representaciones de color solo para visualización :

    • Su script puede tener mensajes interactivos que solicitan información del usuario; el uso de Write-Host , opcionalmente con coloración a través de los parámetros -ForegroundColor y -BackgroundColor , es apropiado, dado que las cadenas de solicitud no deben formar parte de la salida del script y los usuarios también proporcionan su entrada a través del host (generalmente a través de Read-Host ).

    • Del mismo modo, puede usar Write-Host con coloración selectiva para crear explícitamente representaciones más amigables solo para visualización .

  • Creación rápida de prototipos : si desea una forma rápida y sucia de escribir información de estado / diagnóstico directamente en la consola sin interferir con la salida de datos de un script.