Archiv für den Monat: Februar 2021

Pester 3.4.0 entfernen

So genial Pester auch ist, ein kleiner Makel ist der Umstand, dass Windows 10 und WIndows Server mit einer Version vorinstalliert werden (ich habe es bereits irgendwo erwähnt – Pester war das erste Open Source-Programm, das fester Bestandteil einer Windows-Installation ist), die inzwischen vollkommen veraltet ist. Seit der Version 4.0 (aktuell ist die Version 5.1.1 – Stand Feb 2021) hat es viele Änderungen gegeben, so dass man mit der Originalversion nicht mehr arbeiten sollte.

Das Löschen des Modulverzeichnisses scheitert aber zunächst an dem Umstand, dass es sich aufgrund fehlender Berechtigungen nicht löschen lässt. Der TrustedInstaller lässt es nicht zu.

Man muss daher zunächst den Ordner als Administrator in Besitz nehmen und die TrustedInstaller-Berechtigungen entfernen. Auch wenn das alles sowohl im Explorer als auch per PowerShell möglich ist, am einfachsten geht es mit Hilfe der guten, alten Kommandozeilentools takeown und icacls.

Die folgende Befehlsfolge zeigt, wie es für ein bestimmtes Verzeichnis unter einem 32- und 64-Bit-Windows funktioniert.


$PesterModulPfad = "C:\Program Files\WindowsPowerShell\Modules\Pester\3.4.0"
if (Test-Path -Path $PesterModulPfad)
{
    takeown /F $PesterModulPfad /A /R
    icacls $PesterModulPfad /reset
    icacls $pesterPath /grant "*S-1-5-32-544:F" /inheritance:d /T
    Remove-Item -Path $PesterModulPfad -Recurse -Force -Confirm:$false # -WhatIf
}
else
{
    Write-Warning "!!! $PesterModulPfad existiert nicht !!!"
}

Auch wenn jede Menge Syntaxhilfe ausgegeben wird (irgendetwas scheint mit den Aufrufparametern noch nicht zu stimmen), wird das Pester 3.4.0-Verzeichnis am Ende entfernt.

Eine ausführlichere Abhandlung der Thematik kann man in den GitHub-Gists von Jakub Jareš nachlesen (ein „Gist“ ist beim Microsoft-GitHub-Portal die Bezeichnung für einen Codeschnipsel bzw. eine einzelne Datei).

Remove built-in version of Pester 3 (or -All) from Windows 10 Program Files and Program Files (x86). (github.com)

PS: Das Pester-Projekt hat schon seit längerem eine eigene Projektwebseite: https://pester.dev/

Tipp des Tages: Die Befehlshistorie nach bereits eingegebenen Befehlen durchsuchen

Dieser Tipp ist so trivial, dass er eigentlich keiner Erwähnung wert ist, aber mir hat er geholfen, so dass sich davon ausgehe, dass er auch anderen Powershell-Anwendern die tägliche Arbeit etwas erleichtert.

Dank PsReadlLine wird die Befehlshistory in einer separaten Datei abgelegt, so dass sie immer zur Verfügung steht (allerdings nur über die Pfeiltasten und nicht per Get-History – dieses Command listet nur die interne Befehlshistorie auf, die mit dem Beenden der Sitzung verloren ist). Das hat zur Folge, dass die Befehlshistorie der PowerShell durchaus einen Zeitraum von mehreren Wochen oder gar Monaten umfasst.

Möchte man einen Befehl ausführen, den man vor längerer Zeit bereits eingegeben und ausgeführt hatte, muss man lediglich per [F8] danach suchen. Die Suche besteht darin, die ersten zwei oder drei Zeichen des Befehls einzugeben und danach [F8] zu drücken. Die erste Befehlszeile, in der die Eingabe enthalten ist, wird in den Befehlspuffer geholt. Mit jedem [F8] wird der nächste Treffer geholt, per [Umschalt]+[F8] geht es wieder rückwärts.

Tipp des Tages: Hashtable-Property in Key-Value-Paare auflösen

Dieser Tipp klingt eventuell etwas speziell, ist aber für die Weiterverarbeitung bestimmter Rückgaben enorm praktisch. Einige Rückgaben von PowerShell-Commands bestehen aus einer einzigen Hashtable, erscheinen aber bei der Ausgabe wie viele Werte, da die Key-Value-Paare bei der Ausgabe automatisch aufgelöst werden.

Konkretes Beispiel: Auflisten der Umgebungsvariablen über [Environment]::GetEnvironmentVariables().

Auch wenn die Ausgabe nach vielen Werten aussieht, besteht sie nur aus einer Hashtable. Ein Sortieren nach dem Namen der Umgebungsvariablen ist daher nicht möglich.

Abhilfe schafft die universelle GetEnumerator()-Methode, welche die Elemente der Hashtable zurückgibt, und die einfach nur an die Ausgabe gehängt werden muss.

[Environment]::GetEnvironmentVariables().GetEnumerator() | Sort-Object Name

Ein Sortieren nach den Namen der Umgebungsvariablen ist damit möglich.

Ebenfalls sehr praktisch, das Auflisten aller dynamischen Parameter eines Cmdlets:

(Get-Command -Name Get-Content).Parameters.GetEnumerator() | Where-Object { $_.Value.IsDynmic}

Ohne GetEnumerator() wäre das deutlich aufwändiger, da man zuerst alle Keys durchlaufen müsste, um dann in der Wiederholung über den Key den Wert abzurufen. Dafür braucht man Zeit, Ausdauer und gute Nerven. Dank GetEnumerator() wird die Weiterverarbeitung sperriger Rückgaben powershell-typisch und damit einfach und konsistent.