Archiv des Autors: PemoAdmin

PowerShell-Experten-Tipp: Array-Eigenschaften in Klassen

Eigenschaften in per class-Befehl definierten Klassen können einen beliebigen Datentyp besitzen, natürlich auch Array bzw. den Datentyp für ein mehrdimensionales Array mit Werten eines wiederum beliebigen Typs. Die Schreibweise für den Datentyp ist dieselbe wie bei einer Variablendeklaration, also z.B. [Double[,]] für ein zweidimensionales Array mit Double-Werten.

Das folgende Beispiel ist abstrakt und dient lediglich dazu, die Syntax zu veranschaulichen.

Ausgangspunkt ist eine Klasse M. Sie besitzt eine Property Prop1.

Die zweite Klasse N> besitzt eine Array-Property mit Objekten vom Typ N.

Der Eigenschaft Werte werden direkte Werte zugewiesen, das Array muss also nicht initialisiert werden.

Soll eine Klasse eine Eigenschaft besitzen, die auf einem zweidimensionalen Array basiert, wird für Schreibweise des Datentyps die bei der PowerShell allgemein übliche Schreibweise verwendet.

Außerdem muss die Property explizit per New-Object initialisiert werden, da ansonsten das Array nicht angelegt wird.

Tipp: Die Anzahl der Dimensionen liefert die rank-Eigenschaft des Array. Über die Methode GetUpperBound() erhält man die Obergrenze für eine bestimmte Dimension (0, 1 usw.).

Functions wie Functions aufrufen – über einen kleinen Umweg kein Problem

Eine der Grundideen bei der Planung und Umsetzung der PowerShell war damals, dass sie ein möglichst breites „Publikum“ ansprechen soll, und dass niemand gezwungen werden sollte vertraute Gewohnheiten und Schreibweisen beim Scripten aufgeben zu müssen.

Eine der dieser Gewohnheiten ist die bei anderen Skript- und Programmiersprachen übliche Form der Function-Definition und des Aufrufs einer Function. Demnach folgen auf den Befehl, der die Function definiert, die Parameter in runden Klammern:

Beim Aufruf der Function werden die Argumente ebenfalls in runden Klammern gesetzt:

Auch in PowerShell können Functions auf diese Weise definiert und aufgerufen werden, wenngleich dies eher eine Ausnahme ist. Die einzige Einschränkung besteht darin, dass eine Übergabe mehrerer per Komma getrennter Werte wie üblich die Übergabe eines Arrays bedeutet. Werden daher mehrere Werte übergeben, müssen diese als Array angesprochen werden.

Das folgende Beispiel ist nicht nur etwas umfangreicher, es behandelt auch einen Bereich, der im IT-Alltag eher selten vorkommt: Es geht um die Berechnung der Determinante von Vektoren mit zwei Komponenten und anderen Dingen, die etwas mit „analytischer Geometrie“ (aber eher auf dem Niveau des 11. Schuljahres) zu tun haben.

Im ersten Schritt werden lediglich zwei Klassen für Vektoren mit zwei und mit drei Komponenten definiert.

Die Klassendefinition wäre nicht erforderlich und setzt zudem PowerShell ab Version 5.0 voraus, aber mit den Klassendefinitionen wird das Beispiel insgesamt etwas besser nachvollziehbar.

Im nächsten Schritt kommen zwei Function-Definitionen zum Einsatz, über die Vektoren definiert werden:

Dass auf den param-Befehl verzichtet wird ist keine Voraussetzung, um die Function wie bei Programmiersprachen üblich aufrufen zu können. Wichtig ist lediglich, dass die Function einen Array-Parameter besitzt, dem alle Argumente übergeben werden.

Der Aufruf der Function v2 sieht wie folgt aus:

und

Mit den zweiten Vektoren wird im nächsten Schritt mit der Function det2 die Determinante der 2×2-Matrize ausgerechnet, die durch die beiden Vektoren gebildet wird. Auch diese Function wird so definiert, dass sie mit runden Klammern aufgerufen werden muss.

<# .Synopsis Determinante eines Vektors mit 2 Komponenten #>

function det2
{
param([Vektor2[]]$v)
return ($v[0].x * $v[1].y – $v[0].y * $v[1].x)
}

Beim Aufruf der Function det ist ein kleiner Umweg erforderlich: Der Rückgabewert muss einer Variablen zugewiesen werden. Ansonsten funktioniert die Multiplikation mit 0.5 oder einer anderen Zahl nicht. Warum das so ist, muss ich noch herausfinden (ich bin sicher, dass Friedrich die Antwort kennt;)

Fazit: Wer Functions bei PowerShell so verwenden möchte wie bei VBScript, JavaScript und den meisten Programmiersprachen kann dies tun. Eine Einschränkung besteht darin, dass wenn die Argumente per Komma getrennt übergeben werden soll, ein Array-Parameter benötigt wird.

Start-2018 – oder alles Gute in 2018

Nach meinen Weihnachtswünschen nun auch die wie immer von Herzen kommenden Wünsche zum neuen Jahr.

Start-2018

Start-2018 (Bildnachweis: Oliver Le Moal/IStockphoto.com)

Der Umstand, dass in Deutschland die Wirtschaft nach wie vor auf Wachstum ausgerichtet ist, dürfte sich auch positiv auf die IT-Branche auswirken. Bei Microsoft könnte es offenbar besser nicht laufen. Das Unternehmen hat die Gewinnnprognosen der Analysten im Jahr 2017 in jedem Quartal übertroffen, seinem geschätzten Börsenwert zufolge ist es das drittwertvollste Unternehmen weltweit nach Apple und Google, der Aktienkurs steigt und steigt, scheinbar hat man alles richtig gemacht.

Dieses Jahr kommen der Nachfolger von Windows Server inklusive zweier Updates, vermutlich wieder jede Menge neuer Azure-Dienste und vielleicht ein faltbares Surface-Notebook. Trotzdem sollte man gleich den Hörer auflegen falls einem eine vermeintliche Microsoft-Mitarbeiterin am Telefon ein Sicherheitsupdate installieren oder etwas gegen das zu lautes Gebläse unternehmen will (http://www.abendzeitung-muenchen.de/inhalt.az-serie-vorsicht-betrueger-20-stunden-in-den-faengen-der-microsoft-betrueger.ce529473-cf22-4e6d-87fb-5b5d9999c36c.html).

Das positive wirtschaftliche Umfeld dürfte sich auch positiv auf IT-Projekte in Unternehmen und Behörden auswirken. IT-Mitarbeiter sind gefragt und fehlendes Personal könnte sich langsam als Flaschenhals bei größeren Projekten erweisen.

Was die PowerShell angeht so sieht ebenfalls alles ganz entspannt aus:

>WMF 5.1 und damit auch die ISE werden nicht mehr funktional weiterentwickelt, bleiben aber immer ein fester Bestandteil von Windows

>Die Entwicklung fokusiert sich auf die PowerShell 6.0, die voraussichtlich bis Ende Januar offiziell verfügbar sein wird, gleichzeitig beginnt die Weiterentwicklung mit der Version 6.1. Diese PowerShell wird immer als separater Download verfügbar sein, nicht mehr als Update.

>Die PowerShell 6.0 ist aber funktional nur eine Untermenge der Version 5.1, da alles Windows-spezifische nicht dabei ist. Dazu gehören nicht nur die Registry, Systemdienste und WMI, auch eher profane Cmdlets wie Rename-Computer oder auch ConvertFrom-String. Insgesamt gibt es in der aktuellen Version nur knapp 200 Cmdlets was mich ein wenig an die PowerShell 1.0-Zeiten erinnert. Dafür läuft diese Version auch auf einem Rasberry PI.

>Insgesamt hat sich die Weiterentwicklung der PowerShell in den letzten zwei bis drei Jahren stark verlangsamt. Ein Grund ist natürlich, dass das PowerShell-Team mit der Umstellung auf Open Source voll beschäftigt war. Darunter leiden auch andere Projekte (u.a. das vielversprechende Phosphor-Projekt, das offenbar über die Initialversion noch nicht herausgekommen ist – hier ist natürlich auch die Community gefragt!)

>Im April wird es in Hannover wieder eine PowerShell Conference Europe geben (http://www.psconf.eu/). Themen und Sprecher dürften bis Ende Januar feststehen.

Ich wünsche allen, die diesen Blog-Eintrag im Januar lesen, ein gesundes und glückliches Jahr 2018!

Vielleicht sehen wir uns bei einer PowerShell-Schulung in München, Nürnberg, Hamburg oder Stuttgart,

Peter Monadjemi

Frohe Weihnachten

Ich wünsche allen Lesern meines PowerShell-Blogs frohe und gesegnete Weihnachten und die Zeit und vor allem innere Ruhe, um die Feiertage für die wichtigen Dinge im Leben nutzen zu können, weit weg vom Alltag mit seinen zahlreichen Verpflichtungen und Nebensächlichkeiten.

Peter Monadjemi

Weihnachten 2017 vor dem Reichstag in Berlin (auch ohne eine konstituierte Regierung ein schöner und vor allem friedvoller Anblick)

(Quelle: Fotalia.com/Urheber: sborisov)

PowerShell unter Linux installieren – bei einem traditionellen Provider als Alternative zu einer Azure-VM

Die PowerShell unter Linux zu installieren macht inzwischen richtig Spaß und setzt dank einer nahezu idiotensicheren Anleitung für die wichtigsten Linux-Disributionen unter https://github.com/PowerShell/PowerShell auch keinerlei Linux- oder Bash-Kenntnisse voraus. Ein wenig PowerShell-Kenntnisse genügen;)

Auch wenn es naheliegend ist, die Linux VM unter Azure anzulegen, diese Variante besitzt einen Nachteil, der sich mal mehr oder weniger auswirkt: Azure ist aus meiner Sicht relativ teuer. Eine einfache Linux-VM mit 2 Core CPU und 3.5 GB RAM kostet ca. 50€ pro Monat. Natürlich gibt es preiswertere Varianten, aber das Arbeiten soll ja auch etwas Spaß machen. Deutlich preiswerter sind die meisten traditionellen Provider. Hier gibt es eine virtuellen Linux-Server mit vollen Root-Rechten ab 9.99€ (etwa bei Host Europe, bei dem ich z.B. diesen Blog hoste).

Wer jahrelang den Komfort von Azure gewöhnt war, muss bei einem traditionellen Provider erst einmal umdenken. Man bestellt den Server, bekommt kurz danach die Auftragsbestätigung, muss dann einen Auftrag zur Startkonfiguration starten und bekommen dann etwas später die Zugangsdaten (eine gewisse Überraschung war es, dass es aufgrund interner Hardwareprobleme ein paar Tage gedauert hat – dies ist zwar die absolute Ausnahme, kann aber offenbar passieren).

Sobald man die Zugangsdaten in Gestalt einer IP-Adresse und einem generierten Kennwort für das root-Konto erhalten hat, geht es genauso weiter wie bei einer Azure-VM. Als SSH-Client verwende ich seit kurzem das hervorragende MobaXTerm (https://mobaxterm.mobatek.net).

Eine Besonderheit ist noch erwähnenswert: Auf einem nackten Linux-System fehlt am Anfang einiges, u.a. auch curl und das Package für den Download via HTTPS. Beide Packages müssen per apt-get install nachinstalliert werden:

Anschließend wird die PowerShell nach Anleitung installiert. Der Programmname lautet neuerdings pwsh und nicht mehr „powershell“.

Aktuell (Stand: November 2017) ist immer noch die Beta-9. Ich bin gespannt, ob die Version 1.0, wie es auf der PowerShell-Konferenz in Hannover im Mai angedeutet wurde, tatsächlich noch in diesem Jahr kommt.

PowerShell Core in einer Asp.Net Core-Anwendung hosten – die ersten Schritte

Gleich vorweg: Dies ist noch kein vollständiger Blog-Eintrag, es sind vielmehr nur mehr oder weniger zusammenhanglose Notizen, die allen weiterhelfen sollen, die an einem ähnlichen Projekt arbeiten und mir als eine Art „Notizzettel“ dienen sollen.

*** Letzte Aktualisierung: 11/11/2017 ***

Ich will in den nächsten Wochen ein umfangreicheres PowerShell-Skript über einen Websevice anbieten. Technisch ist das sehr einfach, wenn das Projekt auf ASP.NET basiert. Ich möchte das Projekt aber nur unter Asp.Net Core umsetzen, damit es theoretisch auch in einem Container unter Linux laufen kann. Warum nicht, auch wenn es für das Projekt im Moment keine konkreten Vorteile bietet?

Die Herausforderung besteht darin, dass PowerShell Core noch nicht immer nicht offiziell ist und es daher noch keine offiziellen Packages gibt. Ein Pendant zu System.Management.Automation ist das PowerShell Core SDK.

Einen guten Einstieg in die etwas komplizierte Thematik gibt der folgende Artikel:

https://github.com/PowerShell/PowerShell/tree/master/docs/host-powershell#net-core-sample-application

Im Folgenden beschreibe ich die Umsetzung des Projekts.

Ausgangspunkt ist ein leeres Verzeichnis. Vorausgesetzt werden VisuaL Studio Code (mit Visual Studio 2017 Community Edition ginge es zwar leichter, aber es soll ja nicht zu leicht sein) und die neueste Version des .NET Core SDKs, z.B. 2.02.

Die Downloaadresse ist https://www.microsoft.com/net/learn/get-started/windows

Schritt 1: Anlegen eines ASP.NET Core-Projekts vom Typ WebApi

Schritt 2:: Hinzufügen des PowerShell Core SDK-Package

*** Fortsetzung folgt ***

Nächstes Treffen der PowerShell User Group Stuttgart und Umgebung am 30.11.2017 Globalways/Gropiusplatz 2

Es gibt sie noch, die PowwerShell User Group Stuttgart, auch wenn es die letzten Monate eventuell etwas ruhig war um sie bzw. Facebook und Webseite nicht auf dem aktuellen Stand sind.

Und wann ist das nächste Treffen? Ganz einfach, bis auf Weiteres immer am letzten Donnerstag eines Monats. Wo erfahre ich mehr? Immer auf Meetup, also unter

https://www.meetup.com/de-DE/PowerShell-Usergroup-Stuttgart/

Eingeladen ist jeder, der sich für die PowerShell als ein enorm vielseitiges einsetzbares Werkzeug für die Adminstration unter Windows und neuerdings auch Linux interessiert.

Praxistipp: .NET Vesionsnummern auslesen mit einem Tool und einer Prise Regex

Es gibt mehrere Alternativen, um die Versionsnummern aller instlalierten .NET-Versionen zu erhalten. Meine „Lieblingsvariante“ ist immer noch ein kleines Tool mit dem Namen .NET Version Detector von einem belgischen Entwickler mit dem leicht zu merkenden Domännamen asoft.be:

http://www.asoft.be/prod_netver.html

Das kleine Tool zeigt alle vorhandenen Versionen nicht nur in einem Fenster an, sondern schreibt sie wenn das Tool in der Befehlszeile aufgerufen wird auch in eine Textdatei.

Mit einer Prise Regex erhält man die Versionsnummern zurück.

PowerShell-Praxis: Umgang mit mehrdimensionalen Arrays – ein „Schiffe versenken“-Algorithmus

Der Umgang mit Arrays besitzt bei der PowerShell seine Eigenheiten. Auf der seinen Seite genial einfach und komfortabel, doch sobald es um mehrdimensionale Arrays geht lässt der Komfort etwas nach und es wird speziell.

Eines gleich vorweg: Wer bislang eine Programmiersprache oder eine traditionelle Skriptsprache wie VBScript (WSH) verwendet hat und es einfach gewohnt ist mit zweidimensionalen Arrays zu arbeiten, z.B. um tabellarische Daten abbilden zu können: In 95% alle Fälle ist ein simples Array, das per [PSCustonmObject] angelegte Werte aufnimmt, die beliebige Werte aufnehmen, die deutlich einfachere und vor allem Powershell-typische Variante.

Da man aber niemand zwingend sollte, eine vertraut gewordene Gewohnheit aufgeben zu müssen, lassen sich zwei- oder mehrdimensionale Arrays auch bei PowerShell anlegen. Zwei Dinge muss man wissen: Wie ein mehrdimensionales Array angelegt und wie ein mehrdimensionales Array von einer Function zurückgegeben wird.

Mehrdimensionale Arrays anlegen


Ein mehrdimensionales Array wird per New-Object-Cmdlet angelegt. Da das Cmdlet offenbar mit der [,]-Schreibweise nicht klar kommt, muss die Typbezeichnung in Apostrophen gesetzt werden – dadurch fallen aber die äußeren eckigen Klammern weg.

Der folgende Befehl legt ein zweidimensionales Array mit 10 Feldern in der ersten und 2 Feldern in der zweiten Dimension an.

Der folgende Befehl legt ein dreidimensionales Array mit 2 Feldern in jeder Dimension an.

Die Rank-Eigenschaft gibt die Anzahl der Dimensionen an. Per GetLength-Methode erhält man die Größe einer einzelnen Dimension.

Ein mehrdimensionale Array in einer Function zurückgeben


Soll eine Function ein mehrdimensionale Array zurückgeben, muss dem Ausdruck bzw. der Variablen einfach ein Komma vorangestellt werden.

Ein Algorithmus für das Belegen eines Schiffe versenken-Spielfeldes

Ein genialer Algorithmus, der ein zweidimensionales Feld für ein Schiffe versenken-Spiel mit Schiffen belegt und dabei darauf achtet, dass sich keine „Verbände“ überlappen bzw. die Spielfeldgrenzen berücksichtigt werden.

Eine Erklärung folgt in Kürze – bei Fragen einfach fragen;)

Umgang mit generischen Listen (Teil 2)

Im ersten Teil „Umgang mit generischen Listen“ ging es um ein erstes Kennenlernen der generischen Liste. Beantwortet wurde auch die Frage warum man sie überhaupt braucht. Die Antwort war: Für das administrative Skripten bringen sie keine Vorteile und sollten daher auch nicht verwendet werden. Sie sind immer dann praktisch bzw. notwendig, wenn Programmcode aus einem C#-Programm in ein PowerShell-Skript umgesetzt werden soll, oder wenn eine Methode einer .NET-Assembly eine generische Liste als Parameterwert erwartet.

In diesem Teil geht es um die Typenbezeichnung, die die PowerShell bei einer generischen Liste verwendet.

Ausgangspunkt für das Beispiel ist ein von mir definierter Typ mit dem Namen WTToken.

Ob dieser Typ per class-Befehl definiert wird, aus einem C#-Programm stammt oder es ein ganz anderer Typ ist, etwa PSCustomObject, spielt keine Rolle.

Mit dem Typ wird als nächstes eine generische Liste per new()-Methode angelegt.

Damit gibt es eine Liste $Tokenlist, die nur Objekte vom Typ WTToken aufnehmen kann.

Übergebe ich eine andere Sorte von Wert, etwa eine Zahl, kommt es wie zu erwarten zu einer Fehlermeldung. Die Meldung selber ist aber etwas irritierend. Anstatt „Wrong type error“ lautet die Fehlermeldung: Für „Add“ und die folgende Argumenteanzahl kann keine Überladung gefunden werden: „1“.. ??? WTF;)

Die Fehlermeldung will uns Folgendes sagen: Es kann für den Typ, den der Wert (1 Argument) besitzt, der übergeben werden soll, keine Methodenvariante gefunden werden, die diesen Typ akzeptiert. Eigentlich ganz einfach.

Bis jetzt ist hoffentlich noch alles nachvollziehbar.

Im Folgenden wird es kurzzeitig etwas spezieller. Beim Herumexperimentieren mit generischen Listen erhielt ich die obige Fehlermeldung auch dann, wenn der Wert vom Typ WTToken war und damit passen sollte.

Nach ein wenig Herumprobieren kam ich eher per Zufall auf die Lösung. Die PowerShell fügt in die Typenbezeichnung auch den Pfad der Ps1-Datei ein, in der der Typ definiert wird. Vermutlich aus der Überlegung heraus, dass die Typenbezeichnung damit eindeutig wird, da es keine zwei identischen Pfade geben kann.

Legt man jetzt in der ISE ein neues Fenster an und kopiert den Skriptcode, der eben noch funktioniert hatte, in das neue Fenster, kommt es zu obigen Fehler, da die generische Liste einen Typ erwartet, in dem der Pfad des alten Skripts noch enthalten ist. Wird das Objekt in dem neuen Fenster angelegt, erhält sein Typnname nicht den alten Ps1-Pfad und es entsteht ein neuer Typ, der nicht mehr in die generische Liste eingefügt werden kann.

Ein „Problem“ ist dieses Verhalten in der Praxis natürlich nicht. Der Fehler kann nur beim Herumprobieren in der ISE auftreten, da hier Variablen globale Variablen sind und mit ihrem aktuellen Wert und vor allem Typ in jedem neuen Fenster automatisch verwendet werden.

Im Folgenden möchte ich noch einmal zeigen, wie sich das von mir beschriebene Verhalten nachvollziehen lässt.

Schritt 1:

Starte die ISE, gib den folgenden PowerShell-Code ein und speichere das Ganze in einer Datei, z.B. „Test.ps1“.

Führe das Ganze aus. Die Liste in der Variablen Tokenlist besitzt den Typ „System.Collections.Generic.List`1[[WTToken, ⧹E։⧹2017⧹Projekte⧹BoolscherService⧹test.ps1, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null]]“ (der Ps1-Pfad lautet natürlich immer anders).

Schritt 2:

Lege in der ISE ein neues Fenster an und füge den folgenden Code ein

Führe das Ganze aus. Es kommt zu der besagten Fehlermeldung, da WToken jetzt eine Typenbezeichnung erhält, in der anstelle des Ps1-Pfades nur „\powershell“ enthalten ist. Auch wenn es nur eine Kleinigkeit ist, ist es damit ein anderer Typ.