Tag 3 · Block 2: Fehler, Debugging und Geheimnisse
- Führe
Get-Content C:\Kurs\gibt-es-nicht.txtin einemtry/catchaus, ohne weitere Parameter. Wird dercatch-Block ausgeführt? Warum (nicht)? - Ändere es so, dass der
catchgreift. Gib eine verständliche Meldung mit$_.Exception.Messageaus. - Füge einen
finally-Block hinzu, der „Fertig.” ausgibt. Wann läuft er? - Lies den Typ des Fehlers aus (
$_.Exception.GetType().FullName) und schreibe einen speziellencatchfür genau diesen Fehlertyp.
Lösung anzeigen
# 1. Der catch greift NICHT: nicht-terminierender Fehlertry { Get-Content C:\Kurs\gibt-es-nicht.txt }catch { "Fehler abgefangen" }
# 2. -ErrorAction Stop macht ihn terminierendtry { Get-Content C:\Kurs\gibt-es-nicht.txt -ErrorAction Stop }catch { "Fehler: $($_.Exception.Message)" }
# 3. finally läuft immertry { Get-Content C:\Kurs\gibt-es-nicht.txt -ErrorAction Stop }catch { "Fehler: $($_.Exception.Message)" }finally { "Fertig." }
# 4. Fehlertyptry { Get-Content C:\Kurs\gibt-es-nicht.txt -ErrorAction Stop }catch { $_.Exception.GetType().FullName }# -> System.Management.Automation.ItemNotFoundException
try { Get-Content C:\Kurs\gibt-es-nicht.txt -ErrorAction Stop }catch [System.Management.Automation.ItemNotFoundException] { "Datei nicht gefunden" }catch { "Anderer Fehler: $($_.Exception.Message)" }Schreibe die Funktion Read-DateiSicher mit -Pfad. Sie liest die Datei und gibt den Inhalt zurück. Existiert die Datei nicht, gibt sie eine Warnung (Write-Warning) aus und liefert nichts zurück. Teste mit C:\Windows\win.ini und mit einer nicht vorhandenen Datei.
Lösung anzeigen
function Read-DateiSicher { param([Parameter(Mandatory = $true)][string]$Pfad)
try { Get-Content -Path $Pfad -ErrorAction Stop } catch { Write-Warning "Datei '$Pfad' konnte nicht gelesen werden: $($_.Exception.Message)" }}
Read-DateiSicher -Pfad C:\Windows\win.iniRead-DateiSicher -Pfad C:\nichtda.txtDas Verb Read ist ein genehmigtes Verb (Get-Verb).
Ein Skript soll den Dienst Spooler auf mehreren Rechnern abfragen. Einer davon existiert nicht.
- Hinweis:
Get-Service -ComputerNamegibt es in PowerShell 7 nicht. NutzeInvoke-Commandpro Rechner. - Lasse die Liste
@("PSLAB-02", "PSLAB-03", "GIBTSNICHT")durchlaufen. - Fange den Fehler für den ungültigen Rechner ab, gib eine Warnung mit dem Rechnernamen aus und mache mit dem nächsten Rechner weiter.
Lösung anzeigen
$rechner = @("PSLAB-02", "PSLAB-03", "GIBTSNICHT")
foreach ($r in $rechner) { try { Invoke-Command -ComputerName $r -ScriptBlock { Get-Service -Name Spooler } -ErrorAction Stop | Select-Object PSComputerName, Name, Status } catch { Write-Warning "$r nicht erreichbar: $($_.Exception.Message)" }}Die Schleife läuft weiter, weil der Fehler im catch behandelt wurde.
- Erweitere
Get-FreierSpeicheraus Block 1 um[CmdletBinding()]und eineWrite-Verbose-Zeile („Lese Laufwerk X”). Rufe sie mit und ohne-Verboseauf. - Das folgende Skript soll die Summe von 1 bis 10 berechnen und ergibt nicht 55. Finde den Fehler mit einem Breakpoint und den Debug-Befehlen:
$summe = 0foreach ($i in 1..10) { $summe = $i}$summeSpeichere es als C:\Kurs\Skripte\Summe.ps1, setze Set-PSBreakpoint -Script ... -Line 3, starte es und beobachte $i und $summe. Behebe den Fehler.
Lösung anzeigen
function Get-FreierSpeicher { [CmdletBinding()] param([string]$Laufwerk = "C")
Write-Verbose "Lese Laufwerk $Laufwerk" $d = Get-PSDrive -Name $Laufwerk [PSCustomObject]@{ Laufwerk = $Laufwerk; FreiGB = [math]::Round($d.Free / 1GB, 1) }}Get-FreierSpeicherGet-FreierSpeicher -VerboseSet-PSBreakpoint -Script C:\Kurs\Skripte\Summe.ps1 -Line 3C:\Kurs\Skripte\Summe.ps1# Am Prompt [DBG]: $i und $summe eingeben, mit c fortsetzenGet-PSBreakpoint | Remove-PSBreakpointFehler: In Zeile 3 steht $summe = $i statt $summe += $i. Der Wert wird überschrieben und nicht addiert.
- Erstelle mit
Get-Credentialein Anmeldeobjekt fürPSLAB\teilnehmerNN(deine Nummer). Welche Eigenschaften hat es? Zeigt es das Passwort im Klartext an? - Verbinde dich mit diesem Objekt:
Invoke-Command -ComputerName PSLAB-02 -Credential $cred -ScriptBlock { whoami }. - Erzeuge ein
PSCredentialohne Eingabefenster aus einemSecureStringmitConvertTo-SecureString -AsPlainText -Force. Warum ist das in echten Skripten keine gute Idee?
Lösung anzeigen
$cred = Get-Credential -UserName "PSLAB\teilnehmer01" -Message "Passwort eingeben"$cred | Get-Member -MemberType Property$cred.UserName$cred.Password # System.Security.SecureString: kein Klartext
Invoke-Command -ComputerName PSLAB-02 -Credential $cred -ScriptBlock { whoami }
$secure = ConvertTo-SecureString "NurFuerDieUebung1!" -AsPlainText -Force$cred2 = [PSCredential]::new("PSLAB\teilnehmer01", $secure)Das Klartextpasswort steht im Skript und damit in Dateien, Versionsverwaltung und Logs.
- Installiere die Module
Microsoft.PowerShell.SecretManagementundMicrosoft.PowerShell.SecretStorefür deinen Benutzer, falls sie fehlen. - Registriere einen lokalen Tresor
KursTresorals Standard. DerSecretStoreverlangt beim ersten Mal ein Passwort für den Tresor. - Lege ein Geheimnis
LabTokenmit einem beliebigen Wert an (Wert perRead-Host -AsSecureStringabfragen) und lies es wieder aus. Wie bekommst du den Wert als Klartext, wenn du ihn wirklich brauchst? - Lege dein Anmeldeobjekt aus der vorigen Übung als Geheimnis
LabAdminab und verwende es fürInvoke-Command.
Lösung anzeigen
Install-PSResource Microsoft.PowerShell.SecretManagement, Microsoft.PowerShell.SecretStore -Scope CurrentUser -TrustRepository
Register-SecretVault -Name KursTresor -ModuleName Microsoft.PowerShell.SecretStore -DefaultVault
Set-Secret -Name LabToken -Secret (Read-Host -AsSecureString -Prompt "Token")Get-Secret -Name LabToken # SecureStringGet-Secret -Name LabToken -AsPlainText # Klartext, nur wenn nötigGet-SecretInfo
Set-Secret -Name LabAdmin -Secret $cred$c = Get-Secret -Name LabAdminInvoke-Command -ComputerName PSLAB-02 -Credential $c -ScriptBlock { whoami }