Mit .Net auf die Registry zugreifen


1 Einleitung
2 Zugriff auf die Registry [Microsoft.Win32.RegistryKey]
2.1.Lesen und Ändern von Registrywerte
      Beispiel 1: Erstellen eines Keys und einiger Werte
      Beispiel 2a: Auflisten aller Werte eines Keys  
      Beispiel 2b: Auflisten aller Werte eines Keys (kompakter als Beispiel 2a)
      Beispiel 3: einen bestimmten Werte auslesen
      Beispiel 4: Löschen eines Registrywertes

      Beispiel 5: Löschen eines Registryschlüssels
      Beispiel 6: Verändern von Registrywerten
2.2 Existenzprüfung von Schlüsseln und Werten
      Beispiel 1: Existenzprüfung eines Schlüssels
      Beispiel 2: Existenzprüfung eines Wertes
      Beispiel 3: Existenzprüfung von Schlüssel und Wert
 



Die Registry und .Net


1 Einleitung

Nachdem wir in den letzten beiden Kapiteln die Werkzeuge "RegistryProvider" und "WMI - StdRegProv" behandelt haben, fehlen als Letztes noch die .Net-Klassen.
Der Registryprovider ist sehr einfach, aber in seinen Möglichkeiten etwas begrenzt. WMI ist alt und bewährt und lässt kaum Wünsche offen. 
Moderner als die WMI-Klassen ist .Net, dessen Registryklassen ich in diesem Kapitel behandeln werde.

Die beiden wichtigsten Klassen für den Umgang mit der Registry sind 

wobei erstere nur für den lokalen Gebrauch, letztere auch für den Zugriff auf die Registry eines Remoterechners benutzt werden kann.

Auch bei Zugriffen mit .Net braucht man immer den entsprechenden Rootkey (=RootHive), um auf einen Subkey und letztlich auf den gewünschten Wert mit seinen Daten zugreifen zu können. Unter .Net lassen sich die Rootkeys bequem auflisten.

Beispiel 1: Auflisten der RootHives

MSDN: RegistryHive Enumeration

$RootHives = [System.Enum]::GetNames([Microsoft.Win32.RegistryHive])
$RootHives
#Ausgabe

ClassesRoot
CurrentUser
LocalMachine
Users
PerformanceData
CurrentConfig
DynData

Eine kurze Erklärung zu RootHives findet ihr im Kapitel 0.1.1 Struktur der Registry.
 

2 Zugriff auf die Registry  [Microsoft.Win32.RegistryKey]

2.1 Lesen und Ändern von Registrywerten

Beispiel 1: Erstellen eines Keys und einiger Werte

Das Beispiel hat das indentische Ergebniss wie Beispiel 2 im Kapitel 2.1 StdRegProv, aber benutzt .Net Klassen

Set-StrictMode -Version "2.0"
Clear-Host
 
$ComputerName="" #lokaler Rechner
#$ComputerName="Dom1Cli01" 
$SubKey = "Software\_MyNewKey"
$RegField="CurrentUser"
$RootType = [Microsoft.Win32.RegistryHive]::"$RegField"
$RootRegKey = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey($RootType,$ComputerName)

#Key erstellen
$RegSubKey=$RootRegKey.CreateSubKey($SubKey)

#DWordValue anlegen
$ValueName="MyDWord"
[Int32]$Data = 31 #Ohne Typangabe der Variable gibt es eine  Fehlermeldung
$RegistryValueKind = [Microsoft.Win32.RegistryValueKind]::"DWord"
$RegSubKey.SetValue($ValueName,$Data,$RegistryValueKind)

#StringValue anlegen
$ValueName = "MyString"
[String]$Data = "Mein Freund Karl Napf" #Ohne Typangabe der Variable gibt es eine  Fehlermeldung
$RegistryValueKind = [Microsoft.Win32.RegistryValueKind]::"String"
$RegSubKey.SetValue($ValueName,$Data,$RegistryValueKind)

#MultiStringValue anlegen
$ValueName = "MyMultiString"
[String[]]$Datas = @()  #nicht auf einen Datentyp festgelegt ist:  $arrData=@()
$Datas="Karl_Napf","Franz_Ferdinand", "Tom_Turbo"
$RegistryValueKind = [Microsoft.Win32.RegistryValueKind]::"MultiString"
$RegSubKey.SetValue($ValueName,$Datas,$RegistryValueKind)

#ExpandStringValue anlegen
$ValueName = "MyExpandString"
[String]$Data = "%temp%"
$RegistryValueKind = [Microsoft.Win32.RegistryValueKind]::"ExpandString"
$RegSubKey.SetValue($ValueName,$Data,$RegistryValueKind)

#BinaryValue anlegen
$ValueName = "MyBinaryString"
[Byte[]]$Data = 0x4D,0x5A,0x90,0x00,0x03
$RegistryValueKind = [Microsoft.Win32.RegistryValueKind]::"Binary"
$RegSubKey.SetValue($ValueName,$Data,$RegistryValueKind)

- Dieses Beispiel liefert dasselbe Ergebnis unter .Net, wie  in Kapitel 2.1 StdRegProv das Beispiel 2 mittels WMI. Im direkten Vergleich finde ich persönlich die .Net-Klassen eleganter.

- Es muß nicht für alle Wertetypen der RegistryValueKind als dritter Parameter der SetValue-Mehtode mitgegeben werden. Ebenso müssen nicht alle $Data-Variablen gecastet werden. Powershell weist in vielen Fällen automatisch die Typen zu, aber eben nicht immer wie beispielsweise bei BinaryWerten. 

Beispiel 2a: Auflisten aller Werte eines Keys 

Wenn ihr das Beispiel 1 oben ausgeführt habt, könnt ihr dieses Beispiel ohne Anpassungen direkt hinterherschicken. Dieses Beispiel liest unter einem Schlüssel alle Werte aus und bestimmt auch selbstständig den Wertetyp

Set-StrictMode -Version "2.0"
Clear-Host

$ComputerName = ""
#$ComputerName = "Dom1Cli01" 
$SubKey = "Software\_MyNewKey"
$RegField="CurrentUser"
$RootType = [Microsoft.Win32.RegistryHive]::$RegField
$RootKey = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey($RootType,$ComputerName)
$RegKey = $RootKey.OpenSubKey($SubKey)

Foreach($Value in $RegKey.GetValueNames()){
[Microsoft.Win32.RegistryValueKind]$RegistryValueKind=$RegKey.GetValueKind($Value)

 Switch($RegistryValueKind.ToString()){
    "String"{ 
     [String]$Data=$RegKey.GetValue($Value)
     "{0}   {1}   {2}" -f $Value,$RegistryValueKind,$Data
    }
     "ExpandString" { 
       [String]$Data=$RegKey.GetValue($Value)
       "{0}   {1}    {2}" -f $Value,$RegistryValueKind,$Data
    }
     "Binary"{
       [String]$Data=$RegKey.GetValue($Value)
       "{0}   {1}    {2}" -f $Value,$RegistryValueKind,$Data
    } 
      "DWord"{ 
       [Int32]$Data=$RegKey.GetValue($Value)
       "{0}   {1}    {2}" -f $Value,$RegistryValueKind,$Data
    }  
      "MultiString"{
       [String]$Data=$RegKey.GetValue($Value) 
       "{0}   {1}    {2}" -f $Value,$RegistryValueKind,$Data
    }   
     Default {"unbekannter Registrytyp"}
   }#switch  
 }#ForEach
#mögliche Ausgabe

MyDWord   DWord    36
MyString   String   Mein Freund Franz-Ferdinand
MyMultiString   MultiString    Karl Napf Franz Ferdinand Tom Turbo Karl Knall
MyExpandString   ExpandString    C:\Users\KARL_N~1\AppData\Local\Temp
MyBinaryString   Binary    77 90 144 0 3

- Dieses Beispiel liefert dasselbe Ergebnis unter .Net, wie in Kapitel 2.1 StdRegProv das Beispiel 6a mittels WMI. Im direkten Vergleich finde ich persönlich die .Net-Klassen eleganter.

- Es ist nicht immer bei jedem Datentyp notwendig, der Variablen $Data den Datentyp explizit zuzuweisen mit [String]$Data oder [Int32]$Data. Bei MultiString oder Binary ist es aber notwendig und bei DWord sollte man es machen um Fehler bei einer Weiterverarbeitung des Ergebnisses vermeide. Daher habe ich die Typzuweisung überall hinzugefügt. 

- Die Variable $RegField kann die Werte "ClassesRoot","CurrentConfig","CurrentUser","DynData","LocalMachine","PerformanceData" und "Users" annehmen. MSDN:  Registry-Klasse -> siehe unter Felder


Beispiel 2b: Auflisten aller Werte eines Keys (kompakter als Beispiel 2a)

Wenn ihr das Beispiel 1 oben ausgeführt habt, könnt ihr dieses Beispiel ohne Anpassungen direkt hinterherschicken

Zur Verdeutlichung habe ich in Beispiel 2a jedem ValueType seine eigene Bedingung im Switchblock gegeben. Im Gegensatz zu WMI kann man alle Typen als String ausgeben, was den Code dieses Beispiels 2b von dem Switch-Block befreit. 

Set-StrictMode -Version "2.0"
Clear-Host

$ComputerName = ""
#$ComputerName = "Dom1Cli01" 
$SubKey = "Software\_MyNewKey"
$RegField = "CurrentUser"
$RootType = [Microsoft.Win32.RegistryHive]::$RegField
$RootKey = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey($RootType,$ComputerName)
$RegKey = $RootKey.OpenSubKey($SubKey)

Foreach($Value in $RegKey.GetValueNames()){
  [Microsoft.Win32.RegistryValueKind]$RegistryValueKind=$RegKey.GetValueKind($Value)
  [String]$Data=$RegKey.GetValue($Value)
  "{0}   {1}   {2}" -f $Value,$RegistryValueKind,$Data
}
#mögliche Ausgabe

MyDWord   DWord    36
MyString   String   Mein Freund Franz-Ferdinand
MyMultiString   MultiString    Karl Napf Franz Ferdinand Tom Turbo Karl Knall
MyExpandString   ExpandString    C:\Users\KARL_N~1\AppData\Local\Temp
MyBinaryString   Binary    77 90 144 0 3

Sofern man Werte nur auslesen und nicht verändern will, funktioniert dieser Code genauso wie Beispiel 2a. 


Beispiel 3: einen bestimmten Wert auslesen

Set-StrictMode -Version "2.0"
Clear-Host

$ComputerName = ""
#$ComputerName = "Dom1Cli01" 
$SubKey = "Software\_MyNewKey"
$RegField="CurrentUser"
$RootType = [Microsoft.Win32.RegistryHive]::$RegField
$RootKey = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey($RootType,$ComputerName)
$RegKey = $RootKey.OpenSubKey($SubKey)

Try{
  $Value="MyString" 
  [Microsoft.Win32.RegistryValueKind]$RegistryValueKind=$RegKey.GetValueKind($Value)
  [String]$Data=$RegKey.GetValue($Value)
  "{0}   {1}   {2} `n" -f $Value,$RegistryValueKind,$Data 

  $Value="MyExpandString" 
  [Microsoft.Win32.RegistryValueKind]$RegistryValueKind=$RegKey.GetValueKind($Value)
  [String]$Data=$RegKey.GetValue($Value)
  "{0}   {1}   {2} `n" -f $Value,$RegistryValueKind,$Data 
  
  $Value="MyBinaryString"
  [Microsoft.Win32.RegistryValueKind]$RegistryValueKind=$RegKey.GetValueKind($Value)
  [String]$Data=$RegKey.GetValue($Value)
  "{0}   {1}   {2} `n" -f $Value,$RegistryValueKind,$Data

  $Value="MyDword"
  [Microsoft.Win32.RegistryValueKind]$RegistryValueKind=$RegKey.GetValueKind($Value)
  [Int32]$Data=$RegKey.GetValue($Value)
  "{0}   {1}   {2} `n" -f $Value,$RegistryValueKind,$Data

  $Value = "MyMultiString"
  [Microsoft.Win32.RegistryValueKind]$RegistryValueKind = $RegKey.GetValueKind($Value)
  [String]$Data = $RegKey.GetValue($Value)
  "{0}   {1}   {2} `n" -f $Value,$RegistryValueKind,$Data

}Catch{
 "Ein Fehler ist aufgetreten. Wahrscheinlich ist ein Wert nicht vorhanden"
}
#mögliche Ausgabe

MyString   String   Mein Freund Karl Napf 

MyExpandString   ExpandString   C:\DOKUME~1\j184710\LOKALE~1\Temp 

MyBinaryString   Binary   77 90 144 0 3 

MyDword   DWord   31 

Ein Fehler ist aufgetreten. Wahrscheinlich ist der Wert nicht vorhanden

Dieses Beispiel zeigt, wie man die Daten und den Datentyp eines bestimmten RegistryWertes ausliest. 

- Bei einem DWord-Wert sollte man der aufnehmenden Variablen den Datentype [Int32] zuzuweisen.

- Bei einem Multistring-Wert kann es eventuell sinnvoll sein, den String mit dem "Split" aufzuteilen. 3.2.1 Mit der Regex-Klasse instanzbasiert und instanzfrei arbeiten -> Beispiel 3a,b,c


Beispiel 4: Löschen eines Registrywertes

Set-StrictMode -Version "2.0"
Clear-Host

$ComputerName = ""
#$ComputerName = "Dom1Cli01" 
$SubKey = "Software\_MyNewKey"
$RegField = "CurrentUser"
$RootType = [Microsoft.Win32.RegistryHive]::$RegField
$RootKey = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey($RootType,$ComputerName)
$RegKey = $RootKey.OpenSubKey($SubKey,$true) #$true gestattet schreibenden Zugriff

$Value = "MyString" 
$RegKey.DeleteValue($Value)

Für die Methode DeleteValue benötigt die Methode OpenSubKey ".OpenSubKey($SubKey,$true)" die Information, dass schreibend auf diesen Wert zugegriffen werden darf. Dies geschieht durch den zweiten Parameter "$true". 
Ohne $true komm die Fehlermeldung "Cannot write to the registry key." oder auf Deutsch "In den Registrierungsschlüssel kann nicht geschrieben werden."

 

Beispiel 5: Löschen eines Registryschlüssels (DeleteSubKeyTree)

Set-StrictMode -Version "2.0"
Clear-Host
 
$ComputerName = ""
 
$RegField = "CurrentUser"
$SubKeys = "Software\Microsoft\SystemCertificates"
$Value = "TestStore"
 
$RootType = [Microsoft.Win32.RegistryHive]::$RegField
 
$RootKey = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey($RootType,$ComputerName)
$RegKey = $RootKey.OpenSubKey($SubKey,$True) #$true allows writing access
 
#$RegKey.DeleteSubKeyTree($Value,$False)  #no exception if the subkey is not available
 
Try{
   $RegKey.DeleteSubKeyTree($Value) #throws an exception if the subkey is not available
   Write-Host "$Value successfully removed" 
}Catch{
   Write-Host "Deletion of $Value failed" -BackgroundColor DarkRed -ForegroundColor DarkYellow
}

#mögliche Ausgabe

 

Deletion of TestStore failed

MSDN: RegistryKey.DeleteSubKeyTree-Methode(String,Boolean)

MSDN: RegistryKey.DeleteSubKeyTree-Methode (String)  

 

Beispiel 6: Verändern von Registrywerten

Wenn ihr das Beispiel 1 oben ausgeführt habt, könnt ihr dieses Beispiel ohne Anpassungen direkt hinterherschicken

Set-StrictMode -Version "2.0"
Clear-Host

$ComputerName = ""
#$ComputerName = "Dom1Cli01" 
$SubKey = "Software\_MyNewKey"
$RegField="CurrentUser"
$RootType = [Microsoft.Win32.RegistryHive]::$RegField
$RootKey = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey($RootType,$ComputerName)
$RegKey = $RootKey.OpenSubKey($SubKey,$true) #$true gestattet schreibenden Zugriff

#DWordValue ändern (+1)
$ValueName="MyDWord"
[Int32]$Data=$Data=$RegKey.GetValue($ValueName)
"DWord alt Dezimal: {0}" -f $Data
"DWord alt Hex: {0:x}" -f $Data
$Data=$Data+1
$RegKey.SetValue($ValueName,$Data)
$Data=$RegKey.GetValue($ValueName)
"DWord neu Dezimal: {0}" -f $Data
"DWord neu Hex: {0:x}`n" -f $Data

#MultiStringValue verändern (Arrayelement hinzufügen)
$ValueName = "MyMultiString" 
[String[]]$Datas = @()
$Datas=$RegKey.GetValue($ValueName)
"MultiString alt {0}" -f [string]$Datas
$Datas+ = "Karl_Knall"
$RegistryValueKind = [Microsoft.Win32.RegistryValueKind]::"MultiString"
$RegKey.SetValue($ValueName,$Datas,$RegistryValueKind)
$Datas=$RegKey.GetValue($ValueName)
"MultiString neu {0}`n" -f [String]$Datas

#StringValue ändern (Replace)
$ValueName = "MyString"
[String]$Data=$RegKey.GetValue($ValueName)
"REG_SZ alt: {0} " -f $Data
$Data=$Data.Replace("Karl Napf","Franz-Ferdinand")
$RegistryValueKind=[Microsoft.Win32.RegistryValueKind]::"String"
$RegKey.SetValue($ValueName,$Data,$RegistryValueKind)
$Data=$RegKey.GetValue($ValueName)
"REG_SZ neu: {0} `n" -f $Data
#mögliche Ausgabe

DWord alt Dezimal: 31
DWord alt Hex: 1f
DWord neu Dezimal: 32
DWord neu Hex: 20

MultiString alt Karl_Napf+Franz_Ferdinand+Tom_Turbo
MultiString neu Karl_Napf+Franz_Ferdinand+Tom_Turbo+Karl_Knall

REG_SZ alt: Mein Freund Karl Napf 
REG_SZ neu: Mein Freund Franz-Ferdinand


2.2 Existenzprüfung von Schlüsseln und Werten

Anders als im Filesystem, wo die zugehörigen Klassen alle auch Methoden zur Existenzprüfung von Elementen besitzen Das Filesystem -> 2.1.2.3 Existenzprüfung von Elementen, muss man in der Registry dazu über die Interpretation der zurückgelieferten Werte gehen.
Ist der geöffnete RegistryWert ungleich (NotEqual -ne) $null, so existiert der Wert, andernfalls nicht
 

Beispiel 1: Existenzprüfung eines Schlüssels

Set-StrictMode -Version "2.0"
Clear-Host

$ComputerName = ""
#$ComputerName = "Dom1Cli01" 
$SubKey = "Software\_MyNewKey"
$RegField = "CurrentUser"
$RootType = [Microsoft.Win32.RegistryHive]::$RegField
$RootKey = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey($RootType,$ComputerName)
$RegKey = $RootKey.OpenSubKey($SubKey)

If($RegKey -ne $null){
  "Der RegKey $RegKey existiert"
}else{
  "Der RegKey $RegKey existiert nicht" 
}
#mögliche Ausgabe

Der RegKey HKEY_CURRENT_USER\Software\_MyNewKey existiert


Beispiel 2: Existenzprüfung eines Wertes

Set-StrictMode -Version "2.0"
Clear-Host

$ComputerName = ""
#$ComputerName = "Dom1Cli01" 
$SubKey = "Software\_MyNewKey"
$Value = "MyString"
$RegField = "CurrentUser"

$RootType = [Microsoft.Win32.RegistryHive]::$RegField
$RootKey = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey($RootType,$ComputerName)
$RegKey = $RootKey.OpenSubKey($SubKey)

if($RegKey.GetValue($Value) -ne $null){
  "Der Wert $Value unter $RegKey existiert"
}else{
   "Der Wert $Value unter $RegKey existiert vermutlich nicht"
}
#mögliche Ausgabe

Der Wert MyString unter HKEY_CURRENT_USER\Software\_MyNewKey existiert


Beispiel 3: Existenzprüfung von Schlüssel und Wert

Set-StrictMode -Version "2.0"
Clear-Host

$ComputerName = ""
#$ComputerName = "Dom1Cli01" 
$SubKey = "Software\_MyNewKey"
$Value = "MyString"
$RegField = "CurrentUser"
$RootType = [Microsoft.Win32.RegistryHive]::$RegField
$RootKey = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey($RootType,$ComputerName)
$RegKey = $RootKey.OpenSubKey($SubKey)

If($RegKey -ne $Null){
  if($RegKey.GetValue($Value) -ne $Null){
     [Microsoft.Win32.RegistryValueKind]$RegistryValueKind=$RegKey.GetValueKind($Value)
     [String]$Data=$RegKey.GetValue($Value)
     "{0}   {1}   {2} `n" -f $Value,$RegistryValueKind,$Data 
  }else{
    "Der Wert $Value unter $RegKey existiert vermutlich nicht"
  } #if($RegKey.GetValue($Value) -ne $null)
}else{
  "Der Key $RegKey existiert vermutlich nicht"
}#if($RegKey -ne $Null)
#mögliche Ausgabe

Der Wert MyString1 unter HKEY_CURRENT_USER\Software\_MyNewKey existiert vermutlich nicht