Automatisierung mit Objekten statt Text
Ausführen: PowerShell 7 (pwsh) läuft auf Windows, macOS und Linux. Skript als skript.ps1 speichern und mit pwsh ./skript.ps1 starten.
Get-Process), Variablen beginnen mit $Get-Command, Get-Help, Get-Member sind die Entdeckungswerkzeugepwsh) läuft plattformübergreifendpwsh # interaktive Shell (Linux/macOS/Windows)
pwsh -File skript.ps1 # Skript ausführen
pwsh -Command "Get-Date" # einzelner Befehl$, optional typisiert ([int]$x); .NET-Typen und -Methoden stehen zur Verfügung"..." ersetzt Variablen und $(...), '...' wörtlich; Escape-Zeichen ist der Backtick-eq -ne -gt -lt -like -match -in -contains-f und Regex-Operatoren -replace, -split, -match[math]:: und [datetime] für Mathematik und Datum$name = "Mia"
[int]$alter = 17
[double]$groesse = 1.68
$aktiv = $true
$nichts = $null
"{0} {1} {2} {3}" -f $name.GetType().Name, $alter.GetType().Name, $groesse.GetType().Name, $aktiv.GetType().Name
$x = 5
$x += 10
$x *= 2
$x
$a, $b = 1, 2
$a, $b = $b, $a
"$a $b"
$text = "42"
$text + 1
1 + $text
[int]$text + 1
"5" * 3
"abc".Length
[int]"12" + [int]"30"
"3.7" -as [double]
"x" -as [int]
$null -eq $nichts$_ ist das aktuelle ObjektWhere-Object, Select-Object, Sort-Object, Group-Object, Measure-Object, ForEach-ObjectFormat-Table/Format-List nur zur Anzeige am EndeGet-Member entdeckt Eigenschaften und Methoden; alle .NET-Klassen sind nutzbarConvertTo-Json, ConvertFrom-Json, Export-Csv, Import-Csv für Datenformate$leute = @(
[pscustomobject]@{ Name = "Mia"; Alter = 17; Stadt = "Berlin"; Punkte = 120 }
[pscustomobject]@{ Name = "Tom"; Alter = 25; Stadt = "Hamburg"; Punkte = 80 }
[pscustomobject]@{ Name = "Zoe"; Alter = 31; Stadt = "Berlin"; Punkte = 200 }
[pscustomobject]@{ Name = "Ben"; Alter = 9; Stadt = "Köln"; Punkte = 50 }
)
$leute | Where-Object { $_.Alter -ge 18 } | Select-Object -ExpandProperty Name
($leute | Sort-Object Punkte -Descending | Select-Object -First 2).Name -join ", "
$leute | Where-Object Stadt -eq "Berlin" | ForEach-Object { "$($_.Name): $($_.Punkte)" }
$leute | Measure-Object Punkte -Sum -Average -Maximum | ForEach-Object { "$($_.Sum) $($_.Average) $($_.Maximum)" }
$leute | Group-Object Stadt | Sort-Object Name | ForEach-Object { "$($_.Name): $($_.Count)" }
$leute | Select-Object Name, @{ Name = "Doppelt"; Expression = { $_.Punkte * 2 } } | Format-Table -AutoSize | Out-String -Width 60
($leute | Where-Object { $_.Punkte -gt 100 }).Count
$leute.Name
$leute | ForEach-Object -Begin { $summe = 0 } -Process { $summe += $_.Punkte } -End { "Summe $summe" }if/elseif/else, switch (mit -Wildcard, -Regex), ternär ? : und ?? in PowerShell 7for, foreach, while, do, ForEach-Object; break/continue@(), Indizes ab 0, += erzeugt neue Arrays; List[T] für viele Elemente@{ Key = Wert }, [ordered], Splatting @param$x = foreach (...) { ... }$punkte = 78
if ($punkte -ge 90) { "sehr gut" }
elseif ($punkte -ge 75) { "gut" }
else { "weiter üben" }
$status = if ($punkte -ge 50) { "bestanden" } else { "durchgefallen" } # if als Ausdruck
$status
$ergebnis = $punkte -gt 50 ? "über 50" : "bis 50" # ternär (PowerShell 7)
$ergebnis
$name = $null
$name ?? "Gast" # Null-Coalescing (7)
$name ??= "gesetzt"; $name
switch ($punkte) {
{ $_ -ge 90 } { "A"; break }
{ $_ -ge 75 } { "B"; break }
default { "C" }
}
switch -Wildcard ("datei.txt") {
"*.txt" { "Textdatei" }
"*.md" { "Markdown" }
}
switch -Regex ("2025-03-15") { '^\d{4}-\d{2}' { "Datum erkannt" } }function Name { param(...) ... }; Parameter mit Typ, Standardwert, Validierungreturn[CmdletBinding()], Mandatory, ValueFromPipeline, ValidateSet machen Funktionen cmdlet-artigtry/catch/finally, throw, -ErrorAction Stop für abbrechende Fehler$ErrorActionPreference = "Stop" und Set-StrictMode in Skriptenfunction Get-Gruss {
param(
[string]$Name = "Welt",
[string]$Anrede = "Hallo"
)
"$Anrede, $Name!"
}
function Get-Quadrat([int]$Zahl) { $Zahl * $Zahl }
Get-Gruss
Get-Gruss -Name "Mia"
Get-Gruss "Tom" "Hi"
Get-Gruss -Anrede "Servus" -Name "Zoe"
Get-Quadrat 7
Get-Quadrat -Zahl 8
function Get-Statistik {
param([double[]]$Werte)
[pscustomobject]@{
Anzahl = $Werte.Count
Summe = ($Werte | Measure-Object -Sum).Sum
Mittel = [math]::Round(($Werte | Measure-Object -Average).Average, 2)
}
}
$stat = Get-Statistik -Werte 2, 4, 4, 4, 5, 5, 7, 9
"$($stat.Anzahl) $($stat.Summe) $($stat.Mittel)"Get-ChildItem, Get-Content, Set-Content, Copy-Item, Remove-Item, Test-PathSelect-String ersetzt grep; -match/-replace und [regex] für reguläre AusdrückeInstall-Module), z. B. Az, PesterEnter-PSSession/Invoke-Command, Web mit Invoke-RestMethod$dir = Join-Path ([IO.Path]::GetTempPath()) "psdemo_$(Get-Random)"
New-Item -ItemType Directory -Path $dir | Out-Null
Set-Location $dir
"Zeile 1`nZeile 2`nZeile 3" | Set-Content "notiz.txt"
Add-Content "notiz.txt" "Zeile 4"
Get-Content "notiz.txt" | Measure-Object -Line | ForEach-Object Lines
(Get-Content "notiz.txt")[1]
Get-Content "notiz.txt" -TotalCount 2
Test-Path "notiz.txt"; Test-Path "gibt-es-nicht"
New-Item -ItemType Directory "unter" | Out-Null
Copy-Item "notiz.txt" "unter/kopie.txt"
Rename-Item "unter/kopie.txt" "umbenannt.txt"
"a;b`n1;2`n3;4" | Set-Content "daten.csv"
Get-ChildItem | Sort-Object Name | ForEach-Object { "$($_.Name) ($($_.PSIsContainer ? 'Ordner' : "$($_.Length) Bytes"))" }
Get-ChildItem -Recurse -File | ForEach-Object { $_.FullName.Substring($dir.Length + 1) } | Sort-Object
(Import-Csv "daten.csv" -Delimiter ";" | Measure-Object a -Sum).Sum
Get-ChildItem *.txt | Select-String "Zeile 3" | ForEach-Object { "$($_.LineNumber): $($_.Line)" }
Remove-Item "unter" -Recurse
Set-Location ..
Remove-Item $dir -Recurse -Force
Test-Path $dir$Matches.datum) macht Log-Auswertung einfach[pscustomobject] baut eigene Datensätze; Group-Object, Measure-Object fassen zusammen[CmdletBinding(SupportsShouldProcess)] mit -WhatIf für sichere Skriptepwsh ausführen$log = @"
2025-03-01 10:00:01 INFO Dienst gestartet
2025-03-01 10:05:12 ERROR Datenbank nicht erreichbar
2025-03-01 10:06:40 WARN Wiederholungsversuch 1
2025-03-02 08:15:00 INFO Nutzer mia angemeldet
2025-03-02 09:30:21 ERROR Zeitüberschreitung bei /api/daten
2025-03-02 09:31:05 ERROR Zeitüberschreitung bei /api/daten
2025-03-03 12:00:00 INFO Nutzer tom angemeldet
"@ -split "`r?`n" | Where-Object { $_ }
$eintraege = foreach ($zeile in $log) {
if ($zeile -match '^(?<datum>\S+) (?<zeit>\S+) (?<stufe>\w+)\s+(?<text>.*)$') {
[pscustomobject]@{
Datum = [datetime]$Matches.datum
Stufe = $Matches.stufe
Text = $Matches.text
}
}
}
"Einträge gesamt: $($eintraege.Count)"
"--- pro Stufe"
$eintraege | Group-Object Stufe | Sort-Object Count -Descending | ForEach-Object { "{0,-6} {1}" -f $_.Name, $_.Count }
"--- Fehler pro Tag"
$eintraege | Where-Object Stufe -eq "ERROR" | Group-Object { $_.Datum.ToString("yyyy-MM-dd") } | ForEach-Object { "$($_.Name): $($_.Count)" }
"--- häufigste Fehlermeldung"
$eintraege | Where-Object Stufe -eq "ERROR" | Group-Object Text | Sort-Object Count -Descending | Select-Object -First 1 | ForEach-Object { "$($_.Name) ($($_.Count)x)" }
"--- Nutzer"
($eintraege | Where-Object Text -like "Nutzer*" | ForEach-Object { ($_.Text -split " ")[1] } | Sort-Object) -join ", "Where-Object, Select-Object, Sort-ObjectGet-Help/Get-MemberSet-StrictMode, $ErrorActionPreference = "Stop", try/catchVergleich: -eq -ne -gt -ge -lt -le (Groß/Klein egal; -ceq -cne: unterscheidet)
Text: -like -notlike -match -notmatch -replace -split -join -f
Menge: -in -notin -contains -notcontains
Logik: -and -or -not -xor !
Typ: -is -isnot -as
Umleitung: > >> 2> 2>&1 *>
PS 7: ?: ?? ??= && || (Pipeline-Verkettung)