Schneller Directory-Zugriff via Netz in PowerShell

Wer schon etwas intensiver mit der PowerShell gearbeitet hat, kennt das Problem wahrscheinlich: Beim Zugriff auf Directory-Informationen via Netz d.h. bei Netzlaufwerken kann sie quälend langsam sein. Bei einem Befehl wie z.B. dir y:/texte/*power* kann es mehrere Sekunden dauern, bis das Auslisten der passenden Filenamen beginnt, und file name completion ist ebenfalls oft an der Schmerzgrenze, was die Ausführungszeit anbelangt, sobald Netzlaufwerke im Spiel sind.

Als ich neulich einen Server unter Windows Server 2008 R2 neu aufgesetzt habe, ist mir aufgefallen, dass sich dieses Problem dankenswerterweise in Luft aufgelöst hat. Ich habe mal recherchiert, was es damit auf sich hatte und wie es nun gelöst wurde:

Im Artikel Why is Get-ChildItem so Slow? sind die Gründe recht anschaulich erklärt. Einer davon hat mit der Objekt-Hierarchie des .NET Framework im Bereich der Klassen von System.IO zu tun: Gewisse Informationen, welche die PowerShell gar nicht benötigt, werden zeitaufwendig immer via Netz ermittelt, ohne dass die PowerShell etwas dagegen tun kann, weil das Ganze rein klassenintern abläuft. (Das ist eine Art von Problem, die wohl jedem vertraut ist, der schon mal so etwas wie ein „Framework“ gebaut hat.)

Entsprechend besteht die Lösung nicht in einer verbesserten Programmierung innerhalb der PowerShell, sondern in Erweiterungen im .NET Framework, welche für die Version 4 tatsächlich erfolgt sind, wie man hier nachlesen kann. Die konkreten neu in diesem Zusammenhang angebotenen Methoden beschreibt die MSDN Library im Artikel How to: Enumerate Directories and Files.

Etwas ist allerdings ein wenig seltsam: Gemäss der Information hier umfasst Windows Server 2008 R2 das .NET Framework in Version 3.5.1, nicht in Version 4. (Version 4 ist ja im Moment erst im Beta-Stadium.) Vielleicht hat da Microsoft der PowerShell zuliebe heimlich einer paar 4er-Verbesserungen reingemogelt…

Was ich bei meinen Abklärungen auch noch gefunden habe, ist dieser Blog-Eintrag von jemandem namens Tom Shelton, der mittels WIN32-API-Aufrufen und Extension Methods zur Selbsthilfe gegriffen hat und Directory-Zugriffe für Netzlaufwerke bereits heute im ganz normalen .NET Framework 3.5 mit guter Performance hinkriegt.

Veröffentlicht in Keine Kategorie. Schlagwörter: , . Leave a Comment »

Tausendertrennzeichen für Dateigrössen in der PowerShell

Standardmässig gibt die PowerShell beim dir-Befehl (bzw. Get-ChildItem für Directories) Dateigrössen ohne irgendwelche Zifferngruppierung aus, d.h. ohne Tausendertrennzeichen, welche Dateigrössen jenseits von einigen Megabytes überhaupt erst lesbar machen. Das ist für ein sonst so modernes System eigentlich sehr erstaunlich; das konnte MS-DOS wahrscheinlich schon vor 20 Jahren schon besser!

Eine Abklärung in dieser Sache, welche ich diese Woche gemacht habe, ergab zum Glück das Resultat, dass Abhilfe möglich und sogar recht einfach ist, wenn man weiss wie.

Dieser Artikel in einem Blog namens FatBeard’s Adventures in PowerShell zeigt sehr schön die Grundzüge des Prinzips: Wenn Get-ChildItem seine Objekte der Klasse System.IO.FileInfo zu einer textuellen, kolonnenorientierten Darstellung wandelt, entnimmt es die Informationen, wie genau zu formattieren sei, einem XML-File namens FileSystem.Format.ps1xml in der $PSHOME Directory.

Man kann von einem solchen .ps1xml File eine Kopie erstellen, an dieser Änderungen vornehmen, und dann der PowerShell mit Hilfe des Update-FormatData-Kommandos und dessen Option -prependPath mitteilen, dass die Kopie zuerst zu konsultieren sei. (Am besten nimmt man eine entsprechende Zeile in seine $PROFILE Datei auf.)

Es ist relativ einfach, in besagtem File betreffend Filesystem-Klassen folgenden XML-Abschnitt zu lokalisieren, der für die fragliche Kolonne mit den Filegrössen zuständig ist:

<TableColumnItem>
   <PropertyName>Length</PropertyName>
</TableColumnItem>

… und ihn zu ersetzen durch den folgenden:

<TableColumnItem>
   <ScriptBlock>
      [String]::Format("{0:N0}",$_.Length)
   </ScriptBlock>
</TableColumnItem>

Die Kolonne von jetzt 10 Zeichen, die dann für die verbesserte Darstellung nicht mehr reichen, zu verbreitern auf z.B. 15 Zeichen, ist ebenfalls schnell gemacht.

Wer will, kann natürlich noch weiter gehen, etwas mehr programmieren im SkriptBlock und grosse Zahlen in Einheiten von KB, MB und GB ausgeben. Mir persönlich genügen Dateigrössen hübsch mit Tausendertrennzeichen vorerst. Sehen wir in ein paar Jahren weiter, wenn das Zeitalter der Gigabytes, in dem wir uns heute befinden, abgelöst wird durch das Zeitalter der Terabytes.

Veröffentlicht in Keine Kategorie. Schlagwörter: . Leave a Comment »

Einfache Directory History für die PowerShell

Als ich vor einiger Zeit begann, mit der PowerShell zu arbeiten, vermisste ich eine Directory History, also eine Liste mit den zuletzt besuchten Directories und darauf basierend dann eine einfache Möglichkeit, wieder in eine dieser Directories zurückzukehren. Wie man bei Microsoft im Kapitel Managing Current Location der PowerShell-Doku sieht, gibt es zwar einen Stack mit Hilfe von Push-Location und Pop-Location, aber das ist weder automatisch noch besonders praktisch.

Per Google fand ich relativ schnell heraus, dass die PowerShell Community Extensions unter vielen anderen Dingen einen cd-Befehl enthalten, der eine History führt, aber alleine deswegen diese Extensions zu installieren erschien mir als Overkill.

Da cd nur ein Alias ist, kann man diesen Alias relativ leicht ersetzen und das Führen einer Liste besuchter Directories anhängen, wie man es z.B. hier sieht. Aber das gefiel mir auch nicht besonders, denn ich wollte mir nicht Sorgen darüber machen müssen, ob die aktuelle Directory irgendwie an dieser neuen cd-Funktion vorbei wechseln kann, z.B. durch direkte Verwendung von Set-Location in einem Script, und die History dann „Löcher“ bekommt.

Schliesslich hatte ich eine Idee, die zwar etwas hack-mässig ist, dafür aber einfach und zuverlässig funktioniert: Im Profile-Script gibt es eine Function Prompt, welche dazu da ist, wie der Name schon sagt, jeweils den Prompt am Anfang der Kommandozeile auszugeben. (Einige schöne Ideen, was man damit alles machen kann, findet man z.B. hier.) Aber wer sagt denn, dass man in diesem Script nur Ausgaben machen darf? Ebensogut kann man nebenbei beobachten, in welcher Directory man neuerdings gelandet ist, und so auf einfache Weise eine zuverlässige History führen!

Veröffentlicht in Keine Kategorie. Schlagwörter: . 3 Comments »

Die Geschichte vom Backslash

Ich arbeite nun schon eine ganze Weile mit der PowerShell in der 2.0 CTP Version. Ich bin ganz zufrieden damit und kann eigentlich jedem nur empfehlen, sie einmal auszuprobieren.

Lustig ist, was mir mittlerweile am besten daran gefällt und worauf ich nicht mehr verzichten möchte: Die PowerShell erlaubt es mir, in Filenamen den normalen Slash „/“ anstelle des Backslash „\“ zu verwenden.

Hinter dem Backslash als Trennzeichen in Dateinamen in Windows steckt eine ganz interessante Geschichte, die ich hier erwähnen möchte für Leute, die sie noch nicht kennen, auch wenn sie wenig mit .NET zu tun hat:

DOS 1.0 war eigentlich ein von Microsoft eingekauftes Betriebssystem namens QDOS, das in vielen Aspekten grosse Ähnlichkeit hatte mit CP/M. CP/M war ein Betriebssystem, das nur Laufwerksbuchstaben und Dateinamen, aber keine Ordner bzw. Subdirectories kannte. Für die Schalter bzw. Switches seiner Tools verwendete es den normalen Slash „/“ als Einleitungszeichen – eine Konvention, welche DOS 1.0 übernahm.

Als dann DOS 2.0 eine anständige hierarchische Dateiverwaltung bekommen sollte, war die von UNIX her naheliegende Verwendung von „/“ für die Dateinamen durch eben diese Verwendung für Schalter gewissermassen blockiert, worauf Microsoft auf das Nächstbeste d.h. auf den Backslash auswich.

Rückblickend kann man wohl sagen, dass Microsoft damals in den sauren Apfel hätte beissen und trotzdem den Slash verwenden sollen, auch wenn dies bedeutet hätte, eine Menge eigener und fremder Kommandozeilen-basierter Programme anpassen zu müssen.

Es gibt bei der Geschichte vom Backslash jede Menge Details, wie etwa das folgende: Die Microsoft-Programmierer selbst waren durch die Verwendung von XENIX, der damaligen Microsoft’schen UNIX-Variante, bereits an den Slash gewohnt und fanden den Backslash gar nicht lustig. Sie programmierten deshalb eine „geheime“ Option namens SWITCHAR für die CONFIG.SYS, mit der man das Zeichen für Schalter auf ein anderes Zeichen als „/“ umdefinieren konnte, wonach der normale Slash in Dateinamen zulässig wurde.

(Ich bin schon so lange im Geschäft, dass ich diese Option selbst noch verwendet habe, auf einem WANG PC; ich frage mich jetzt nur, wie ich eigentlich davon erfahren hatte damals…)

Eine ausführliche Version der Geschichte findet man hier, die Geschichte des Zeichens „\“ selbst hier.

Windows akzeptiert übrigens in Filenamen bis heute sowohl Backslash wie auch Slash, auch wenn es bei Aufbereitungen und Abfragen von Dateinamen konsequent auf Backslash wandelt. Folgende .NET/C#-Zeile ist vollkommen ok und funktioniert:

      FileInfo f = new FileInfo("C:/Work/Backslash/Program.cs");
Veröffentlicht in Keine Kategorie. Schlagwörter: . 1 Comment »