Bericht vom 1. Treffen der PowerShell User Group Stuttgart – und ein paar Tipps zum Umgang mit Hashtables

Am 12.1.2017 fand das erste Treffen der PowerShell User Group Stuttgart statt. Gastgeber waren die Firma Microsoft, die uns einen Raum in ihren schönen Firmenbüro in Vaihingen bei Stuttgart zur Verfügung stellte. Wenn ich mich nicht verzählt habe, waren wir insgesamt zu neunt, so dass die magische Grenze von 10 knapp verfehlt wurde. Aber für das erste Treffen, dessen Termin zudem so kurzfristig angesetzt wurde, war das bereits ein guter Anfang.

Nachdem Friedrich anhand eines von ihm entwickelten „Frameworks“ für die Rechnerkonfiguration, das er in seiner Firma einsetzt, einige recht spezielle Techniken vorgestellt hatte, unter anderem eine auf eigenen Attributen basierende Parametertyp-Konvertierung, gab ich einen Überblick über das Thema Hashtable, das in meinen Schulungen in der Regel eine gewisse Verständnishürde darstellt – inzwischen war es bereits 21 Uhr 20, so dass das ganze Treffen etwas länger ging als geplant. Kurz nach 22 Uhr war dann Schluss.

Noch ein Nachtrag zu einem meiner Beispiele, in der ich eine Hashtable mit einigen Tausend Datensätzen so ansprechen wollte, dass der Datensatz über eine Zahl ausgewählt wird, die die Rolle der Id des Datensatzes spielt.

Der folgende Befehl hat leider nicht funktioniert:

8000 ist der Wert eines Schlüssels. Der Befehl gab, sooft ich es auch probierte, einfach nichts zurück. Da es bereits etwas später war (und die Raumtemperatur für meinen Geschmack deutlich zu hoch eingestellt war) gab ich es dann auf. Die naheliegende Lösung $Liste[8000].Nachname war mir etwas zu trivial, da es auch anders gehen sollte.

Heute habe ich mich noch einmal auf die Suche nach einer Lösung gemacht und bin hier fündig geworden: http://blog.danskingdom.com/accessing-powershell-variables-with-periods-in-their-name.

Die Lösung besteht darin, den Index in runde Klammern zu setzen:

Und da wir gerade dabei sind: Einträge zu eine Hashtable per += hinzufügen ist deutlich langsamer als per Add-Methode.

Das erste Treffen der neuen PowerShell User Group Stuttgart fand in den Räumen von Microsoft in Vaihingen statt

Runspace-Debugging in 5 Minuten

Mit der Version 5.0 der PowerShell wurde das Debuggen eines Runspaces ermöglicht. In der Praxis wird man diese Technik vermutlich eher selten benötigen. Wer sich dennoch aus welchen Gründen auch immer für das Thema interessieren sollte, der Umgang mit Runspaces ist relativ einfach (ein Runspace ist der „Bereich“, in dem ein PowerShell-Befehl ausgeführt wird – jede Sitzung/Session enthält mindestens einen Runspace – es lassen sich beliebig viele weitere Runspaces anlegen, in denen beliebige Befehle ausgeführt werden – interessant ist diese Option immer dann, wenn die Befehle asynchron ausgeführt werden).

Das folgende kleine Beispiel führt einen Scriptblock in einem weiteren Runspace aus. Per Wait-Debugger wird der Debuggmodus aktiviert. Anschließend kann man sich per Debug-Runspace mti dem Runspace verbinden und die Befehle des Scriptblocks debuggen. Die Id des Runspace erhält man per Get-Runspace-Cmdlet.

Im nächsten Schritt muss man sich per Get-Runspace die Id des neuen Runspace holen. Danach kann man diesen Runspace mit dem Debug-Runspace-Cmdlet debuggen und die einzelnen Befehle über die Debug-Kommandos (s, v, l usw.) ausführen.

Frohe Weihnachten…

Ich wünsche allen Lesern dieses Blogs frohe, sorgenfreie und gesegnete Weihachten und einen guten Start in das neue Jahr 2017.

Speziell was das Thema PowerShell angeht wird es wie fast in jedem Jahr auch 2017 abwechslungsreich bleiben. Mit SSH und einer „PowerShell 6.0“ auf allen Plattformen kommt ein neues Thema dazu, andere Themen wie Testen von Skripten, DSC-Ressourcen und allgemein Einstellungen mit dem Pester-Modul oder generell die Bedeutung einer „Release-Pipeline“ für Skripte und DSC-Ressourcen werden an Bedeutung zunehmen. Interessant wird es sein zu beobachten inwieweit Cloud-Angeboote wie Microsoft OMS (Operations Management Suite), mit der sich Windows Server überwachen lassen, auch in Deutschland angenommen werden.

Mein neues zur Buch zur PowerShell 5.0 wird auch hoffentlich im ersten Quartal erscheinen, so dass mir schon alleine aus diesem Grund die Arbeit nicht ausgehen wird.

Vielleicht sehen wir uns 2017 auf einer PowerShell-Schulung oder auf einem Treffen der PowerShell User Group, z.B. am 12.1.2017 in Stuttgart.

Ihr
Peter Monadjemi

Das Ende meiner Loseblatt-Sammlung, das Ende einer Ära und das fehlende Schlusswort der letzten Aktualisierung

Vor einigen Tagen kam die letzte Aktualisierung der Loseblattsammlung mit dem Titel „Automatisierte Administration mit Scriptsprachen unter Windows NT 4.0/2000, 2003 und 2008“, für die ich über 10 Jahre als Herausgeber beim WEKA Verlag (vormals Interest Verlag) in Augsburg zuständig war.

Loseblatt. Das weckt natürlich Erinnerungen an die späten 80er und frühen 90er Jahre und sicher nicht nur positive. Damals wurden die Loseblatt-Werke zu allen möglichen Themen rund um das Thema Computer in allen Magazinen mit großem Aufwand beworben. Die Angebote klangen auch verlockend – über 1.000 Seiten Praxis-Know how, zusammmengestellt von namhaften Experten, in zwei voluminösen A5-Ringbüchern für nur 59 DM (Preis fiktiv), jederzeit kündbar, Geldzurückgarantie usw. Der Preis war natürlich nur ein Lockangebot für ein Abonnement, das, sobald es zustande kam, nicht mehr ganz so einfach kündbar war. Die meisten Abonnenenten liessen ihr Abo vermutlich mehr aus Bequemlichkeit weiterlaufen und erhielten alle paar Wochen einen Schwung von Blättern im DIN A5-Format, die sie theoretisch selber in den großen Ringordner im A5-Format einsortieren sollten, den sie als Teil des Begrüßungspakets erhalten hatten. Damals, als Internet noch etwas war, das jemand im fernen Kalifornien erfunden hatte, war ein Loseblatt-Abo eine Gewähr dafür an jene Informationen zu kommen, die ansonsten nur mit sehr viel Aufwand erhältlich gewesen wären.

Spätestens vor 5 Jahren hätte das Loseblatt-Werk eigentlich „tot“ sein müssen, da es inzwischen auch jede Menge Angebote im Internet gab, die Informationen so aufbereiteten, dass sie aktuell, informativ und leicht konsumierbar waren. Mein Scripting-Handbuch hielt sich tapfer trotz stetig sinkender Abo-Zahlen – am Ende im unteren zweistelligen Bereich. Jetzt ist Schluss und ich denke, dass es insgesamt gut so ist, da ich es niemanden mehr zumuten möchte Informationen zur PowerShell oder Windows Server alleine aus dem Lesen von A5-Seiten zu beziehen.

Leider wurde in der letzten Aktualisierung vom Dezember diesen Jahres mein Schlusswort im Editorial nicht abgedruckt. Für den unwahrscheinlichen Fall, dass ein ehemaliger Abonnent diesen Blog-Eintrag lesen sollte, hier sind die Sätze, die ich gerne noch an die verbliebenen Leser gerichtet hätte:


Mit dieser Aktualisierung wird das Loseblattwerk Scripting eingestellt. Die erste Aktualisierung erschien im Jahr 2000. Damals waren Themen wie Hyper-V, System Center, Azure und auch PowerShell noch visionäre Themen. Heute, 16 Jahre später, sind sie Alltag für alle, die sich in ihrem beruflichen Umfeld mit Microsoft-Produkten im Server-Umfeld beschäftigen müssen. Konstant geblieben ist über die Jahre die Notwendigkeit sich weiterbilden zu müssen und dabei Spaß am Beschäftigen mit neuen Themen zu haben. Wer sich diese Fähigkeiten erhält, ist für alles was in Zukunft noch kommen mag gut vorbereitet. Und natürlich: Vielen Dank, dass Sie dem Werk so lange die Treue gehalten haben.

Turn PowerShell scripts into an exe with Posh2Exe (update 12/14/2016)

I recently relased a small Windows console application that turns any ps1 script file into an exe file by embedding the ps1 as a resource into the exe.

Get the source code and compile the exe in Visual Studio

The project is on github:

https://github.com/pemo11/Posh2Exe

Right now you have to use Visual Studio (any of the current releases will do – I recommend Visual Studio 2015 Community Edition as the latest release) to create the exe file Posh2Exe.exe. I will provide a download link for the exe in the near future and also a small extension for the ISE so that making an exe out of the currently loaded ps1 will be very simple because you only have to click on a button.

Calling Posh2Exe in the Console Window (not in the ISE) is really simple:

This will embed test.ps1 into an exe test.exe (the name is not very original of course;). The exe can be run everywhere where WMF 4.0 or above and .NET 4.0 (which is a prerequisite for WMF 4.0) is installed.

If the ps1 file uses parameters the parameters has to be written like parametername:value separated by at least one blank.

I tested the current version of posh2exe with several scripts and it worked well for me.

Since its a kind of bare bone PowerShell host implementation some things do not work at the moment like Read-Host with the AsSecureString-Parameter or the different prompt-methods of the InternalHostUserInterface.

Another thing to consider is the fact that the PSScriptRoot variable has no value because there is no script file that will be executed just text. The workaround is to use [System.AppDomain]::CurrentDomain.BaseDirectory to get the path the exe is started from and [Environment]::CurrentDirectory to get the current path for the executing exe instead of $PSScriptRoot. For my own scripts that runs either as a ps1 file or inside an exe I using a simple query to decide how to get the path either the ps1 file or the exe is running in.

Big plans for the future…

One more thing I would like to add is a debug mode with the help of the „Debugger API“. So it will be possible to debug the script that is executed as part of the exe file with the PowerShell Debugger.

Runspaces debuggen

Seit der PowerShell 5.0 ist es möglich, Skripts zu debuggen, die in einem zusätzlich angelegten Runspace ausführen. Doch warum sollte man das tun? Zum Beispiel, weil ein Skript in einem asynchron, also per BeginInvoke ausgeführten Runspace parallel zu anderen Runspaces ausführen kann und sich damit eine effektive Form des „Multitaskings“ bei der Ausführung eines Skripts ergibt.

Runspaces gab es bei der PowerShell von Anfang an, denn ein Runspace spielt eine zentrale Rolle für die Ausführung von Befehlen. Jeder Befehl wird in einem Runspace ausgeführt. In der Regel ist es jener Default-Namespace, der automatisch mit dem Start der Host-Anwwendung angelegt wird. Über ein [RunspaceFactory]::CreateRunspace() werden weitere Runspaces angelegt. Anschließend wird eine Pipeline [PowerShell]::Create() angelegt, mit Befehlen oder einem Skript gefüllt und mit einem Runspace verbunden.

Erst seit der Version 5.0 ist es möglich, ein Skript in einem separaten Runspace zu debuggen. Im Mittelpunkt stehen die Cmdlets Enter-PSHostProcess, Get-Runspace und Debug-Runspace.

Das folgende Beispiel geht von einem kleinen Skript aus mit dem Namen Skript.ps1. Sein Inhalt spielt keine Rolle. Wichtig ist nur, dass es in einem separaten Runspace (synchron) ausgeführt wird. Dies geschieht in einem Skript, das in der PowerShell ISE ausgeführt wird.

Damit das Skript bei seiner Ausführung nicht einfach durchrauscht, wird in der Zeile mit dem Invoke-Aufruf ein Haltepunkt gesetzt und das Skript gestartet. Dadurch wird ein Runspace angelegt, ein Skript in den Runspace geladen, aber noch nicht ausgeführt.

Ein Skript wird in einem weiteren Runspace ausgeführt

Im zweiten Schritt wird die PowerShell-Konsole gestartet und der ISE-Prozess per Enter-PSHostProcess betreten:

Der Prompt der Konsole ändert sich zu [Prozess: 1234], wobei 1234 für die Prozess-ID steht.

Ein Get-Runspace listet alle Runspaces im ISE-Prozess auf. Wichtig ist der „RunspaceX“-Runspace und seine Id. Seine State-Eigenschaft muss den Wert „Opened“ und seine Avaivalibilty-Eigenschaft den Wert „Available“ besitzen.

Im Konsolenhost werden die Runspaces des ISE-Prozesses aufgelistet

Dieser Runspace wird per Debug-Runspace-Cmdlet mit der Id des Runspaces debuggt:

Neben dem Standard-Runspace steht auch der Runspace „RunspaceX“ zur Auswahl

Damit wird der Runspace in den Debug-Modus versetzt. Damit auch etwas passiert, muss der Invoke-Aufruf in der ISE ausgeführt werden. Damit steht der Debugger in der PowerShell-Konsole zur Verfügung und das Skript kann bei der Ausführung in seinem Runspace debuggt werden. Die einzige Einschränkung besteht darin, dass die Ausgaben gesammelt und erst am Ende zusammen ausgegeben werden.

Der Debugger wird über [Strg]+[C], der Host-Prozess über exit verlassen.

Der Runspace „RunspaceX“ wird debuggt

Die Möglichkeit jeden Runspace debuggen zu können ist eine wichtige Neuerung bei der Version 5.0, auch wenn sie nur weniger Anwender verwenden werden.

Jetzt muss ich noch herausbekommen wie ich ein Skript debuggen kann, das in einer von mir umgesetzten Host-Anwendung in einem Remote-Runspace ausgeführt wird.

eBook zum Thema PowerShell und Azure

Unter GitHub gibt es seit kurzem ein eBook, das den Einsatz der PowerShell im Zusammenspiel mit Azure sehr schön beschreibt:

https://github.com/gitralf/ersteschritte/blob/master/Azure_PowerShell_Erste_Schritte.pdf

Der Autor ist Ralf Wiegand, der bei Microsoft Deutschland für das Thema „Deutsche Cloud“ zuständig ist. Seinen Blog findet ihr unter https://blogs.technet.microsoft.com/ralfwi/.

Tipp: Einen Scriptblock vorzeitig verlassen mit dem return-Befehl

Wie verlässt man einen Scriptblock vorzeitig? Mit dem return-Befehl, da ein Scriptblock lediglich eine anonyme Function ist.

Der eventuell naheliegendere break-Befehl funktioniert nur, wenn der Scriptblock per & aufgerufen. Beim Aufruf über Invoke bewirkt er, dass der Scriptblock offenbar nicht ausgeführt wird.

Flexible Typenkonvertierung dank PSTypeConverter – ein kleines Beispiel erklärt wie die Typenkonvertierung bei der PowerShell funktioniert

Die in diesem Blog-Eintrag vorgestellte Technik ist zwar unabhängig von einer bestimmten PowerShell-Version – für die Umsetzung des Beispiels wird die Version 3.0 vorausgesetzt, wenngleich es mit der Version 2.0 theoretisch auch funktionieren sollte

Eine der Stärken der PowerShell ist die flexible Typenkonvertierung und -erweitererung. Dazu gehört vor allem die Fähigkeit, durch Typenkonvertierung an Objekte weitere Members anzuhängen. Dies geschieht immer so, dass es der Anwender nicht mitbekommt, sofern er oder sie überhaupt mit dem etwas anspruchsvolleren Konzept der Typen vertraut ist und/oder sich überhaupt dafür interessiert.

Wer z.B. ein Get-Process-Cmdlet ausführt, erhält zwar Objekte vom Typ System.Diagnostics.Process zurück, doch in „Wirklichkeit“ basieren die Objekte auf einem dynamischen Typ, der aus dem PowerShell-Typensystem hervorgegangen ist und um zahlreiche Members erweitert wurde. Das „wahre“ Objekt stellt jedes PowerShell-Objekt über seine PsObject-Eigenschaft zur Verfügung. Die Grundlage für die Typenerweiterung beim Process-Objekt ist die Datei Types.ps1xml im PowerShell-Installationsverzeichnis, in der die nachträglich angehängten Members für den Typ System.Diagnostics.Process definiert werden. Ein Beispiel: Die Eigenschaft Ws wird als AliasProperty nachträglich angehängt, damit die Eigenschaft mit dem etwas sperrigen Namen Workingset64 (bzw. Workingset) über einen kurzen Namen abgesprochen werden kann.

Die Typenkonvertierung eines Objekts kann auch dynamisch erfolgen, also ohne, dass die zusätzlich hinzugefügten Members bereits festgelegt wurden. Ein Beispiel ist der Typ-Alias [Xml], der Text in ein System.Xml.XmlDocument-Objekt konvertiert, sofern es sich um wohlgeformtes XML handelt, und dabei die Elemente und Attribute als Eigenschaften anhängt.

Durch den Xml Typalias findet eine Typenkonvertierung statt. Aus Text vom Typ String wird ein XmlDocument-Objekt, das auf dem gleichnamigen Typ basiert. Die Grundlage für die Typenkonvertierung ist eine Klasse, die sich von der PSTypeConverter-Klasse im System.Management.Automation ableitet. Benötigt man einen eigenen Typenkonvertierer, muss man „nur“ eine .Net-Assembly erstellen, in der diese Klasse abgeleitet und die Typenkovnertierung in der überschriebenen ConvertFrom-Methode durchgeführt wird.

Beispiele für den praktischen Einsatz von PsTypeConverter sind etwas schwer zu finden. Ein sehr guter Blog-Eintrag von Glenn Sizemore macht das Prinzip der Umsetzung deutlich und hat mich dazu motiviert, das Thema ebenfalls endlich einmal aufzugreifen (eigentlich steht das seit jenem PowerShell Deep Dive aus, der 2010 in Frankfurt a.M. stattfand):

http://practical-admin.com/blog/powershell-custom-types-type-conversion-and-ets/

Dynamische Typenkonvertierung an einem Beispiel

Das folgende Beispiel zeigt die Umsetzung eines Typenkonverters, der aus einer Ini-Datei ein Objekt macht, über das die Sektionen der Datei und die Einträge innerhalb einer Sektion zur Verfügung gestellt werden. Das Objekt ist ebenfalls Teil des Projekts. Voraussetzung für die Umsetzung der kleinen Übung sind Visual Studio (es kann auch eine ältere Version sein). Ich empfehle die aktuelle Version Visual Studio 2015 Community Edition. Auch wenn es im Folgenden um richtige Programmierung in der Programmiersprache C+ geht, muss man kein Profi-Entwickler sein, um die Umsetzung selber durchführen zu können. Theoretisch könnte man das kleine Projekt auch komplett in der PowerShell ISE umsetzen, doch müsste man dann auf den wertvollen C#-Debugger verzichten.

Schritt 1: Erstellen der Typenkonverter-Assembly

Im ersten Schritt wird mit Visual Studio eine .Net-Assembly erstellt, in der eine Klasse sich von PSTypeConverter ableitet. Voraussetzung ist, dass ein Verweis auf System.Management.Automation eingebunden wurde was am einfachsten über den Paket-Manager geschieht. Dieser wird über das Tools-Menü und die Einträge Nuget Package Manager und Package Manager Console geöffnet. Ein Install-Package System.Management.Automation fügt die PowerShell-Assembly hinzu.

Die vorhandene Klassendatei Class1.cs wird in PSIniTypeConverter.cs umbenannt und der folgende Befehlscode eingefügt:

Die Klasse enthält relativ wenige Befehle, da die eigentliche Konvertierung in der Klasse IniObject erledigt wird. Die wichtigste Methode ist ConvertFrom, denn hier wird die Konvertierung angestoßen. Die Abfrage auf den Typ des Parameters destinationType wäre in diesem Beispiel nicht erforderlich. Ich habe sie eingebaut damit deutlich wird, dass sich auch mehrere Typen konvertieren lassen.

Schritt 2: Ein neuer Typ wird definiert

Im nächsten Schritt wird eine weitere Klasse eingefügt mit dem Namen IniObject.cs. Diese Klasse definiert den Typen, in den ein String konvertiert werden soll. Die Klasse besitzt den folgenden Inhalt.

Damit ist die Programmierung bereits abgeschlossen. Das Projekt sollte ich zum jetzigen Zeitpunkt ohne Fehler erstellen lassen. Das Ergebnis ist eine Assembly-Datei mit dem Namen PSIniTypeConverter.dll.

Schritt 3: Die Assembly soll in einem PowerShell-Skript geladen werden

Um die PowerShell-Typenkonvertierung per F5-Taste im Rahmen von Visual Studio testen zu können, wird in den Projekteigenschaften im Register Debug dafür gesorgt, dass mit dem Projektstart Powershell.exe gestartet wird. Dazu muss unter „Start external programm“ der vollständige Pfad von Powershell.exe eingetragen werden.

In den Projekteigenschaften wird eingestellt, dass mit dem Projektstart die PowerShell startet

In den Projekteigenschaften wird eingestellt, dass mit dem Projektstart die PowerShell startet

über die „Command line arguments“ wird ein kleines PowerShell-Skript mit dem Namen „Init.ps1“ gestartet, das dem Projekt hinzuzgefügt wurde (dank der genialen PowerShell Tools for Visual Studio von Doug Finke gibt es eine Vorlage für Ps1-Dateien mit Intellisense), und über das u.a. die Assembly geladen wird:

Per „-noexit“ wird erreicht, dass das Konsolenfenster geöffnet bleibt. Da in diesem Fall ein Profilskript ausgeführt werden soll, fehlt der Schalter „-Noprofile“ (in der Regel ist es sinnvoll, dass keine Profilskripte gestartet werden).

Das PowerShell-Skript ist wie folgt aufgebaut:

Zuerst wird die Assemblydatei und damit der Typenkonverter per Import-Module geladen. Anschließend werden der Typ, der eine Ini-Datei repräsentieren soll, und der Typenkonverter über eine Typendefinitionsdatei bekannt gemacht (mehr dazu gleich). Außerdem wird ein Typenalias mit dem Namen „IniObject“ definiert, damit bei der Typenkonvertierung nicht jedes Mal der Namespace vorangestellt werden muss. Außerdem wird für einen ersten Test eine Variable IniText vordefiniert, die den Inhalt einer Ini-Datei darstellen soll.

Schritt 4: Der Typenkonvertierer wird bekannt gemacht


Damit die Powershell sowohl den neuen Typ PSIniTypeConverter.IniObject als auch den Typenkonvertierer PSIniTypeConverter.IniTypeConverter kennt, werden diese über eine Typendefinitionsdatei bekannt gemacht. Diese heißt IniObject.Types.ps1xml, wird im Rahmen des Skripts über das Update-TypeData-Cmdlet geladen. Die Typendefinitionsdatei ist wie folgt aufgebaut:

Wird das Projekt jetzt per F5 gestartet, wird die PowerShell-Konsole gestartet und das Skript wird ausgeführt. Außerdem liegt bereits eine Variable IniText vor.

Das Visual Studio-Projekt wurde erfolgreich erstellt

Das Visual Studio-Projekt wurde erfolgreich erstellt

Der folgende Aufruf sollte eine Typenkonvertierung von String nach IniObject durchführen.

Das Beispielprojekt gibt es unter der folgenden Adresse: psinitypeconverter.

Zusammenfassung

PowerShell-Typenkonvertierer sind eine innovative Idee, die die Übernahme von Textdaten, die einem beliebigen Format vorliegen können, vereinfachen. Mit einem einzigen Typenalias kann eine komplette Textdatei in PowerShell-Objekte konvertiert werden. Ohne diese Option müsste man die Daten eventuell Zeile für Zeile einlesen, zerlegen und daraus Objekte machen. Ob sich der Aufwand für eigene Typenkonvertierer wirklich lohnt sei einmal dahin gestellt. Da es für wichtige Datentypen, etwa IP-Adressen, bereits Konvertierer gibt, dürfte sich die Anzahl der echten Anwendungsfälle in Grenzen halten.

Das kleine Beispiel, das ich in diesem Blogpost vorgestellt habe, soll in erster Linie dazu dienen ein wichtiges Merkmnal der PowerShell, das sie seit der Version 1.0 besitzt, die dynamische Typenkonvertierung, besser nachvollziehen zu können.

HAL ist IBM – der unwiederlegbare Beweis

In Stanley Kubriks Science Fiction-Klassiker „Odysee im Weltraum“ aus dem Jahr 1968 (!) heißt der emotional einfühlsame Supercomputer an Bord des Raumschiffs HAL 9000. Angeblich ist HAL eine Anspielung auf IBM, das zur Zeit der Entstehung des Films ein Codewort für allumfassende Computerintelligenz gewesen sein dürfte (so wie heute Facebook). Ich habe das bislang nicht geglaubt, bis ich, weil ich nichts Besseres zu tun hatte, den folgenden PowerShell-Befehl eingehackt hatte: