Archiv der Kategorie: Tipps

„Virtuelle Computer“ per Hosts-Datei erzeugen

In Schulungen habe ich nicht immer ein Netzwerkumgebung zur Verfügung. Um dennoch eine Abfrage gegen mehrere Computer halbwegs realistisch vorführen zu können, trage ich eine Reihe von Computernamen in die Hosts-Datei ein und ordne ihnen jeweils 127.0.0.1 zu.

Das klappt zwar mit Ping&Co, nicht aber per ComputerName-Parameter.

Eine kleine Namensauflösung per DNS-Resolve löst das in der Regel nicht existierende Problem und zeigt nebenbei dem Schüler was mit der PowerShell so alles möglich ist:

Angenommen, die Hosts-Datei enthält Einträge für PC1, PC2, PC3 usw. dann legt der folgende Befehl für jeden dieser nicht vorhandenen Computer eine CIM-Session an.

Und dann

Tipp: Mit Subst nicht mehr existierende Laufwerke mappen

Es kommt auch im Jahr 2017 noch vor, dass Anwendungen irgendwelche absoluten Pfade speichern und sollte das Laufwerk aus irgendeinem Grund nicht mehr existieren, lästige Fehlmeldungen anzeigen. Jedes Mal. Und das nicht bei irgendwelchen „Wald&Wiesen-Apps“, sondern z.B. auch bei Visual Studio.

Ich verstehe nicht, warum Microsoft Milliarden in Machine Learning investiert, aber Visual Studio nicht einfach lernen kann, dass z.B. ein Laufwerk H: nicht existiert, auch wenn der Laufwerksbuchstabe einem nicht existierenden USB-Laufwerk zugeordnet wurde.

Abhilfe schaft das Ur-Alt-Kommando Subst. Der folgende Befehl mapt den Pfad E:\ auf das nicht mehr existierende Laufwerk H:

Der Befehl kann in der PS-Befehlszeile direkt so eingegeben. In der Regel wird es aber einen Fehler geben, der besagt, dass H: ein ungültiger Parameter ist. Der Grund ist, dass der Laufwerksbuchstabe H: einem nicht existierenden USB-Laufwerk zugeordnet ist. Abhilfe schafft die Datenträgerverwaltung (einfach „Diskmgmt.msc“ eingeben), in der ihr bei dem Laufwerk einfach den Laufwerksbuchstaben löscht. Danach klappt es auch mit Subst und es gibt keine lästigen Fehlermeldungen nach jedem Windows-Start oder bei anderen Gelegenheiten.

Managed Service Accounts (MSAs) erstellen – per Befehlszeile und mit einem GUI-Tool

Ein Managed Service Account (MSA) ist, vereinfacht, ein Dienstkonto (also ein Benutzerkonto, das ausschließlich von Systemdiensten für die Anmeldung verwendet wird), das von Windows insofern verwaltet wird, dass sich der Admin nicht mehr um das Erneuern von Kennwörter kümmern muss.

MSAs wurden mit Windows Server 2008 R2 eingeführt.

Bis zur aktuellen Windows Server-Version können MSAs nur per PowerShell angelegt werden.

Das Anlegen eines MSA besteht aus drei Schritten:

1. Anlegen des MSA per New-ADServiceAccount-Cmdlet

Bei diesem Schritt wird das Konto auf einem DC angelegt.

2. Hinzufügen des MSA auf dem jeweiligen Computer, auf dem es später verwendet werden soll, per Add-ADComputerServiceAccount-Cmdlet

$ServiceAccountHost ist der Name des Computers, $ServiceAccount Name des MSA oder gleich das ganze Objekt, das den MSA repräsentiert.

3. Installieren des MSA auf dem Computer, auf dem es später verwendet werden soll, per Install-ADServiceAccount-Cmdlet.

Das war im Prinzip alles. In der Praxis kann allerdings eines „schief gehen“, so dass die im Grunde einfachen Cmdlets zu Fehlermeldungen führen.

Ein Aspekt ist, dass auf dem DC ein „Kds Rootkey“ angelegt werden muss, der sofort wirksam wird.

Ein weiterer Aspekt ist ein Bug, der inzwischen behoben werden sollte, durch den der Name eines MSA nicht länger als 16 Zeichen werden dürfte.

Alles ein wenig umständlich. Zum Glück gibt es ein geniales GUI-Tool von Cjwdev, mit dessen Hilfe das Anlegen eines MSA sehr einfach wird:

http://cjwdev.co.uk/Software/MSAGUI/Info.html

Die aktuelle Version ist 1.6.

Nuget-Packages direkt laden

Nuget-Packages sind Paketdateien, die in der Regel Assembly-Dateien enthalten, die von Entwicklern für ihre Projekte verwendet werden. Seit Visual Studio 2012 werden solches Packages über die Paketverwaltung oder über das PowerShell-Konsolenfenster per Install-Package hinzugefügt.

In einem PowerShell-Skript benötigt man im Allgemeinen keine Packages. Wie immer gibt es Ausnahmen. Eine solche Ausnahme ist das sehr nützliche HtmlAgilityPack, das aus einer Assembly-Datei besteht, mit deren Hilfe sich die Inhalte einer Html-Seite per XPath und vertrauten XML-Methoden wie SelectNodes und SelectSingleNode ansprechen lassen.

Lee Holmes beschreibt die Technik des „Html Scraping“ mit Hilfe des HtmlAgilityPack sehr schön unter der folgenden Adresse:

http://www.leeholmes.com/blog/2010/03/05/html-agility-pack-rocks-your-screen-scraping-world/

Ich habe darüber auch bereits etwas geschrieben, aber wer den Artikel von Lee Holmes liest, weiß damit alles Wissenswerte und kann sich das Lesen anderer Blog-Einträge erst einmal sparen.

Bis auf eine Kleinigkeit eventuell: Normalerweise lädt man die Assembly-Datei von der Codeplex-Projektseite herunter. Es gibt zwei Gründe, die dagegen sprechen: Das Codeplex-Portal soll irgendwann in naher Zukunft eingestellt werden. Die Methode ist nicht besonders elegant, wozu gibt es das PackageManagement-Modul seit PowerShell 5.0?

Damit auch Nuget-Packages geladen werden, muss eine Package Source für die Adresse https://www.nuget.org/api/v2 existieren (dies ist zwar die „alte“ Adresse, sie funktioniert natürlich nach wie vor). Das Get-PackageSource-Cmdlet fragt diese ab:

Sollte die Package Source wider Erwarten noch nicht dabei sein, muss sie zuerst per Register-PackageSource angelegt werden:

Dabei muss auch der Providername, in diesem Fall Nuget angegeben werden. Das Ergebnis ist eine neue Package Source mit dem Namen „NugetP“.

Damit kann das HtmlAgilityPack-Package per Install-Package-Cmdlet heruntergeladen werden:

Abgelegt wird das „Package“ mit seinen Dateien unter C:\Program Files\PackageManagement\NuGet\Packages. Die entscheidende Datei HtmlAgilitypack.dll befindet sich in einem der zahlreichen Unterverzeichnisse, z.B. unter HtmlAgilityPack.1.4.9.5\lib\Net45. Sie wird per Add-Type-Cmdlet und dessen Path-Parameter geladen.

Eine Alternative ist der direkte Aufruf von Nuget.exe, das zuerst per dir lokalisiert werden muss.

Sollte das aus irgendeinem Grund nicht funktionieren, kann es erforderlich sein, die Nuget-Paketquelle zuerst zu aktivieren:

Ein Nuget sources list listet alle vorhandenen Sources auf, ein Nuget list alle verfügbaren Pakete.

Windows 7 – von 2 auf 5.1 – mit Zwischenschritt über die Version 5.0

Vor einiger Zeit hatte ich beschrieben, wie man unter Windows 7 in einem Schritt von Version 2.0 auf 5.0 aktualisiert:

http://poshadmin.de/?p=616

Möchte man gleich auf die aktuelle Version 5.1 umsteigen, was ich empfehle, ist wieder etwas mehr Aufwand erforderlich, denn auch hier muss zuerst auf Version 5.0 aktualisiert werden. Erst danach kann das Update für die Version 5.1 installiert werden.

Es ist interessant, dass das Update für Windows 7 als Zip-Datei zur Verfügung gestellt wird, das aus einer Ps1- und der Msu-Dateu besteht. Offiziell soll man die Ps1-Datei starten, die eine Reihe von Tests durchführt, um zu entscheiden, ob das Update durchgeführt werden kann usw. Wer WMF 5.0 bereits installiert hat, startet die Msu-Datei direkt.

Sollte die Installationsdatei wider Erwarten doch in einer Update-Endlosschleife höngen bleiben, liegt dies an der Datei WSUSSCAN.cab. In diesem Fall sieht es fast so aus, als müsste die ganze Prozedur auch für das 5.1-Update für jede einzelne (!) Cab-Datei wiederholt werden. Erst wenn die Neustart-Meldung erscheint, wurden alle Teil-Updates installiert.

Was ich Bruce (Payette) noch hätte fragen können…

Die PoshConf 2017 liegt schon wieder über eine Woche zurück, ein kurzer Bericht folgt in Kürze. Es ist immer wieder ein Erlebnis Bruce Payette, einer Köpfe hinter der PowerShell-Skriptsprache zu treffen. Theoretisch kann man ihn alles fragen was man jemals über die PowerShell wissen wollte, es aber niemanden fragen konnte. Theoretisch. Praktisch gehen die 3 Tage doch schnell vorüber und in dem dicht gefüllten Konferenzprogramm bleibt dann noch zu wenig Zeit. Das nächste Mal schreibe ich mir die Fragen vorher auf bzw. sammele sie in diesem Blog.

Hier ist schon die erste Frage:

Warum braucht ein PowerShell-Ausdruck immer dieses eine Paar runder Klammern extra?

Hier ein Beispiel. Der folgende Befehl soll per Write-Progress den Wert einer Variablen ausgeben und sie vor der Ausgabe um eins erhöhen. Das erledigt der folgende Befehl:

Es stört mich jedes Mal, dass ich es erst nach ein paar Mal ausprobieren hinbekomme, weil ich jedes Mal das zweite Paar runder Klammern weglasse, dass eigentlich überflüssig sein sollte. Eigentlich. Wahrscheinlich hat es was mit den verschiedenen Modi des PowerShell-Interpreters zu tun.

Aus aktuellem Anlass: SMB1 deaktivieren

Zur Zeit treibt der WannaCry-Trojaner sein Unwesen und richtet teilweise erheblichen Schaden an, da die Infrastruktur im öffentlichen Raum (in erster Linie offenbar Krankenhäuser in Großbritannien) vorübergehend nur eingeschränkt funktionsfähig ist. Über den Ursprung des Trojaners möchte ich nicht spekulieren, genauso wenig, ob es unter Windows mehr Sicherheitslücken gibt wie unter Linux&Co. Ein Fakt ist, dass Microsoft einen enormen Aufwand betreibt, um durch das zeitnahe zur Verfügung stellen von Patches den durch die Verwendung von Windows eingetretenen Schaden zu begrenzen. Allerdings darf man nicht Ursache und Wirkung verwechseln. Die Verbreitung wird leider durch den Umstand verursacht, dass es offenbar immer noch Menschen gibt, die E-Mail-Anhänge doppelt anklicken.

Die Verbreitung im LAN geschieht offenbar über eine Lücke im SMB1-Protokoll. Dieses lässt sich per PowerShell sehr einfach deaktivieren:

Die PowerShell muss dazu als Administrator gestartet werden. Ein Get-SmbServerConfiguration fragt die aktuelle Einstellung ab. Dank PS-Remoting ist es theoretisch eine Kleinigkeit, diese Abfrage in der gesamten Domäne durchzuführen. Wenn man dann noch mit Pscribo einen kleinen Report anfertigt, aus dem hervorgeht, dass auf 100% der Computern in der Domäne SMB1 deaktiviert wurde, dürfte das Ganze beim Vorgesetzten einen guten Eindruck machen (natürlich vorausgesetzt, dass SMB1 nicht doch für irgendetwas Unternehmenskritisches benötigt wird;)

ipconfig /displaydns-Output mit ConvertFrom-String verarbeiten

Ipconfig ist ein vielseitiges Tool. Ich benutze es immer noch, auch wenn z.B. Get-NetIPAddress einen etwas übersichtlicheren Output produziert.

Ein Pedant zum Schalter /displaydns gibt es bei den PowerShell-Commmands nicht. Leider ist die Ausgabe etwas unübersichtlich. Da man sich im Allgemeinen nur für die Hostnamen interessiert, mit denen irgendwelche Prozesse auf dem PC eine Verbindung herstellen, wäre es praktisch, wenn es eine Möglichkeit gäbe zu erreichen, dass nur diese Namen ausgegeben werden.

Mit dem vielseitigen ConvertFrom-String-Cmdlet, das ab der Version 5.0 zur Verfügung steht, gibt es eine solche Möglichkeit. Das Cmdlet ist leistungsfähig, aber etwa spärlich dokumentiert und bereits deutlich anspruchsvoller als z. B. Select-String.

Die Idee ist, dass aus meinen Mix aus Mustertext und vereinfachter regulärer Ausdrucks-Syntax ein Muster für einen unregelmäßig strukturierten Text zur Verfügung gestellt wird.

Das folgende Muster ist für die Ipconfig-Ausgabe mit dem Schalter displaydns gedacht:

Wichtig sind die geschweifte Klammer, über die einem Element des Textes ein Name gegeben wird. Der Mustertext wird in einer Textdatei gespeichert.

Der folgende Befehl gibt nur die Hostnamen aus dem DisplayDns-Output aus:

Mit dem ConvertFrom-String-Cmdlet kann man viel Zeit verbringen. Vieles habe ich nur per „Trial and error“ herausgefunden. Der Aufwand lohnt sich, denn wenn ein Muster funktioniert erhält man damit ein mächtiges Werkzeug für die Textauswertung.

Grafische Oberflächen für PowerShell-Skripte – ein WPF-Template (Teil 1)

Ein PowerShell-Skript mit einer kleinen Benutzeroberfläche auszustatten ist grundsätzlich nicht schwer – die größte Herausforderung für einen Admin, der kein Entwickler ist, ist es, das Prinzip zu verstehen und einen Einstieg zu finden. Natürlich gibt es seit vielen Jahren sehr viel Material im Web, unzählige Tutorials und Beispiele und mit ShowUI ein Modul, das einen genialen Ansatz verfolgt, aber leider seit Jahren nicht mehr weiterentwickelt wird. Aber, weniger wäre eventuell in diesem Fall mehr. Die Fülle des Angebots macht den Einstieg nicht unbedingt leichter, zumal viele der Beispiele bereits einige Jahre alt und etwas umständlich umgesetzt wurden.

Mit Windows Forms und WPF gibt es zwei Alternativen (mit HTML und JavaScript gibt es noch eine dritte Alternative, wie das sehr interessante Phosphor-Module zeigt). Beide haben ihre kleineren Vor- und Nachteile. Beide sind allerdings an Windows gebunden. Wer bereits „cross Plattform“ denkt und plant, sollte sich mit dem Phosphor-Modul von David Wilson beschäftigen: https://github.com/PowerShell/Phosphor. Der Autor hat es auf der letzten PoshConf Eu persönlich vorgestellt.

Ich bevorzuge in der Regel WPF, da mir der Umstand, dass das Fenster in XML, genauer gesagt in XAML, definiert wird, etwas besser gefällt. Auch wenn weder Eingabehilfen noch keinen Designer gibt (sieht man von Visual Studio ab), ist die Umsetzung etwas einfacher als bei Windows Forms, wenngleich ich seit vielen Jahren mit WPF programmiere, so dass mir die ganze Syntax bereits sehr vertraut ist (man muss lediglich daran denken, dass es auf die Groß-/Kleinschreibung ankommt).

Um nicht jedes Mal bei Null beginnen und sich von Irgendwo her im Web ein XAML-Grundgerüst besorgen zu müssen, stelle ich im Folgenden ein Grundgerüst für ein PowerShell-Skript vor, das ein Fenster mit einem Label, einer Textbox und einem Button anzeigt. Nach einem Klick auf den Button wird der Inhalt der Textbox in einer Messagebox angezeigt und das Fenster wird wieder geschlossen.

Das Template ist als Ausgangspunkt für eigene Dialogfelder gut geeignet. Das erforderliche Know-how zu WPF findet man an vielen Stellen im Web, z. B. http://wpftutorial.net und http://www.wpf-tutorial.com. Auf beiden Seiten findet man viele kleine XAML-Beispiele für die Standard-Controls, die man 1:1 in die XAML-Definition des PowerShell-Skripts übernehmen kann.

Kopiert das folgende Skript einfach in die ISE oder in die Konsole (dank PSReadline kein Problem) und startet das Ganze. Das Fenster sollte daraufhin angezeigt werden.

Auch wenn das natürlich eine Menge Text ist, ist das Ganze am Ende doch eine relativ überschaubare Angelegenheit.

Die Farbwahl es zugegeben etwas gewagt, aber es sollte kein Problem sein, dass sich jeder passendere Farben ausdenkt.

Tipp: Wer hauptsächlich mit der ISE arbeitet, kann den gesamten Text per New-ISESnippet-Cmdlet als Textausschnitt ablegen und ihn dadurch als Ausschnitt verfügbar machen. In Visual Studio Code ist es etwas mehr Arbeit, wenngleich die neueren Versionen der PowerShell Extensions auch Snippets unterstützen. Ein paar Infos findet ihr unter der folgenden Adresse: https://code.visualstudio.com/docs/editor/userdefinedsnippets

Abbildung: Das WPF Dialogbox-Template in Aktion

PowerShell-Tipp: Dateien umbenennen

Eigentlich ist das Umbenennen von Dateien per PowerShell keiner besonderen Erwähnung wert, eigentlich aber doch. Vor kurzem musste ich im Rahmen der Überarbeitung meines Windows 10-Buches auf das Creators Update (eine Menge Arbeit, aber das nur nebenbei, vor allem, wenn man zu spät anfängt;) eine Ordner mit Dateien umbenennen. Ich war gerade dabei den Ordner mit F2-Taste drücken, neuen Namen eintragen, Enter-Taste drücken, F2-Taste drücken, neuen Namen eintragen usw. durchzugehen bis mir einfiel, dass es dafür doch die PowerShell gibt. Leider ist das Rename-Item-Cmdlet etwas seltsam, ich kann mir nie merken, ob man für den NewName-Parameter nur den Namen übergibt oder den gesamten Pfad, so dass es gerade für einen PowerShell-Neuling eine große Hürde darstellt.

Der folgende Befehl nennt alle Dateien im aktuellen Verzeichnis um, in dem er ein „PM_“ zu Beginn des Dateinamens entfernt:

Soll nicht nur der Name, sondern gleich der Pfad der Datei geändert werden, nimmt man dafür das Move-Item-Cmdlet.