Tipps für Zwischendurch: COM-Methoden mit Enum-Werten aufrufen

Dieser Tipp ist etwas spezieller.

Ausgangspunkt ist eine COM-Dll (früher OLE Server oder COM Server genannt), die eine Methode Calculate anbietet, die drei Parameter besitzt. Der erste Parameter ist vom Typ eines Enum mit dem Namen „OpType“, die anderen beiden Parameter sind vom Typ int.

Das Anlegen eines COM-Objekts mit der ProgId ist einfach:

Der Aufruf von Calculate funktioniert zunächst nur, wenn für den Enum-Wert eine Zahl übergeben, z.B. eine 0.

Der Enum OpType ist zunächst nicht bekannt. Ein „Trick“ besteht darin, ihn per Enum-Befehl nachzubauen, den es ab Version 5.0 gibt.

Damit klappt auch der folgende Aufruf:

Tipps für Zwischendurch: Registry-Suche – besser ohne PowerShell

Das Durchsuchen der Registry ist nicht gerade die Stärke der PowerShell. Einfacher geht es mit dem reg-Kommando, dessen Syntax zudem übersichtlich per /? abrufbar ist.

Hier eine Kostprobe. Gesucht sind alle Einträge, die ein „MathLibV1“ enthalten.

Per PowerShell wäre eine solche Suche deutlich umständlicher und vor allem langsamer. Das beginnt bereits mit dem Umstand, dass es keinen Befehl gibt, der die Registry nach Werten durchsucht. Das mit Version 5.0 dazu gekommende Get-ItemPropertyValue-Cmdlet klingt praktisch, ist aber sehr limitiert, da der Name-Parameter keine Platzhalter akzeptiert.

Geht es nur um eine schnelle Suche, ist reg einfach unschlagbar.

Kleine Tipps für Zwischendurch: Namespaces mit using abkürzen

Ich war sehr überrascht als ich in einem Diskussionsthread zu PowerShell Core folgende Zeile fand:

Sollte es wie bei C# auch bei der PowerShell einen using-Befehl geben mit dem sich Namespacenamen abkürzen lassen? Gibt es diese praktische Abkürzung auch bei der Version 5.1.

Die Antwort ist ja, Namespaces lassen sich tatsächlich auf diese Weise abkürzen was gerade größere Skripte mit vielen Typenangaben deutlich übersichtlicher machen wird.

Dazu noch ein Beispiel.

Nicht spektakuär, aber auf alle Fälle eine praktische Erweiterung. Ich frage mich nur, wie ich sie bislang habe übersehen können.

Kleine Tipps für Zwischendurch: Warum beim Vergleich $null links stehen sollte

Wer mit Visual Studio Code scriptet oder öfter den PSScriptAnalyzer verwendet, was immer eine gute Idee ist, wird sich schon öfter über folgende Warnung gewundert haben:

$null should be on the left side of equality comparisons. (PSPossibleIncorrectComparisonWithNull)

Warum sollte es eine Rolle spielen, ob $null links oder rechts vom -eq Operator steht? In praktisch jeder Programmiersprache, spielt dies keine Rolle. Nun, PowerShell ist einigen Kleinigkeiten etwas anders („seltsam“ wäre als Umschreibung wohl etwas zu subjektiv;).

Hier ist ein kleines Beispiel.

Im ersten Schritt lege ich ein leeres Array an.

Die Variable $Zahlen ist eigentlich leer, daher sollte die folgende Abfrage einen $true-Wert liefern.

Es kommt aber weder $true noch $false heraus, es kommt gar nichts heraus. Was zunächst sehr seltsam erscheint (warum liefert ein Vergleich kein Ergebnis?), ergibt einen Sinn, wenn man das Prinzip des Vergleichs kennt. Da das Array leer ist, wird kein Vergleich durchgeführt. Also kein Ergebnis. Der Vergleich wird also nicht mit der Variablen $Zahlen durchgeführt, sondern mit allen Elementen des Arrays. Und da das Array kein Element enthält, wird kein Vergleich durchgeführt. Und damit resultiert kein Ergebnis. Was am Anfang eventuell noch als etwas seltsam erschien, ergibt jetzt einen Sinn. So sollte es sein.

Möchte man die Variable $Zahlen richtig vergleichen, muss $null auf der linken Seite stehen:

Jetzt wird das Array als Ganzes verglichen. Der Vergleich führt zu einem $false, da die Variable mit einem leeren Array einen Wert besitzt.

PowerShell Module schreiben – mit ein paar Tools geht es leichter

Das Schreiben eines PowerShell Moduls ist grundsätzlich nicht schwer. Im einfachsten Fall speichert man lediglich eine Ps1-Datei mit ein paar Functions als Psm1-Datei in ein leeres Verzeichnis und fertig ist das Modul. Möchte man es richtig machen, steckt eine Menge Arbeit dahinter (ich muss es wissen, denn in meiner Freizeit arbeite ich seit ein paar Wochen an meinem Osmium-Modul, das es in ein paar Wochen auf GitHub bzw. in der PowerShell Gallery geben wird).

Welche Tools Modulautoren unterstützen können, hat PowerShell-Experte David Christian in einem Blog-Eintrag zusammengestellt:

https://overpoweredshell.com//Tools-Module-Authors-Should-Leverage/

Kleine Tipps für Zwischendurch: ForEach-Wiederholung mit Zählvariable

Ein kleiner Nachteil der praktischen ForEach-Methode von Arrays ist, dass es keine Zählvariable gibt. Mit dem ++-Operator spart man sich zumindestens einen weiteren Befehl, der die Variable inkrementiert.

Tipp: Oracle Datenbanken per PowerShell ansprechen

Wer Oracle hört, denkt wahrscheinlich zunächst an hochpreisige Produkte und komplizierte Installationen. Das ist natürlich nur bedingt der Fall.

In jedem Fall ist der Zugriff auf eine Oracle DB per PowerShell sehr einfach. Voraussetzung ist, dass ODP.NET (z.B. als Teil der Developer Tools for Visual Studio) installiert wurde. Die Developer Tools installiert man auch dann, wenn kein Visual Studio vorhanden ist. In jedem Fall gibt es danach eine Assembly mit dem Namen Oracle.ManagedDataAccess.dll in dem Verzeichnis, in das die Developer Tools installiert wurden.

Das folgende kleine Beispiel geht von einer vorhandenen Datenbank aus. Benutzername und Kennwort sind natürlich frei erfunden. Wichtig ist nur, dass der Pfad der Dll-Datei stimmt.

Für eine konkrete Datenbankabfrage muss lediglich ein OracleCommand-Objekt angelegt, der CommandText-Eigenschaft ein SQL-Kommando zugeordnet und per ExecuteReader() ein DataReader geholt werden, der dann per Read() durchlaufen wird. Sollte alles kein Problem sein.

PS: Ein Listener muss dazu nicht mehr konfiguriert werden. Die Oracle DB läuft ohnehin nicht auf dem Computer, auf dem die Abfrage ausgeführt wird.

Wenn das Laden einer Assembly per Add-Type mit der Fehlermeldung „Operation not supported“ fehlschlägt…

Das Laden einer Assembly in einem PowerShell-Skript ist im Grunde sehr einfach: Per Add-Type und dem Path-Parameter.

Vor kurzem hatte ich einen Fall, bei dem sich eine Assembly (Npgsql.dll für den Zugriff auf PostgreSQL-Datenbanken) einfach nicht laden lies. Es war frustrierend, da mir wieder einmal klar wurde wieviel (Lebens-)zeit ich schon mit solchem Sch… verbracht hatte (sorry;).

Am Ende war die Lösung so trivial, dass ich einen Tritt in den Hintern verdient gehabt hätte. Ich hatte vergessen, die Datei zu „entsperren“ also den Zone.Identifier-ADS aus der Datei zu entfernen.

Nach einem Neustart der ISE lies sie sich problemlos laden. Ich hätte vielleicht auch eher nach dem Fehlercode 0x80131515 googlen sollen. Dann wäre ich auf einen StackOverflow-Beitrag gestoßen, der alles erklärt:

https://stackoverflow.com/questions/13799260/powershell-runtime-exception-could-not-load-file-or-assembly

„Suchet und ihr werdet finden“ (Matthäus 7,7)

Kleine Tipps für Zwischendurch: Hex-Zahlen als Dezimalzahlen ausgeben

Das Umwandeln eines Hex-Wertes in einen Dezimalwert ist wirklich sehr einfach:

„Hex“ ist aber keine „magische Zutat“, sondern die wie immer sehr praktische Eigenschaft der PowerShell, das die Felder einer Konstantenliste nicht nur nicht vollständig qualifiziert werden müssen, sondern auch abgekürzt werden können. Offiziell wäre der Name System.Globalization.NumberStyles.HexNumber.

Kleine Tipps für Zwischendurch: Textabfragen mit Sls (Select-String)

Der Umstand, dass bei der PowerShell alles auf Objekten basiert, bietet nicht nur Vorteile. Ein Ausnahme von der Regel ist das Durchsuchen der History.

Wer

eintippt erwartet, dass alle Befehlszeilen ausgeben, die das Wort „startapp“ enthalten. Dem ist aber nicht so, da für das gewünschte Resultat explizit die CommandLine-Eigenschaft abgefragt werden müsste.

Auch ein

bringt nicht. Wer es mit ? alias Where-Object

eingeben. Das ist für das mal eben-Abfragen der History natürlich keine Option. Zum Glück gibt es mit Select-String und seinem Alias sls eine einfache Alternative:

Dieser Befehl durchsucht den Output von Get-History unabhängig von den Namen einzelner Eigenschaften nach dem Wort „startapp“.

Dass bei dieser Abfrage MatchInfo-Objekte resultieren, was eventuell eine Weiterverarbeitung etwas erschweren könnte, wollen wir großzügig übersehen.