Die Registry und WMI


1 Einleitung
2 Bearbeiten der Registry
2.1 StdRegProv
         Beispiel 1: Untersuchen der Klasse "Root\default:StdRegProv"
         Beispiel 2: Erstellen eines Keys und einiger Werte
         Beispiel 3: Auslesen einzelner RegistryWerte
         Beispiel 4: Ändern vorhandener Registrywerte
         Beispiel 5: Löschen eines einzelnen Wertes oder eines ganzen Keys
         Beispiel 6a: Auflisten aller Werte eines Keys (Methode EnumValues)
         Beispiel 6b: Ausgabe eines bestimmten Wertes (Methode EnumValues)
   2.2 Win32_Registry
         Beispiel 1: Allgemeine Informationen über die Registry

 


Die Registry und WMI


1 Einleitung

Auf das Thema WMI bin ich im Kapitel Grundlagen -> Automation Interfaces -> WMI wesentlich genauer eingegangen.

WMI besitzt zwei Klassen, mit denen auf die Regsitry lokal oder remote zugegriffen werden kann. 

  • StdRegProv: Mit dieser Klasse können Registryeinträge lokal oder remote gelesen und geschrieben werden
  • Win32_Registry: Mit dieser Klasse können einige Informationen lokal oder remote ausgelesen werden

Auch bei Zugriffen mit WMI braucht man immer den entsprechenden RootKey, um auf einen Subkey und letztlich auf den Wert mit seinen Daten zugreifen zu können. Bei WMI werden die RootKeys mit Zahlen angegeben:

The following trees are defined in Winreg.h.

HKEY_CLASSES_ROOT (2147483648 (0x80000000))
HKEY_CURRENT_USER (2147483649 (0x80000001))
HKEY_LOCAL_MACHINE (2147483650 (0x80000002))
HKEY_USERS (2147483651 (0x80000003))
HKEY_CURRENT_CONFIG (2147483653 (0x80000005))
HKEY_DYN_DATA (2147483654 (0x80000006))

[Quelle]: msdn.microsoft.com/en-us/library/windows/desktop/aa390388%28v=vs.85%29.aspx

2 Bearbeiten der Registry
 

2.1 StdRegProv

Für die Registry bietet natürlich auch WMI einige Möglichkeiten an, deren Hauptvorteil gegenüber dem PowershellregistryProvider die einfache Remotefähigkeit ist.

Die wichtigste Klasse ist die StdRegProv-Klasse aus dem WMI-Namespace "root/default". Da dieser Namespace im Normalfall nicht der StandardNamespace eines Windowsrechners ist, muss dieser beim Aufruf der Klasse explizit mit angegeben werden. Über WMI-Namespaces findet ihr im Kapitel Grundlagen -> Automation Intefaces -> WMI -> 1.1 Namespaces einige Informationen. 

Eine kleine zusätzliche Hürde ist die Erstellung einer Instanz aus der Klasse StdRegProv. Eine Instanz wird nicht mit der sonst bei WMI-Klassen üblichen Syntax erzeugt -Beispiele findet ihr unter WMI -> 2.1 Dataqueries, sondern mit der in Beispiel 1 gezeigten Syntax. 
 
Beispiel 1: Untersuchen der Klasse "Root\default:StdRegProv"

Set-StrictMode -Version "2.0"
Clear-Host

$Computer = "."
$WMI = [wmiclass]"\\$computer\root\default:stdRegProv"
#$WMI = new-object System.Management.ManagementClass "\\$Computer\Root\default:StdRegProv"
$WMI.Methods | Format-Wide {$_.Name} -Column 4
#Ausgabe

CreateKey                 DeleteKey                EnumKey                  EnumValues
DeleteValue               SetDWORDValue            SetQWORDValue            GetDWORDValue
GetQWORDValue             SetStringValue           GetStringValue           SetMultiStringValue
GetMultiStringValue       SetExpandedStringValue   GetExpandedStringValue   SetBinaryValue
GetBinaryValue            CheckAccess              SetSecurityDescriptor    GetSecurityDescriptor

Mit diesen Methoden kann man nun nach Herzenslust auf die lokale Registry, ebenso wie auf die Registry eines Remoterechners zugreifen.
 
Beispiel 2: Erstellen eines Keys und einiger Werte

Set-StrictMode -Version "2.0"
Clear-Host

 
$Computer = "."
$WMI = New-Object System.Management.ManagementClass "\\$Computer\Root\default:StdRegProv" 
#$WMI = [WmiClass]"\\$Computer\root\default:stdRegProv"

$HKCU = 2147483649 #weitere Werte stehen zu Beginn des Kapitel 2

#Key erstellen
$Key = "Software\_MyNewKey"
$Result = $WMI.CreateKey($HKCU,$Key)

#DWordValue anlegen
$ValueName = "MyDWord"
[Int32]$Data = 31 #Ohne Typangabe der Variable gibt es eine Fehlermeldung
$Result=$WMI.SetDWordValue($HKCU,$Key,$ValueName,$Data)  #Result.Returnvalue 

#StringValue anlegen
$ValueName = "MyString"
[String]$Data = "Mein Freund Karl Napf" #Ohne Typangabe der Variable gibt es eine Fehlermeldung
$Result = $WMI.SetStringValue($HKCU,$Key,$ValueName,$Data)

#MultiStringValue anlegen
$ValueName = "MyMultiString"
[String[]]$Datas = @()  #nicht auf einen Datentyp festgelegt ist:  $arrData=@()
$Datas = "Karl_Napf","Franz_Ferdinand", "Tom_Turbo"
$Result = $WMI.SetMultiStringValue($HKCU,$Key,$ValueName,$Datas)

#ExpandStringValue anlegen
$ValueName = "MyExpandString"
[String]$Data = "%temp%"
$Result = $WMI.SetExpandedStringValue($HKCU,$Key,$ValueName,$Data)

#BinaryValue anlegen
$ValueName = "MyBinaryString"
[Byte[]]$Data = 0x4D,0x5A,0x90,0x00,0x03
$Result=$WMI.SetBinaryValue($HKCU,$Key,$ValueName,$Data)

Dieses Beispiel erzeugt unter dem HKCU\Software\_MyNewKey einige Werte unterschiedlichen Datentyps. 

Beispiel 3: Auslesen einzelner RegistryWerte 

Wenn ihr mit Beispiel 2 den BeispielKey angelegt habt, könnt ihr dieses Beispiel direkt hinterherschicken, um die zugehörigen Daten der Werte auszulesen. Je nach Wertetyp muss die passende Methode gewählt werden.

Set-StrictMode -Version "2.0"
Clear-Host
 
$Computer = "."
#$WMI = new-object System.Management.ManagementClass "\\$Computer\Root\default:StdRegProv" 
$WMI = [WmiClass]"\\$Computer\root\default:stdRegProv"
$HKCU = 2147483649 #weitere Werte stehen zu Beginn des Kapitel 2

$Key = "Software\_MyNewKey"

#DWordValue auslesen
$ValueName = "MyDWord"
$Result=$WMI.GetDWordValue($HKCU,$Key,$ValueName)  
"`n"
"DWord Dezimal: {0}" -f $Result.UValue
"DWord Hex: {0:x} `n" -f $Result.UValue

#StringValue auslesen
$ValueName = "MyString"
$Result=$WMI.GetStringValue($HKCU,$Key,$ValueName)
"REG_SZ: {0} `n" -f $Result.SValue

#MultiStringValue auslesen
$ValueName = "MyMultiString"
$Result = $WMI.GetMultiStringValue($HKCU,$Key,$ValueName)
$Result.SValue | foreach{
 "REG_MULTI_SZ: {0}" -f $_
}

"`n"
#ExpandStringValue auslesen
$ValueName = "MyExpandString"
$Result = $WMI.GetExpandedStringValue($HKCU,$Key,$ValueName)
"REG_EXPANDED_SZ: {0} `n" -f $Result.SValue

#BinaryValue auslesen
$ValueName = "MyBinaryString"
$Result = $WMI.GetBinaryValue($HKCU,$Key,$ValueName) 
"REG_BINARY"
$Result.UValue
#Ausgabe, wenn der Key HKCU\Software\_MyTestKey aus Beispiel 2 existiert

DWord Dezimal: 31
DWord Hex: 1f 

REG_SZ: Mein Freund Karl Napf 

REG_MULTI_SZ: Karl_Napf
REG_MULTI_SZ: Franz_Ferdinand
REG_MULTI_SZ: Tom_Turbo

REG_EXPANDED_SZ: C:\WINDOWS\TEMP 

REG_BINARY
77
90
144
0
3

Unter MSDN: StdRegProv class sind alle Methoden der Klasse StdRegProv aufgeführt

Im Beispiel 6b lasse ich WMI selbst den Datentyp bestimmen.


Beispiel 4: Ändern vorhandener Registrywerte

Wenn ihr mit Beispiel 2 den BeispielKey angelegt habt, könnt ihr dieses Beispiel direkt hinterherschicken, in dem vorhandene Werte verändert werden.

Set-StrictMode -Version "2.0"
Clear-Host
 
$Computer = "."
#$WMI = New-Object System.Management.ManagementClass "\\$Computer\Root\default:StdRegProv" 
$WMI = [WmiClass]"\\$computer\root\default:stdRegProv"
$HKCU = 2147483649 #weitere Werte stehen zu Beginn des Kapitel 2

$Key = "Software\_MyNewKey"

#DWordValue ändern (+1)
$ValueName = "MyDWord"
$Result = $WMI.GetDWordValue($HKCU,$Key,$ValueName)  
"DWord alt Dezimal: {0}" -f $Result.UValue
"DWord alt Hex: {0:x}" -f $Result.UValue
[Int32]$Data = $Result.UValue+1
$Result = $WMI.SetDWordValue($HKCU,$Key,$ValueName,$Data)
$Result = $WMI.GetDWordValue($HKCU,$Key,$ValueName) 
"DWord neu Dezimal: {0}" -f $Result.UValue
"DWord neu Hex: {0:x} `n" -f $Result.UValue

#StringValue ändern (Replace)
$ValueName = "MyString"
$Result=$WMI.GetStringValue($HKCU,$Key,$ValueName)
[String]$Data=$Result.SValue
"REG_SZ alt: {0} " -f $Result.SValue
$Data=$Data.Replace("Karl Napf","Franz-Ferdinand")
$Result=$WMI.SetStringValue($HKCU,$Key,$ValueName,$Data)
$Result=$WMI.GetStringValue($HKCU,$Key,$ValueName)
"REG_SZ neu: {0} `n" -f $Result.SValue

#MultiStringValue verändern (Arrayelement hinzufügen)
$ValueName = "MyMultiString"
$Result = $WMI.GetMultiStringValue($HKCU,$Key,$ValueName)
$Result.SValue | foreach{
 "REG_MULTI_SZ alt: {0}" -f $_
}
[string[]]$Datas = $Result.SValue
$Datas += "Karl_Knall"
$Result = $WMI.SetMultiStringValue($HKCU,$Key,$ValueName,$Datas)
$Result = $WMI.GetMultiStringValue($HKCU,$Key,$ValueName)
$Result.SValue | foreach{
 "REG_MULTI_SZ neu: {0}" -f $_
}
#Ausgabe

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

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

REG_MULTI_SZ alt: Karl_Napf
REG_MULTI_SZ alt: Franz_Ferdinand
REG_MULTI_SZ alt: Tom _urbo
REG_MULTI_SZ neu: Karl_Napf
REG_MULTI_SZ neu: Franz_Ferdinand
REG_MULTI_SZ neu: Tom_Turbo
REG_MULTI_SZ neu: Karl_Knall

Unter MSDN: StdRegProv class sind alle Methoden der Klasse StdRegProv aufgeführt


Beispiel 5: Löschen eines einzelnen Wertes oder eines ganzen Keys

Wenn ihr mit Beispiel 2 den BeispielKey angelegt habt, könnt ihr dieses Beispiel direkt hinterherschicken, indem ein Wert oder der gesamte Key gelöscht wird

Set-StrictMode -Version "2.0"
Clear-Host
 
$Computer = "."
$WMI = New-Object System.Management.ManagementClass "\\$Computer\Root\default:StdRegProv" 
#$WMI = [wmiclass]"\\$computer\root\default:stdRegProv"

$HKCU=2147483649 #weitere Werte stehen zu Beginn des Kapitel 2

$Value = "MyString"
$Key = "Software\_MyNewKey"

#Wert löschen
$Result=$WMI.DeleteValue($HKCU,$Key,$Value)
If($Result.ReturnValue -eq 0) {
  "Das Löschen des Wertes war erfolgreich"
  }else{
  "Das Löschen des Wertes war nicht erfolgreich"
  }

<#
#Key löschen
$Result = $WMI.DeleteKey($HKCU,$Key)
If($Result.ReturnValue -eq 0) {
  "Das Löschen des Keys war erfolgreich"
  }else{
  "Das Löschen des Keys war nicht erfolgreich"
  }
#>
#mögliche Ausgabe

Das Löschen des Wertes war nicht erfolgreich


Beispiel 6a: Auflisten aller Werte eines Keys (Methode EnumValues)

Wenn ihr mit Beispiel 2 den BeispielKey angelegt habt, könnt ihr dieses Beispiel direkt hinterherschicken, indem alle Werte eines Keys samt ValueType ausgelesen werden.

Set-StrictMode -Version "2.0"
Clear-Host

#Mögliche Werte der RegValueKinds als Hash
$RegValueKinds = @{1 = "REG_SZ";
                  2 = "REG_EXPAND_SZ";
                  3 = "REG_BINARY"
                  4 = "REG_DWORD"
                  7 = "REG_MULTI_SZ"
                  }

$Computer="."
$WMI = New-Object System.Management.ManagementClass "\\$Computer\Root\default:StdRegProv"
#$WMI = [wmiclass]"\\$computer\root\default:stdRegProv"
$HKCU=2147483649 #weitere Werte für andere RootKeys zu Beginn des Kapitels 2
$Key = "Software\_MyNewKey"

#Hier werden alle Werte inkl. dem RegValueType unter dem Key in die Variable $Result gelesen

$EnumValues=$WMI.EnumValues($HKCU,$Key)
[String[]]$sNames=$EnumValues.sNames
[Int[]]$Types=$EnumValues.Types

#ab hier werden die Daten von jedem Value ausgelesen, abhängig vom Datentyp (=$Types[$i])

for($i=0;$i -lt $sNames.count;$i++){
  switch($Types[$i])
  {
    1 {$Data=$WMI.GetStringValue($HKCU,$Key,$sNames[$i])
        "{0}   {1}   {2}" -f $sNames[$i],$RegValueKinds.Get_Item($Types[$i]),$Data.SValue
      }
    2 {$Data=$WMI.GetExpandedStringValue($HKCU,$Key,$sNames[$i])
        "{0}   {1}    {2}" -f $sNames[$i],$RegValueKinds.Get_Item($Types[$i]),$Data.SValue
      }
    3 {$Data=$WMI.GetBinaryValue($HKCU,$Key,$sNames[$i])
        "{0}   {1}    {2}" -f $sNames[$i],$RegValueKinds.Get_Item($Types[$i]),[String]$Data.UValue
      }
    4 {$Data=$WMI.GetDWordValue($HKCU,$Key,$sNames[$i])
        "{0}   {1}    {2}" -f $sNames[$i],$RegValueKinds.Get_Item($Types[$i]),$Data.UValue
      }  
    7 {$Data=$WMI.GetMultiStringValue($HKCU,$Key,$sNames[$i])
        "{0}   {1}    {2}" -f $sNames[$i],$RegValueKinds.Get_Item($Types[$i]),[String]$Data.sValue
      }   
    default {"unbekannter Registrytyp"}
  }  
}
#Ausgabe

MyDWord   REG_DWORD    32
MyString   REG_SZ   Mein Freund Franz-Ferdinand
MyExpandString   REG_EXPAND_SZ    C:\WINDOWS\TEMP
MyBinaryString1   REG_BINARY    77 90 144 0 3
MyMultiString   REG_MULTI_SZ    Karl Napf Franz Ferdinand Tom Turbo Karl Knall

 Kap2.1 StdRegProv Beispiel_6a.ps1.txt

Das Beispiel liefert dasselbe Ergebnis wie das .Net Beispiel 2a unter Kapitel 3.1.1 Lesen und Ändern von Registrywerten

 

Beispiel 6b: Ausgabe eines bestimmten Wertes (Methode EnumValues)

Wenn ihr mit Beispiel 2 den BeispielKey angelegt habt, könnt ihr dieses Beispiel direkt hinterherschicken, indem ein bestimmter Wert samt ValueType ausgelesen wirde.

Set-StrictMode -Version "2.0"
Clear-Host
Remove-Variable -scope script * -EA 0  

#Mögliche Werte der RegValueKinds als Hash
$RegValueKinds = @{1 = "REG_SZ";
                  2 = "REG_EXPAND_SZ";
                  3 = "REG_BINARY"
                  4 = "REG_DWORD"
                  7 = "REG_MULTI_SZ"
                  }

$Computer="."
$WMI = New-Object System.Management.ManagementClass "\\$Computer\Root\default:StdRegProv"
#$WMI = [wmiclass]"\\$computer\root\default:stdRegProv"
$HKCU=2147483649
#weitere Werte für andere RootKeys zu Beginn des Kapitels 2 
$Key = "Software\_MyNewKey"
$Name = "MyMultiString"

#Hier werden alle Werte inkl. dem RegValueType unter dem Key in die Variable $Result gelesen
$EnumValues=$WMI.EnumValues($HKCU,$Key)  
[String[]]$sNames=$Enumvalues.sNames
[Int[]]$Types=$EnumValues.Types

for($i=0;$i -lt $sNames.count;$i++){
 if($sNames[$i] -eq $Name){  
  switch($Types[$i])
  {
    1 {$Data=$WMI.GetStringValue($HKCU,$Key,$Name)
        "{0}   {1}   {2}" -f $Name,$RegValueKinds.Get_Item($Types[$i]),$Data.SValue
      }
    2 {$Data=$WMI.GetExpandedStringValue($HKCU,$Key,$sNames[$i])
        "{0}   {1}    {2}" -f $Name,$RegValueKinds.Get_Item($Types[$i]),$Data.SValue
      }
    3 {$Data=$WMI.GetBinaryValue($HKCU,$Key,$sNames[$i])
        "{0}   {1}    {2}" -f $Name,$RegValueKinds.Get_Item($Types[$i]),[string]$Data.UValue
      }
    4 {$Data=$WMI.GetDWordValue($HKCU,$Key,$sNames[$i])
        "{0}   {1}    {2}" -f $Name,$RegValueKinds.Get_Item($Types[$i]),$Data.UValue
      }  
    7 {$Data=$WMI.GetMultiStringValue($HKCU,$Key,$sNames[$i])
        "{0}   {1}    {2}" -f $Name,$RegValueKinds.Get_Item($Types[$i]),[string]$Data.sValue
      }   
    default {"unbekannter Registrytyp"}
   } #switch
  } #if
} #for
#Ausgabe

MyMultiString   REG_MULTI_SZ    Karl_Napf Franz_Ferdinand Tom_Turbo

Im Gegensatz zu Beispiel 3 lasse ich hier WMI selbst den Typ der Daten bestimmen und mit der entsprechenden Methode ausgeben.

 

2.2 Win32_Registry

MSDN: Win32_Registry class 

WMI bringt mit Win32_Registry eine weitere RegistryKlasse mit, mit deren Hilfe man sich einige Informationen über die aktuelle Registry auslesen kann. Der Wert dieser Informationen hält sich meines Erachtens aber eher in Grenzen. Nichtsdestotrotz ein Beispiel, was man von dieser Klasse alles erfahren kann.


Beispiel 1: Allgemeine Informationen über die Registry

Set-StrictMode -Version "2.0"
Clear-Host
 
$Computer = "." 
$Namespace = "root\CIMV2" 
$Win32_Registry=Get-WmiObject -class Win32_Registry -computername $Computer -namespace $Namespace

"Caption: {0}" -f $Win32_Registry.Caption
"Computername: {0}" -f $Win32_Registry.__Server
"aktuelle Größe in Mb: {0}" -f $Win32_Registry.CurrentSize
"maximale Größe in Mb: {0}" -f $Win32_Registry.MaximumSize
"Installationsdatum: {0:d}" -f $Win32_Registry.ConvertToDateTime(($Win32_Registry.InstallDate))
"Status: {0} " -f $Win32_Registry.Status
#mögliche Ausgabe

Caption: Registrierung
Computername: Dom1Srv01
aktuelle Größe in Mb: 9
maximale Größe in Mb: 120
Installationsdatum: 14.04.2008
Status: OK