Schluss mit Write-Host — PowerShells Ausgabeströme und Log-Design
· Go Komura · PowerShell, Windows, Protokollierung, Betriebsoptimierung, Automatisierung, Skript, Design, Wartbarkeit
„Das Skript läuft, aber wenn es fehlschlägt, habe ich keine Ahnung, was passiert ist“ — das ist mit Abstand die häufigste Beschwerde, die wir über produktiv eingesetzte PowerShell-Skripte hören. Und verfolgt man die Ursache, landet man fast immer bei derselben Struktur: Der Zustand der Verarbeitung wird ausschließlich über Write-Host ausgedrückt, und bei einem nächtlichen Lauf, den niemand beobachtet hat, ist nichts übrig geblieben.
PowerShell besitzt sechs Ausgabeströme, und jeder unterscheidet sich darin, für wen die Information bestimmt ist. Ist es ein zurückzugebender Wert? Etwas, das ein Mensch lesen soll? Etwas, das nur während einer Untersuchung gebraucht wird? Schreibt man mit diesem Unterschied im Kopf, verhält sich dasselbe Skript bei interaktiver Ausführung hilfreich und bei unbeaufsichtigter Ausführung maschinenlesbar. Leitet man stattdessen alles in Write-Host, sammelt sich nur Information an, die weder als Wert nutzbar ist noch in einem Log erhalten bleibt.
Dieser Artikel behandelt die Rollen der sechs Ströme, wo Write-Host tatsächlich hingehört, den Mechanismus, durch den Rückgabewerte von Funktionen verunreinigt werden, wie man dem Aufrufer die Kontrolle über die Ausführlichkeit überlässt, sowie ein strukturiertes Log-Muster, das sich im Produktivbetrieb tatsächlich einsetzen lässt.
1. Das Wichtigste zuerst
- PowerShell besitzt sechs Ausgabeströme. Erfolg (1), Fehler (2), Warnung (3), Ausführlich (4), Debug (5) und Information (6), jeweils per Nummer umleitbar.
*>erfasst alle Ströme.1 - Ab PowerShell 5.0 schreibt
Write-Hostin den Informationsstrom. Das bedeutet, es lässt sich mit6>umleiten und mit-InformationVariableerfassen. Davor konnte es weder erfasst noch unterdrückt werden.2 Write-Hostist ausschließlich für „Anzeige für einen Menschen“ gedacht. Sie können es nicht verwenden, um Werte zurückzugeben. Werte, die durch die Pipeline weitergereicht werden, laufen überWrite-Output(oder eine bloße Ausgabe).23- Eine Funktion gibt jedes innerhalb von ihr ausgegebene Objekt zurück. Ob ein
returnvorhanden ist, spielt keine Rolle. Der Standardweg ist, unerwünschte Ausgaben mit$null = ...zu verwerfen.4 - Fortschritt gehört zu
Write-Progress, der Verlauf der Verarbeitung zuWrite-Verbose. Die Fortschrittsanzeige ist kein umleitbarer Datenstrom.5 - Eine Funktion mit
[CmdletBinding()]erhält automatisch die gemeinsamen Parameter wie-Verbose,-Debugund-InformationAction. Die Ausführlichkeit in die Hand des Aufrufers zu legen, ist die richtige Antwort.67 - Die Standardwerte lohnt es sich zu merken.
$VerbosePreference,$DebugPreferenceund$InformationPreferencesind SilentlyContinue;$WarningPreferenceund$ErrorActionPreferencesind Continue.8 - Logs, die Sie später auswerten möchten, sollten strukturiert sein (ein JSON-Objekt pro Zeile). Möchten Sie das Bildschirmbild reproduzieren, lassen Sie
Start-Transcriptmitlaufen.9
2. Die sechs Ströme und ihre Adressaten
| # | Strom | Schreibender Befehl | Vorgesehener Leser | Standardeinstellung |
|---|---|---|---|---|
| 1 | Erfolg | Write-Output / bloße Ausgabe |
Nachgelagerte Verarbeitung (die Pipeline) | — |
| 2 | Fehler | Write-Error / throw |
Menschen + Überwachung | Continue |
| 3 | Warnung | Write-Warning |
Menschen | Continue |
| 4 | Ausführlich | Write-Verbose |
Menschen bei der Untersuchung | SilentlyContinue |
| 5 | Debug | Write-Debug |
Entwickler | SilentlyContinue |
| 6 | Information | Write-Information / Write-Host |
Menschen + Aufzeichnung | SilentlyContinue |
Die wichtigste Zeile dieser Tabelle ist die erste. Der Erfolgsstrom ist nicht der Ort, um Nachrichten für Menschen zu schreiben. Schreiben Sie dort eine für Menschen lesbare Zeichenkette hinein, fließt in dem Moment, in dem Sie diese Funktion mit | verketten, eine unerwartete Zeichenkette in die nachfolgende Verarbeitung.
function Get-KsTargetFile {
Write-Output "Searching for targets..." # [SCHLECHT] mischt sich in den Rückgabewert
Get-ChildItem -Path $path -Filter '*.csv'
}
# Der Aufrufer erwartet ein Array von FileInfo, aber am Anfang steht eine Zeichenkette
$files = Get-KsTargetFile
$files[0].FullName # -> leer (weil das erste Element eine Zeichenkette ist)
Richtig ist, Fortschrittsmeldungen an den ausführlichen oder den Informationsstrom zu senden.
function Get-KsTargetFile {
[CmdletBinding()]
param([string] $Path)
Write-Verbose "Searching for targets: $Path" # nur angezeigt, wenn -Verbose angegeben ist
Get-ChildItem -Path $Path -Filter '*.csv' # der Rückgabewert ist ausschließlich FileInfo
}
3. Ist Write-Host wirklich böse?
Die Behauptung „Write-Host niemals verwenden“ hat sich einst weit verbreitet, aber im modernen PowerShell hat sich die Lage geändert. Ab PowerShell 5.0 ist Write-Host als Schreibvorgang in den Informationsstrom (Nummer 6) implementiert, sodass Sie es mit 6> umleiten oder mit -InformationVariable erfassen können.2 Die damalige Kritik — „es kann nur auf den Bildschirm gehen und lässt sich nie wieder aufgreifen“ — trifft nicht mehr zu.
Dennoch sind die Einsatzmöglichkeiten begrenzt.
Wo Write-Host angemessen ist
- In interaktiven Werkzeugen, wenn Sie farbige Überschriften oder Trennlinien wünschen (
-ForegroundColor) - Wenn Sie dem Benutzer mitteilen, was das Skript als Nächstes tun wird
- Wenn die dekorierte Anzeige selbst, nicht ein Verarbeitungswert, der eigentliche Zweck ist
Wo Write-Host nicht verwendet werden darf
- Wenn Sie einen Wert als Rückgabewert der Funktion übergeben möchten (→
Write-Output) - Wenn Sie ein Betriebslog für die spätere Analyse hinterlassen möchten (→ strukturiertes Logging, oder
Write-Information) - Wenn der Aufrufer die Anzeige ein- und ausschalten können soll (→
Write-Verbose)
In einem unbeaufsichtigten Skript gibt es überhaupt kein Anzeigeziel. Ein Skript, das seinen Zustand nur über Write-Host ausdrückt, wird in dem Moment, in dem es von der Aufgabenplanung ausgeführt wird, zu „einem Skript, das nichts verrät“. Genau darauf zielt der Titel dieses Artikels ab.
4. Dem Aufrufer die Kontrolle überlassen — [CmdletBinding()] und die gemeinsamen Parameter
Der eigentliche Wert von Write-Verbose liegt darin, dass der Aufrufer entscheidet, ob es angezeigt wird. Fügt man einer Funktion einfach [CmdletBinding()] hinzu, stehen automatisch gemeinsame Parameter wie -Verbose, -Debug, -WarningAction, -InformationAction und -ErrorAction zur Verfügung.67
function Invoke-KsImport {
[CmdletBinding()]
param(
[Parameter(Mandatory)] [string] $CsvPath
)
Write-Verbose "Import started: $CsvPath" # standardmäßig nicht angezeigt
Write-Information "Importing: $CsvPath" -Tags 'KsImport' # standardmäßig nicht angezeigt (aber erfassbar)
$rows = Import-Csv -Path $CsvPath
if ($rows.Count -eq 0) {
Write-Warning "$CsvPath contains nothing to import" # standardmäßig angezeigt
return
}
Write-Verbose "Processing $($rows.Count) rows"
$rows | ForEach-Object { ConvertTo-KsRecord $_ } # allein dies ist der Rückgabewert
}
# Normaler Lauf: nur Warnungen werden angezeigt, und der Rückgabewert sind die Datensätze
$records = Invoke-KsImport -CsvPath 'D:\in\orders.csv'
# Während der Untersuchung: wir wollen auch den Fortschritt sehen
$records = Invoke-KsImport -CsvPath 'D:\in\orders.csv' -Verbose
# Nur den Informationsstrom in einer Variablen erfassen, dann in eine Log-Datei schreiben
$records = Invoke-KsImport -CsvPath 'D:\in\orders.csv' -InformationVariable info
$info | ForEach-Object { $_.MessageData } | Add-Content -Path $logPath
Man sieht häufig Implementierungen, die eine $LogLevel-Variable erfinden und mit if-Anweisungen verzweigen, aber sich auf den Standardmechanismus zu stützen ist kürzer und vermittelt anderen die eigene Absicht. Dass das Hinzufügen von -Verbose Details liefert, ist gemeinsames Wissen aller PowerShell-Nutzer.
Beachten Sie, dass Präferenzvariablen wie $VerbosePreference für den aktuellen Gültigkeitsbereich und dessen untergeordnete Bereiche gelten.8 Ruft man eine Funktion mit -Verbose auf, beginnen auch die von innen aufgerufenen Cmdlets, ausführliche Ausgaben zu erzeugen, sodass mehr Ausgabe entstehen kann als erwartet.
5. Verunreinigte Rückgabewerte — eine PowerShell-spezifische Falle
PowerShell-Funktionen geben jedes innerhalb von ihnen ausgegebene Objekt zurück, auch ohne explizites return.4 Das ist ein mächtiges Designmerkmal, zugleich aber auch die Quelle der meisten Unfälle.
function New-KsWorkFolder {
param([string] $Path)
New-Item -Path $Path -ItemType Directory # [FALLE] DirectoryInfo mischt sich in den Rückgabewert
$list = [System.Collections.Generic.List[string]]::new()
$list.Add('log') # [FALLE 2] .Add() ist void, daher kein Schaden
$sb = [System.Text.StringBuilder]::new()
$sb.Append('x') # [FALLE 3] der StringBuilder selbst wird zurückgegeben
return $Path
}
$p = New-KsWorkFolder -Path 'D:\work' # $p wird zu einem dreielementigen Array (DirectoryInfo, StringBuilder, string)
Die Lösung besteht darin, „die unerwünschte Ausgabe wegzuwerfen“. Es gibt drei Schreibweisen, aber $null = ... ist die leichteste.
$null = New-Item -Path $Path -ItemType Directory # empfohlen
New-Item -Path $Path -ItemType Directory | Out-Null # langsamer um die Kosten der Pipe
[void] $sb.Append('x') # häufig für .NET-Methoden verwendet
Schreiben Sie einen Test, und Sie bemerken dieses Verhalten sofort. Wie wichtig Tests sind, die „die Form des Rückgabewerts festlegen“, wird in „PowerShell mit Pester testen — Ein praktischer Ansatz, um Betriebsskripte widerstandsfähiger zu machen“ behandelt.
6. Umleitung und Erfassung
Ströme lassen sich einzeln per Nummer umleiten.1
.\Invoke-NightlyExport.ps1 3> warnings.log # nur Warnungen in eine separate Datei
.\Invoke-NightlyExport.ps1 4>&1 | Tee-Object -FilePath run.log # ausführliche Ausgaben in den Erfolgsstrom einfließen lassen
.\Invoke-NightlyExport.ps1 *> all.log # alle Ströme in eine Datei
.\Invoke-NightlyExport.ps1 2>&1 | Where-Object { $_ -is [System.Management.Automation.ErrorRecord] }
> überschreibt und >> hängt an. Beachten Sie jedoch, dass das Zusammenführen per Umleitung Typen vermischt. Führen Sie wie im obigen Beispiel den Fehlerstrom eines PowerShell-Skripts oder einer Funktion zusammen, bleiben die Elemente ErrorRecord-Objekte, sodass Sie sie wie oben nach Typ sortieren können.
Andererseits verhält sich 2>&1 bei einem externen Programm (einem nativen Befehl) anders. Ab PowerShell 7.4 wird die umgeleitete Ausgabe als Bytestrom behandelt und wird nach dem Zusammenführen zu Zeichenketten, sodass eine Sortierung nach ErrorRecord nicht mehr funktioniert. Wenn Sie stdout und stderr eines externen Befehls unterscheiden müssen, empfangen Sie sie getrennt, statt sie zusammenzuführen (siehe „Externe Programme korrekt aus PowerShell aufrufen“).
Wenn Sie einen vollständigen Nachweis eines Laufs behalten möchten, ist Start-Transcript die einfache Option. Es zeichnet die Befehle und Ausgaben der Sitzung als Text auf, sodass Sie später rekonstruieren können, „was zu diesem Zeitpunkt auf dem Bildschirm stand“.9
Start-Transcript -Path "C:\Logs\export_$(Get-Date -f yyyyMMdd_HHmmss).log" -Append
try { Invoke-KsExport }
finally { Stop-Transcript }
7. Logs später analysierbar machen — strukturiertes Logging
Logs, die Menschen lesen, und Logs, die Maschinen aggregieren, sind unterschiedliche Dinge. Wenn Sie wissen möchten, „wie oft ist dieser Fehler letzten Monat aufgetreten?“, wird frei formulierter Text zu einem Ausdauerkampf mit grep. Schreiben Sie ein JSON-Objekt pro Zeile (JSON Lines), und die Auswertung lässt sich vollständig mit PowerShell erledigen.
function Write-KsLog {
[CmdletBinding()]
param(
[Parameter(Mandatory)] [ValidateSet('INFO','WARN','ERROR')] [string] $Level,
[Parameter(Mandatory)] [string] $Message,
[hashtable] $Data,
[string] $Path = $script:KsLogPath
)
$entry = [ordered]@{
ts = (Get-Date).ToString('o') # ISO 8601: leicht zu sortieren und zu korrelieren
level = $Level
message = $Message
script = $MyInvocation.ScriptName
host = $env:COMPUTERNAME
user = $env:USERNAME
}
# Zusätzliche Informationen unter data ablegen. Mischt man sie auf die oberste Ebene, kann
# der Aufrufer mit Schlüsseln wie level oder user die Basisfelder überschreiben
if ($Data) { $entry['data'] = $Data }
# -Compress bringt es auf eine Zeile. Anhängen mit Add-Content (UTF-8)
$entry | ConvertTo-Json -Compress -Depth 5 | Add-Content -Path $Path -Encoding utf8
# Die für Menschen bestimmte Anzeige stützt sich auf den Standardmechanismus (wird auf dem Bildschirm angezeigt, aber kein Wert wird zurückgegeben)
switch ($Level) {
# -ErrorAction nicht angeben. Legte man es hier fest, könnte der Aufrufer
# daraus mit -ErrorAction Stop keinen abbrechenden Fehler mehr machen
'ERROR' { Write-Error $Message }
'WARN' { Write-Warning $Message }
default { Write-Verbose $Message }
}
}
# Anwendungsbeispiel
Write-KsLog -Level INFO -Message 'Import complete' -Data @{ rows = 1250; file = 'orders.csv'; ms = 4210 }
# -> {"ts":"...","level":"INFO","message":"Import complete","script":"...","host":"...","user":"...",
# "data":{"rows":1250,"file":"orders.csv","ms":4210}}
Die Auswertung sieht dann so aus.
Get-Content 'C:\Logs\ks.log' |
ForEach-Object { $_ | ConvertFrom-Json } |
Where-Object { $_.level -eq 'ERROR' -and [datetime]$_.ts -ge (Get-Date).AddDays(-30) } |
Group-Object message | Sort-Object Count -Descending | Select-Object Count, Name
Ihre Logs auf Windows’ Standard-Protokollierungsinfrastruktur (Ereignisprotokoll und ETW) zu legen, ist eine weitere Option. Wenn Sie über eine Anbindung an Überwachungswerkzeuge oder die Sammlung von mehreren Rechnern nachdenken, hat dieser Weg Vorteile. Einen Designvergleich finden Sie in „Einführung in Windows-Ereignisprotokoll und ETW — Die Logs Ihrer Geschäftsanwendung auf die Standardmechanismen des Betriebssystems legen“, und die Rotation von Log-Dateien wird in „PowerShell-Skripte in der Praxis — Protokollauswertung, Archivierung und Reporting sicher automatisieren“ behandelt.
8. Der Umgang mit der Fortschrittsanzeige
Write-Progress nutzt die Fortschrittsanzeigefunktion des Hosts, und es ist kein umleitbarer Datenstrom.5 Mit anderen Worten, Sie können es nicht in einem Log festhalten. Bei unbeaufsichtigter Ausführung gibt es keinen Anzeigeort, und in manchen Umgebungen ist der Aktualisierungsaufwand der Fortschrittsanzeige alles andere als vernachlässigbar.
# Die Fortschrittsanzeige am Anfang eines unbeaufsichtigten Skripts abschalten
$ProgressPreference = 'SilentlyContinue'
Wenn Sie Fortschritt in Ihrem Betriebslog haben möchten, ist es praktisch, nur die Meilensteine in den ausführlichen Strom zu schreiben.
$i = 0
foreach ($row in $rows) {
$i++
if ($i % 100 -eq 0) { Write-Verbose "$i / $($rows.Count) complete" }
...
}
9. Bewährte Praxis in der Praxis (Entscheidungstabelle)
| Auszugebende Information | Was zu verwenden ist | Warum |
|---|---|---|
| Werte für nachgelagerte Verarbeitung | Write-Output / bloße Ausgabe |
Der Erfolgsstrom ist ausschließlich für Daten3 |
| Fortschritt (nur bei Untersuchung gewünscht) | Write-Verbose |
Vom Aufrufer mit -Verbose gesteuert7 |
| Ereignisse, die betrieblich festgehalten werden sollen | Write-Information + strukturiertes Logging |
Mit -InformationVariable erfassbar2 |
| Dekorierte Anzeige in einem interaktiven Werkzeug | Write-Host |
Läuft über den Informationsstrom, daher ebenfalls erfassbar2 |
| Erwartete, aber beachtenswerte Zustände | Write-Warning |
Standardmäßig angezeigt, mit -WarningVariable erfassbar8 |
| Fehlschläge | Write-Error / throw |
Siehe den eigenen Artikel zur Fehlerbehandlung |
| Interner Zustand während der Entwicklung | Write-Debug |
Nur wenn -Debug angegeben ist7 |
| Fortschritt | Write-Progress (nur interaktiv) |
Erscheint nie in Logs. Bei unbeaufsichtigter Ausführung abschalten5 |
| Ein vollständiger Nachweis des Laufs | Start-Transcript |
Als Absicherung neben dem eigenen Logging mitlaufen lassen9 |
10. Zusammenfassung
- Die Ausgabe von PowerShell teilt sich in sechs Ströme auf. Der Erfolgsstrom ist ausschließlich für Daten, und das Vermischen mit für Menschen bestimmten Nachrichten zerstört den Rückgabewert.
- Ab PowerShell 5.0 schreibt
Write-Hostin den Informationsstrom und ist daher erfassbar, kann aber weiterhin nicht dazu verwendet werden, Werte zurückzugeben oder Betriebslogs zu erzeugen. - Eine Funktion gibt alles zurück, was innerhalb von ihr ausgegeben wird. Der Standardweg ist, unerwünschte Ausgaben mit
$null = ...zu verwerfen. - Fügen Sie
[CmdletBinding()]hinzu und verwenden SieWrite-Verbose/Write-Information, um die Kontrolle über die Ausführlichkeit dem Aufrufer zu überlassen. Das ist kürzer als eine eigene Log-Level-Variable und vermittelt die Absicht. - Logs, die Sie später aggregieren möchten, sollten strukturiert sein, ein JSON-Objekt pro Zeile. Geht es darum, den Bildschirm zu reproduzieren, lassen Sie
Start-Transcriptmitlaufen. - Die Fortschrittsanzeige ist kein Datenstrom, daher landet sie nie in einem Log. Bei unbeaufsichtigter Ausführung ist die praktische Antwort, sie mit
$ProgressPreference = 'SilentlyContinue'abzuschalten.
Beispielcode zum Download
Der in diesem Artikel behandelte Code ist in direkt ausführbarer Form gepackt. Er enthält das strukturierte Log mit einem JSON pro Zeile sowie die Art und Weise, Funktionen zu schreiben, die ihren Rückgabewert nicht verunreinigen.
Beispielcode herunterladen (zip)
Die Beispiele dieses Artikels wurden tatsächlich unter PowerShell 7.6 ausgeführt und verifiziert (14 Pester-Tests). Führen Sie das im zip enthaltene Invoke-SampleTests.ps1 aus, um dieselbe Verifikation auf Ihrer eigenen Maschine zu reproduzieren.
# Syntaxprüfung + statische Analyse + Pester-Tests
./Invoke-SampleTests.ps1
Die Konfigurationswerte (Pfade, Servernamen, Mandanten-IDs usw.) sind Beispiele. Führen Sie sie nicht unverändert in einer Produktivumgebung aus — passen Sie sie an Ihre eigene Umgebung an.
Verwandte Artikel
- Fehlerbehandlung und Retry-Design in PowerShell — Von der try/catch-Falle bis zu Exit-Codes und bewährten Retry-Verfahren
- Parameterdesign und Modularisierung in PowerShell — Von „einem funktionierenden Skript“ zu „einem Skript, das Sie weitergeben können“
- PowerShell-Skripte in der Praxis — Protokollauswertung, Archivierung und Reporting sicher automatisieren
- Einführung in Windows-Ereignisprotokoll und ETW — Die Logs Ihrer Geschäftsanwendung auf die Standardmechanismen des Betriebssystems legen
- PowerShell mit Pester testen — Ein praktischer Ansatz, um Betriebsskripte widerstandsfähiger zu machen
- Mindestanforderungen an einen eigenen Logger, mit einer Checkliste für Integrationstests
Verwandte Beratungsbereiche
Die KomuraSoft LLC übernimmt Reviews des Log-Designs in Betriebsskripten, die Auflösung der Situation „wir wissen nicht, warum es fehlgeschlagen ist“ sowie den Aufbau von Log-Grundlagen, die in Überwachung und Aggregation einfließen.
- Technische Beratung & Design-Review
- Fehlersuche & Ursachenanalyse
- Wartung & Modernisierung bestehender Windows-Software
- Kontakt
Referenzlinks
-
Microsoft Learn, about_Redirection. Dazu, dass PowerShell Erfolgs-, Fehler-, Warn-, Ausführlich-, Debug- und Informationsströme besitzt, die jeweils durch eine Nummer gekennzeichnet sind; zur Umleitung in eine Datei mit
>und>>; zum Zusammenführen mit einem anderen Strom übern>&1; und zur Umleitung aller Ströme mit*>. ↩ ↩2 -
Microsoft Learn, Write-Host. Dazu, dass Write-Host ab PowerShell 5.0 zu einem Wrapper um Write-Information wird, der in den Informationsstrom schreibt und dadurch eine Umleitung mit 6> ermöglicht; zur Dekoration über -ForegroundColor / -BackgroundColor; und dazu, dass seine Ausgabe nicht durch die Pipeline weitergereicht wird. Damit verbunden behandelt Write-Information das explizite Schreiben in den Informationsstrom und die Klassifizierung mit -Tags. ↩ ↩2 ↩3 ↩4 ↩5
-
Microsoft Learn, Write-Output. Zum Senden von Objekten in den Erfolgsstrom (die Pipeline) und dazu, dass das Ergebnis eines Ausdrucks auf dieselbe Weise ausgegeben wird, auch ohne expliziten Aufruf. ↩ ↩2
-
Microsoft Learn, about_Return. Dazu, dass PowerShell-Funktionen jedes innerhalb der Funktion ausgegebene Objekt an den Aufrufer zurückgeben, unabhängig davon, ob return vorhanden ist, und dazu, dass return die Syntax ist, um einen Wert zurückzugeben und dabei den aktuellen Gültigkeitsbereich zu verlassen. ↩ ↩2
-
Microsoft Learn, Write-Progress. Zur Ausgabe des Fortschritts eines Befehls als Fortschrittsanzeige des Hosts, zur Steuerung dieser Anzeige mit $ProgressPreference, und dazu, dass sie ab PowerShell 7.4 auch über den gemeinsamen Parameter -ProgressAction gesteuert werden kann. ↩ ↩2 ↩3
-
Microsoft Learn, about_Functions_CmdletBindingAttribute. Dazu, dass erweiterte Funktionen mit dem Attribut [CmdletBinding()] sich wie kompilierte Cmdlets verhalten und die gemeinsamen Parameter automatisch verfügbar werden. ↩ ↩2
-
Microsoft Learn, about_CommonParameters. Zum Verhalten von -Verbose / -Debug / -WarningAction / -InformationAction / -ErrorAction und den entsprechenden -*Variable-Parametern sowie zu ihrer Beziehung zu den Präferenzvariablen. ↩ ↩2 ↩3 ↩4
-
Microsoft Learn, about_Preference_Variables. Dazu, dass $VerbosePreference, $DebugPreference und $InformationPreference standardmäßig SilentlyContinue sind, während $WarningPreference und $ErrorActionPreference standardmäßig Continue sind; zur Steuerung der Fortschrittsanzeige mit $ProgressPreference; und dazu, dass diese für den aktuellen Gültigkeitsbereich und dessen untergeordnete Bereiche gelten. ↩ ↩2 ↩3
-
Microsoft Learn, Start-Transcript. Zur Aufzeichnung der Befehle und Konsolenausgaben einer Sitzung in einer Textdatei, zum Anhängen mit -Append, und zum Beenden mit Stop-Transcript. ↩ ↩2 ↩3
Verwandte Artikel
Aktuelle Artikel mit denselben Schlagwörtern führen zu verwandten Themen weiter.
Wo Sie nachsehen sollten, wenn ein PowerShell-Skript langsam ist — Arrays, Pipelines und Abgleich
Die klassischen Ursachen langsamer PowerShell-Skripte im Überblick. Warum += bei einem Array O(n²) ist, der Unterschied zwischen Pipeline...
Parallelverarbeitung in PowerShell — Die Wahl zwischen ForEach-Object -Parallel und Jobs
Ein praxisnaher Überblick über die Unterschiede zwischen ForEach-Object -Parallel, Start-ThreadJob und Start-Job und wann welches zum Ein...
Externe EXEs aus PowerShell korrekt aufrufen — Die Fallstricke bei Argument-Quoting, Exitcodes und Zeichensalat
Rufen Sie robocopy oder eine hauseigene EXE aus PowerShell auf, und die Argumente zerbrechen, der Exitcode ist nicht verfügbar, und die A...
Zugangsdaten in PowerShell sicher handhaben — Klartext-Passwörter aus Ihren Skripten verbannen
Ein praktischer Leitfaden, um Klartext-Passwörter aus PowerShell-Skripten zu entfernen und sicher zu speichern: was SecureString wirklich...
Parameterdesign und Modularisierung für PowerShell-Skripte — Von der „funktionierenden“ zur „übergabefähigen“ Skript
Eine schrittweise Vorgehensweise, um ein PowerShell-Skript auf eine Qualität zu heben, die Sie an andere übergeben können. Behandelt den ...
Verwandte Themen
Diese Seiten ordnen den Artikel in einen größeren Leistungs- und Entscheidungskontext ein.
Technische Windows-Themen
Portal zu Windows-Entwicklung, Fehleranalyse und der Nutzung bestehender Assets.
Leistungen zu diesem Thema
Dieser Artikel ist direkt mit den folgenden Leistungen verbunden.
Windows-App-Entwicklung
Geschäftsanwendungen, Geräteintegration und Kommunikationstools von den Anforderungen bis zur Umsetzung.
Technische Beratung und Design-Review
Klärung von Änderungsstrategie, Entwurf und Umgang mit bestehenden Assets.
Häufige Fragen
Fragen, die in Beratungen zu diesem Artikelthema häufig gestellt werden.
- Darf ich Write-Host niemals verwenden?
- Es ist nicht verboten — treffender ist, dass die Einsatzmöglichkeiten begrenzt sind. Ab PowerShell 5.0 schreibt Write-Host in den Informationsstrom (Nummer 6), sodass es sich mit 6> umleiten und mit -InformationVariable erfassen lässt. Dennoch handelt es sich um einen Befehl, der davon ausgeht, dass seine Ausgabe standardmäßig immer auf dem Bildschirm erscheint, und Sie können ihn nicht verwenden, um einen Wert in die Pipeline zu leiten. Die Aufteilung lautet: Write-Host für dekorierte Ausgaben, die für Menschen in einem interaktiven Werkzeug gedacht sind; Write-Verbose oder Write-Information für Fortschritt und ergänzende Informationen; und Write-Output (oder eine bloße Ausgabe) für Werte, die nachgelagerte Schritte verarbeiten müssen.
- In den Rückgabewert meiner Funktion mischen sich unbeabsichtigte Werte.
- Das liegt daran, dass eine PowerShell-Funktion jedes innerhalb von ihr ausgegebene Objekt zurückgibt, unabhängig davon, ob ein explizites return vorhanden ist. Wenn Sie einen Befehl oder eine Methode aufrufen, die einen Wert zurückgibt — etwa New-Item oder .Append() eines StringBuilders —, ohne mit dem Ergebnis etwas zu tun, fließt dieser Rückgabewert in den Erfolgsstrom und erreicht den Aufrufer. Umgekehrt geben Methoden mit void-Rückgabe, wie .Add() von List[T], nichts aus, sodass keine Unterdrückung nötig ist. Die Lösung besteht darin, die unerwünschte Ausgabe mit $null = ... zu verwerfen, | Out-Null anzuhängen oder mit [void] zu casten. Leistungsmäßig ist $null = ... von den dreien die leichteste Variante.
- Ich möchte die ausführliche Protokollierung eines Skripts zur Laufzeit ein- und ausschalten können.
- Schreiben Sie den zwischenzeitlichen Fortschritt mit Write-Verbose und fügen Sie der Funktion [CmdletBinding()] hinzu. Allein dadurch erscheint die Ausgabe nur, wenn der Aufrufer -Verbose angibt. Möchten Sie sie dauerhaft aktivieren, setzen Sie $VerbosePreference = 'Continue' am Anfang des Skripts. Ebenso lässt sich Write-Debug vom Aufrufer mit -Debug und Write-Warning mit -WarningAction steuern. Statt eine eigene Log-Level-Variable zu erfinden, vermittelt es die eigene Absicht anderen Lesern deutlich besser, wenn Sie sich auf die Standardmechanismen von PowerShell stützen.
- Wie kann ich alles — ausführliche Ausgaben, Warnungen eingeschlossen — in einer Datei festhalten?
- Es gibt drei Ansätze, je nach Bedarf. Um einfach alle Ströme in eine Datei zu schreiben, leiten Sie mit *> um. Um einen vollständigen Nachweis dessen zu behalten, was auf dem Bildschirm erschien, ist Start-Transcript die einfache Option. Wollen Sie die Ausgabe später programmatisch analysieren, ist ein strukturiertes Log mit einem JSON-Objekt pro Zeile aus einer eigenen Log-Funktion die zuverlässige Wahl — und selbst dann lohnt es sich, zusätzlich als Absicherung ein Transkript mitlaufen zu lassen.
- Kann die Ausgabe von Write-Progress in einer Log-Datei festgehalten werden?
- Nein. Die Fortschrittsanzeige ist eine Funktion der Hostanzeige und wird getrennt von den umleitbaren Datenströmen behandelt. Bei unbeaufsichtigter Ausführung gibt es keinen Ort zur Anzeige, behandeln Sie Fortschritt daher als etwas Eigenständiges gegenüber den Informationen, die Sie in Logs festhalten. Bei unbeaufsichtigter Ausführung kann das Setzen von $ProgressPreference = 'SilentlyContinue', um die Fortschrittsanzeige ganz zu stoppen, je nach Umgebung spürbar schneller machen. Möchten Sie den Fortschritt dennoch im Log haben, ist es praktischer, nur die Meilensteine — „50 von 100 abgeschlossen“ — mit Write-Verbose zu schreiben.
Autorenprofil
Profilseite des Artikelautors.
Go Komura
Geschäftsführer von KomuraSoft LLC
Spezialisiert auf Windows-Softwareentwicklung, technische Beratung und Fehleranalyse, insbesondere bei bestehenden Systemen und schwer reproduzierbaren Störungen.