Perl-Zugriff auf die Windows Registry

Verwaltung der Registry-Datenbank

Perl wird häufig als System-unabhängiges Werkzeug zur Systemverwaltung eingesetzt. Dabei muss man gelegentlich kleine System-spezifische Teile in Kauf nehmen. Der Zugriff auf die Windows Registry-Datenbank ist nur auf Windows-Systemen durchführbar und sinnvoll. Alle anderen Programmteile können System-unabhängig programmiert werden.
Änderungen in der Registry-Datenbank können die Funktion von Betriebssystem und Programmen beeinträchtigen, evtl. sogar Daten zerstören. Alle Hinweise erfolgen daher ohne Gewähr ! Die Verwendung der Tipps und Beispiele erfolgt auf eigenes Risiko !
Perl Perl Scripts für CGI und Systemverwaltung
Win32::TieRegistry Dieses Perl-Modul ermöglicht den Zugang zur Registry
Trennzeichen Änderung des Trennzeichens für Registry-Pfade
Daten lesen Daten eines einzelnen Schlüssels lesen
Schlüssel lesen Namen aller Sub-Schlüssel lesen
Daten schreiben Daten eines einzelnen Schlüssels ändern oder schreiben
Daten löschen Gefährlich, aber technisch möglich
System-Befehle Befehle an das System erteilen und die Antwort auswerten
Perl Module Zusatz-Module für den Registry-Zugriff

Modul Win32::TieRegistry bietet Zugriff auf die Win-Registry

Mit Anweisung use wird der Funktionsumfang von Perl erweitert. Das Modul Win32 ist in allen Win-Distributionen von Perl normalerweise enthalten, daher genügt diese Anweisung zur Einbindung des Moduls.

Anweisung use strict ist nicht notwendig, wird aber unbedingt empfohlen: Dann müssen alle Perl-Variablen ausdrücklich deklariert werden. Damit vermeidet man das oft langwierige debuggen bei einfachen Tippfehlern.
use strict;
use Win32::TieRegistry;
Danach verwenden sie das Objekt $Registry für den Zugriff (Beispiele unten). Vergeben sie daher die Namen $Registry oder $registry nicht für eigene Variable !

Verwenden sie nicht mehr das veraltete Modul
Win32::Registry

Dokumentation:

In der Doku von ActivePerl finden sie die Daten im Kapitel Modules | Win32 | TieRegistry
Die Doku ist Online verfügbar. Schneller und sparsamer ist die Verwendung der genau zur installation Perl-Version passenden Doku, die in jeder Distribution normalerweise im Verzeichnis perl/html mit der Start-Datei index.html enthalten ist.

Registry

Die Registry-Datenbank verwendet als Grund-Element den Schlüssel (key). Er hat immer einen Namen und kann Daten sowie beliebig viele weitere Schlüssel enthalten.
Die Registry bildet daher einen 'hierarchischen Baum', ähnlich wie ein Datei-Verzeichnis. Ein Pfad (als String) führt zu jedem einzelnen Schlüssel. Die Registry hat aus unerfindlichen Gründen keinen Wurzel-(root)-Schlüssel, daher wird dieser von Perl 'künstlich' ergänzt.
In der nächsten Ebene befinden u.a. sich die Schlüssel
HKEY_CLASSES_ROOT
HKEY_CURRENT_USER
HKEY_LOCAL_MACHINE
HKEY_USERS
HKEY_CURRENT_CONFIG

Für diese Basis-Schlüssel können sie auch Kurznamen (siehe Doku) verwenden. In den weiteren Ebenen folgen die vielen subkeys jedes dieser keys.

Der Registry-Pfad verwendet als Trennzeichen zwischen den Ebenen den \ Backslash.
Schließen sie die Namen von keys in Perl-Programmen immer mit einem zusätzlichen Trennzeichen vor dem letzten Element ab (Beispiele unten).

Beispiel:
HKEY_LOCAL_MACHINE\HARDWARE\DESCRIPTION\System\CentralProcessor\0
Dieser Schlüssel enthält einige Daten zum Prozessor (CPU) ihres PC, z.B. den Hersteller VendorIdentifier, die Bezeichnung Identifier und die Taktrate ~MHz

RegEdit
Das Standard-Programm regedit.exe ist in jedem Windows-System enthalten und dient zum Lesen und Ändern der Registry-Daten.
Vorsicht ! - Ändern oder löschen sie niemals voreilig Registry-Daten. Davor sollte man sich genau informieren und eine Dokumentation und/oder Sicherungskopie der Registry anfertigen. Trotz aller Vorsicht kann es vorkommen, dass man dabei System, Programme oder Daten, im Extremfall sogar die Hardware beschädt. Im schlimmsten Fall lässt sich den Schaden nicht mehr reparieren.

Sicherheit
Windows-Systeme bieten nicht die Standard-Zugriffrechte wie alle anderen gängigen Betrebssysteme. Deshalb kann hier nicht genau vorhergesagt werden, welche Zugriffsrechte ihr PC bietet:
+ Wenn der Lese-Zugriff auf die Registry für einen oder mehrere User möglich ist, dann können dabei vertrauliche Daten gelesen werden.
+ Wenn der Schreib-Zugriff möglich ist, dann können dabei wichtige Daten von System und Programmen geändert oder sogar zerstört werden.
+ Es ist technisch möglich, auf die Registry aller im Netzwerk erreichbaren PC zuzugreifen. Das sollte allerdings aus Sicherheits-Gründen unterbunden sein.

Konsolen-Programme

Der Zugriff auf die Windows-Registry ist (nur) für Konsolen-Programme sinnvoll, d.h. in (Perl)-Programmen, die auf der Windows-Konsole cmd.exe laufen.
Derartige Programme können manuell gestartet werden, meist jedoch durch andere Verwaltungs-Programme oder zeit-gesteuert.

Neustart
Je nach Art der Daten werden Änderungen an Registry-Daten evtl. erst nach einem Neustart des Systems wirksam !

CGI-Programme (Dynamische Webseiten)

Der Zugriff auf den eigenen PC ist für Webseiten aus gutem Grunde verboten. Der 'eigene PC' ist für ein Perl Script-Programm zur Erzeugung einer dynamischen Webseite der Webserver, nicht der PC der/des AnwenderIn. Derartige Zugriffe wären gefährlich, sie sollten dieses Verbot daher keinesfalls durch besondere Maßnahmen lockern oder aufheben.
Der Zugriff auf die Windows Registry ist daher für CGI-Programme kein Thema.

Hashes und Pointers

Hashes eignen sich besonders gut, um Registry-Schlüssel und deren Daten abzubilden.
Das Modul Win32::TieRegistry verwendet daher vorwiegend Hashes.
Details zu Perl-Hashes auf der Seite Arrays & Hashes.

Wenn ein Hash mit einem Registry Schlüssel verknüpft wurde, dann sind die Namen aller SubKeys mit der Standard Perl-Funktion keys verfügbar.
Verknüpfung eines Hashes mit der Registry
my %RegHash ;
use Win32::TieRegistry ( TiedHash => \%RegHash );
Der Operator \ liefert eine Adresse (Pointer), in diesem Fall die Adresse des Hash %RegHash.
Verwenden sie an Stelle eines eigenen Hash das vordefinierte Hash %Registry:

So erhält man die Namen aller Subschlüssel eines keys:
$regkey="HKEY_LOCAL_MACHINE";
$regkey.="\\Software";
$regkey.="\\\\Microsoft";
@k = keys( %{$Registry -> {$regkey}} );
Array @k enthält alle Namen.

Trennzeichen ändern

Die Registry verwendet als Trennzeichen (Delimiter) für die Pfad-Texte den \ Backslash.
Wenn sie das nicht ändern, dann müssen sie jedes Zeichen \ maskieren, d.h. einen weiteren Backslash voranstellen, wenn der Pfad in einem Text-String angegeben wird.
Backslash als Trennzeichen
$regkey="HKEY_CURRENT_CONFIG";
$regkey.="\\Software";
$regkey.="\\Fonts";
$regkey.="\\\\FONTS.FON";
Es ist wesentlich praktischer, das Trennzeichen zu ändern:
Man kann dafür jedes andere Zeichen verwenden, normalerweise den / Slash, der in allen (anderen) gängigen Systemen als Trennzeichen verwendet wird.
Das Beispiel zeigt, wie der / als Trennzeichen definiert wird. Das alte (vorherige) Trennzeichen wird zurückgegeben. Man kann es in einer Variablen aufheben und zuletzt wieder einsetzen.
Das Trennzeichen gilt nur für dieses Perl-Programm, d.h. Perl übersetzt jedes / in Registry-Pfaden vor der Verwendung in ein \ Zeichen. Daher hat diese Festlegung keine weiteren Folgen für andere Programme oder für die Registry selbst.
Trennzeichen ändern
$delim = $Registry->Delimiter("/");
print "old delimiter = $delim\n";
Verwendung
$regkey="HKEY_CURRENT_CONFIG";
$regkey.="/Software";
$regkey.="/Fonts";
$regkey.="//FONTS.FON";
Alle weiteren Beispiele dieser Seite gehen von einer Änderung des Trennzeichens aus.

Daten lesen

Das Beispiel zeigt, wie man die Daten einzelner Registry-Schlüssel lesen kann.
Der Name wird direkt (in " ") oder über eine Variable (hier $regkey ) angegeben (aus Platzgründen erfolgt hier die Eingabe des Namens schrittweise).
# $daten = $Registry{$keyname};
$regkey="HKEY_CURRENT_CONFIG";
$regkey.="/Software";
$regkey.="/Fonts";
$regkey.="//FIXEDFON.FON";
$regdat= $Registry->{$regkey};
print "Registry-Daten($regkey) = $regdat\n";
Wenn mehrere Registry-Schlüssel aus einem Bereich verwendet werden, dann ist es sinnvoll, einen 'übergeordneten' Schlüssel an ein Hash zu binden:
Hier wird ein Schlüssel an eine Variable ($sw) gebunden, diese wird im Perl-Programm weiter verwendet, hier z.B. zum Lesen einiger Daten in die Variable $swdat. Das ist schneller und übersichtlicher, als den kompletten Pfad jedesmal neu festzulegen.
$regkey="HKEY_CURRENT_CONFIG";
$regkey.="/Software";
$regkey.="/Windows";
$regkey.="/CurrentVersion/";
$sw = $Registry -> {$regkey};
$swdat = $sw -> {"/ProductID"};
$swdat = $sw -> {"/CommonFilesDir"};

REG_DWORD

Registry-Daten dieses Typs werden von den gezeigten Perl-Funktionen als Hexadezimal-String in der Form 0x12345678 zurückgegeben.
Das Beispiel rechts zeigt eine Perl-Funktion zur Decodierung der Daten.
Der Hex-String wird mit der Standard-Funktion hex interpretiert.
Negative Werte sind im 2er-Komplement gespeichert: Deshalb wird das höchstwertige Bit getestet und die Dezimalzahl bei Bedarf entsprechend umgewandelt.
Details zum 2er-Komplement.

sub reg_dword {
my ($r)=@_;
my $rn = hex($r);
if($rn & 0x80000000) {
$rn = $rn - 0xFFFFFFFF - 1;
}
return $rn;
}

Schlüssel lesen

Die Registry verwendet zahlreiche interne Schlüssel, deren Namen man erst einmal finden muss, um an die gewünschten Daten heranzukommen.

Beispiel: Wenn ein Win-PC seine IP-Adresse von einem DHCP-Server bekommt, dann ist diese IP-Adresse hinter einem internen Schlüssel versteckt. Sie sollten den (evtl. variablen) Namen dieses Schlüssels (das letzte Element in {} ) nicht in einem Programm codieren, sondern ihr Programm muss den internen Namen dieses Schlüssels selbst besorgen.
Daten aus einem bekannten Schlüssel lesen:
$regkey = "HKEY_LOCAL_MACHINE";
$regkey.="/SYSTEM";
$regkey.="/CurrentControlSet";
$regkey.="/Services/Tcpip";
$regkey.="/Parameters/Interfaces";
$regkey.="//{ABC123-456-XYZ}";
$regdat = $Registry->{$regkey};
print "ip-adr = $regdat\n";
Dazu muss man zuerst recherchieren, in welchem übergeordneten Schlüssel der gesuchte interne Schlüssel enthalten ist. Einige Strukturen sind im Internet recht gut dokumentiert, bei anderen hilft oft nur Versuch und Irrtum.
Das Beispiel zeigt, wie alle SubKeys eines Schlüssels $regkey gewonnen und in einer Schleife ausgewertet werden: Unter den Ergebnissen befindet sich der gesuchte interne Schlüssel.

Für dieses Beispiel (danamische IP-Adresse) müssen darüber hinaus alle Sub-SubKeys der gefundenen Namen analysiert werden. Die gesuchte Adresse befindet sich in einem Sub-SubKey mit dem Namen DhcpIPAddress
Die Namen der Sub-SubKeys werden in der Variablen $s2 gespeichert und in einer weiteren Schleife ausgewertet. Zur besseren Übersicht sind weitere Details weggelassen.
$regkey = "HKEY_LOCAL_MACHINE";
$regkey.="/SYSTEM";
$regkey.="/CurrentControlSet";
$regkey.="/Services/Tcpip";
$regkey.="/Parameters/Interfaces/";
$s1= $Registry->{$regkey};
foreach( keys %$s1 ) {
$k1=$_;
print "subkey = $k1\n";
# alle subkeys von $k1:
$s2= $Registry->{$regkey.$_};
}

Daten schreiben

Alle Hinweise erfolgen ohne Gewähr !
Die Verwendung der Tipps und Beispiele erfolgt auf eigenes Risiko !
Tipp: Virtuelle PC sind ideale Test-Systeme: Wenn bei heiklen Experimenten Fehler auftreten, dann wird der (virtuelle) PC nicht repariert sondern einfach gelöscht und durch eine neue Kopie ersetzt.
Schreiben, Erzeugen und Ändern von Registry-Daten erfolgt genau analog zum Lesen, durch Zuweisung von Daten mit dem = Operator. Vorhandene Schlüssel und Daten werden überschrieben, nicht vorhandene neu angelegt.
Beispiel:
Die interne PC-Uhr kann mit Zeit-Servern aus dem Internet synchronisiert werden. Dafür sind vom Hersteller meist nur 2 Zeit-Server vorgesehen.
Wenn man andere verwenden will, muss man diese eintragen, z.B. die NTP-Adresse der PTB (Braunschweig). Sie erscheint anschließend in der Auswahl-Liste der verwendbaren Zeit-Server und kann zur Zeit-Synchronisation des PC verwendet werden.
# $Registry->{$keyname} = $data;
$regkey = "HKEY_LOCAL_MACHINE/Software";
$regkey.="/Microsoft/Windows";
$regkey.="/CurrentVersion";
$regkey.="/DateTime/Servers/";
$Registry -> {"$regkey//3"} = "ptbtime1.ptb.de";
Erzeugung von Umgebungs-Variablen
Es ist eine lohnende Aufgabe, wichtige Daten in Form von Umgebungs-Variablen für alle Programme verfügbar zu machen. Damit umgeht man elegant die Geheimnistuerei des Herstellers:
Die Daten müssen nur einmalig (bzw. bei einer Änderung) erfasst und als Umgebungs-Variable festgelegt werden. Danach können sie von allen (eigenen) Programmen verwendet werden.
Für jeden User wird ein eigener ControlSet angelegt. Tragen sie den Schlüssel für jeden angelegten User ein, dessen Daten werden bei der Anmeldung automatisch in den aktuellen CurrentControlSet kopiert.
$regkey = "HKEY_LOCAL_MACHINE/SYSTEM";
$regkey.="/ControlSet*/Control";
$regkey.="/Session Manager/Environment";
$Registry -> {"$regkey//HTTP_PROXY} = "192.168.0.1:8080";
Ersetzen sie ControlSet* durch ControlSet001, ControlSet002, ... sowie die angegebene IP-Adresse durch den passenden Wert für ihren eigenen PC.
Kontrollieren sie die Wirkung nach einem Neustart:
Öffnen sie eine Konsole cmd.exe und geben sie den Befehl ein
C:\> set h
Alle mit h beginnenden Umgebungs-Variablen werden angezeigt, darunter auch HTTP_PROXY
Die Umgebungs-Daten aller Programme (z.B. Perl, PHP, ..) enthalten nun die definierte Variable !
Tipp:
Bevor sie potentiell gefährliche Operationen vornehmen, sollten sie ihr Vorhaben sorgfältig testen: Ändern sie die Registry-Daten manuell mit Programm regedit.exe und testen sie das Verhalten. Verwenden sie nach Möglichkeit einen eigenen Test-PC, der nicht in ein Netzwerk integriert ist und keine wertvollen Daten enthält.

Beachten sie insbesondere die Möglichkeit, dass andere PC eine andere System-Variante verwenden und dort die Schlüssel andere Namen haben können. Auch die Daten gleicher Schlüssel können evtl. je nach System eine andere Bedeutung haben !

Daten löschen

Sie sollten sehr sorgfältig überlegen, ob das Löschen einzelner Registry-Daten oder von Schlüsseln inkl. aller SubKeys und Daten sinnvoll ist. Das ist relativ gefährlich und fast nie wirklich notwendig.
Das Löschen von Keys erfolgt genauso wie das Löschen anderer Hash-Elemente mit der Perl Standard-Funktion delete
Details zu Perl-Hashes und zur Funktion delete auf der Seite Arrays & Hashes.

Perl-Module

Perl bietet eine große Anzahl zusätzlicher Module mit spezialisierten Funktionen.
Am Server ihres Web-Providers können sie keine Module installieren, für den eigenen Gebrauch können die Module jedoch praktische Funktionen enthalten, die evtl. viel Arbeit sparen.
Beispiele für Stichworte bei der Suche nach nützlichen Modulen:
registry, system, win32, windows, ..