Cómo generar algo en PowerShell

211

Estoy ejecutando un script de PowerShell desde un archivo por lotes. El script busca una página web y comprueba si el contenido de la página es la cadena "OK".

El script de PowerShell devuelve un nivel de error al script por lotes.

El script por lotes es ejecutado por ScriptFTP , un programa de automatización FTP. Si se produce un error, puedo hacer que ScriptFTP envíe la salida de la consola completa al administrador por correo electrónico.

En el script de PowerShell, me gustaría generar el valor de retorno del sitio web si no está "OK", por lo que el mensaje de error se incluye en el resultado de la consola y, por lo tanto, en el correo de estado.

Soy nuevo en PowerShell y no estoy seguro de qué función de salida usar para esto. Puedo ver tres:

  • Host de escritura
  • Salida de escritura
  • Error de escritura

¿Cuál sería el uso correcto para escribir en el equivalente de Windows stdout?

Pekka
fuente

Respuestas:

197

Simplemente dar salida a algo es PowerShell es algo bello, y uno de sus mayores puntos fuertes. Por ejemplo, el común Hello, World! la aplicación se reduce a una sola línea:

"Hello, World!"

Crea un objeto de cadena, asigna el valor mencionado anteriormente y, al ser el último elemento en la canalización de comandos, llama al .toString()método y genera el resultado STDOUT(de forma predeterminada). Una cosa de belleza.

El otro Write-* comandos son específicos para enviar el texto a sus secuencias asociadas y tienen su lugar como tal.

Goyuix
fuente
9
Eso no es realmente lo que pasa. Es una expresión literal de cadena y lo único en su cartera. Por lo tanto, es equivalente a "Hello, World!" | Out-Host. Out-Hostpor otro lado, envía objetos al host de PowerShell para su visualización y su implementación depende del host. El host de la consola los envía al controlador de salida estándar (pasando por Out-Defaultel camino), de hecho. PowerShell ISE los muestra en su panel de salida, sin embargo, y otros hosts pueden hacer otras cosas por completo.
Joey
55
Los objetos tampoco se convierten ciegamente en cadenas, sino que pasan a través de un formateador que decide qué hacer con ellos. Es por eso que ve Get-ChildItemla salida de la tabla en forma de tabla, por ejemplo, y resultados con muchas propiedades (por ejemplo, WMI) predeterminadas en su Format-Listlugar.
Joey
120

Creo que en este caso necesitarás Write-Output .

Si tienes un script como

Write-Output "test1";
Write-Host "test2";
"test3";

luego, si llama al script con salida redirigida, algo así yourscript.ps1 > out.txt, aparecerá test2en la pantalla test1\ntest3\nen "out.txt".

Tenga en cuenta que "test3" y la línea Write-Output siempre agregarán una nueva línea a su texto y no hay forma en PowerShell de detener esto (es decir, echo -nes imposible en PowerShell con los comandos nativos). Si desea la funcionalidad (algo básica y fácil en Bash ) de echo -n, consulte la respuesta de samthebest .

Si un archivo por lotes ejecuta un comando de PowerShell, lo más probable es que capture el comando Write-Output. He tenido "largas discusiones" con los administradores del sistema sobre lo que se debe escribir en la consola y lo que no. Ahora hemos acordado que la única información si el script se ejecutó con éxito o murió tiene que ser Write-Hosteditado, y todo lo que es el autor del script podría necesitar saber sobre la ejecución (qué elementos se actualizaron, qué campos se configuraron, etc.) a Escribir-Salida. De esta manera, cuando envía un script al administrador del sistema, él puede runthescript.ps1 >someredirectedoutput.txtver fácilmente en la pantalla, si todo está bien. Luego envíe el "someredirectedoutput.txt" a los desarrolladores.

naivistas
fuente
9

Creo que lo siguiente es una buena exhibición de Echo vs. Write-Host . Observe cómo test () en realidad devuelve una matriz de entradas, no una única int como se podría hacer creer fácilmente.

function test {
    Write-Host 123
    echo 456 # AKA 'Write-Output'
    return 789
}

$x = test

Write-Host "x of type '$($x.GetType().name)' = $x"

Write-Host "`$x[0] = $($x[0])"
Write-Host "`$x[1] = $($x[1])"

Salida terminal de lo anterior:

123
x of type 'Object[]' = 456 789
$x[0] = 456
$x[1] = 789
usuario2426679
fuente
Puedo ver esto todo el día ... Pero ¿por qué $x = testsolo se imprime 123y no también 456?
not2qubit
7

Puede usar cualquiera de estos en su escenario ya que escriben en las transmisiones predeterminadas (salida y error). Si estaba canalizando la salida a otro comando, desearía usar Write-Output , que finalmente terminará en Write-Host .

Este artículo describe las diferentes opciones de salida: PowerShell O es para Salida

GrayWizardx
fuente
1
Gracias por el enlace. Dios, esto es complicado . Si Write-host es algún tipo de punto final o función de vaciado, intentaré con eso e informaré de nuevo.
Pekka
3
Write-Host "Found file - " + $File.FullName -ForegroundColor Magenta

Magenta puede ser uno de los valores del enumerador "System.ConsoleColor": negro, azul oscuro, verde oscuro, azul oscuro, rojo oscuro, magenta oscuro, amarillo oscuro, gris, gris oscuro, azul, verde, cian, rojo, magenta, amarillo, blanco.

El + $File.FullNamees opcional y muestra cómo colocar una variable en la cadena.

Jordán
fuente
2

Simplemente no puede hacer que PowerShell omita esas molestas líneas nuevas. No hay script o cmdlet que haga esto.

¡Por supuesto, Write-Host no tiene sentido porque no puedes redirigirlo / canalizarlo! Simplemente tienes que escribir el tuyo:

using System;

namespace WriteToStdout
{
    class Program
    {
        static void Main(string[] args)
        {
            if (args != null)
            {
                Console.Write(string.Join(" ", args));
            }
        }
    }
}

P.ej

PS C:\> writetostdout finally I can write to stdout like echo -n
finally I can write to stdout like echo -nPS C:\>
samthebest
fuente
Podrías hacer esto en PowerShell. [System.Console] :: Write ("stringy") Sin embargo, no podrá redirigirlo en PowerShell.
Nicholi
1
Seguro que puede. Ver esta pregunta
Slogmeister Extraordinaire
1

¿Qué sería lo correcto para escribir en Windows el equivalente de stdout?

En efecto , pero desafortunadamente , tanto Windows PowerShell como PowerShell Core a partir de v7.0 envían todas sus 6 (!) Secuencias de salida a stdout cuando se les llama desde el exterior , a través de PowerShell CLI .

  • Ver este problema de GitHub para una discusión de este comportamiento problemático, que probablemente no se solucionará por razones de compatibilidad con versiones anteriores.

  • En la práctica, esto significa que cualquier llamada de PowerShell a la que envíe la salida será vista como salida estándar por un llamador externo:

    • Por ejemplo, si ejecuta la siguiente desde cmd.exe, verá ninguna salida, porque la redirección de la salida estándar a NULse aplica por igual a todas las corrientes de PowerShell:

      • C:\>powershell -noprofile -command "Write-Error error!" >NUL
    • Sin embargo - curiosamente - si redirigir stderr , PowerShell hace enviar su flujo de error en stderr , de manera que con 2>usted puede capturar la salida de error de la corriente de forma selectiva; las siguientes salidas solo 'hi'- la salida de flujo de éxito - mientras captura la salida de flujo de error en el archivo err.txt:

      • C:\>powershell -noprofile -command "'hi'; Write-Error error!" 2>err.txt

El comportamiento deseable es:

  • Envíe el flujo de salida de éxito1 de PowerShell (número ) a stdout .
  • Envíe la salida de todas las demás secuencias a stderr , que es la única opción, dado que entre los procesos solo existen 2 secuencias de salida: stdout (salida estándar) para datos y stderr (error estándar) para mensajes de error y todos los demás tipos de mensajes, como como información de estado, que no son datos .

  • Es aconsejable hacer esta distinción en su código, a pesar de que actualmente no se está respetando .


Dentro de PowerShell :

  • Write-Hostes para mostrar la salida y omite el flujo de salida de éxito ; como tal, su salida no puede capturarse (directamente) en una variable ni suprimirse ni redirigirse.

    • Su intención original era simplemente crear comentarios de los usuarios y crear interfaces de usuario simples, basadas en la consola (salida en color).

    • Debido a la incapacidad previa para ser capturado o redirigido, PowerShell versión 5 se realizó Write-Hosten el flujo de información recientemente introducido (número 6), por lo que desde entonces es posible capturar y redirigir la Write-Hostsalida.

  • Write-Errorestá destinado a escribir errores sin terminación en la secuencia de errores (número 2); conceptualmente, el flujo de error es el equivalente de stderr.

  • Write-Outputescribe en la secuencia de éxito [salida] (número 1), que es conceptualmente equivalente a stdout; es el flujo para escribir datos (resultados).

    • Sin embargo, rara vez se necesita el uso explícitoWrite-Output debido a la función de salida implícita de PowerShell :
      • La salida de cualquier comando o expresión que no se captura, suprime o redirige explícitamente se envía automáticamente a la secuencia de éxito ; por ejemplo, Write-Output "Honey, I'm $HOME"y "Honey, I'm $HOME"son equivalentes, siendo este último no solo más conciso, sino también más rápido.
mklement0
fuente