Die Grundlagen der PowerShell-Befehle ── Was man zuerst lernen sollte und wie man sicher damit arbeitet

· · PowerShell, Windows, Kommandozeile, Automatisierung, Legacy-Bestände

1. Das Wichtigste zuerst

PowerShell ist eine Befehlsumgebung, die sich für die Prüfung von Windows-Einstellungen, das Organisieren von Dateien, die Untersuchung von Protokollen, die Verarbeitung von CSV-Dateien, die Steuerung von Diensten und die Automatisierung wiederkehrender Aufgaben einsetzen lässt.

Allerdings müssen Sie von Anfang an keine komplexen Skripte schreiben. Wenn Sie sich zunächst nur den folgenden Ablauf merken, sind Sie in der Praxis bereits recht gut gerüstet.

Suchen  Ansehen  Filtern  Sortieren  Ausgeben  bei Bedarf ändern

Die Grundlage von PowerShell ist nicht das „Auswendiglernen langer Befehle“. Wichtig sind die folgenden drei Dinge.

  1. Befehle mit Get-Command und Get-Help nachschlagen können
  2. Ergebnisse über die |-Pipeline an den nächsten Befehl weiterreichen können
  3. Vor dem Löschen, Stoppen oder Ändern die Auswirkungen mit -WhatIf oder -Confirm prüfen

PowerShell lässt „Untersuchung“ und „Änderung“ auf demselben Bildschirm zu. Das ist praktisch, bedeutet aber auch, dass sich Löschungen und Stopps ebenso sofort ausführen lassen — die Gewohnheit, mit einer reinen Lesekontrolle zu beginnen, ist deshalb entscheidend.

Der in diesem Artikel vorkommende Code ist zusammen mit einer nach Kapiteln gegliederten Sammlung thematischer Skripte (so aufgebaut, dass Sie in einem temporären Ordner sicher einen Übungsarbeitsbereich anlegen und ausprobieren können) und Pester-Tests als vollständiges Beispielpaket auf GitHub veröffentlicht.

powershell-command-basics - komurasoft-blog-samples (GitHub)

So lesen Sie diesen Artikel

Dieser Artikel hat 26 Kapitel. Sie müssen ihn nicht von Anfang bis Ende durchlesen. Je nach Ziel verlieren Sie weniger leicht die Orientierung, wenn Sie mit den folgenden Kapiteln beginnen.

Ziel Zu lesende Kapitel
Sie fangen gerade erst mit PowerShell an Kapitel 1–8 (Denkweise, Nachschlagen, Pipeline, Dateioperationen) und Kapitel 24 (Lernreihenfolge)
Sie wollen Protokolle oder Einstellungen untersuchen Kapitel 9 (Text), Kapitel 12 (Prozesse/Dienste), Kapitel 13 (Ereignisprotokolle), Kapitel 21 (Untersuchungsbeispiel)
Sie wollen CSV- oder JSON-Daten verarbeiten Kapitel 10, 11, 15
Sie wollen Verarbeitungslogik in ein Skript packen Kapitel 14, 16, 17, 18
Sie wollen Löschen/Verschieben sicher ausführen Kapitel 19, 22, 25
Sie wollen nur Befehle nachschlagen Kapitel 20 (Liste der Grundbefehle), Kapitel 23 (häufige Stolperfallen)

Die Lernreihenfolge selbst ist in Kapitel 24 „Die Reihenfolge, in der man Befehle lernt“ zusammengefasst. Wenn Sie zum ersten Mal selbst Hand anlegen, halten Sie sich nur an Stufe 1 aus Kapitel 24 (Get-Command, Get-Help, Get-Member, Get-Location, Set-Location, Get-ChildItem, Get-Content, Select-String) und folgen Sie damit dem Haupttext. Sobald Sie diese acht kennen, können Sie den Rest bei Bedarf nachschlagen.

Abgrenzung zur „praktischen Befehlssammlung“

Es gibt noch einen weiteren PowerShell-Artikel. Da die beiden unterschiedliche Rollen haben, nutzen Sie sie wie folgt.

Artikel Inhalt Wann lesen
Dieser Artikel (Grundlagen) Das Bediensystem: wie man Befehle findet, das Konzept der Pipeline, die sichere Reihenfolge für Änderungsbefehle Zuerst lesen
Praktische PowerShell-Befehlssammlung Bausteine nach Zweck: Anzahl-/Summenauswertung (Measure-Object), Auswertung nach Kategorie (Group-Object), Differenzvergleich (Compare-Object), Protokollierung von Arbeitsschritten (Start-Transcript) usw. Wenn bei der eigentlichen Arbeit „das möchte ich tun“ auftaucht

CSV, Prozesse, Dienste, Ereignisprotokolle sowie die Vorsichtsmaßnahmen bei Format-* tauchen in beiden Artikeln auf. Dieser Artikel behandelt „warum man es so schreibt“, die Befehlssammlung behandelt „welcher Baustein in welcher Situation zum Einsatz kommt“.

2. Der Unterschied zwischen PowerShell und der Eingabeaufforderung

PowerShell sieht der klassischen Eingabeaufforderung (cmd.exe) ähnlich, doch die zugrunde liegende Denkweise unterscheidet sich.

Aspekt Eingabeaufforderung PowerShell
Hauptausgabe Zeichenketten Objekte
Befehlsnamen dir, copy usw. Get-ChildItem, Copy-Item usw.
Ergebnisverarbeitung Vor allem Zeichenkettenverarbeitung Filtern und Sortieren über Eigenschaften
Automatisierung Batchdateien .ps1-Skripte
Stärken Kompatibilität mit alten Kommandozeilen-Beständen Windows-Verwaltung, CSV, JSON, APIs, Routineaufgaben

Beim Abrufen einer Dateiliste betrachten Sie in cmd.exe die Ausgabe von dir meist als reine Zeichenkette. In PowerShell wird eine Datei dagegen als Objekt mit Eigenschaften wie Name, Length und LastWriteTime behandelt.

Get-ChildItem

Ist dieser Unterschied einmal klar, lässt sich ein Vorgang wie „nur die innerhalb der letzten 7 Tage aktualisierten Dateien anzeigen, sortiert nach dem neuesten Änderungsdatum“ ganz natürlich formulieren.

Get-ChildItem -File |
  Where-Object { $_.LastWriteTime -gt (Get-Date).AddDays(-7) } |
  Sort-Object LastWriteTime -Descending |
  Select-Object Name, Length, LastWriteTime

3. Windows PowerShell 5.1 und PowerShell 7.x

Windows bringt sowohl das schon lange vorhandene Windows PowerShell 5.1 als auch die neuere Reihe PowerShell 7.x mit.

In der Praxis hilft folgende Betrachtung.

Variante Ausführbare Datei Hauptsächlicher Einsatz
Windows PowerShell 5.1 powershell.exe Alte Windows-spezifische Module, bestehende Skripte, Pflege interner Bestände
PowerShell 7.x pwsh.exe Neue Skripte, plattformübergreifend, laufende Funktionsverbesserungen

Wer neu einsteigt, kann sich problemlos an PowerShell 7.x orientieren. Allerdings sind alte interne Verwaltungsskripte und Windows-spezifische Module manchmal für Windows PowerShell 5.1 geschrieben.

Deshalb prüft man in der Praxis zuerst die Version.

$PSVersionTable

Für Skripte, die erst ab einer bestimmten Version laufen sollen, reduziert eine Bedingung am Anfang das Fehlerrisiko.

#Requires -Version 7.0

Mit welcher Version laufen die Beispiele dieses Artikels?

Die folgenden Beispiele sind, sofern nicht anders vermerkt, so geschrieben, dass sie unverändert sowohl unter Windows PowerShell 5.1 als auch unter PowerShell 7.x laufen. Bei denselben Befehlen unterscheidet sich jedoch in folgenden Punkten das Ergebnis — prüfen Sie das, bevor Sie sie übernehmen.

Wo sich Unterschiede zeigen Windows PowerShell 5.1 PowerShell 7.x
Standard-Anzeigespalten von Get-Process Handles, NPM(K), PM(K), WS(K), CPU(s), Id, SI, ProcessName NPM(K), PM(M), WS(M), CPU(s), Id, SI, ProcessName (Speicher in MB)
Bedeutung von -Encoding UTF8 UTF-8 (mit BOM) UTF-8 (ohne BOM). Soll ein BOM gesetzt werden, geben Sie utf8BOM an
Wenn -Encoding weggelassen wird Unterschiedlich je Befehl (Out-File verwendet UTF-16LE, Set-Content ANSI, Export-Csv ASCII) Immer utf8NoBOM

In den Beispielen dieses Artikels wird bei schreibenden Befehlen -Encoding UTF8 explizit angegeben, um eine ungewollte Zeichenkodierung zu vermeiden. Die Grundlagen zu BOM und Zeilenumbrüchen selbst werden im Artikel „Windows-Zeichenkodierung und Zeilenumbrüche - Grundlagen zu Mojibake und CRLF/LF“ behandelt.

4. Cmdlet-Namen folgen dem Muster Verb-Substantiv

PowerShells Standardbefehle haben grundsätzlich die Form Verb-Substantiv.

Get-Process
Get-Service
Get-ChildItem
Copy-Item
Remove-Item
Export-Csv

Wer sich dieses Muster einprägt, findet auch unbekannte Befehle leichter.

Verb Bedeutung Beispiel
Get Abrufen Get-Process
Set Festlegen Set-Location
New Erstellen New-Item
Copy Kopieren Copy-Item
Move Verschieben Move-Item
Remove Löschen Remove-Item
Start Starten Start-Service
Stop Stoppen Stop-Process
Import Einlesen Import-Csv
Export Ausgeben Export-Csv

Auch kurze Namen wie dir, ls, cat und cd funktionieren, die meisten davon sind jedoch Aliase.

Get-Command dir

Wenn Sie etwas als Skript behalten wollen, ist es sicherer, den vollständigen Namen statt eines Alias zu verwenden.

# lesbar, aber im Skript zu vermeiden
ls *.log

# Absicht ist eindeutig
Get-ChildItem -Filter *.log

5. Die drei Nachschlagebefehle, die man zuerst lernt

PowerShell hat sehr viele Befehle, deshalb ist es praxistauglicher, „wie man nachschlägt“ zu lernen als auswendig zu lernen.

1. Get-Command ── verfügbare Befehle finden

Get-Command ist der Befehl, um installierte Befehle, Funktionen, Aliase und Anwendungen zu finden.

# Befehle mit dem Substantiv Process finden
Get-Command -Noun Process

# Dienstbezogene Befehle finden
Get-Command *Service*

# CSV-bezogene Befehle finden
Get-Command *Csv*

Wenn Sie sich an einen Befehlsnamen nur ungefähr erinnern, verwenden Sie Platzhalter.

Get-Command *Item*
Get-Command *Content*
Get-Command *Json*

2. Get-Help ── die Verwendung ansehen

Get-Help ist der Befehl, um Beschreibung, Parameter und Beispiele eines Befehls anzusehen.

Get-Help Get-ChildItem
Get-Help Get-ChildItem -Examples
Get-Help Get-ChildItem -Full
Get-Help Get-ChildItem -Online

Am Anfang ist -Examples besonders praktisch.

Get-Help Where-Object -Examples

Ist die Hilfe veraltet oder unvollständig, aktualisieren Sie sie in einer PowerShell-Sitzung mit Administratorrechten.

Update-Help

Je nach Umgebung sind dafür eine Internetverbindung und entsprechende Rechte nötig. Auf Firmen-PCs kann dies an Proxys oder Verwaltungsrichtlinien scheitern.

3. Get-Member ── den Inhalt eines Objekts ansehen

Die Ausgabe von PowerShell ist meist keine „Zeichenkette“, sondern ein „Objekt“. Mit Get-Member lässt sich prüfen, welche Eigenschaften und Methoden dieses Objekt hat.

Get-Process | Get-Member
Get-Service | Get-Member
Get-ChildItem | Get-Member

Dienste haben zum Beispiel Eigenschaften wie Status und Name.

Get-Service | Select-Object Name, Status

Dateien haben Name, Length, LastWriteTime und weitere.

Get-ChildItem -File | Select-Object Name, Length, LastWriteTime

Wenn unklar ist, „wonach man filtern soll“, prüfen Sie zuerst mit Get-Member die Eigenschaftsnamen.

6. Grundlagen der Pipeline

PowerShells | reicht das Ergebnis des linken Befehls an den rechten Befehl weiter.

Get-Process | Sort-Object CPU -Descending | Select-Object -First 10

Dieses Beispiel führt die folgende Verarbeitung von links nach rechts durch.

Prozessliste abrufen
   nach CPU-Auslastung absteigend sortieren
   nur die obersten 10 anzeigen

Wie wird die Ausgabe angezeigt?

Das Ergebnis von Get-Process wird standardmäßig als Tabelle mit den folgenden Spalten angezeigt. Die Werte unterscheiden sich je nach Umgebung, geprüft wird also die „Reihenfolge der Spalten“.

NPM(K)    PM(M)      WS(M)     CPU(s)      Id  SI ProcessName
------    -----      -----     ------      --  -- -----------
Spalte Bedeutung
NPM(K) Speicherverbrauch im nicht auslagerbaren Pool (KB)
PM(M) Auslagerbarer Speicherverbrauch (MB)
WS(M) Größe des Arbeitssatzes (kürzlich referenzierte Speicherseiten) (MB)
CPU(s) Über alle Prozessoren verbrauchte Prozessorzeit (Sekunden)
Id Prozess-ID
SI Sitzungs-ID
ProcessName Prozessname

Das ist die Standardanzeige von PowerShell 7.x. Unter Windows PowerShell 5.1 steht vorn zusätzlich Handles (Anzahl offener Handles), und die Speicherspalten heißen PM(K)/WS(K) mit Werten in KB. Auch wenn sich die Spaltennamen unterscheiden, sind die Eigenschaftsnamen, die Sie bei Sort-Object oder Where-Object angeben (CPU, WorkingSet, Id, Name usw.), dieselben. Anzeigespaltenname und Eigenschaftsname sind zweierlei — greift eine Filterbedingung nicht, prüfen Sie mit Get-Process | Get-Member den tatsächlichen Eigenschaftsnamen.

Häufig genutzte Kombinationen sind diese.

Befehl Rolle Beispiel
Where-Object Nach Bedingung filtern Nur gestoppte Dienste abrufen
Sort-Object Sortieren Nach neuestem Änderungsdatum sortieren
Select-Object Spalten oder Anzahl auswählen Nur Name und Größe anzeigen
ForEach-Object Jedes Element verarbeiten Pro Datei verarbeiten
Export-Csv Als CSV ausgeben Untersuchungsergebnis speichern

Where-Object ── nach Bedingung filtern

# Nur gestoppte Dienste anzeigen
Get-Service | Where-Object { $_.Status -eq "Stopped" }

# Nur Dateien über 100MB anzeigen
Get-ChildItem -File |
  Where-Object { $_.Length -gt 100MB }

# Nur Dateien anzeigen, deren Name backup enthält
Get-ChildItem -File |
  Where-Object { $_.Name -like "*backup*" }

$_ steht für das aktuelle Objekt, das gerade durch die Pipeline fließt.

Where-Object { $_.Length -gt 100MB }

Das prüft: „Ist die Length der gerade betrachteten Datei größer als 100MB?“

Ab PowerShell 3.0 lässt sich auch eine vereinfachte Syntax verwenden.

Get-Service | Where-Object Status -EQ "Stopped"

Solange Sie noch Einsteiger sind, ist die Scriptblock-Syntax jedoch leichter nachzuvollziehen.

Get-Service | Where-Object { $_.Status -eq "Stopped" }

Sort-Object ── sortieren

# Nach Speicherverbrauch absteigend
Get-Process |
  Sort-Object WorkingSet -Descending |
  Select-Object -First 10 Name, Id, WorkingSet

# Nach neuestem Änderungsdatum
Get-ChildItem -File |
  Sort-Object LastWriteTime -Descending |
  Select-Object -First 20 Name, LastWriteTime

Select-Object ── nur die benötigten Spalten auswählen

Get-Process |
  Select-Object Name, Id, CPU, WorkingSet

Auch zum Begrenzen der Anzahl wird es verwendet.

Get-Process | Select-Object -First 5
Get-Process | Select-Object -Last 5

Vor der Ausgabe in eine CSV lässt sich das Ergebnis mit Select-Object auf die benötigten Spalten reduzieren, was die Weiterverarbeitung erleichtert.

Get-Service |
  Select-Object Name, DisplayName, Status, StartType |
  Export-Csv .\services.csv -NoTypeInformation -Encoding UTF8

7. Format-Befehle zuletzt verwenden

PowerShell hat Befehle, um die Anzeige zu formatieren.

Format-Table
Format-List
Format-Wide

Diese sind für die „Bildschirmanzeige“ gedacht. Werden sie vor der CSV-Ausgabe oder vor der Weitergabe an die nachfolgende Verarbeitung eingesetzt, entstehen statt der ursprünglichen Eigenschaften Anzeigeobjekte.

# Vermeiden: Anzeigeinformationen mischen sich in die CSV
Get-Process |
  Format-Table Name, CPU |
  Export-Csv .\process.csv -NoTypeInformation

# Richtig: zuerst Eigenschaften auswählen, dann CSV ausgeben
Get-Process |
  Select-Object Name, CPU |
  Export-Csv .\process.csv -NoTypeInformation -Encoding UTF8

Wer sich merkt, dass Format-* „nur ganz zum Schluss für die Bildschirmanzeige“ gedacht ist, vermeidet die meisten Zwischenfälle.

8. Grundlagen der Datei- und Ordneroperationen

Am häufigsten werden in PowerShell Datei- und Ordneroperationen genutzt.

Was Sie tun möchten Befehl
Aktuellen Ort ansehen Get-Location
Ort wechseln Set-Location
Auflistung ansehen Get-ChildItem
Datei/Ordner erstellen New-Item
Kopieren Copy-Item
Verschieben Move-Item
Umbenennen Rename-Item
Löschen Remove-Item
Existenz prüfen Test-Path

Den aktuellen Ort prüfen

Get-Location

Wechseln.

Set-Location C:\Work

Enthält der Pfad Leerzeichen, setzen Sie ihn in Anführungszeichen.

Set-Location "C:\Work Files\Reports"

Die Dateiliste ansehen

Get-ChildItem
Get-ChildItem -File
Get-ChildItem -Directory
Get-ChildItem -Recurse

Bei der Ausführung erscheint unter der Überschrift des Zielordners eine Tabelle mit den folgenden Spalten.

   Directory: C:\Work

Mode                LastWriteTime         Length Name
----                -------------         ------ ----

Mode sind Zeichen für Attribute: d steht für Verzeichnis, a für das Archivattribut, r für schreibgeschützt, h für versteckt, s für System und l für Link. Bei Verzeichniszeilen bleibt Length (Größe) leer. LastWriteTime und Length, wie sie hier stehen, sind genau die Eigenschaftsnamen, die sich in Where-Object oder Sort-Object verwenden lassen.

Zum Filtern nach Erweiterung ist -Filter praktisch.

Get-ChildItem -Filter *.log

Um auch Unterordner zu durchsuchen, verwenden Sie -Recurse.

Get-ChildItem C:\Logs -Filter *.log -Recurse

An Orten mit einer großen Anzahl von Dateien sollten Sie nicht sofort -Recurse einsetzen, sondern den Zielordner zuerst eingrenzen.

Erstellen

# Ordner erstellen
New-Item -ItemType Directory -Path .\archive

# Leere Datei erstellen
New-Item -ItemType File -Path .\memo.txt

Wenn möglicherweise schon etwas existiert, prüfen Sie zuerst.

if (-not (Test-Path .\archive)) {
  New-Item -ItemType Directory -Path .\archive
}

Kopieren

Copy-Item .\report.xlsx .\backup\report.xlsx

Um einen ganzen Ordner zu kopieren, verwenden Sie -Recurse.

Copy-Item .\data .\backup\data -Recurse

Ist ein Überschreiben möglich, prüfen Sie vorher die Auswirkungen.

Copy-Item .\data .\backup\data -Recurse -WhatIf

Verschieben

Move-Item .\old.log .\archive\old.log

Wenn Sie mehrere Dateien nach Bedingung verschieben, setzen Sie zuerst -WhatIf.

Get-ChildItem .\logs -Filter *.log |
  Where-Object { $_.LastWriteTime -lt (Get-Date).AddDays(-30) } |
  Move-Item -Destination .\archive -WhatIf

Passt alles, entfernen Sie -WhatIf.

Get-ChildItem .\logs -Filter *.log |
  Where-Object { $_.LastWriteTime -lt (Get-Date).AddDays(-30) } |
  Move-Item -Destination .\archive

Löschen

Löschen behandeln Sie besonders vorsichtig.

Remove-Item .\old.log -WhatIf

Führen Sie es erst aus, nachdem Sie bestätigt haben, dass das Ziel korrekt ist.

Remove-Item .\old.log

Die Kombination aus Platzhaltern und -Recurse ist mächtig. Führen Sie sie nicht sofort in einem Produktivordner aus, sondern prüfen Sie erst über eine Auflistung.

# Zuerst das Ziel prüfen
Get-ChildItem C:\Logs -Filter *.tmp -Recurse |
  Select-Object FullName, Length, LastWriteTime

# Als Nächstes das geplante Löschen prüfen
Get-ChildItem C:\Logs -Filter *.tmp -Recurse |
  Remove-Item -WhatIf

# Zuletzt ausführen
Get-ChildItem C:\Logs -Filter *.tmp -Recurse |
  Remove-Item

9. Textdateien lesen, durchsuchen und schreiben

Bei der Protokolluntersuchung kommen Textdatei-Operationen ständig zum Einsatz.

Eine Datei lesen

Get-Content .\app.log

Um nur das Ende zu sehen, verwenden Sie -Tail.

Get-Content .\app.log -Tail 50

Um ein fortlaufend erweitertes Protokoll zu beobachten, verwenden Sie -Wait.

Get-Content .\app.log -Tail 20 -Wait

Zeichenketten suchen

Select-String -Path .\app.log -Pattern "ERROR"

Mehrere Dateien lassen sich gleichzeitig durchsuchen.

Select-String -Path .\logs\*.log -Pattern "ERROR", "WARN"

Aus den Suchergebnissen lassen sich Dateiname, Zeilennummer und Inhalt auch in eine CSV extrahieren.

Select-String -Path .\logs\*.log -Pattern "ERROR" |
  Select-Object Path, LineNumber, Line |
  Export-Csv .\error-lines.csv -NoTypeInformation -Encoding UTF8

In eine Datei schreiben

"hello" | Set-Content .\memo.txt -Encoding UTF8
"next line" | Add-Content .\memo.txt -Encoding UTF8

Zum Speichern von Befehlsergebnissen sind Export-Csv oder ConvertTo-Json gegenüber Out-File oft später leichter weiterzuverarbeiten.

Get-Process |
  Select-Object Name, Id, CPU |
  Export-Csv .\process.csv -NoTypeInformation -Encoding UTF8

10. Grundlagen im Umgang mit CSV

In der Geschäftsprozessautomatisierung kommt CSV sehr häufig vor. In PowerShell lässt sich eine CSV nicht als Zeichenketten, sondern als „Objekte mit Spalten“ behandeln.

Eine CSV einlesen

Angenommen, es gibt folgende users.csv.

Name,Department,Enabled
Suzuki,Sales,true
Tanaka,Accounting,false
Sato,Sales,true

Einlesen.

$users = Import-Csv .\users.csv
$users

Die Spaltennamen werden zu Eigenschaften.

$users | Select-Object Name, Department

Nach Bedingung filtern

$users |
  Where-Object { $_.Department -eq "Sales" }

CSV-Werte kommen häufig als Zeichenketten herein, achten Sie deshalb bei true/false oder Zahlen darauf.

$users |
  Where-Object { $_.Enabled -eq "true" }

In eine CSV ausgeben

$users |
  Where-Object { $_.Department -eq "Sales" } |
  Export-Csv .\sales-users.csv -NoTypeInformation -Encoding UTF8

Die eiserne Regel ist, Format-Table niemals vor Export-Csv zu setzen.

# Vermeiden
$users | Format-Table | Export-Csv .\out.csv -NoTypeInformation

# Richtig
$users | Select-Object Name, Department, Enabled | Export-Csv .\out.csv -NoTypeInformation -Encoding UTF8

11. Grundlagen im Umgang mit JSON

JSON kommt auch bei Konfigurationsdateien und Web-APIs häufig vor.

$data = Get-Content .\settings.json -Raw | ConvertFrom-Json
$data

Ein Objekt in JSON umwandeln.

[pscustomobject]@{
  Name = "BatchJob"
  Enabled = $true
  Retry = 3
} | ConvertTo-Json

Bei tiefer Verschachtelung geben Sie -Depth an.

$config | ConvertTo-Json -Depth 10 | Set-Content .\settings.json -Encoding UTF8

12. Grundlagen zu Prozessen und Diensten

Prozesse ansehen

Get-Process

Die Prozesse mit dem größten Speicherverbrauch prüfen.

Get-Process |
  Sort-Object WorkingSet -Descending |
  Select-Object -First 10 Name, Id, WorkingSet

Nach Namen filtern.

Get-Process -Name notepad

Das Stoppen sollte vorsichtig erfolgen.

Stop-Process -Name notepad -WhatIf

Passt alles, ausführen.

Stop-Process -Name notepad

Dienste ansehen

Get-Service

Nur gestoppte Dienste ansehen.

Get-Service |
  Where-Object { $_.Status -eq "Stopped" }

Nach Namen filtern.

Get-Service -Name "Spooler"

Auch beim Neustart prüfen Sie zuerst das Ziel.

Get-Service -Name "Spooler"
Restart-Service -Name "Spooler" -WhatIf

Diensteingriffe wirken sich leicht auf den Geschäftsbetrieb aus. Prüfen Sie in Produktivumgebungen deshalb zuerst das Vorgehen, das Wartungsfenster und das Wiederherstellungsverfahren.

13. Grundlagen der Ereignisprotokolle

Bei der Untersuchung von Windows sind Ereignisprotokolle unverzichtbar.

Aktuelle Fehler prüfen.

Get-WinEvent -LogName System -MaxEvents 100 |
  Where-Object { $_.LevelDisplayName -eq "Error" } |
  Select-Object TimeCreated, ProviderName, Id, Message

Wie wird die Ausgabe angezeigt?

Das Ergebnis von Get-WinEvent erhält standardmäßig eine Überschrift je Protokollanbieter (ProviderName), darunter folgt eine Tabelle mit diesen Spalten.

   ProviderName: PowerShell

TimeCreated              Id LevelDisplayName  Message
-----------              -- ----------------  -------

Wählen Sie wie im Beispiel oben mit Select-Object Spalten aus, entfällt diese Anbieter-Überschrift, und es entsteht eine Tabelle nur mit den gewählten Spalten. Message ist lang und wird auf dem Bildschirm abgeschnitten. Wollen Sie einen einzelnen Eintrag vollständig lesen, grenzen Sie zunächst auf einen Eintrag ein und zeigen Sie ihn dann mit Format-List an.

Get-WinEvent -LogName System -MaxEvents 1 | Format-List *

LevelDisplayName enthält Critical, Error, Warning, Information oder Verbose. Bei umfangreichen Protokollen ist es schneller, die Bedingung an -FilterHashtable zu übergeben, statt mit Where-Object zu filtern (Level = 3 steht für Warnung, Level = 4 für Information).

Die letzten 50 Einträge des Anwendungsprotokolls ansehen.

Get-WinEvent -LogName Application -MaxEvents 50 |
  Select-Object TimeCreated, ProviderName, Id, LevelDisplayName, Message

Nach Zeitraum filtern.

$start = (Get-Date).AddHours(-24)

Get-WinEvent -FilterHashtable @{
  LogName = "System"
  StartTime = $start
} |
  Select-Object TimeCreated, ProviderName, Id, LevelDisplayName, Message

Das Speichern der Untersuchungsergebnisse in einer CSV erleichtert später das Teilen.

Get-WinEvent -LogName System -MaxEvents 500 |
  Where-Object { $_.LevelDisplayName -in @("Error", "Warning") } |
  Select-Object TimeCreated, ProviderName, Id, LevelDisplayName, Message |
  Export-Csv .\system-events.csv -NoTypeInformation -Encoding UTF8

14. Variablen, Arrays und Hashtabellen

Auch mit kurzen Befehlen allein lässt sich arbeiten, aber sobald es etwas länger wird, sind Variablen praktisch.

Variablen

$path = "C:\Logs"
Get-ChildItem $path

PowerShell-Variablen beginnen mit $.

$today = Get-Date
$limit = (Get-Date).AddDays(-30)

Arrays

$extensions = @("*.log", "*.txt", "*.csv")
foreach ($ext in $extensions) {
  Get-ChildItem C:\Work -Filter $ext
}

Hashtabellen

Eine Hashtabelle ist eine Sammlung von Schlüssel-Wert-Paaren.

$params = @{
  Path = "C:\Logs"
  Filter = "*.log"
  Recurse = $true
}

Get-ChildItem @params

Diese Schreibweise mit @params nennt man „Splatting“. Sie macht den Code besser lesbar, wenn die Zahl der Parameter zunimmt.

15. Ergebnisse mit PSCustomObject aufbereiten

Wenn Sie Untersuchungsergebnisse tabellarisch zusammenfassen möchten, ist [pscustomobject] praktisch.

[pscustomobject]@{
  ComputerName = $env:COMPUTERNAME
  UserName     = $env:USERNAME
  CheckedAt    = Get-Date
}

Mehrere Ergebnisse lassen sich erzeugen und in eine CSV umwandeln.

Get-ChildItem C:\Logs -Filter *.log |
  ForEach-Object {
    [pscustomobject]@{
      Name          = $_.Name
      FullName      = $_.FullName
      SizeMB        = [math]::Round($_.Length / 1MB, 2)
      LastWriteTime = $_.LastWriteTime
    }
  } |
  Export-Csv .\log-files.csv -NoTypeInformation -Encoding UTF8

16. Grundlagen der Skriptdatei .ps1

Häufig genutzte Verarbeitung packen Sie in .ps1-Dateien.

Als Beispiel erstellen wir ein Skript, das alte Protokolle auflistet.

# Find-OldLogs.ps1
param(
  [string]$Path = "C:\Logs",
  [int]$Days = 30,
  [string]$OutputPath = ".\old-logs.csv"
)

$limit = (Get-Date).AddDays(-$Days)

Get-ChildItem -Path $Path -Filter *.log -File -Recurse |
  Where-Object { $_.LastWriteTime -lt $limit } |
  Select-Object FullName, Length, LastWriteTime |
  Export-Csv -Path $OutputPath -NoTypeInformation -Encoding UTF8

Write-Host "Exported: $OutputPath"

Ausführungsbeispiel.

.\Find-OldLogs.ps1 -Path C:\Logs -Days 60 -OutputPath .\old-logs.csv

Werden Argumente über param() entgegengenommen, lassen sich die Bedingungen später leicht ändern.

17. Grundlagen der Ausführungsrichtlinie

Beim Versuch, eine .ps1 auszuführen, kann folgender Fehler auftreten.

... kann nicht geladen werden, da die Ausführung von Skripts auf diesem System deaktiviert ist ...

Prüfen Sie in diesem Fall die aktuelle Ausführungsrichtlinie.

Get-ExecutionPolicy
Get-ExecutionPolicy -List

Wenn Sie auf einem persönlichen Entwicklungsrechner nur lokal erstellte Skripte ausführen möchten, wird häufig RemoteSigned im Gültigkeitsbereich des aktuellen Benutzers gesetzt.

Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser

Auf Firmen-PCs kann dies jedoch durch Gruppenrichtlinien gesteuert sein. Umgehen Sie das nicht eigenmächtig, sondern klären Sie es mit der Administration oder den betrieblichen Regeln ab.

Die Ausführungsrichtlinie ist eine Sicherheitsfunktion, die die Bedingungen steuert, unter denen PowerShell Skripte ausführt. Sie ist jedoch keine vollständige Sicherheitsgrenze. In Organisationen muss sie zusammen mit Signierung, AppLocker, Microsoft Defender, Rechteverwaltung und Protokollprüfung betrachtet werden.

18. Grundlagen der Fehlerbehandlung

PowerShell setzt die Verarbeitung mitunter auch dann fort, wenn ein Fehler auftritt.

Bei wichtigen Vorgängen verwenden Sie -ErrorAction Stop zusammen mit try/catch.

try {
  Copy-Item .\source.txt .\backup\source.txt -ErrorAction Stop
  Write-Host "Copy succeeded"
}
catch {
  Write-Error "Copy failed: $($_.Exception.Message)"
}

Auch beim Verarbeiten mehrerer Dateien lässt sich ein Fehlschlag nachträglich nachvollziehen, wenn er protokolliert wird.

$results = foreach ($file in Get-ChildItem .\input -File) {
  try {
    Copy-Item $file.FullName .\backup -ErrorAction Stop

    [pscustomobject]@{
      FileName = $file.Name
      Status   = "OK"
      Message  = ""
    }
  }
  catch {
    [pscustomobject]@{
      FileName = $file.Name
      Status   = "NG"
      Message  = $_.Exception.Message
    }
  }
}

$results | Export-Csv .\copy-result.csv -NoTypeInformation -Encoding UTF8

19. Die sichere Reihenfolge zum Ausführen von Änderungsbefehlen

In PowerShell ist das Vorgehen wichtig, um Änderungsbefehle — Löschen, Verschieben, Stoppen — sicher zu handhaben.

Die grundlegende Reihenfolge lautet:

1. Ziele mit Get-Befehlen ansehen
2. Mit Where-Object filtern
3. Mit Select-Object die Zielliste prüfen
4. Mit Export-Csv protokollieren
5. Mit -WhatIf die geplante Änderung prüfen
6. Real ausführen

Als Beispiel: .tmp-Dateien löschen, die älter als 30 Tage sind.

Schritt 1: Ziele ansehen

Get-ChildItem C:\Temp -Filter *.tmp -File -Recurse

Schritt 2: Nach Bedingung filtern

$limit = (Get-Date).AddDays(-30)

Get-ChildItem C:\Temp -Filter *.tmp -File -Recurse |
  Where-Object { $_.LastWriteTime -lt $limit }

Schritt 3: Nur die benötigten Spalten anzeigen

$targets = Get-ChildItem C:\Temp -Filter *.tmp -File -Recurse |
  Where-Object { $_.LastWriteTime -lt $limit }

$targets |
  Select-Object FullName, Length, LastWriteTime

Schritt 4: Einen Nachweis sichern

$targets |
  Select-Object FullName, Length, LastWriteTime |
  Export-Csv .\delete-targets.csv -NoTypeInformation -Encoding UTF8

Schritt 5: Mit WhatIf prüfen

$targets | Remove-Item -WhatIf

Schritt 6: Ausführen

$targets | Remove-Item

Mit dieser Reihenfolge lassen sich Zwischenfälle der Art „wir wissen nicht, was wir gelöscht haben“ vermeiden.

20. Liste häufig genutzter Grundbefehle

Ort und Dateien

Ziel Befehlsbeispiel
Aktuellen Ordner anzeigen Get-Location
Ordner wechseln Set-Location C:\Work
Auflistung anzeigen Get-ChildItem
Nur Dateien anzeigen Get-ChildItem -File
Nur Ordner anzeigen Get-ChildItem -Directory
Auch Unterordner durchsuchen Get-ChildItem -Recurse
Existenz prüfen Test-Path .\file.txt
Ordner erstellen New-Item -ItemType Directory .\backup
Kopieren Copy-Item .\a.txt .\backup\a.txt
Verschieben Move-Item .\a.txt .\archive\a.txt
Geplante Löschung prüfen Remove-Item .\a.txt -WhatIf

Objektverarbeitung

Ziel Befehlsbeispiel
Nach Bedingung filtern Where-Object { $_.Status -eq "Running" }
Sortieren Sort-Object LastWriteTime -Descending
Spalten auswählen Select-Object Name, LastWriteTime
Nur die obersten anzeigen Select-Object -First 10
Jedes Element verarbeiten ForEach-Object { $_.Name }
Inhalt untersuchen Get-Member

Ein- und Ausgabe

Ziel Befehlsbeispiel
Text lesen Get-Content .\app.log
Ende ansehen Get-Content .\app.log -Tail 50
Zeichenketten suchen Select-String -Path .\app.log -Pattern "ERROR"
CSV einlesen Import-Csv .\users.csv
CSV ausgeben Export-Csv .\out.csv -NoTypeInformation -Encoding UTF8
JSON einlesen Get-Content .\a.json -Raw \| ConvertFrom-Json
JSON ausgeben $obj \| ConvertTo-Json -Depth 10

Windows-Untersuchung

Ziel Befehlsbeispiel
Prozessliste Get-Process
Dienstliste Get-Service
Ereignisprotokoll Get-WinEvent -LogName System -MaxEvents 100
Umgebungsvariablen Get-ChildItem Env:
PowerShell-Version $PSVersionTable
Ausführungsrichtlinie Get-ExecutionPolicy -List

21. Praxisbeispiel: Protokolle untersuchen und einen Bericht erstellen

Betrachten wir folgende Anforderung.

Aus den .log-Dateien unter C:\App\Logs sollen Zeilen mit ERROR aus Dateien gefunden werden, die innerhalb der letzten 7 Tage aktualisiert wurden, und in einer CSV zusammengefasst werden.

Statt sofort die fertige Form zu schreiben, bauen wir sie schrittweise auf.

Schritt 1: Protokolldateien finden

Get-ChildItem C:\App\Logs -Filter *.log -File -Recurse

Schritt 2: Auf die letzten 7 Tage eingrenzen

$since = (Get-Date).AddDays(-7)

Get-ChildItem C:\App\Logs -Filter *.log -File -Recurse |
  Where-Object { $_.LastWriteTime -ge $since }

Schritt 3: Nach ERROR suchen

$since = (Get-Date).AddDays(-7)

Get-ChildItem C:\App\Logs -Filter *.log -File -Recurse |
  Where-Object { $_.LastWriteTime -ge $since } |
  Select-String -Pattern "ERROR"

Schritt 4: In eine CSV ausgeben

$since = (Get-Date).AddDays(-7)

Get-ChildItem C:\App\Logs -Filter *.log -File -Recurse |
  Where-Object { $_.LastWriteTime -ge $since } |
  Select-String -Pattern "ERROR" |
  Select-Object Path, LineNumber, Line |
  Export-Csv .\error-report.csv -NoTypeInformation -Encoding UTF8

Schritt 5: In ein Skript umwandeln

# Export-ErrorReport.ps1
param(
  [string]$LogPath = "C:\App\Logs",
  [int]$Days = 7,
  [string]$Pattern = "ERROR",
  [string]$OutputPath = ".\error-report.csv"
)

$since = (Get-Date).AddDays(-$Days)

Get-ChildItem $LogPath -Filter *.log -File -Recurse |
  Where-Object { $_.LastWriteTime -ge $since } |
  Select-String -Pattern $Pattern |
  Select-Object Path, LineNumber, Line |
  Export-Csv $OutputPath -NoTypeInformation -Encoding UTF8

Write-Host "Exported: $OutputPath"

Ausführungsbeispiel.

.\Export-ErrorReport.ps1 -LogPath C:\App\Logs -Days 14 -Pattern "ERROR|FATAL" -OutputPath .\errors.csv

22. Praxisbeispiel: Alte Dateien archivieren

Als Nächstes ein Beispiel, das statt löscht verschiebt.

Von den Dateien in C:\Work\Reports sollen die seit mindestens 90 Tagen nicht mehr aktualisierten .xlsx-Dateien nach C:\Work\Archive verschoben werden.

Ziele prüfen

$source = "C:\Work\Reports"
$dest = "C:\Work\Archive"
$limit = (Get-Date).AddDays(-90)

$targets = Get-ChildItem $source -Filter *.xlsx -File |
  Where-Object { $_.LastWriteTime -lt $limit }

$targets | Select-Object FullName, Length, LastWriteTime

Archivziel erstellen

if (-not (Test-Path $dest)) {
  New-Item -ItemType Directory -Path $dest
}

Nachweis ausgeben

$targets |
  Select-Object FullName, Length, LastWriteTime |
  Export-Csv .\archive-targets.csv -NoTypeInformation -Encoding UTF8

Mit WhatIf prüfen

$targets | Move-Item -Destination $dest -WhatIf

Ausführen

$targets | Move-Item -Destination $dest

Sind Namenskollisionen möglich, schlägt dies so fehl. Legen Sie in der Praxis vorab Regeln fest: Jahr-Monat-Ordner trennen, dem Zielnamen einen Zeitstempel anhängen, oder bei bereits vorhandener Datei überspringen.

23. Häufige Stolperfallen

Symptom Ursache Abhilfe
Befehle sind zu lang zum Merken Versuch, sie auswendig zu lernen Mit Get-Command, Get-Help -Examples nachschlagen
$_ ist unverständlich Unzureichendes Verständnis des aktuellen Pipeline-Werts In der Form Where-Object { $_.Name -like "*log*" } einprägen
Die CSV enthält seltsame Inhalte Export-Csv wird nach Format-Table ausgeführt Export-Csv nach Select-Object ausführen
Pfade mit Leerzeichen schlagen fehl Fehlende Anführungszeichen Wie in "C:\Work Files\a.txt" einschließen
Skript lässt sich nicht ausführen Ausführungsrichtlinie Mit Get-ExecutionPolicy -List prüfen
Zu viele Löschziele Bedingung zu weit gefasst Zuerst mit Select-Object FullName und -WhatIf prüfen
Eigenschaftsname unklar Objektstruktur nicht betrachtet Get-Member verwenden
Zeichensalat Kodierungsannahme stimmt nicht -Encoding bei Ein-/Ausgabe und die verwendete Anwendung prüfen

24. Die Reihenfolge, in der man Befehle lernt

Sie müssen nicht von Anfang an alle Befehle lernen.

Folgende Reihenfolge ist empfehlenswert.

Stufe 1: Ansehen und Finden

Get-Command
Get-Help
Get-Member
Get-Location
Set-Location
Get-ChildItem
Get-Content
Select-String

Stufe 2: Filtern und Aufbereiten

Where-Object
Sort-Object
Select-Object
ForEach-Object
Format-Table
Format-List

Stufe 3: Ein- und Ausgabe

Import-Csv
Export-Csv
ConvertFrom-Json
ConvertTo-Json
Set-Content
Add-Content
Out-File

Stufe 4: Ändern

New-Item
Copy-Item
Move-Item
Rename-Item
Remove-Item
Start-Service
Stop-Service
Restart-Service
Stop-Process

Änderungsbefehle lernen Sie stets zusammen mit den passenden Prüfbefehlen.

# Ansehen
Get-ChildItem .\logs -Filter *.tmp

# Geplante Löschung ansehen
Get-ChildItem .\logs -Filter *.tmp | Remove-Item -WhatIf

# Ausführen
Get-ChildItem .\logs -Filter *.tmp | Remove-Item

25. Betriebliche Checkliste für den Praxiseinsatz

Setzen Sie PowerShell im Geschäftsbetrieb ein, erhöht die Prüfung folgender Punkte die Sicherheit.

  • Geprüft, ob die ausgeführte PowerShell powershell.exe oder pwsh.exe ist
  • Die Version mit $PSVersionTable geprüft
  • Vor Änderungen die Ziele mit Get-*-Befehlen angezeigt
  • Die Bedingung von Where-Object auf dem Bildschirm geprüft
  • Vor Löschen, Verschieben oder Stoppen -WhatIf verwendet
  • Die Zielliste vor der Ausführung in einer CSV gespeichert
  • In Produktivumgebungen Backup oder Wiederherstellungsverfahren geprüft
  • Die Ausführungsrichtlinie des Skripts und interne Regeln geprüft
  • Protokollausgabe für den Fehlerfall vorbereitet
  • In geteilten Skripten vollständige Befehlsnamen statt Aliase verwendet

26. Zusammenfassung

Die Grundlage von PowerShell besteht nicht darin, eine große Menge an Befehlen auswendig zu lernen. In der Praxis zahlt sich aus, sich folgendes Muster anzueignen.

Mit Get-Command suchen
Mit Get-Help die Verwendung ansehen
Mit Get-Member die Eigenschaften prüfen
Mit Get-* die Ziele ansehen
Mit Where-Object filtern
Mit Select-Object die Spalten aufbereiten
Mit Export-Csv einen Nachweis sichern
Mit -WhatIf die geplante Änderung prüfen
Zuletzt ausführen

PowerShell ist gerade deshalb eine mächtige Umgebung, weil es Dateien löschen, Dienste stoppen, Prozesse beenden und sogar die Registrierung bearbeiten kann. Genau deshalb sollten Sie zuerst nicht „die gefährlichen Befehle“ lernen, sondern „das Vorgehen, um Ziele sicher zu prüfen“.

Ansehen  Filtern  Protokollieren  Testen  Ausführen

Halten Sie diese Reihenfolge ein, wird PowerShell nicht nur ein schwarzer Bildschirm bleiben, sondern ein praktisches Werkzeug, um Windows-Arbeit zu organisieren, zu untersuchen und zu automatisieren.

Verwandte Artikel

Mit diesem Thema verbundene Leistungen

Windows-App-Entwicklung

Wir unterstützen die Entwicklung von Windows-Software wie Geschäftsanwendungen, Anlagenanbindung und Kommunikationstools.

Leistung ansehen / Kontakt

Nutzung und Migration bestehender Assets

Wir unterstützen bei der Bestandsaufnahme, Überarbeitung und Migration bestehender Assets, darunter alte Batchdateien, VBScript, VBA, PowerShell sowie COM/ActiveX.

Kontakt

Aktuelle Artikel mit denselben Schlagwörtern führen zu verwandten Themen weiter.

Diese Seiten ordnen den Artikel in einen größeren Leistungs- und Entscheidungskontext ein.

Dieser Artikel ist direkt mit den folgenden Leistungen verbunden.

Häufige Fragen

Fragen, die in Beratungen zu diesem Artikelthema häufig gestellt werden.

Womit sollte man beim Lernen von PowerShell zuerst anfangen?
Nicht mit dem Auswendiglernen von Befehlen, sondern damit, wie man nachschlägt. Drei Dinge sind entscheidend: Befehle mit Get-Command und Get-Help finden können, Ergebnisse über die Pipeline (|) an den nächsten Befehl weiterreichen können, und vor dem Löschen, Stoppen oder Ändern die Auswirkungen mit -WhatIf oder -Confirm prüfen. Ist der Name einer Objekteigenschaft unklar, prüft man den Inhalt mit Get-Member. Der Grundablauf lautet: „Suchen → Ansehen → Filtern → Sortieren → Ausgeben → bei Bedarf ändern“.
Was unterscheidet PowerShell von der Eingabeaufforderung?
Der größte Unterschied ist, dass die Ausgabe der Eingabeaufforderung vor allem aus Zeichenketten besteht, während die Ausgabe von PowerShell aus Objekten besteht. Eine Datei wird beispielsweise als Objekt mit Eigenschaften wie Name, Length und LastWriteTime behandelt, wodurch sich Filtern mit Where-Object und Sortieren mit Sort-Object ganz natürlich schreiben lassen. Auch die Befehlsnamen folgen einheitlich der Form Verb-Substantiv, etwa Get-ChildItem oder Copy-Item, wodurch sich auch unbekannte Befehle leichter finden lassen.
Sollte ich Windows PowerShell 5.1 oder PowerShell 7.x verwenden?
Wer neu einsteigt, kann sich problemlos an PowerShell 7.x (pwsh.exe) orientieren. Allerdings sind alte interne Verwaltungsskripte und Windows-spezifische Module manchmal für Windows PowerShell 5.1 (powershell.exe) geschrieben. In der Praxis prüft man deshalb zuerst mit $PSVersionTable die Version, und für Skripte, die erst ab einer bestimmten Version laufen sollen, reduziert eine Bedingung wie #Requires -Version 7.0 am Anfang des Skripts das Fehlerrisiko.
Wie führe ich Löschungen oder Änderungen in PowerShell sicher aus?
Indem man die Reihenfolge „Ansehen → Filtern → Protokollieren → Testen → Ausführen“ einhält. Konkret: zuerst mit einem Get-Befehl die Ziele anzeigen, mit Where-Object filtern, mit Select-Object die Zielliste prüfen, mit Export-Csv einen Nachweis als CSV sichern, mit -WhatIf die geplante Änderung prüfen und erst dann den eigentlichen Befehl ausführen. Da sich in PowerShell Untersuchung und Änderung auf demselben Bildschirm ausführen lassen, ist die Gewohnheit, mit einer reinen Lesekontrolle zu beginnen, entscheidend.

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.

Zurück zum Blog