{"id":55000962,"date":"2014-12-01T00:00:00","date_gmt":"2020-05-22T21:13:50","guid":{"rendered":"http:\/\/access-im-unternehmen.aix-dev.de\/aiu\/?p=962"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-30T00:00:00","slug":"Das_Windows_Management_Instrumentarium","status":"publish","type":"post","link":"https:\/\/access-im-unternehmen.de\/Das_Windows_Management_Instrumentarium\/","title":{"rendered":"Das Windows Management Instrumentarium"},"content":{"rendered":"<p><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/vg07.met.vgwort.de\/na\/0c70b9dd329640eab4773aa24aac23a1\" width=\"1\" height=\"1\" alt=\"\"><\/p>\n<p><b>Wenn Sie in Ihrer Datenbank externe Informationen &uuml;ber System, Hardware oder Software ben&ouml;tigen, so lassen sich diese unter VBA meist nur &uuml;ber umfangreiche API-Routinen gewinnen. Dabei gibt es mit dem Windows Management Instrumentarium, kurz WMI, eine Schnittstelle, die fast keine W&uuml;nsche offen l&auml;sst und Ihnen enorm viel Programmierarbeit abnehmen kann. Das ist Grund genug, diese Schnittstelle einmal genauer unter die Lupe zu nehmen.<\/b><\/p>\n<p><b>Beispieldatenbank<\/b><\/p>\n<p>Die Beispiele dieses Artikels finden Sie in der Datenbank <b>1409_WMI.mdb<\/b>.<\/p>\n<p><b>Wie funktioniert das WMI<\/b><\/p>\n<p>Windows bringt WMI als einen Service mit, der in der Systemverwaltung auf den Namen <b>Windows-Verwaltungsinstrumentation<\/b> h&ouml;rt und automatisch gestartet wird. Wirklich aktiv wird es allerdings erst, wenn eine Anfrage an den Service gestellt wird.<\/p>\n<p>Dann findet man im Taskmanager den neuen Prozess <b>WmiPrvSE.exe<\/b>, eine Datei, die aus dem Unterverzeichnis<b> \\wbem<\/b> des Windows-Systemordners heraus gestartet wird. Der Prozess selbst verwaltet nur die Anfragen und hat deshalb den Namen <b>WMI Provider Host<\/b>.<\/p>\n<p>Bei Anfragen entscheidet er, welche zus&auml;tzlichen Dlls zu laden sind, in denen die eigentlichen Funktionen zur Ermittlung der Systemkomponenten untergebracht sind. Diese Dlls sind die <b>Provider<\/b>, also Datenlieferanten, und ebenfalls im <b>\\wbem<\/b>-Verzeichnis beheimatet.<\/p>\n<p>Sie finden dort au&szlig;erdem zahlreiche Dateien mit der Endung <b>.mof<\/b>. Das sind Textdateien, die die Struktur jedes Providers beschreiben.<\/p>\n<p>Wir kommen noch darauf zu sprechen, wie eine Anfrage an den Service gestellt wird. Der Ablauf sieht schematisch danach jedenfalls so aus:<\/p>\n<ul>\n<li>Anfrage an WMI-Service<\/li>\n<li>Der Service befragt den Provider Host.<\/li>\n<li>Der Provider Host durchsucht beim ersten Start das Verzeichnis <b>\\wbem <\/b>nach allen Provider-Definitionen und baut daraus im Speicher eine Art Datenbank auf.   Aus dieser wird je nach Anfrageschl&uuml;sselw&ouml;rtern der geeignete Provider herausgesucht und die entsprechende Dll geladen. <\/li>\n<li>&uuml;ber eine COM-Schnittstelle wird ein Klassenobjekt aus der Dll erzeugt, das zu einem gesuchten Objekt, etwa einer Druckerinstanz, die Eigenschaften zur&uuml;ckliefert. Die Dll wei&szlig; selbst, welche weiteren Dlls sie zum L&ouml;sen der Aufgabe ben&ouml;tigt, und verwendet dazu normale API-Methoden.<\/li>\n<li>Die Ergebnisse laufen den Weg zur&uuml;ck bis zum Ausl&ouml;ser der Anfrage<\/li>\n<\/ul>\n<p>Der gesamte Vorgang ist standardisiert, sodass es keine Rolle spielt, ob Sie Hardware- oder Software-Komponenten abfragen wollen &#8211; der Ablauf ist immer identisch. <\/p>\n<p>Da das WMI intern eine Datenbank &uuml;ber alle m&ouml;glichen abfragbaren Objekte aufbaut, liegt es nahe, dass diese &uuml;ber einen SQL-Dialekt angesprochen werden kann. Das ist auch der Fall: Die Abfragesprache nennt sich <b>WQL<\/b>. Damit ist es m&ouml;glich, ein Abbild der WMI-Datenbank in das Datenmodell einer Access-Datenbank zu &uuml;berf&uuml;hren. Die L&ouml;sung dazu finden Sie in der Beispieldatenbank zum Beitrag. Das Datenmodell sieht aus wie in Bild 1 und zeigt eine hierarchische Struktur. Um es zu erl&auml;utern und die Entsprechungen zur WMI-Datenbank deutlich zu machen, nehmen wir ein einfaches WQL-Beispiel zur Hand:<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2014_06\/pic_962_001.png\" alt=\"Analogie des WMI-Datenmodells unter Access\" width=\"575\" height=\"137,0639\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 1: Analogie des WMI-Datenmodells unter Access<\/span><\/b><\/p>\n<pre>SELECT Caption FROM Win32_Printer<\/pre>\n<p>Analog zu einer Access-Abfrage handelt sich bei <b>Caption<\/b> offenbar um ein Feld, das aus der Datenherkunft <b>Win32_Printer<\/b> stammt. Gesucht werden hier alle Bezeichnungen der im System installierten Drucker. <b>Win32_Printer<\/b> scheint demnach eine Tabelle oder selbst eine Abfrage zu sein. Tats&auml;chlich trifft eher Letzteres zu. Was unter Access eine Tabelle oder Abfrage ist, nennt sich unter WMI allerdings Objektklasse. <\/p>\n<p><b>WMI-Datenmodell<\/b><\/p>\n<p>Welches ist aber die Datenbank, aus der die Objektabfrage stammt Um bei der Analogie zu bleiben, nehmen wir an dieser Stelle das Ergebnis der Routinen der Beispieldatenbank vorweg und verweisen auf Bild 2.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2014_06\/pic_962_002.png\" alt=\"Root-Provider-Liste des WMI\" width=\"400\" height=\"488,0734\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 2: Root-Provider-Liste des WMI<\/span><\/b><\/p>\n<p>Das ist der Inhalt der im vorherigen Bild dargestellten Tabelle <b>tblWMIRoot<\/b>. Was unter Access als die aktuelle Datenbank <b>CurrentDb<\/b> bekannt ist, w&auml;re im WMI die Objektklasse <b>root<\/b>.<\/p>\n<p>Sie besteht aus einer Auflistung von Grundklassen, bestimmten Standardkategorien, auch Namespaces genannt, von denen der Provider <b>CIMV2<\/b> der wichtigste ist. <b>CIMV2<\/b> ist eine Abk&uuml;rzung f&uuml;r <b>Common Information Model<\/b> Version 2. <b>root<\/b> w&auml;re der Name der Datenbank, <b>CIMV2<\/b> eine Abfrage auf die Tabelle der Root-Provider. Also s&auml;he die Syntax der Abfrage <b>Win32_Printer<\/b> eigentlich so aus:<\/p>\n<pre>SELECT * FROM root.CIMV2 _\r\n   WHERE Name = ''Win32_Printer''<\/pre>\n<p>Dass diese Abfrage unter WQL so nicht funktioniert, werden wir noch sehen. Wichtig ist hier zun&auml;chst das Prinzip.<\/p>\n<p>Lie&szlig;e man die Bedingung in der Abfrage weg, so k&auml;me man auf eine Liste aller <b>CIMV2<\/b>-Klassen. In der Beispieldatenbank steht daf&uuml;r die Tabelle <b>tblWMIClasses<\/b>. Ihr Inhalt ist auszugsweise in Bild 3 zu begutachten. <b>IDNamespace<\/b> ist ein Bezug zu <b>ID<\/b> der Root-Klasse; hier die <b>5<\/b> f&uuml;r <b>CIMV2<\/b>. Die Tabelle ist wiederum mit der Tabelle <b>tblWMI-ClassesProps<\/b> verlinkt, indem deren Feld <b>IDClass<\/b> mit der ID verkn&uuml;pft und als Unterdatenblatt dargestellt wird. In <b>tblWMIClassesProps<\/b> stehen die Eigenschaften der jeweiligen Klasse und damit eigentlich deren Feldnamen. In der Abbildung sind f&uuml;r die Klasse <b>Win32_CurrentTime<\/b> (aktuelle Systemzeit) die Eigenschaftsfelder ausgeklappt. Wollte man etwa den Tag des aktuellen Datums abfragen, so w&auml;re der Wert des Feldes <b>Day<\/b> der Abfrage <b>Win32_CurrentTime<\/b> zu ermitteln. <\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2014_06\/pic_962_003.png\" alt=\"WMI-Objektklassen und die Eigenschaftsfelder einer Klasse\" width=\"575\" height=\"427,6382\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 3: WMI-Objektklassen und die Eigenschaftsfelder einer Klasse<\/span><\/b><\/p>\n<p><b>Das WMI abfragen<\/b><\/p>\n<p>Schauen wir uns nun an, wie das Abfragen der Systemzeit unter VBA konkret realisiert werden kann. Grunds&auml;tzlich gibt es da zwei Wege, die beschritten werden k&ouml;nnen: eine Variante ohne und eine mit Verweis-Bibliothek. Zur verweislosen L&ouml;sung finden Sie nachfolgend zwei Routinen. <\/p>\n<p>Sie k&ouml;nnen eine Instanz des WMI sehr einfach erhalten, indem Sie einen speziellen sogenannten Moniker-String an die VBA-Funktion <b>GetObjekt<\/b> &uuml;bergeben:<\/p>\n<pre><span style=\"color:blue;\">Set<\/span> objWMI = GetObject(\"winmgmts:\")<\/pre>\n<p>Sie erhalten damit jedoch nicht etwa die oberste Ebene der WMI-Datenbank, also <b>root<\/b>, sondern bereits den <b>CIMV2<\/b>-Provider. Denn der voll ausgeschriebene Moniker-String m&uuml;sste so lauten:<\/p>\n<pre>GetObject(\"winmgmts:\/\/.\/root\/cimv2\")<\/pre>\n<p>WMI verwendet, wenn bestimmte Parameter im String weggelassen werden, automatisch Defaults. Zu diesen Defaults geh&ouml;ren der angesprochene Computer, die <b>root<\/b>-Datenbank und der <b>CIMV2<\/b>-Provider. Die Syntax des Moniker-Strings lautet genau genommen<\/p>\n<pre>winmgmts:\/\/[Computer]\/root\/[Provider]<\/pre>\n<p>F&uuml;r <b>Computer<\/b> k&ouml;nnen Sie einfach einen Punkt verwenden, wenn Sie das lokale System ansprechen wollen. Damit wird bereits deutlich, dass man &uuml;ber das WMI auch andere vernetzte Rechner abfragen kann, soweit die Berechtigungen dazu ausreichen! F&uuml;r <b>Computer<\/b> kann man also ebenfalls die IP-Nummer oder den Netzwerknamen des Rechners angeben:<\/p>\n<pre>winmgmts:\/\/192.168.0.2\/root\/cimv2\r\nwinmgmts:\/\/Harry2\/root\/cimv2<\/pre>\n<p>WMI ist &uuml;brigens unsensibel, was Gro&szlig;- und Kleinschreibung angeht. Meist ist es egal, wie Sie einen Ausdruck schreiben.<\/p>\n<p>In der Routine <b>TestWMIDate1<\/b> (s. Listing 1)  aus dem Modul <b>mdlWMI<\/b> wird also zun&auml;chst ein Objekt <b>objWMI<\/b> gesetzt, das dem Klassenkatalog des Haupt-Providers <b>CIMV2 <\/b>entspricht. In Analogie zu Access entspr&auml;che dieses Objekt erst einer Datenbank. Und diese kann wie unter Access &uuml;ber <b>OpenRecordset<\/b> abgefragt werden, nur dass sich der Befehl hier <b>ExecQuery<\/b> nennt. Im WQL-String werden also die Felder <b>Day<\/b>, <b>Month <\/b>und <b>Year <\/b>des Providers <b>Win32_CurrentTime<\/b> abgefragt.<\/p>\n<pre><span style=\"color:blue;\">Sub <\/span>TestWMIDate1()\r\n     <span style=\"color:blue;\">Dim <\/span>objWMI<span style=\"color:blue;\"> As Object<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>objSet<span style=\"color:blue;\"> As Object<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>obj<span style=\"color:blue;\"> As Object<\/span>\r\n     <span style=\"color:blue;\">Set<\/span> objWMI = GetObject(\"winmgmts:\/\/.\/root\/cimv2\")\r\n     <span style=\"color:blue;\">Set<\/span> obj<span style=\"color:blue;\">Set<\/span> = objWMI.ExecQuery(\"SELECT Day, Month, Year FROM Win32_CurrentTime\")\r\n     <span style=\"color:blue;\">Set<\/span> obj = objSet.ItemIndex(0)\r\n     <span style=\"color:blue;\">Debug.Print<\/span> obj.GetObjectText_\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 1: Erste Variante zum Ermitteln von Datumsangaben &uuml;ber das WMI<\/span><\/b><\/p>\n<p>Als Resultat bekommen Sie &uuml;ber diese Abfrage nicht ein Recordset, sondern ein WMI-<b>ObjectSet<\/b>, das in der Routine der Variablen <b>objSet<\/b> zugewiesen wird. Zwar kann ein Recordset viele Datens&auml;tze enthalten, doch in unserem Fall gibt es nun mal nur ein aktuelles Datum.<\/p>\n<p>Das Resultat besteht also nur aus einem Datensatz (WMI-Objekt). Dieser Datensatz muss jetzt f&uuml;r die weitere Verwendung in einer weiteren Objektvariablen <b>obj<\/b> gespeichert werden. Man erh&auml;lt ihn &uuml;ber die Funktion <b>ItemIndex<\/b>([Datensatznummer]) des <b>ObjectSets<\/b>. Und schlie&szlig;lich l&auml;sst sich der Inhalt des Datensatzobjekts extrem einfach &uuml;ber die Anweisung <b>GetObjectText_<\/b> ausgeben. Heraus kommt dabei etwa dies:<\/p>\n<pre>instance of Win32_LocalTime\r\n{\r\n     Day = 21;\r\n     Month = 09;\r\n     Year = 2014;\r\n};<\/pre>\n<p><b>GetObjectText_<\/b> entspricht damit dem Pendant <b>GetString<\/b> eines ADO-Recordsets.<\/p>\n<p>Da sich das Ergebnis in dieser Form schlecht weiterverwenden l&auml;sst, zeigt die Prozedur <b>TestWMIDate2<\/b> in Listing 2, wie man stattdessen die einzelnen Feldwerte des Datensatzes auslesen kann. Sie gleicht anfangs genau der besprochenen Routine, verwendet dann aber die Auflistung <b>Properties_<\/b> des Datensatzobjekts, um die Eigenschaftswerte zur&uuml;ckzugeben. Sie werden als String zu einem Ergebnis zusammengesetzt, der das aktuelle Datum wiedergibt:<\/p>\n<pre><span style=\"color:blue;\">Sub <\/span>TestWMIDate2()\r\n     <span style=\"color:blue;\">Dim <\/span>objWMI<span style=\"color:blue;\"> As Object<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>objSet<span style=\"color:blue;\"> As Object<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>obj<span style=\"color:blue;\"> As Object<\/span>\r\n     <span style=\"color:blue;\">Set<\/span> objWMI = GetObject(\"winmgmts:\/\/.\/root\/cimv2\")\r\n     <span style=\"color:blue;\">Set<\/span> obj<span style=\"color:blue;\">Set<\/span> = objWMI.ExecQuery (\"SELECT Day, Month, Year FROM Win32_CurrentTime\")\r\n     <span style=\"color:blue;\">Set<\/span> obj = objSet.ItemIndex(0)\r\n     <span style=\"color:blue;\">With<\/span> obj.Properties_\r\n         <span style=\"color:blue;\">Debug.Print<\/span> .Item(\"Day\") & \".\" & .Item(\"Month\") & \".\" & .Item(\"Year\")\r\n     End <span style=\"color:blue;\">With<\/span>\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 2: Zweite Variante zum Ermitteln von Datumsangaben &uuml;ber das WMI<\/span><\/b><\/p>\n<pre>21.09.2014<\/pre>\n<p>Warum erst hier, werden Sie fragen H&auml;tte man, wie in einer Access-Abfrage, nicht gleich den Datums-String zusammensetzen k&ouml;nnen<\/p>\n<pre>SELECT Day & ''.'' & Month & ''.'' &  Year\r\nAS DatumAktuell FROM Win32_CurrentTime<\/pre>\n<p>Aber das l&auml;sst WQL eben nicht zu. Im SQL-String k&ouml;nnen nur einzelne Felder angegeben, aber nicht weiteren Operationen unterzogen werden, und die Zuweisung an einen Alias-Namen ist ebenso unm&ouml;glich.<\/p>\n<p><b>WQL-Syntax<\/b><\/p>\n<p>Die anderen relevanten Unterschiede von WQL zu JET-SQL sollen nicht verschwiegen werden. Was etwa auch nicht geht, ist die Verkn&uuml;pfung mehrerer Tabellen in der Abfrage per <b>Joins<\/b>.<\/p>\n<p>Zwar lassen sich Verkn&uuml;pfungen zwischen Provider-Klassen auf etwas kompliziertere Weise auch herstellen, Erl&auml;uterungen dazu w&uuml;rden jedoch den Rahmen des Beitrags sprengen. Forschen Sie bei Interesse nach den WQL-Stichw&ouml;rtern <b>Associators Of<\/b> oder <b>References Of<\/b>.<\/p>\n<p><!--30percent--><\/p>\n<p>M&ouml;glich hingegen sind Bedingungen per <b>WHERE<\/b>-Statement und die Zusammensetzung von Bedingungen &uuml;ber <b>OR <\/b>und <b>AND<\/b>. F&uuml;r unser Datumsbeispiel mit nur einem Ergebnisdatensatz macht eine bedingte Filterung keinen Sinn. Daher hier ein anderes Beispiel:<\/p>\n<pre>SELECT Caption FROM Win32_Printer _\r\nWHERE Shared=<span style=\"color:blue;\">True<\/span> _\r\nAND Name LIKE ''%Epson%''<\/pre>\n<p>Hier wird nach der Bezeichnung von installierten Druckern gefragt, die erstens f&uuml;r die gemeinsame Verwendung freigegeben sind (<b>Shared<\/b>) und au&szlig;erdem den Ausdruck <b>Epson<\/b> im Namen haben. Im Unterschied zu Jet-SQL ist beim <b>LIKE<\/b>-Operator das Zeichen % statt * zu verwenden.<\/p>\n<p>Ansonsten k&ouml;nnen in Bedingungen auch die &uuml;blichen Vergleichsoperatoren =, >, <, >=, <=, <> sowohl f&uuml;r numerische Werte wie f&uuml;r Text verwendet werden. Auch <b>IS NULL <\/b>und <b>IS NOT NULL <\/b>f&uuml;r die Unterscheidung von leeren Feldwerten lassen sich setzen:<\/p>\n<pre>SELECT Caption FROM Win32_Printer _\r\nServerName IS NOT NULL<\/pre>\n<p>Das ermittelt alle Drucker, bei denen ein Servername gesetzt ist, also etwa Netzwerkdrucker.<\/p>\n<p>Alle weiteren Informationen zu WQL entnehmen Sie bitte der Referenz von Microsoft: WQL (SQL for WMI)<\/p>\n<p><b>Geht es auch k&uuml;rzer<\/b><\/p>\n<p>Die bisher vorgestellten Routinen lassen sich noch weiter komprimieren. In TestWMIDate3 (s. Listing 3) wurde auf eine Abfrage per <b>ExecQuery<\/b> verzichtet, weil der Provider f&uuml;r <b>Win32_CurrentTime<\/b> bereits in den Moniker-String verfrachtet wurde. Das geht problemlos, und der Schritt &uuml;ber das <b>ObjectSet <\/b>wird &uuml;bersprungen. <b>GetObject<\/b> gibt mit dieser Syntax nun direkt das Datensatzobjekt zur&uuml;ck!<\/p>\n<pre><span style=\"color:blue;\">Sub <\/span>TestWMIDate3()\r\n     <span style=\"color:blue;\">Dim <\/span>obj<span style=\"color:blue;\"> As Object<\/span>\r\n     <span style=\"color:blue;\">Set<\/span> obj = GetObject(\"winmgmts:root\/cimv2:Win32_CurrentTime\")\r\n     <span style=\"color:blue;\">With<\/span> obj.Instances_.ItemIndex(0).Properties_\r\n         <span style=\"color:blue;\">Debug.Print<\/span> .Item(\"Day\") & _\r\n             \".\" & .Item(\"Month\") & _\r\n             \".\" & .Item(\"Year\")\r\n     End <span style=\"color:blue;\">With<\/span>\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 3: Dritte Variante zum Ermitteln von Datumsangaben &uuml;ber das WMI<\/span><\/b><\/p>\n<p>In der Prozedur <b>TestWMIDate4<\/b> (s. Listing 4) wurde au&szlig;erdem die Angabe von <b>root\/cimv2 <\/b>weggelassen, da WMI diese Werte ohnehin als Default annimmt. Die Prozedur zeigt dar&uuml;ber hinaus, dass durch komplexe Verschachtelung der Objekte mit nur einer Code-Zeile zum Ergebnis zu kommen ist. In diesem Fall allerdings nur f&uuml;r das aktuelle Jahr. F&uuml;r den kompletten Datums-String f&auml;llt uns keine einzeilige L&ouml;sung ein.<\/p>\n<pre><span style=\"color:blue;\">Sub <\/span>TestWMIDate4()\r\n     <span style=\"color:blue;\">Debug.Print<\/span> GetObject(\"winmgmts:Win32_CurrentTime\").Instances_.ItemIndex(0).Properties_(\"Year\")\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 4: Vierte Variante zum Ermitteln von Datumsangaben &uuml;ber das WMI<\/span><\/b><\/p>\n<p><b>Die Bibliothek Microsoft WMI Scripting Library<\/b><\/p>\n<p>Kommen wir zur Programmvariante mit Verweis. Auch wenn anzustreben ist, das VBA-Projekt einer Access-Datenbank nicht mit Verweisen zu &uuml;berfrachten, gibt es keinen triftigen Grund, vom Verweis auf das WMI abzusehen. Denn alle Versionen von Windows unterst&uuml;tzen die Bibliothek, und Kompatibilit&auml;tsprobleme m&uuml;ssen nicht bef&uuml;rchtet werden.<\/p>\n<p>Sie setzen einen Verweis auf die Bibliothek, indem Sie im <b>Verweise<\/b>-Dialog des VBA-Editors den Eintrag <b>Microsoft WMI Scripting V 1.2 Library<\/b> anhaken. Die Versionsnummer kann sich eventuell unterscheiden. Im Objektkatalog finden Sie die Klassen der Bibliothek dann &uuml;ber die Combobox links oben, wenn Sie <b>WbemScripting<\/b> ausw&auml;hlen. In der Beispieldatenbank ist f&uuml;r unser Datumsproblem nat&uuml;rlich auch die Verweisvariante enthalten, wiedergegeben in Listing 5.<\/p>\n<pre><span style=\"color:blue;\">Sub <\/span>TestWMIDate5()\r\n     <span style=\"color:blue;\">Dim <\/span>objLoc<span style=\"color:blue;\"> As <\/span><span style=\"color:blue;\">New<\/span> SWbemLocator\r\n     <span style=\"color:blue;\">Dim <\/span>objWMI<span style=\"color:blue;\"> As <\/span>SWbemServices\r\n     <span style=\"color:blue;\">Dim <\/span>objSet<span style=\"color:blue;\"> As <\/span>SWbemObject<span style=\"color:blue;\">Set<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>obj<span style=\"color:blue;\"> As <\/span>SWbemObject\r\n     <span style=\"color:blue;\">Set<\/span> objWMI = objLoc.ConnectServer (\"192.168.178.28\", \"root\/cimv2\")\r\n''    <span style=\"color:blue;\">Set<\/span> objWMI = objLoc.ConnectServer(\"192.168.178.28\", \"root\\cimv2\", \"Benutzername\", _\r\n''    \"Password\", \"NTLMDomain:Domainname\")\r\n     <span style=\"color:blue;\">Set<\/span> obj<span style=\"color:blue;\">Set<\/span> = objWMI.ExecQuery(\"SELECT Day, Month, Year FROM Win32_CurrentTime\")\r\n     <span style=\"color:blue;\">Set<\/span> obj = objSet.ItemIndex(0)\r\n     <span style=\"color:blue;\">With<\/span> obj.Properties_\r\n         <span style=\"color:blue;\">Debug.Print<\/span> .Item(\"Day\") & \".\" & .Item(\"Month\") & \".\" & .Item(\"Year\")\r\n     End <span style=\"color:blue;\">With<\/span>\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 5: Verwenden der WMI-Klassenobjekte zur Datumsbestimmung<\/span><\/b><\/p>\n<p>Das Hauptobjekt <b>objWMI<\/b>, welches wir zuvor &uuml;ber <b>GetObject<\/b> und den Moniker-String erhielten, muss in der Verweisl&ouml;sung &uuml;ber einen Zwischenschritt bereitgestellt werden. Erst wird ein generelles WMI-Objekt <b>SWbemLocator<\/b> per <b>New<\/b>-Anweisung erzeugt. Die einzige Methode des Objekts ist die Funktion <b>ConnectServer<\/b>, die dann ein Services-Object <b>objWMI<\/b> zur&uuml;ckgibt.<\/p>\n<p>Der Name der Funktion deutet schon an, dass nicht nur das lokale System angesprochen werden kann, sondern auch andere Rechner in Netz. Deshalb lassen sich optional neben dem Namen des Rechners oder dessen IP hier auch weitere Parameter &uuml;bergeben, wie Benutzername, Passwort und Domain. Das ist dann sinnvoll, wenn man auf dem entfernten Rechner einen Account mit administrativen Rechten besitzt &#8211; nur dann lassen sich auch alle WMI-Provider auslesen. Dieser Teil ist im Listing oben auskommentiert. Der zus&auml;tzliche Parameter f&uuml;r die Domain oder Workgroup muss &uuml;brigens genau die Syntax haben, wie im Beispiel:<\/p>\n<pre>NTLM:[DomainName]<\/pre>\n<p>NTLM ist ein K&uuml;rzel f&uuml;r einen Login per <b>Windows LAN Manager<\/b>. Die zus&auml;tzlichen Parameter d&uuml;rfen <b>nicht<\/b> angegeben werden, wenn man den lokalen Rechner selbst abfragen will! Es kommt andernfalls zu einer Fehlermeldung.<\/p>\n<p>Sobald das Service-Objekt steht, sieht die L&ouml;sung nicht anders aus, wie in den Beispielen zuvor. &uuml;ber <b>ExecQuery<\/b> wird die Anfrage ans WMI gestellt, das Antwortobjekt einer <b>ObjectSet<\/b>-Variablen zugewiesen, der einzige Datensatz &uuml;ber <b>ItemIndex<\/b> ermittelt und dessen Felder &uuml;ber die <b>Properties_<\/b>-Auflistung ausgegeben.<\/p>\n<p>Der einzige Unterschied besteht darin, dass die Objektvariablen dezidiert auf Klassentypen der WMI-Bibliothek gecastet sind. Das macht das Schreiben von Code nun einfacher, da die VBA-IntelliSense immer die Syntaxvervollst&auml;ndigung zu den Objekten anbietet.<\/p>\n<p><b>Antwortobjekte und Eigenschaften enumerieren<\/b><\/p>\n<p>Sollten Sie in Ihrer Datenbank von WMI-Anfragen h&auml;ufiger Gebrauch machen wollen, so ist es sinnvoll, hierzu eine allgemeinere Routine einzubauen. Das Ger&uuml;st daf&uuml;r zeigt Listing 6. <\/p>\n<pre><span style=\"color:blue;\">Sub <\/span>AskWMI(sProvider<span style=\"color:blue;\"> As String<\/span>, <span style=\"color:blue;\">Optional<\/span> sFields<span style=\"color:blue;\"> As String<\/span> =\"*\", _\r\n    <span style=\"color:blue;\">Optional<\/span> sRoot<span style=\"color:blue;\"> As String<\/span> = \"cimv2\")\r\n     <span style=\"color:blue;\">Dim <\/span>objLoc<span style=\"color:blue;\"> As <\/span><span style=\"color:blue;\">New<\/span> SWbemLocator\r\n     <span style=\"color:blue;\">Dim <\/span>objWMI<span style=\"color:blue;\"> As <\/span>SWbemServices\r\n     <span style=\"color:blue;\">Dim <\/span>objSet<span style=\"color:blue;\"> As <\/span>SWbemObject<span style=\"color:blue;\">Set<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>obj<span style=\"color:blue;\"> As <\/span>SWbemObject\r\n     <span style=\"color:blue;\">Dim <\/span>objProp<span style=\"color:blue;\"> As <\/span>SWbemProperty\r\n     <span style=\"color:blue;\">Dim <\/span>sTmp<span style=\"color:blue;\"> As String<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>n<span style=\"color:blue;\"> As Long<\/span>\r\n     <span style=\"color:blue;\">Set<\/span> objWMI = objLoc.ConnectServer(\".\", \"root\/\" & sRoot)\r\n     <span style=\"color:blue;\">Set<\/span> obj<span style=\"color:blue;\">Set<\/span> = objWMI.ExecQuery(\"SELECT \" & sFields & \" FROM \" & sProvider)\r\n     For Each obj In obj<span style=\"color:blue;\">Set<\/span>\r\n         sTmp = obj.Path_\r\n         n = <span style=\"color:blue;\">InStr<\/span>(1, sTmp, \":\")\r\n         sTmp = <span style=\"color:blue;\">Mid<\/span>(sTmp, n + 1)\r\n         sTmp = <span style=\"color:blue;\">Replace<\/span>(sTmp, \"=@\", \"\")\r\n         sTmp = <span style=\"color:blue;\">Replace<\/span>(sTmp, sProvider & \".\", \"\")\r\n         <span style=\"color:blue;\">Debug.Print<\/span> sTmp\r\n         For Each objProp In obj.Properties_\r\n             <span style=\"color:blue;\">Debug.Print<\/span> objProp.Name, CStr(Nz(objProp.Value))\r\n         <span style=\"color:blue;\">Next<\/span> objProp\r\n         <span style=\"color:blue;\">Debug.Print<\/span>\r\n     <span style=\"color:blue;\">Next<\/span> obj\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 6: Allgemeine Routine zum Abfragen von WMI-Providern<\/span><\/b><\/p>\n<p>Der Prozedur <b>AskWMI<\/b> ist als Parameter nur der Name des WMI-Providers zu &uuml;bergeben &#8211; etwa <b>Win32_CurrentTime<\/b>. Optional kann die Ergebnismenge eingeschr&auml;nkt werden, indem zus&auml;tzlich die Zahl der abzufragenden Felder in <b>sFields<\/b> angegeben wird &#8211; etwa <b>Day,Month,Year<\/b>. Damit w&auml;ren wir beim altbekannten Beispiel:<\/p>\n<pre>AskWMI \"Win32_CurrentTime\", _\"Day, Month, Year\"<\/pre>\n<p>Rufen Sie diese Zeile im VBA-Direktfenster auf. Der Ablauf in der Routine entspricht dem der Prozedur <b>TestWMIDate5<\/b>. Neu ist hier eine <b>For..Each<\/b>-Schleife, die die Objektdatens&auml;tze und innerhalb derer wiederum deren <b>Properties<\/b> durchl&auml;uft. <\/p>\n<p>Das Ergebnis &uuml;berrascht etwas, denn die Datumsangaben werden doppelt ausgegeben. Was l&auml;uft hier falsch In der Routine selbst nichts. Die Annahme, die aktuelle Systemzeit k&ouml;nne nur einen Datensatz enthalten, tr&uuml;gte n&auml;mlich. Um dem auf die Schliche zu kommen, ist in der Prozedur zus&auml;tzlich ein Teil eingebaut, der den Namen des Antwortobjekts selbst ermittelt. In den Eigenschaften steht der ja nicht drin. Zu diesem Zweck l&auml;sst sich die Eigenschaft <b>Path_ <\/b>eines WMI-Objekts missbrauchen. Ihr Wert besteht aus einem String, der die Herkunft des Objekts im WMI darstellt. In unserem Beispiel enth&auml;lt <b>Path_ <\/b>etwa<\/p>\n<pre><\/font>Harry2\\root\\cimv2:Win32_LocalTime=@<\/pre>\n<p>Au&szlig;er dem Rechnernamen, <b>root<\/b> und dem Haupt-Provider <b>cimv2<\/b> steht dort auch noch die eigentliche Klasse <b>Win32_LocalTime<\/b>. In der Routine <b>AskWMI<\/b> wird per Textfunktionen dieser Klassenname extrahiert und das Ergebnis (<b>sTmp<\/b>) ausgegeben, bevor die Eigenschaften enumeriert werden. Nun wird klar, weshalb zwei Objekte im Ergebnis stecken: <b>Win32_LocalTime und Win32_UTCTime<\/b>! Die Werte der Eigenschaften beider Klassen unterscheiden sich jedoch in der Regel nicht.<\/p>\n<p>Bei <b>Win32_CurrentTime<\/b> handelt es sich um einen zusammengesetzten Provider, der zwei untergeordnete Klassen beherbergt. Wollen Sie nur einen Datensatz im Ergebnis, so fragen Sie einfach die Subklasse ab:<\/p>\n<pre>AskWMI \"Win32_LocalTime\", _\"Day, Month, Year\"<\/pre>\n<p>Und das w&auml;re schlie&szlig;lich das Resultat:<\/p>\n<pre>Win32_LocalTime\r\nDay           21\r\nMonth         09\r\nYear          2014<\/pre>\n<p><b>Was kann mit dem WMI abgefragt werden<\/b><\/p>\n<p>Allein im letzten Absatz wurde deutlich, dass man die Namen der WMI-Provider genau kennen muss, um zum richtigen Ergebnis zu kommen. Alle Informationen dar&uuml;ber, welche WMI-Provider es gibt und welche Eigenschaften sie haben, ist online bei Microsoft im Windows SDK unter diesem Link dokumentiert: WMI Providers.<\/p>\n<p>Wahrscheinlich werden Sie erschlagen sein, nachdem Sie sich diese Dokumentation zu Gem&uuml;te gef&uuml;hrt haben. Es existieren &uuml;ber Tausend Provider allein im Zweig <b>CIMV2<\/b>, kategorisiert nach Systemabteilungen, wie Hardware, Software, OS. Hinzu kommen noch einige speziellere Provider, etwa zu Registry-Abfragen, Netzwerk oder System.<\/p>\n<p>Damit Sie sich nicht immer erneut durch diese Dokumente w&uuml;hlen m&uuml;ssen, wenn Sie auf der Suche nach einem passenden Provider sind, enth&auml;lt die Beispieldatenbank einige Prozeduren, die alle Provider und deren Eigenschaftennamen in Tabellen abspeichern. Von diesem Unterfangen war eingangs bereits die Rede gewesen, und das Datenmodell wurde ebenfalls bereits dargestellt.<\/p>\n<p>Die Prozedur im Modul <b>mdlWMI<\/b>, die diesen Transfer &uuml;bernimmt, nennt sich <b>WMIClasses<\/b>. Sie hier zu erl&auml;utern, w&uuml;rde zu weit f&uuml;hren. Rufen Sie sie einfach im VBA-Direktfenster auf und warten Sie einige Zeit, bis darin ein <b>OK<\/b> zu sehen ist.<\/p>\n<p>Je nach der Geschwindigkeit Ihres Rechners kann es schon mal einige Minuten dauern. Rufen Sie anschlie&szlig;end noch die Prozedur <b>CleanWMIClasses<\/b> auf, die die Datens&auml;tze um Dubletten bereinigt und Provider ohne Eigenschaften &#8211; das kommt vor &#8211; l&ouml;scht.<\/p>\n<p>Danach sind die drei Tabellen der Beispieldatenbank komplett gef&uuml;llt. Um eine Orientierung zu geben: bei uns fanden sich 14 Haupt-Provider (<b>tblWMIRoot<\/b>), &uuml;ber 3.000 Klassen-Provider (<b>tblWMIClasses<\/b>) und zu diesen 31.000 Eigenschaften (<b>tblWMIClassesProps<\/b>).<\/p>\n<p>Wozu diese Prozedur jeweils neu aufrufen, wenn doch Microsoft in der Dokumentation klar vorgibt, welche Provider es gibt Hierf&uuml;r gibt es einen Grund: Einige Software installiert zus&auml;tzliche WMI-Provider, die dann im System verankert sind. Dies macht MS etwa bei den Office-Paketen.<\/p>\n<p>Office 2007 installiert einen ganz neuen Zweig im WMI, der in der Tabelle <b>tblWMIRoot<\/b> als Eintrag <b>MSAPPS12<\/b> in Erscheinung tritt. Ein solcher MSAPPS12-Provider ist zum Beispiel die Klasse <b>Win32_Access12ComAddin<\/b>. &uuml;ber diesem Provider l&auml;sst sich per WMI abfragen, welche Access-COM-Addins im System installiert und ob sie aktiviert sind:<\/p>\n<pre>AskWMI \"Win32_Access12ComAddin\",,\"MSAPPS12\"<\/pre>\n<p>Gleichzeitig macht dies klar, dass nicht alle Provider, die auf Ihrem System ermittelt wurden, auch auf anderen Rechnern funktionieren. Deshalb sollten Sie beim Einsatz eines Providers immer pr&uuml;fen, ob auch eine Online-Dokumentation f&uuml;r ihn existiert. F&uuml;r den Zweig <b>CIMV2<\/b> und die Win32-Provider ist das immer der Fall &#8211; und diese lassen eigentlich keine W&uuml;nsche offen.<\/p>\n<p><b>Performance<\/b><\/p>\n<p>Grunds&auml;tzlich kann das WMI mit spezialisierten API-Routinen nicht mithalten. Zum einen erfordert der &uuml;berbau zus&auml;tzliche Rechenzeit, zum anderen f&uuml;llt WMI h&auml;ufig alle Eigenschaftenfelder zu einem Objekt mit Werten, auch wenn diese gar nicht ben&ouml;tigt werden. Die Ermittlung dieser Eigenschaftswerte kostet erheblichen Rechenaufwand. <b>Win32_Printer<\/b> etwa hat 86 Eigenschaftenfelder!<\/p>\n<p>Das sind reichlich viele, wenn Sie lediglich die Namen der installierten Drucker erfahren m&ouml;chten. Machen Sie es sich deshalb zur Angewohnheit, wirklich nur die Felder in die WQL-Abfrage zu nehmen, die Sie auch ben&ouml;tigen. In der Regel kommt das der Performance zugute. <\/p>\n<p>Bei manchen Providern n&uuml;tzt leider auch das nichts. Um alle installierten Programme des Systems aufzulisten, wie dies &uuml;ber die Systemsteuerung m&ouml;glich ist, k&ouml;nnten Sie den Provider <b>Win32_Product<\/b> verwenden und das Feld Name abfragen. Eigentlich eine sch&ouml;ne Sache, w&uuml;rde WMI daf&uuml;r nicht Minuten ben&ouml;tigen&#8230;<\/p>\n<p><b>Abfragen leicht gemacht<\/b><\/p>\n<p>Nur, um Ihnen einen &uuml;berblick &uuml;ber die Vielfalt der WMI-Provider zu geben, wurden die drei Tabellen in der Beispieldatenbank allerdings nicht angelegt. Sie sind vielmehr die Basis f&uuml;r ein Abfrage-Tool, das in Gestalt des Formulars <b>frmWMI<\/b> daherkommt (s. Bild 4). <\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2014_06\/pic_962_004.png\" alt=\"Tool f&uuml;r beliebige Anfragen an das WMI (frmWMI)\" width=\"575\" height=\"680,6125\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 4: Tool f&uuml;r beliebige Anfragen an das WMI (frmWMI)<\/span><\/b><\/p>\n<p>Im Kombinationsfeld ganz oben w&auml;hlen Sie den <b>WMI Namespace<\/b> aus, also den Root-Provider, etwa <b>CIMV2<\/b>. Diese Combobox ist einfach an die Tabelle <b>tblWMI-Root<\/b> gebunden. Nach Aktualisierung der Combobox &ouml;ffnet sich die n&auml;chste Combobox mit den WMI-Klassen, die f&uuml;r den Namespace verf&uuml;gbar sind. Die Combobox ist an die Tabelle <b>tblWMI-Classes<\/b> gebunden, der Inhalt wird jedoch mit der <b>ID<\/b> des Namespaces gefiltert:<\/p>\n<pre><span style=\"color:blue;\">Set<\/span> cbClasses.Recordset = _\r\n    CurrentDb.OpenRecordset(\"SELECT ID,Class FROM tblWMIClasses WHEREIDNamespace=\" _\r\n    & cbNamespace.Value &\" ORDER BY Class\")<\/pre>\n<p>Wird eine WMI-Klasse aus der Liste gew&auml;hlt, dann &ouml;ffnet sich das dritte Kombinationsfeld mit den f&uuml;r diese Klasse m&ouml;glichen Eigenschaftenfeldern. Das Steuerelement ist an die Tabelle <b>tblWMIClassesProps<\/b> gebunden, gefiltert &uuml;ber die ID der Klasse:<\/p>\n<pre><span style=\"color:blue;\">Set<\/span> cbProperties.Recordset = _\r\n    CurrentDb.OpenRecordset(\"SELECTIDClass, Property FROM tblWMIClassesProps WHEREIDClass=\" _\r\n    & cbClasses.Value & \" ORDER BY Property\")<\/pre>\n<p>Nun geht es weiter mit den Feldern, die Sie im Abfrageergebnis haben m&ouml;chten. W&auml;hlen Sie jeweils eine Eigenschaft aus und klicken danach auf den Button mit dem Pluszeichen.<\/p>\n<p>Im Textfeld <b>Eigenschaften<\/b> werden dann die Felder kommasepariert aneinander gef&uuml;gt. Sie k&ouml;nnen das Textfeld auch manuell bearbeiten oder mit dem <b>(-)<\/b>-Button leeren.<\/p>\n<p>Danach kann bereits der Button <b>Ausf&uuml;hren<\/b> bet&auml;tigt werden. Das WMI wird nun abgefragt und das Ergebnis als Liste im untersten Textfeld pr&auml;sentiert. Im Beispiel sind das alle Netzwerkadapter des Systems, zu denen auch virtuelle, wie etwa die WAN-Miniports, geh&ouml;ren.<\/p>\n<p>Im Formular ist jedoch noch ein Bedingungsfeld untergebracht, &uuml;ber welches das Resultat gefiltert werden kann. Die Bedingung <b>PhysicalAdapter = True<\/b> m&uuml;ssen Sie manuell in das Bedingungsfeld setzen. Nach Ausf&uuml;hren der Abfrage sind nur noch die nicht-virtuellen Netzwerkadapter aufgef&uuml;hrt. Die Syntax der Bedingungszeile muss WQL-konform sein. <\/p>\n<p>Sie haben damit ein Instrument, mit dem Sie die einzelnen WMI-Provider testen k&ouml;nnen, wobei nicht nur interessiert, ob die Felder das zur&uuml;ckgeben, was man erwartet, sondern auch, ob die Performance der Abfrage f&uuml;r Ihren angepeilten Verwendungszweck ausreicht. <\/p>\n<p>Haben Sie eine brauchbare Anfrage zurechtgebastelt, dann k&ouml;nnen Sie daraus eine gesonderte Routine f&uuml;r Ihre Datenbank programmieren, wie in den Listings eingangs des Beitrags beschrieben. In diesem Zusammenhang sollte auf noch einige Probleme eingegangen werden, auf die Sie sto&szlig;en k&ouml;nnten. Die vom <b>Ausf&uuml;hren<\/b>-Button ausgel&ouml;ste Ereignisprozedur des Formulars ist n&auml;mlich etwas umfangreicher, als man erwarten w&uuml;rde. &auml;hnlich, wie in der Prozedur AskWMI werden auch hier die Objekte und deren Eigenschaften in Schleifen enumeriert. Der Wert einer Eigenschaft wird jedoch einer Spezialbehandlung unterzogen (siehe Listing 7). Neben den Datentypen String, Integer, Long etc., kann ein Wert n&auml;mlich auch ein Array erhalten, welches etwa &uuml;ber <b>Debug.Print<\/b> nicht als String ausgegeben werden kann. <\/p>\n<pre>     For Each oObj In o<span style=\"color:blue;\">Set<\/span>\r\n         For n = 0 To <span style=\"color:blue;\">UBound<\/span>(arrProps) - 1\r\n             sProp = arrProps(n)\r\n             sText = sText & sProp & \" = \"\r\n             vValue = oObj.Properties_(sProp).Value\r\n             <span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">Not<\/span> IsNull(vValue)<span style=\"color:blue;\"> Then<\/span>\r\n''               If oObj.Properties_(cbProperties.Value).IsArray Then\r\n                 <span style=\"color:blue;\">If <\/span>IsArray(vValue)<span style=\"color:blue;\"> Then<\/span>\r\n                     sValue = \"{\"\r\n                     For i = 0 To <span style=\"color:blue;\">UBound<\/span>(vValue)\r\n                         sValue = sValue & vValue(i) & \", \"\r\n                     <span style=\"color:blue;\">Next<\/span> i\r\n                     sValue = <span style=\"color:blue;\">Left<\/span>(sValue, <span style=\"color:blue;\">Len<\/span>(sValue) - 2) & \"}\"\r\n                 <span style=\"color:blue;\">Else<\/span>\r\n                     sValue = Nz(vValue)\r\n                 <span style=\"color:blue;\">End If<\/span>\r\n             <span style=\"color:blue;\">End If<\/span>\r\n             sText = sText & sValue & <span style=\"color:blue;\">vbCrLf<\/span>\r\n             sValue = \"\"\r\n         <span style=\"color:blue;\">Next<\/span> n\r\n         sText = sText & <span style=\"color:blue;\">vbCrLf<\/span>\r\n         DoEvents\r\n         <span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">Len<\/span>(sText) &gt; 10000<span style=\"color:blue;\"> Then<\/span> <span style=\"color:blue;\">Exit For<\/span>\r\n     <span style=\"color:blue;\">Next<\/span> oObj<\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 7: Ausschnitt aus der Ereignisprozedur cmdExecute_Click<\/span><\/b><\/p>\n<p>Zun&auml;chst wird die Variant-Variable <b>vValue<\/b> mit <b>IsNull<\/b> darauf getestet, ob sie &uuml;berhaupt einen Wert enth&auml;lt. Falls ja, dann wird mit der VBA-Funktion <b>IsArray<\/b> gepr&uuml;ft, ob ein Array vorliegt. Ist das der Fall, so m&uuml;ssen die einzelnen Elemente des Arrays in einer Schleife durchlaufen und in der Ergebnisvariablen <b>sValue<\/b> aneinandergef&uuml;gt werden. Zur Unterscheidung von Nicht-Array-Werten werden au&szlig;erdem geschweifte Klammern um das Ergebnis gelegt. &uuml;brigens hat auch ein WMI-Property-Objekt die Funktion <b>IsArray<\/b> eingebaut, wie an der auskommentierten Zeile im Listing zu sehen ist. Die Methode arbeitet aus unerfindlichen Gr&uuml;nden jedoch nicht zuverl&auml;ssig.<\/p>\n<p>Wenn Sie ein Beispiel f&uuml;r die R&uuml;ckgabe eines Array suchen, so befragen Sie <b>Win32_Printer<\/b> einmal nach der Eigenschaft <b>PrinterPaperNames<\/b>. Das Ergebnis sieht dann etwa so aus:<\/p>\n<pre>PrinterPaperNames = {Letter, Tabloid, Ledger, Legal, A3, A4, B4 (JIS), B5 (JIS), \r\nUmschlag DL, Umschlag C5, Umschlag C3, Umschlag C4, Umschlag C6,...)<\/pre>\n<p><b>Zusammenfassung<\/b><\/p>\n<p>&uuml;ber das Windows Management Instrumentarium kann eine unglaubliche Vielfalt an Systemeigenschaften ausgelesen werden, an die sonst nur mit aufw&auml;ndigem API-Code zu gelangen w&auml;re. Dieser Beitrag soll das R&uuml;stzeug daf&uuml;r geben, damit Sie erfolgreich eigene WMI-Anfragen in Ihren VBA-Code integrieren und sich damit eine Menge Recherchen im Netz ersparen k&ouml;nnen.<\/p>\n<h3>Downloads zu diesem Beitrag<\/h3>\n<p>Enthaltene Beispieldateien:<\/p>\n<p>1409_WMI.accdb<\/p>\n<p>1409_WMI.mdb<\/p>\n<p><a href=\"..\/fileadmin\/beispiele\/{99B83489-3FF1-4C08-921F-1063E2AF54EF}\/aiu_962.zip\">Download<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Wenn Sie in Ihrer Datenbank externe Informationen &uuml;ber System, Hardware oder Software ben&ouml;tigen, so lassen sich diese unter VBA meist nur &uuml;ber umfangreiche API-Routinen gewinnen. Dabei gibt es mit dem Windows Management Instrumentarium, kurz WMI, eine Schnittstelle, die fast keine W&uuml;nsche offen l&auml;sst und Ihnen enorm viel Programmierarbeit abnehmen kann. Das ist Grund genug, diese Schnittstelle einmal genauer unter die Lupe zu nehmen.<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"om_disable_all_campaigns":false,"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"_uf_show_specific_survey":0,"_uf_disable_surveys":false,"footnotes":""},"categories":[662014,66062014,44000025],"tags":[],"class_list":["post-55000962","post","type-post","status-publish","format-standard","hentry","category-662014","category-66062014","category-VBA_und_Programmiertechniken"],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v20.9 (Yoast SEO v27.3) - https:\/\/yoast.com\/product\/yoast-seo-premium-wordpress\/ -->\n<title>Das Windows Management Instrumentarium - Access im Unternehmen<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/access-im-unternehmen.de\/Das_Windows_Management_Instrumentarium\/\" \/>\n<meta property=\"og:locale\" content=\"de_DE\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Das Windows Management Instrumentarium\" \/>\n<meta property=\"og:description\" content=\"Wenn Sie in Ihrer Datenbank externe Informationen &uuml;ber System, Hardware oder Software ben&ouml;tigen, so lassen sich diese unter VBA meist nur &uuml;ber umfangreiche API-Routinen gewinnen. Dabei gibt es mit dem Windows Management Instrumentarium, kurz WMI, eine Schnittstelle, die fast keine W&uuml;nsche offen l&auml;sst und Ihnen enorm viel Programmierarbeit abnehmen kann. Das ist Grund genug, diese Schnittstelle einmal genauer unter die Lupe zu nehmen.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/access-im-unternehmen.de\/Das_Windows_Management_Instrumentarium\/\" \/>\n<meta property=\"og:site_name\" content=\"Access im Unternehmen\" \/>\n<meta property=\"article:published_time\" content=\"2020-05-22T21:13:50+00:00\" \/>\n<meta property=\"og:image\" content=\"http:\/\/vg07.met.vgwort.de\/na\/0c70b9dd329640eab4773aa24aac23a1\" \/>\n<meta name=\"author\" content=\"Andr\u00e9 Minhorst\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Verfasst von\" \/>\n\t<meta name=\"twitter:data1\" content=\"Andr\u00e9 Minhorst\" \/>\n\t<meta name=\"twitter:label2\" content=\"Gesch\u00e4tzte Lesezeit\" \/>\n\t<meta name=\"twitter:data2\" content=\"8\u00a0Minuten\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Das_Windows_Management_Instrumentarium\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Das_Windows_Management_Instrumentarium\\\/\"},\"author\":{\"name\":\"Andr\u00e9 Minhorst\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#\\\/schema\\\/person\\\/13395c4bcd7d7963efe33be9c584d93f\"},\"headline\":\"Das Windows Management Instrumentarium\",\"datePublished\":\"2020-05-22T21:13:50+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Das_Windows_Management_Instrumentarium\\\/\"},\"wordCount\":1534,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#organization\"},\"image\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Das_Windows_Management_Instrumentarium\\\/#primaryimage\"},\"thumbnailUrl\":\"http:\\\/\\\/vg07.met.vgwort.de\\\/na\\\/0c70b9dd329640eab4773aa24aac23a1\",\"articleSection\":[\"2014\",\"6\\\/2014\",\"VBA und Programmiertechniken\"],\"inLanguage\":\"de\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/access-im-unternehmen.de\\\/Das_Windows_Management_Instrumentarium\\\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Das_Windows_Management_Instrumentarium\\\/\",\"url\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Das_Windows_Management_Instrumentarium\\\/\",\"name\":\"Das Windows Management Instrumentarium - Access im Unternehmen\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Das_Windows_Management_Instrumentarium\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Das_Windows_Management_Instrumentarium\\\/#primaryimage\"},\"thumbnailUrl\":\"http:\\\/\\\/vg07.met.vgwort.de\\\/na\\\/0c70b9dd329640eab4773aa24aac23a1\",\"datePublished\":\"2020-05-22T21:13:50+00:00\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Das_Windows_Management_Instrumentarium\\\/#breadcrumb\"},\"inLanguage\":\"de\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/access-im-unternehmen.de\\\/Das_Windows_Management_Instrumentarium\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"de\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Das_Windows_Management_Instrumentarium\\\/#primaryimage\",\"url\":\"http:\\\/\\\/vg07.met.vgwort.de\\\/na\\\/0c70b9dd329640eab4773aa24aac23a1\",\"contentUrl\":\"http:\\\/\\\/vg07.met.vgwort.de\\\/na\\\/0c70b9dd329640eab4773aa24aac23a1\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Das_Windows_Management_Instrumentarium\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/access-im-unternehmen.de\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Das Windows Management Instrumentarium\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#website\",\"url\":\"https:\\\/\\\/access-im-unternehmen.de\\\/\",\"name\":\"Access im Unternehmen\",\"description\":\"Das Magazin f\u00fcr Datenbankentwickler auf Basis von Microsoft Access\",\"publisher\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/access-im-unternehmen.de\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"de\"},{\"@type\":\"Organization\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#organization\",\"name\":\"Andr\u00e9 Minhorst Verlag\",\"url\":\"https:\\\/\\\/access-im-unternehmen.de\\\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"de\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#\\\/schema\\\/logo\\\/image\\\/\",\"url\":\"https:\\\/\\\/access-im-unternehmen.de\\\/wp-content\\\/uploads\\\/2019\\\/09\\\/aiu_wp.png\",\"contentUrl\":\"https:\\\/\\\/access-im-unternehmen.de\\\/wp-content\\\/uploads\\\/2019\\\/09\\\/aiu_wp.png\",\"width\":370,\"height\":111,\"caption\":\"Andr\u00e9 Minhorst Verlag\"},\"image\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#\\\/schema\\\/logo\\\/image\\\/\"}},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#\\\/schema\\\/person\\\/13395c4bcd7d7963efe33be9c584d93f\",\"name\":\"Andr\u00e9 Minhorst\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"de\",\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/1b9d010cf1716692cb9c34f21554e07d17d461acaea5b61b8cb21cbec678d48a?s=96&d=mm&r=g\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/1b9d010cf1716692cb9c34f21554e07d17d461acaea5b61b8cb21cbec678d48a?s=96&d=mm&r=g\",\"contentUrl\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/1b9d010cf1716692cb9c34f21554e07d17d461acaea5b61b8cb21cbec678d48a?s=96&d=mm&r=g\",\"caption\":\"Andr\u00e9 Minhorst\"}}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Das Windows Management Instrumentarium - Access im Unternehmen","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/access-im-unternehmen.de\/Das_Windows_Management_Instrumentarium\/","og_locale":"de_DE","og_type":"article","og_title":"Das Windows Management Instrumentarium","og_description":"Wenn Sie in Ihrer Datenbank externe Informationen &uuml;ber System, Hardware oder Software ben&ouml;tigen, so lassen sich diese unter VBA meist nur &uuml;ber umfangreiche API-Routinen gewinnen. Dabei gibt es mit dem Windows Management Instrumentarium, kurz WMI, eine Schnittstelle, die fast keine W&uuml;nsche offen l&auml;sst und Ihnen enorm viel Programmierarbeit abnehmen kann. Das ist Grund genug, diese Schnittstelle einmal genauer unter die Lupe zu nehmen.","og_url":"https:\/\/access-im-unternehmen.de\/Das_Windows_Management_Instrumentarium\/","og_site_name":"Access im Unternehmen","article_published_time":"2020-05-22T21:13:50+00:00","og_image":[{"url":"http:\/\/vg07.met.vgwort.de\/na\/0c70b9dd329640eab4773aa24aac23a1","type":"","width":"","height":""}],"author":"Andr\u00e9 Minhorst","twitter_card":"summary_large_image","twitter_misc":{"Verfasst von":"Andr\u00e9 Minhorst","Gesch\u00e4tzte Lesezeit":"8\u00a0Minuten"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/access-im-unternehmen.de\/Das_Windows_Management_Instrumentarium\/#article","isPartOf":{"@id":"https:\/\/access-im-unternehmen.de\/Das_Windows_Management_Instrumentarium\/"},"author":{"name":"Andr\u00e9 Minhorst","@id":"https:\/\/access-im-unternehmen.de\/#\/schema\/person\/13395c4bcd7d7963efe33be9c584d93f"},"headline":"Das Windows Management Instrumentarium","datePublished":"2020-05-22T21:13:50+00:00","mainEntityOfPage":{"@id":"https:\/\/access-im-unternehmen.de\/Das_Windows_Management_Instrumentarium\/"},"wordCount":1534,"commentCount":0,"publisher":{"@id":"https:\/\/access-im-unternehmen.de\/#organization"},"image":{"@id":"https:\/\/access-im-unternehmen.de\/Das_Windows_Management_Instrumentarium\/#primaryimage"},"thumbnailUrl":"http:\/\/vg07.met.vgwort.de\/na\/0c70b9dd329640eab4773aa24aac23a1","articleSection":["2014","6\/2014","VBA und Programmiertechniken"],"inLanguage":"de","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/access-im-unternehmen.de\/Das_Windows_Management_Instrumentarium\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/access-im-unternehmen.de\/Das_Windows_Management_Instrumentarium\/","url":"https:\/\/access-im-unternehmen.de\/Das_Windows_Management_Instrumentarium\/","name":"Das Windows Management Instrumentarium - Access im Unternehmen","isPartOf":{"@id":"https:\/\/access-im-unternehmen.de\/#website"},"primaryImageOfPage":{"@id":"https:\/\/access-im-unternehmen.de\/Das_Windows_Management_Instrumentarium\/#primaryimage"},"image":{"@id":"https:\/\/access-im-unternehmen.de\/Das_Windows_Management_Instrumentarium\/#primaryimage"},"thumbnailUrl":"http:\/\/vg07.met.vgwort.de\/na\/0c70b9dd329640eab4773aa24aac23a1","datePublished":"2020-05-22T21:13:50+00:00","breadcrumb":{"@id":"https:\/\/access-im-unternehmen.de\/Das_Windows_Management_Instrumentarium\/#breadcrumb"},"inLanguage":"de","potentialAction":[{"@type":"ReadAction","target":["https:\/\/access-im-unternehmen.de\/Das_Windows_Management_Instrumentarium\/"]}]},{"@type":"ImageObject","inLanguage":"de","@id":"https:\/\/access-im-unternehmen.de\/Das_Windows_Management_Instrumentarium\/#primaryimage","url":"http:\/\/vg07.met.vgwort.de\/na\/0c70b9dd329640eab4773aa24aac23a1","contentUrl":"http:\/\/vg07.met.vgwort.de\/na\/0c70b9dd329640eab4773aa24aac23a1"},{"@type":"BreadcrumbList","@id":"https:\/\/access-im-unternehmen.de\/Das_Windows_Management_Instrumentarium\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/access-im-unternehmen.de\/"},{"@type":"ListItem","position":2,"name":"Das Windows Management Instrumentarium"}]},{"@type":"WebSite","@id":"https:\/\/access-im-unternehmen.de\/#website","url":"https:\/\/access-im-unternehmen.de\/","name":"Access im Unternehmen","description":"Das Magazin f\u00fcr Datenbankentwickler auf Basis von Microsoft Access","publisher":{"@id":"https:\/\/access-im-unternehmen.de\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/access-im-unternehmen.de\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"de"},{"@type":"Organization","@id":"https:\/\/access-im-unternehmen.de\/#organization","name":"Andr\u00e9 Minhorst Verlag","url":"https:\/\/access-im-unternehmen.de\/","logo":{"@type":"ImageObject","inLanguage":"de","@id":"https:\/\/access-im-unternehmen.de\/#\/schema\/logo\/image\/","url":"https:\/\/access-im-unternehmen.de\/wp-content\/uploads\/2019\/09\/aiu_wp.png","contentUrl":"https:\/\/access-im-unternehmen.de\/wp-content\/uploads\/2019\/09\/aiu_wp.png","width":370,"height":111,"caption":"Andr\u00e9 Minhorst Verlag"},"image":{"@id":"https:\/\/access-im-unternehmen.de\/#\/schema\/logo\/image\/"}},{"@type":"Person","@id":"https:\/\/access-im-unternehmen.de\/#\/schema\/person\/13395c4bcd7d7963efe33be9c584d93f","name":"Andr\u00e9 Minhorst","image":{"@type":"ImageObject","inLanguage":"de","@id":"https:\/\/secure.gravatar.com\/avatar\/1b9d010cf1716692cb9c34f21554e07d17d461acaea5b61b8cb21cbec678d48a?s=96&d=mm&r=g","url":"https:\/\/secure.gravatar.com\/avatar\/1b9d010cf1716692cb9c34f21554e07d17d461acaea5b61b8cb21cbec678d48a?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/1b9d010cf1716692cb9c34f21554e07d17d461acaea5b61b8cb21cbec678d48a?s=96&d=mm&r=g","caption":"Andr\u00e9 Minhorst"}}]}},"_links":{"self":[{"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/posts\/55000962","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/comments?post=55000962"}],"version-history":[{"count":0,"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/posts\/55000962\/revisions"}],"wp:attachment":[{"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/media?parent=55000962"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/categories?post=55000962"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/tags?post=55000962"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}