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 torpemente6>
; 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.
-
Cuando se envía a la consola
, si el
primer
objeto tiene
formato de tabla
(si se aplica
-
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) esSystem.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.
-
Como principiante, puede pensar erróneamente que
-
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 cmdletWrite-Information
.
Por el contrario, laOut-Host
todavía no se puede redirigir.
-
Dicho esto, comenzando con PowerShell v5.0, ahora
puede
redirigir su salida a través del
flujo de información
recientemente introducido (número
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 deRead-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.
-
Sin embargo, generalmente es mejor usar
Write-Verbose
yWrite-Debug
en tales casos.
-
Sin embargo, generalmente es mejor usar