Comment sortir quelque chose dans PowerShell

211

J'exécute un script PowerShell à partir d'un fichier de commandes. Le script récupère une page Web et vérifie si le contenu de la page est la chaîne "OK".

Le script PowerShell renvoie un niveau d'erreur au script batch.

Le script batch est exécuté par ScriptFTP , un programme d'automatisation FTP. Si une erreur se produit, je peux demander à ScriptFTP d'envoyer la sortie complète de la console à l'administrateur via E-Mail.

Dans le script PowerShell, je voudrais sortir la valeur de retour du site Web si elle n'est pas "OK", donc le message d'erreur est inclus dans la sortie de la console, et donc dans le courrier d'état.

Je suis nouveau sur PowerShell et je ne sais pas quelle fonction de sortie utiliser pour cela. J'en vois trois:

  • Write-Host
  • Sortie écriture
  • Erreur d'écriture

Quelle serait la bonne chose à utiliser pour écrire sur l'équivalent de Windows stdout?

Pekka
la source

Réponses:

197

Produire simplement quelque chose est PowerShell est une chose de beauté - et l'un de ses plus grands atouts. Par exemple, le Bonjour, monde! l'application est réduite à une seule ligne:

"Hello, World!"

Il crée un objet chaîne, attribue la valeur susmentionnée et, étant le dernier élément du pipeline de commandes, il appelle la .toString()méthode et génère le résultat STDOUT(par défaut). Une chose de beauté.

Les autres Write-*commandes sont spécifiques à la sortie du texte dans leurs flux associés et ont leur place en tant que telles.

Goyuix
la source
9
Ce n'est pas vraiment ce qui se passe. C'est une expression littérale de chaîne et la seule chose dans son pipeline. C'est donc équivalent à "Hello, World!" | Out-Host. Out-Hostd'autre part, envoie des objets à l'hôte PowerShell pour affichage et son implémentation dépend de l'hôte. L'hôte de la console les envoie à la poignée de sortie standard (en passant le Out-Defaultlong du chemin), en effet. Cependant, PowerShell ISE les affiche dans son volet de sortie et d'autres hôtes peuvent faire tout autre chose.
Joey
5
Les objets ne sont pas non plus convertis à l'aveugle en chaîne, mais passent par un formateur qui décide de ce qu'il faut en faire. C'est pourquoi vous voyez Get-ChildItemla sortie de venir sous forme de tableau, par exemple, et les résultats avec de nombreuses propriétés (par exemple WMI) par défaut à la Format-Listplace.
Joey
120

Je pense que dans ce cas, vous aurez besoin d' écriture-sortie .

Si vous avez un script comme

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

puis, si vous appelez le script avec une sortie redirigée, quelque chose comme yourscript.ps1 > out.txt, vous obtiendrez test2à l'écran test1\ntest3\ndans le "out.txt".

Notez que «test3» et la ligne de sortie d'écriture ajouteront toujours une nouvelle ligne à votre texte et il n'y a aucun moyen dans PowerShell de l'arrêter (c'est-à-dire, echo -nest impossible dans PowerShell avec les commandes natives). Si vous voulez (la fonctionnalité quelque peu basique et facile dans Bash ) de echo -nvoir la réponse de samthebest .

Si un fichier de commandes exécute une commande PowerShell, il capturera très probablement la commande Write-Output. J'ai eu de "longues discussions" avec les administrateurs système sur ce qui devrait être écrit sur la console et ce qui ne devrait pas l'être. Nous avons maintenant convenu que la seule information si le script a été exécuté avec succès ou est mort doit être Write-Hostéditée, et tout ce qui est l'auteur du script peut avoir besoin de savoir sur l'exécution (quels éléments ont été mis à jour, quels champs ont été définis, et cetera) en écriture-sortie. De cette façon, lorsque vous soumettez un script à l'administrateur système, il peut facilement runthescript.ps1 >someredirectedoutput.txtet voir à l'écran, si tout va bien. Renvoyez ensuite le fichier "someredirectedoutput.txt" aux développeurs.

naïvistes
la source
9

Je pense que ce qui suit est une bonne exposition d'Echo vs Write-Host . Remarquez comment test () retourne réellement un tableau d'ints, pas un seul entier comme on pourrait facilement le croire.

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])"

Sortie terminale de ce qui précède:

123
x of type 'Object[]' = 456 789
$x[0] = 456
$x[1] = 789
user2426679
la source
Je peux regarder ça toute la journée ... Mais pourquoi $x = testne fait qu'imprimer 123et pas aussi 456?
not2qubit
7

Vous pouvez utiliser n'importe lequel de ces éléments dans votre scénario, car ils écrivent dans les flux par défaut (sortie et erreur). Si vous dirigiez la sortie vers une autre commande, vous voudriez utiliser Write-Output , qui se terminera finalement dans Write-Host .

Cet article décrit les différentes options de sortie: PowerShell O est pour la sortie

GrayWizardx
la source
1
Merci pour le lien. Dieu, c'est compliqué . Si Write-host est une sorte de point d'extrémité ou de fonction de vidage, j'essaierai d'aller avec cela et de faire rapport.
Pekka
3
Write-Host "Found file - " + $File.FullName -ForegroundColor Magenta

Le magenta peut être l'une des valeurs de l'énumérateur "System.ConsoleColor" - noir, bleu foncé, vert foncé, cyan foncé, rouge foncé, DarkMagenta, jaune foncé, gris, gris foncé, bleu, vert, cyan, rouge, magenta, jaune, blanc.

L' + $File.FullNameoption est facultative et montre comment insérer une variable dans la chaîne.

Jordan
la source
2

Vous ne pouvez tout simplement pas faire en sorte que PowerShell supprime ces nouvelles lignes ennuyeuses. Il n'y a aucun script ou applet de commande qui fait cela.

Bien sûr, Write-Host est un non-sens absolu car vous ne pouvez pas le rediriger / le canaliser! Il vous suffit d'écrire le vôtre:

using System;

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

Par exemple

PS C:\> writetostdout finally I can write to stdout like echo -n
finally I can write to stdout like echo -nPS C:\>
samthebest
la source
Vous pouvez le faire en PowerShell lui-même. [System.Console] :: Write ("stringy") Cependant, vous ne pourrez pas du tout le rediriger en PowerShell.
Nicholi
1
Sûr que vous pouvez. Voir cette question
Slogmeister Extraordinaire
1

Quelle serait la bonne chose à utiliser pour écrire sur l'équivalent Windows de stdout?

En effet , mais très malheureusement , à la fois Windows PowerShell et PowerShell Core à partir de la v7.0, envoient tous leurs 6 (!) Flux de sortie à stdout lorsqu'ils sont appelés de l'extérieur , via la CLI de PowerShell .

  • Consultez ce problème GitHub pour une discussion de ce comportement problématique, qui ne sera probablement pas résolu par souci de compatibilité descendante.

  • En pratique, cela signifie que le flux PowerShell auquel vous envoyez la sortie sera considéré comme une sortie standard par un appelant externe:

    • Par exemple, si vous exécutez ce qui suit à partir de cmd.exe, vous ne verrez aucune sortie, car la redirection stdout à NULs'applique également à tous les flux PowerShell:

      • C:\>powershell -noprofile -command "Write-Error error!" >NUL
    • Cependant - curieusement - si vous redirigez stderr , PowerShell n'envoie son flux d'erreur à stderr , de sorte que , 2>vous pouvez capturer la sortie flux d'erreur de manière sélective; les sorties suivantes uniquement 'hi'- la sortie du flux de réussite - tout en capturant la sortie du flux d'erreur dans le fichier err.txt:

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

Le comportement souhaitable est:

  • Envoyez le flux de sortie de réussite1 de PowerShell (numéro ) à stdout .
  • Envoyer la sortie de tous les autres flux à stderr , qui est la seule option, étant donné qu'entre les processus, il n'existe que 2 flux de sortie - stdout (sortie standard) pour les données et stderr (erreur standard) pour les messages d'erreur et tous les autres types de messages - tels que comme informations d'état - ce ne sont pas des données .

  • Il est conseillé de faire cette distinction dans votre code, même si elle n'est actuellement pas respectée .


À l'intérieur de PowerShell :

  • Write-Hostsert à afficher la sortie et contourne le flux de sortie de réussite - en tant que tel, sa sortie ne peut ni être (directement) capturée dans une variable ni supprimée ni redirigée.

    • Son intention initiale était simplement de créer des commentaires des utilisateurs et de créer des interfaces utilisateur simples basées sur la console (sortie colorée).

    • En raison de l'impossibilité antérieure d'être capturé ou redirigé, PowerShell version 5 a fait Write-Hostle flux d'informations nouvellement introduit (nombre 6), donc depuis lors, il est possible de capturer et de rediriger la Write-Hostsortie.

  • Write-Errorest destiné à écrire des erreurs sans fin dans le flux d'erreurs (nombre 2); conceptuellement, le flux d'erreur est l'équivalent de stderr.

  • Write-Outputécrit dans le flux de succès [sortie] (nombre 1), qui est conceptuellement équivalent à stdout; c'est le flux dans lequel écrire les données (résultats).

    • Cependant, l'utilisation explicite de Write-Outputest rarement nécessaire en raison de la fonctionnalité de sortie implicite de PowerShell :
      • La sortie de toute commande ou expression qui n'est pas explicitement capturée, supprimée ou redirigée est automatiquement envoyée au flux de réussite ; par exemple, Write-Output "Honey, I'm $HOME"et "Honey, I'm $HOME"sont équivalents, ce dernier étant non seulement plus concis, mais aussi plus rapide.
mklement0
la source