Jak wyprowadzić coś w PowerShell

210

Używam skryptu PowerShell z pliku wsadowego. Skrypt pobiera stronę internetową i sprawdza, czy zawartość strony to ciąg „OK”.

Skrypt PowerShell zwraca poziom błędu do skryptu wsadowego.

Skrypt wsadowy jest wykonywany przez ScriptFTP , program do automatyzacji FTP. Jeśli wystąpi błąd, mogę poprosić ScriptFTP o przesłanie pełnego wyjścia konsoli do administratora za pośrednictwem wiadomości e-mail.

W skrypcie PowerShell chciałbym wyprowadzić zwracaną wartość ze strony internetowej, jeśli nie jest ona „OK”, więc komunikat o błędzie zostaje dołączony do wyjścia konsoli, a tym samym do wiadomości statusu.

Jestem nowy w PowerShell i nie jestem pewien, której funkcji wyjściowej użyć do tego. Widzę trzy:

  • Host zapisu
  • Zapis-wyjście
  • Napisz błąd

Jaka byłaby właściwa rzecz do pisania w ekwiwalencie Windows stdout?

Pekka
źródło

Odpowiedzi:

196

Po prostu wysyłanie czegoś do PowerShell to kwestia piękna - i jedna z jego największych zalet. Na przykład wspólne Hello, World! aplikacja jest zredukowana do jednej linii:

"Hello, World!"

Tworzy obiekt łańcuchowy, przypisuje wspomnianą wartość i będąc ostatnim elementem w potoku poleceń, wywołuje .toString()metodę i wyświetla wynik STDOUT(domyślnie). Coś pięknego.

Inne Write-*polecenia są specyficzne dla wysyłania tekstu do powiązanych strumieni i mają swoje miejsce jako takie.

Goyuix
źródło
9
To nie do końca tak się dzieje. Jest to dosłowne wyrażenie łańcuchowe i jedyna rzecz na świecie. Zatem jest to równoważne z "Hello, World!" | Out-Host. Out-Hostz drugiej strony wysyła obiekty do hosta PowerShell w celu wyświetlenia, a jego implementacja zależy od hosta. Out-DefaultRzeczywiście host konsoli wysyła je do standardowego uchwytu wyjściowego (przechodząc po drodze). Jednak PowerShell ISE wyświetla je w okienku wyjściowym, a inne hosty mogą robić jeszcze inne rzeczy całkowicie.
Joey,
5
Obiekty również nie są ślepo konwertowane na ciąg znaków, ale przechodzą przez formater, który decyduje, co z nimi zrobić. Dlatego widzisz Get-ChildItemna przykład dane wyjściowe w postaci tabeli, a Format-Listzamiast nich wyniki z wieloma właściwościami (np. WMI) .
Joey,
120

Myślę, że w tym przypadku będziesz potrzebować Write-Output .

Jeśli masz skrypt podobny do

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

następnie, jeśli wywołasz skrypt z przekierowanym wyjściem, coś w rodzaju yourscript.ps1 > out.txt, pojawi się test2na ekranie test1\ntest3\nw „out.txt”.

Zauważ, że „test3” i wiersz Write-Output zawsze dołączają nowy wiersz do tekstu i nie ma możliwości, aby PowerShell to powstrzymał (to znaczy, że nie jest echo -nto możliwe w PowerShell z natywnymi poleceniami). Jeśli chcesz (nieco podstawowa i łatwa w Bash ) funkcjonalność, echo -nzobacz odpowiedź samthebest .

Jeśli plik wsadowy uruchamia polecenie PowerShell, najprawdopodobniej przechwyci polecenie Write-Output. Przeprowadziłem „długie dyskusje” z administratorami systemu na temat tego, co należy napisać na konsoli, a co nie. Uzgodniliśmy teraz, że jedyną informacją, czy skrypt wykonał się pomyślnie lub zmarł, musi być Write-Host„zredagowany” i wszystko, co jest autorem skryptu, może wymagać wiedzieć o wykonaniu (jakie elementy zostały zaktualizowane, jakie pola zostały ustawione itd.) do zapisu-wyjścia. W ten sposób, po przesłaniu skryptu do administratora systemu, może on łatwo runthescript.ps1 >someredirectedoutput.txtzobaczyć na ekranie, czy wszystko jest w porządku. Następnie odeślij plik „someredirectedoutput.txt” z powrotem do programistów.

naiwiści
źródło
9

Myślę, że poniższe przedstawienie jest dobrym przykładem Echo vs. Write-Host . Zauważ, jak test () faktycznie zwraca tablicę liczb całkowitych, a nie pojedynczą liczbę całkowitą, w którą można łatwo uwierzyć.

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

Wyjście końcowe powyższego:

123
x of type 'Object[]' = 456 789
$x[0] = 456
$x[1] = 789
użytkownik2426679
źródło
Mogę na to patrzeć cały dzień ... Ale dlaczego $x = testdrukuje, 123a nie także 456?
not2qubit
7

Możesz użyć dowolnego z nich w scenariuszu, ponieważ zapisują one w domyślnych strumieniach (dane wyjściowe i błędy). Jeśli przesyłałeś dane wyjściowe do innego polecenia, powinieneś użyć Write-Output , które ostatecznie zakończy się w Write-Host .

W tym artykule opisano różne opcje danych wyjściowych: PowerShell O służy do danych wyjściowych

GrayWizardx
źródło
1
Dzięki za link. Boże, to skomplikowane . Jeśli Host zapisu jest jakimś punktem końcowym lub funkcją opróżniania, spróbuję to zrobić i zgłosić się z powrotem.
Pekka
3
Write-Host "Found file - " + $File.FullName -ForegroundColor Magenta

Magenta może być jedną z wartości modułu wyliczającego „System.ConsoleColor” - Czarny, DarkBlue, DarkGreen, DarkCyan, DarkRed, DarkMagenta, DarkYellow, Szary, DarkGray, Niebieski, Zielony, Cyjan, Czerwony, Magenta, Żółty, Biały.

+ $File.FullNameJest opcjonalny, i pokazuje, jak wprowadzić zmienną do łańcucha.

Jordania
źródło
2

Po prostu nie można zmusić programu PowerShell do opuszczenia tych irytujących nowych linii. Nie ma takiego skryptu ani polecenia cmdlet.

Oczywiście Write-Host jest absolutnym nonsensem, ponieważ nie można przekierować / potokować z niego! Musisz po prostu napisać własny:

using System;

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

Na przykład

PS C:\> writetostdout finally I can write to stdout like echo -n
finally I can write to stdout like echo -nPS C:\>
samthebest
źródło
Możesz to zrobić w samym programie PowerShell. [System.Console] :: Write („stringy”) Jednak nie będziesz w stanie przekierować go w ogóle w PowerShell.
Nicholi
1
Oczywiście że możesz. Zobacz to pytanie
Slogmeister Extraordinaire
1

Jaka byłaby właściwa rzecz do napisania w Windows odpowiedniku standardowego?

W efekcie , ale bardzo niestety , zarówno Windows PowerShell , jak i PowerShell Core od wersji 7.0, wysyłają wszystkie swoje 6 (!) Strumienie wyjściowe na standardowe wyjście, gdy są wywoływane z zewnątrz , za pośrednictwem CLI PowerShell .

  • Zobacz ten problem GitHub, aby omówić to problematyczne zachowanie, które prawdopodobnie nie zostanie naprawione ze względu na kompatybilność wsteczną.

  • W praktyce oznacza to, że cokolwiek PowerShell strumieniu wysłać wyjście będzie postrzegana jako stdout wyjściu przez zewnętrznego rozmówcy:

    • Na przykład, jeśli uruchomisz następujące z cmd.exe, nie zobaczysz żadnych danych wyjściowych, ponieważ standardowe przekierowanie do NULstosuje się jednakowo do wszystkich strumieni PowerShell:

      • C:\>powershell -noprofile -command "Write-Error error!" >NUL
    • Jednak - co ciekawe - jeśli przekierować stderr , PowerShell nie wysyłać jej strumień błędów na stderr , tak że z 2>ty może przechwycić wyjście błędów strumienia selektywnie; tylko następujące wyniki 'hi'- wyjście strumienia sukcesu - podczas przechwytywania wyniku strumienia błędów w pliku err.txt:

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

Pożądane zachowanie jest:

  • Wyślij PowerShell jest strumień wyjściowy sukces (numer 1) do stdout .
  • Wyślij dane wyjściowe ze wszystkich innych strumieni do stderr , co jest jedyną opcją, biorąc pod uwagę, że między procesami istnieją tylko 2 strumienie wyjściowe - stdout (standardowe wyjście) dla danych i stderr (standardowy błąd) dla komunikatów o błędach i wszystkie inne typy komunikatów - takie jako informacje o statusie - to nie są dane .

  • Wskazane jest wprowadzenie tego rozróżnienia w kodzie, nawet jeśli obecnie nie jest ono przestrzegane .


Wewnątrz programu PowerShell :

  • Write-Hostsłuży do wyświetlania danych wyjściowych i omija strumień wyjściowy sukcesu - jako taki, jego dane wyjściowe nie mogą być (bezpośrednio) uchwycone w zmiennej, ani tłumione, ani przekierowywane.

    • Jego pierwotnym celem było po prostu tworzenie opinii użytkowników i tworzenie prostych interfejsów użytkownika opartych na konsoli (kolorowe wydruki).

    • Ze względu na wcześniejszej niezdolności do niewoli lub przekierowywany PowerShell w wersji 5 wykonane Write-Hostna nowo wprowadzonego strumienia informacji (liczby 6), więc od tego czasu jest możliwe do przechwytywania i przekierować Write-Hostwyjście.

  • Write-Errorsłuży do zapisywania błędów nie kończących się w strumieniu błędów (liczba 2); koncepcyjnie strumień błędów jest odpowiednikiem stderr.

  • Write-Outputzapisuje do strumienia powodzenia [wyjściowego] (liczba 1), który jest koncepcyjnie równoważny stdout; to strumień do zapisywania danych (wyników).

    • Jednak jawne użycie Write-Outputjest rzadko potrzebne ze względu na domyślną funkcję wyjściową PowerShell :
      • Dane wyjściowe z dowolnego polecenia lub wyrażenia, które nie zostały wyraźnie przechwycone, pominięte lub przekierowane, są automatycznie wysyłane do strumienia powodzenia ; np. Write-Output "Honey, I'm $HOME"i "Honey, I'm $HOME"są równoważne, przy czym te ostatnie są nie tylko bardziej zwięzłe, ale także szybsze.
mklement0
źródło