Archiv des Autors: PemoAdmin

Mein Blog zieht um (bzw. wird eingestellt)

Irgendwann muss Schluss sein. Nachdem ich viele Jahre über die PowerShell „gebloggt“ hatte (leider nicht von Anfang an, wenngleich ich die PowerShell noch aus der Zeit kenne, in der sie lediglich unter dem Codenamen „Monad Shell“ – kurz und prägnant msh, bekannt war, bis jemand, vermutlich aus der Marketingabteilung, auf den Namen „PowerShell“ kam, der in der damals noch sehr kleinen Community nicht ganz unumstritten war, um es einmal moderat zu formulieren), ist jetzt Schluss.

Ich stelle den Blog daher am 31.5 2021 ein. Danach wird auch die Seite nicht mehr aufrufbar sein.

Ich werde aber auch in Zukunft in meinem „Hauptblog“ https://codeinsel.de über die PowerShell schreiben.

Flexibles Replace dank MatchEvaluator

Eine simple Anforderung soll (unbedingt;) per Regex gelöst werden: Der Ersatz einer Umgebungsvariablen in der alten Schreibweise aus einer Pfadangabe.

Beispiel:

Aus einem %temp%\test123 soll %temp% durch den Pfad des temp-Verzeichns im Benutzerprofil ersetzt werden.

Das Problem: Der Replace-Operator ermöglicht keine Ausdrücke in dem Einsetzwert.

Der folgende Befehl ersetzt lediglich %temp% durch temp:

"%temp%\test1234.dat" -replace "%(\w+)%", '$1'

Statt „temp“ soll z.B. [Environment]::GetEnvironment(Variable($1) eingesetzt werden.

Auch wenn ich einiges ausprobiert hatte, der zweite Wert darf nur aus $1, $S2 usw. bestehen. Ein Ausdruck, bei dem $1 als Operand vorkommt, ist nicht erlaubt.

Zum Glück gibt es eine flexible Alternative. Diese besteht darin, die statische Replace-Methode der Regex-Klasse zu verwenden beim Aufruf einen MatchEvaluator zu übergeben, der bei der PowerShell lediglich aus einem ScriptBlock besteht, dem der Match als Parameterwert übergeben wird:

$t = "%temp%\Test1234.dat" $m = "%(\w+)%" $MatchEval = { param($match) [Environment]::GetEnvironmentVariable($match.groups[1].value) } [Regex]::Replace($t, $m, $MatchEval)

PowerShell DevOps Global Summit 2021

Heute (29.4.2021) ist der letzte Tag des PowerShell DevOps Global Summit 2021, an dem ich dieses Mal virtuell teilnehme (auch wenn es natürlich sehr viel schöner gewesen wäre, im sehr schönen Meydenbauer Center in Bellevue/WA an der Konferenz teilzunehmen – vor allem die Happy Hour am Abend ist sehr gut;).

Es war eher ein spontaner Entschluss – die Konferenzteilnahme kostet 300 USD, was absolut in Ordnung ist.

Mein Zwischenfazit ist, dass alle Vorträge bislang sehr gut waren. Auch wenn es in einigen Vorträgen eher um die „Basics“ ging (etwa SQL Server-Konfiguration per DSC oder die API der PowerShell), waren die Vorträge eine sehr gute Mischung aus etwas Theorie und sehr viel Praxis. Und darauf kommt es am Ende immer an. Auch die Sprecher selber sind alle sehr gut.

Nicht ganz so inspirierend wie früher war die Keynote mit Jeffrey Snover und Joey Aiello. Erster ist bekanntlich der Erfinder der PowerShell, Letzter der Leiter des Entwicklerteams (beide waren auch bereits bei einer der letzten European PowerShell Conferences in Hannover dabei, so dass sie viele PowerShell-Fans inzwischen auch persönlich kennen dürften – zum Smalltalk gibt es auf der Konferenz stets viele Gelegenheiten). Es ging wieder einmal in erster Linie um einen Rückblick und über die Abrufzahlen von der Projektwebseite (Windows holt auf) und was mit PowerShell 7.2 kommen könnte. Zum einen ist das normal für ein größeres Open Source-Projekt. Zum anderen macht sich bei Menschen, die täglich in einem halben Dutzend Videokonferenzen sein dürften, irgendwann auch einmal die „Zoom-Müdigkeit“ bemerkbar. Immerhin haben die Konferenzveranstalter nicht Ms Teams verwendet, sondern eine kleine Plattform, die speziell für Online-Konferenzen gedacht ist, und die insgesamt sehr gut funktioniert hat.

Es war auch nett, einige der aus der PowerShell Community bekannten Namen zu lesen. Auch wenn der Austausch meistens nur im Chat-Fenster stattfand, kam doch etwas „Konferenz-Feeling“ auf.

Die Adresse des PowerShell Summits noch zum Schluss: https://events.devopscollective.org/event/powershell-devops-global-summit-2021/

Abb. Dieses Mal nur virtuell – der „State of the Union“-Vortrag 2021 zum aktuellen Stand der PowerShell mit PowerShell-Erfinder Jeffrey Snover und PowerShell-Chef-Projektleiter Joey Aiello

Neue PowerShell-Bücher

Gleich vorweg, diesen Eintrag wollte ich bereits im August 2020 schreiben, bin aber offenbar nicht dazu gekommen, ihn fertig zustellen – wie die Zeit vergeht…

Es gibt sie noch, die PowerShell-Bücher, in denen auch für erfahrene PowerShell-Anwender etwas Neues drin steht. Man findet sie allerdings weniger bei den Fachverlagen, diese Bücher werden schon seit längerem durch die Autoren direkt herausgegeben und über eBook-Plattformen wie lulu.com oder leanpub.com angeboten.

Das erste Buch von zwei Büchern, das ich kurz vorstellen möchte, ist allerdings nicht per Print on Demand erhältlich, das wäre aufgrund des Umfangs wahrscheinlich technisch gar nicht möglich. Es ist „das“ Standardwerk zur PowerShell im deutschsprachigen Raum von Holger Schwichtenberg, das ich vor ein paar Wochen vom Hanser Verlag erhalten habe (vielen Dank noch einmal an dieser Stelle – ich hätte es mir aber auch nicht gekauft, davon gleich mehr).

Es gibt sie noch, die dicken Wälzer, die im Buchregal nicht zu übersehen sind
Abb. Es gibt sie noch, die dicken Wälzer, die im Buchregal nicht zu übersehen sind

PowerShell 5/7 ist ein Buch, in dem praktisch alles drin steht was man als Anwender, aber auch als Entwickler zur PowerShell wissen muss und wissen könnte – natürlich gibt es immer noch Randbereiche, die auch in diesem Buch nicht behandelt werden, mir fehlt z.B. das Thema Release-Pipeline für PowerShell-Module oder mehr Informationen zum Script Analyzer, aber das sind wie gesagt Randbereiche, in die sich jeder erfahrene Anwender über das Know-how auf den entsprechenden Webseiten selber einarbeiten kann.

Zwei eher kuriose Details zu dem Buch:

  1. Mit 1.386 Seiten ist es glaube ich mein dickstes Buch im Regal (ein paar Seiten mehr als „Windows Server 2008“ von Eric Tierling) und mit Sicherheit ein paar Seiten mehr als „Krieg und Frieden“ von Tolstoy.
  2. Es dürfte das weltweit einzige IT-Buch sein, bei dem zwei nicht zusammenhängende Versionsnummern im Titel stehen.

Das zweite Buch geht in die entgegengesetzte Richtung. Anstatt ein zusammenhängendes Thema zu beschreiben, enthält es viele Themen, die lediglich den fortgeschrittenen Einsatz der PowerShell zum Thema haben. Es ist das PowerShell Conference Book, Volume 3, das von den Organisatoren des jährlich stattfindenden DevOps Summit herausgegeben wird.

https://leanpub.com/psconfbook3

Mit einem Minimum-Preis von 49.99 USD ist es nicht gerade günstig (ich hatte es gleich zum „Einführungspreis“ von 20 USD gekauft), aber es enthält das sprichwörtlich „geballte Wissen“, das man normaleweise nur durch Teilnahme an einer solchen Konferenz erhält und die ist bekanntlich deutlich kostspieliger (ähnliche Überlegungen dürften auch die Herausgeber angestellt haben). Laut Webseite verdienen die Autoren an dem Buch nichts, der Gewinn fließt komplett an eine Stiftung (https://events.devopscollective.org/onramp/scholarship/).

Abb. Geballtes Wissen einer Fachkonferenz

EIne weitere Buchempfehlung betrifft ein Buch, das ich bislang weder gekauft noch gelesen habe, sondern nur das kostenlose Probekapitel kenne. In „Shell of an Idea“ beschreibt PowerShell Guru Don Jones ausführlich die Anfänge des PowerShell-Projekts bei Microsoft und dabei vor allem über die Widrigkeiten, denen das kleine Team von Anfang ausgesetzt war (es hätte nicht viel gefehlt und wir hätten anstelle der PowerShell einen 1:1 Port einer gewöhnlichen Unix-Shell erhalten). Das Vorwort ist natürlich von Jeffrey Snover, dem geistigen Vater der PowerShell. Auch wenn das Buch bestimmt sehr interessant ist und ich es natürlich auch irgendwann in naher Zukunft lesen werde, es ist nur etwas für die paar Tausend „Hardcore PowerShell Fans“ auf der ganzen Welt, die aus erster Hand erfahren wollen wie alles anfing (vieles hat Jeffrey Snover in den letzten Jahren in zahlreichen Interviews und in seinen Vorträgen, die es fast alle auf YouTube gibt, bereits erzählt).

Unterschied zwischen PowerShell und Python – kurz, knapp und sehr eindrucksvoll

Der Vergleich zwischen Programmiersprache A und Programmiersprache B ist im Allgemeinen wie der sprichwörtliche Vergleich zwischen Äpfel und Birnen. Zwei Programmiersprachen lassen sich einfach nicht objektiv vergleichen. Der folgende „Vergleich“ zwischen PowerShell und Python ist daher auch nicht ganz ernst gemeint.

Eine Stärke von Python ist, dass es keine echte Limitierung für die Größe von ganzen Zahlen gibt.

Der folgende Ausdruck liefert in Python eine Zahl, die in einem typischen Konsolenfenster ganze 245 Zeilen (!) umfasst.

Bei der PowerShell besteht das Ergebnis dagegen aus nur einem einzigen Zeichen. Mathematisch korrekt sind beide;)

Die PowerShellv erwendete für sehr große Zahlen eine praktische Abkürzung;)

Tipp des Tages: Source-Abfrage bei Get-WinEvent

Bei PowerShell 7 gibt es bekanntlich kein Get-EventLog-Cmdlet mehr, statt dessen gibt es das universelle Get-WinEvent-Cmdlet, das es bereits bei der Windows PowerShell gab. Das Cmdlet ist zwar insgesamt leistungsfähiger, aber auch nicht ganz so pflegeleicht, da Filterparameter entweder über eine Hashtable oder einen XPath-Ausdruck angegeben werden müssen.

Ich habe ein wenig suchen müssen, um das Pendant für den Source-Parameter von Get-Eventlog für Get-WinEvent ausfindig zu machen. Es ist in beiden Fällen die Angabe „Providername“ innerhalb des Suchausdrucks.

Die beiden folgenden Befehle geben die letzten 10 Einträge aus dem System-Eventlog zurück, die vom Service Control Manager geschrieben wurden.


Get-WinEvent -FilterHashtable @{Logname="System";Providername='Service Control Manager'} -MaxEvents 10

und


Get-WinEvent -FilterXPath "Event/System/Provider[@Name='Service Control Manager']" -LogName System -MaxEvents 10

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.

Tipp des Tages: Ein Sql-Skript nach Tabellennamen gruppieren

Ausgangspunkt ist eine (sehr große) Sql-Skriptdatei, die mehrere Zehntausend Insert Into-Befehlszeilen enthält (es können auch ein paar mehr sein;). Insgesamt werden ca. ein Dutzend unterschiedliche Tabellen angesprochen.

Problem: Ich möchte die Namen aller Tabellen enthalten.

Lösung: Zerlegen der Datei per Select-String und einem einfachen Regex und gruppieren nach einer per Select-Object angelegten Property. Also, alles klassische PowerShell-Zutaten, die auch Anwendern geläufig sind, die die PowerShell nur sporadisch benutzen.

PS D:\Datenbanken\Select-String .\VGEFA.sql -Pattern "[dbo].[(\w+)]" | Select-Object @{n="TabName";e={$_.Matches[0].Groups[1].Value}} | Group-Object TabName