Archiv der Kategorie: Tipps

PowerShell-Remoting mit SSH

PowerShell-Remoting mit SSH ist gut dokumentiert. Zwei sehr gute Artikel sollten für einen erfolgreichen Probelauf genügen:

https://www.thomasmaurer.ch/2020/04/enable-powershell-ssh-remoting-in-powershell-7/

und

https://4sysops.com/archives/enable-powershell-core-6-remoting-with-ssh-transport/

Ein dritter Artikel beschreibt die Verwendung der Public Key-Authentifizierung als Alternative zur Passwort-Eingabe:

https://4sysops.com/archives/powershell-remoting-with-ssh-public-key-authentication/

Was eventuell noch nicht jeder weiß, der sich für das Thema SSH mit PowerShell interessiert. Seit ein paar Monaten gibt es in der PowerShell Gallery ein kleines Modul des PowerShell-Teams, mit dessen einzigem Enable-SSHRemoting-Command das Einrichten von SSH auf dem Remote-Computer sehr einfach wird. Der Eintrag

PasswordAuthentication yes

muss allerdings auch in diesem Fall einkommentiert werden, falls eine Kennwort-Authentifizierung gewünscht ist. Für das erste Kennenlernen ist dies die einfachste Variante.

Das Modul gibt es unter

https://www.powershellgallery.com/packages/Microsoft.PowerShell.RemotingTools/0.1.0

Damit hat es sogar bei mir auf Anhieb funktioniert;)

Insgesamt sind damit folgende Schritte auf dem SSH-Server zu erledigen:

  1. PowerShell 7 installieren
  2. OpenSSH Client und OpenSSH Server installieren
  3. Enable-SSHRemoting ausführen oder den subsystem-Eintrag in der sshd-config-Datei „zu Fuß“ anlegen
  4. sshd-Dienst (nicht ssh) neu starten – unter Linux service ssh restart (eigentlich gar nicht so schwer;)

Damit kann per New-PSSession, Enter-PSSession und Invoke-Command unter einer PowerShell ab Version 6.0 SSH über den SSHTransport-Parameter verwendet werden:

#requires -version 
$hostname="Ubunti
#$hostname="172.23.25.12"
$Username="pemo"
$S1 = New-PSSession -Hostname $Hostname -Username $Username -SSHTransport -Subsystem powershell
Invoke-Command -ScriptBlock { Get-Process} -Session $S1
Remove-PSSession -Session $S1

Der Subsystem-Parameter wählt den Namen des auf dem SSH-Server angelegten subsystem-Eintrag in sshd_config aus. Das Passwort wird bei jedem (!) Aufruf abgefragt. Wer das nicht möchte, muss Public Key-Authentizierung verwenden. Wie das geht, wird in einem der genannten Blog-Artikel beschrieben.

Viel Erfolg!

Abb. Dank snap besteht die Installation der PowerShell unter Ubuntu aus einem Aufruf (sofern sie nicht bereits vorinstalliert ist)

Tipp des Tages: Text-Dateien im BOM-Format finden

Die PowerShell ISE hat die etwas lästige Eigenart, dass Textdateien mit einem sog. BOM-Header gespeichert. Das bedeutet konkret, dass die Datei mit den Byte-Werten 255 und 254 beginnt oder FF EF als Hexadezimalzahlen. BOM steht für Byte Order Mark und soll einen Hinweis darauf geben, dass als Zeichencode UTF-8 verwendet wird (ich hoffe, ich gebe das korrekt wieder). Mehr dazu unter https://de.wikipedia.org/wiki/Byte_Order_Mark.

Dass eine einfache Angelegenheit erstaunlich kompliziert sein kann, macht eine ausführliche Abhandlung deutlich, die das Zusammenspiel von VS Code mit der PowerShell in Bezug auf die Zeichencodierung beschreibt:

https://docs.microsoft.com/en-us/powershell/scripting/dev-cross-plat/vscode/understanding-file-encoding?view=powershell-7

Ich muss leider zugegeben, dass ich immer wieder in Situationen komme, in denen in die Umlaute einer in VS-Code gespeicherten Ps1-Datei durch „seltsame“ Sonderzeichen ersetzt werden (die in der oben genannten Doku natürlich alle beschrieben werden).

Wie dem auch sei, mich hat es einfach einmal interessiert, welche Ps1-oder allgemein Textdateien einen solchen BOM-Header besitzen. Der folgende Befehl gibt zunächst für die Windows PowerShell alle iese Dateien aus, in dem er jeweils die ersten beiden Bytes der Datei liest und diese als Hex-Werte mit FFEF vergleicht:

Der obige Befehl funktioniert nur mit der Windows PowerShell, da es den Wert Byte für den Encoding-Parameter nicht bei PowerShell 7 gibt. Dafür gibt es mit dem AsByteStream-Parameter zwar ein flexibleres Konzept, allerdings darf der TotalCount-Parameter nicht mit diesem Parameter kombiniert werden, so dass ein Select-Object mit -First 2 erforderlich wird.

Der folgende Befehl entspricht dem letzten Befehl, nur dass er ab PowerShell 6 funktioniert:

Tipp des Tages: Befehlszeilentools mit –% ausführen

Hin und wieder kommt es vor, dass sich ein Befehlszeilentools nicht in der PowerShell-Konsole ausführen lässt. Der Grund dafür hat etwas mit der Art und Weise zu tun, wie das Befehlszeilentool seine Argumente verarbeitet, insbesondere was Anführungszeichen betrifft. Das klassissche Beispiel ist Find.

Der folgende Aufruf funktioniert nicht:

Abgesehen davon, dass es eigentlich keinen Grund für diesen Aufruf gibt, dürfte es zumindestens von theoretischem Interesse sein, warum bei diesem harmlosen Befehl ein „FIND: Parameterformat falsch“-Fehler die Folge ist.

Die Antwort: Die Anführungszeichen müssen escaped werden. Für diesen und möglichweisere andere solcher Spezialfälle bietet die PowerShell bereits seit der Version 3.0 (?) den praktischen Schalter –%, der einfach den Argumenten vorangestellt wird:

–% bewirkt, dass die PowerShell den folgeden Text nicht mehr selber interpretiert. Etwas einfacher geht es natürlich mit Where-Object bzw. einfach nur mit einem ?.

Tipp des Tages: Quelltextdateien durchsuchen und das Ergebnis sortieren mit einer Prise Regex

Dieser kleine Tipp ist für Entwickler interessant, die ihre Quelltetdateien nach einem Eintrag wie Substring(22,1) oder Substring(37,1) durchsuchen und die Rückgabe nach der ersten Ziffer in der runden Klammern sortieren möchten. Klingt vielleicht kompliziert, ist aber mit der üblichen Prise Regex dann doch relativ einfach.

Der Regex bedeutet: Suche alle Zeilen, die ein strZulassung:Subtring(<Zahl>, <Zahl>) enthalten, wobei <Zahl> jeweils für eine Zahl steht. Die erste Zahl soll als Gruppe abgreifbar sein, daher noch ein Paar runder Klammern. Die runden Klammern der Function müssen per \ escaped werden. Ausgangspunkt ist eine Verzeichnishierarchie mit Quelltextdateien (hier .prg-Dateien).

Ich kann nur empfehlen, sich mit dem Thema reguläre Ausdrücke etwas zu beschäftigen, denn bereits mit den absoluten Basics kommt man relativ weit (die PowerShell-Hilfe about_regular_expressions ist für den Einstieg absolut ausreichend).

Natürlich kennt auch die Visual Studio-Suche reguläre Ausdrücke, nur lässt sich das Ergebnis nicht so einfach sortieren.

Tipp des Tages: Verzeichnis anlegen und dahin wechseln

In Unix-Shells gibt es den beliebten &&-Operator zum Ausführen eines zweiten Prozesses, z.B. um in ein per mkdir angelegtes Verzeichnis per cd zu wechseln. Bei PowerShell geht es dank der Objekte etwas einfacher:

Zuerst legt mkdir ein neues Verzeichnis an. Da dieses als (DirectoryInfo-) Objekt zurückgeben wird, kann der Pfad des neuen Verzeichnisses per FullName-Property an cd übergeben wird.

Allerdings ist die Schreibweise nicht gerade intuitiv. Vor allem, wenn man die PowerShell nur sporadisch verwendet.

Das „Geheimnis“ von Set-Culture

Wie viele Stunden habe ich schon damit verbracht herauszufinden, wie sich während der Ausführung eines PowerShell-Befehls die „Kultur“ vorübergehend ändern lässt? Die Frage kann natürlich außer mir niemand beantworten. Ich kenne die Antwort auch nicht, aber es waren einige Stunden (mehr als 3). Dabei ist alles sehr einfach.

Set-Culture setzt die Kultur auf die angegebene Einstellung für das aktuelle Benutzerkonto. Aber nicht in der aktuellen PowerShell-Sitzung, sondern erst in der nächsten. Ganz witzig ist auch, dass sich unmittelbar nach der Ausführung des Befehls sich das Datum im SysTray-Feld der Taskleiste an die neue Kultur anpasst. Praktisch ohne Verzögerung, was für einen PowerShell schon etwas ungewöhnlich ist.

Fazit: Das Set-Culture-Cmdlet funktioniert auch ohne irgendwelche Klimmzüge, aber nicht so wie man es vielleicht erwarten würde.

PowerShell-Know how als Teil der Windows-Problemlöser

Auf diesen Blog-Eintrag wollte ich schon seit Jahren hinweisen, da ich ihn sehr gut finde:

https://chentiangemalc.wordpress.com/2011/05/08/windows-7-can-teach-you-powershellinbuilt-wealth-of-scripts/

Der Autor hat sich die Mühe gemacht, die vielen PowerShell-Skripte, die unter der Haube der zahlreichen Diagnosehilfen von Windows ihren Dienst verrichten, aufzulisten und ihren Inhalt zu untersuchen.

Auch wenn, wie es PowerShell-Experte Jeffrey Hicks es in einem Kommentar korrekt anmerkt, einige (oder eher viele?) der vorgestellten Techniken veraltet bzw. nicht ganz optimal sind, zum Lernen der verschiedenen PowerShell-Techniken sind die Skripts dann doch gut geeignet.

Auf alle Fälle ist es erstaunlich, welche Fülle an PowerShell-Know how abseits der offiziellen Module bereits bei Windows 7 im Windows-Verzeichnis dabei war.

Tipp des Tages: Dienste entfernen auch ohne PowerShell

Triviale Aufgaben können ihre Tücken haben. Beispiel: Wie ich entferne ich einen Systemdienst, der sich auch per WMI nicht mehr entfernen lässt, da z.B. im onStop-Event eine Exception auftritt? Ganz einfach durch Beenden der Exe-Datei. Doch welche Exe-Datei ist es genau? Eine Kombination aus Sc.exe und Taskkill.exe löst das kleine Problem.

Warum Sc.exe und nicht Get-Service? Weil Ersteres mit dem queryex-Parameter auch die Prozess-ID mit ausgibt.

sc.exe queryex VISEFService

Anschließend genügt der Aufruf von

Taskkill /pid 1234 /F

wenn 1234 die Prozess-ID ist.

Natürlich geht das alles auch per PowerShell, aber inzwischen bin ich an dem Punkt angekommen wo es in erster Linie darum geht, dass ich nicht zu viel tippen muss (man wird älter und bequemer;). Und geht es nur darum, eine bestimmte Aufgabe zu erledigen, sind die alten Kommandozeilentools immer noch eine sehr gute Wahl.

Per PowerShell sähe der Aufruf in etwa so aus:

stop-process (Get-CimInstance Win32_Service -Filter "Name='VISEFService'").ProcessId

Es ist nicht unbedingt der Umfang der Zeile, sondern eher der andere Denkansatz, an den man sich erst gewöhnen muss. Im Moment habe ich eher das Gefühl, dass wir uns wieder zur klassischen „Kommandozeilen-Denkweise“ zurückbewegen.

Tipp des Tages: Verzeichnisse aus der path-Umgebungsvariablen entfernen

Hin und wieder kann es erforderlich sein, einzelne Verzeichnisse aus der path-Umgebungsvariablen zu entfernen. Was sich zunächst schwierig anhören könnte, ist in der Praxis dann doch ein relativ einfacher Befehl.

Der folgende Befehl entfernt alle Verzeichnisse, die ein Python36 enthalten, aus der Path-Umgebungsvariablen.

$env:path = $env:path.split(";").where{$_ -notmatch "Python36"} -join ";"

Die Änderung gilt natürlich nur für die aktuelle PowerShell-Sitzung. Soll sie dauerhaft sein, muss der neue Wert der Umgebungsvariablen über die SetEnvironmentVariable()-Methode der Environment-Klasse für den aktuellen Benutzer oder systemweit gespeichert werden.