Windows, etc.

PC-Inventur mit Excel und WMI

Alle Rechner im lokalen Netzwerk inventarisieren

Es soll schon vorgekommen sein, dass Administratoren eines Netzwerks irgendwann über den von ihnen verantworteten Maschinen-Park den Überblick verloren haben. Dann kommen so Fragen wie: "Wo steht noch mal der P4-Rechner der vorletzte Woche geliefert wurde?", "Bei wieviel Maschinen muss ich denn noch ein paar Speicherriegel nachrüsten?", "Haben inzwischen alle Rechner 3COM-Netzwerkkarten?". Ist das Netzwerk etwas größer, dann wird der Ruf nach einer entsprechenden Inventar-Software für viel Geld recht schnell laut. Wie man mit Windows-Bordmitteln an ein paar grundlegende Informationen herankommt soll dieser Artikel zeigen.

Ausgangspunkt der Überlegung war die sog. Windows Management Instrumentation-Schnittstelle, kurz WMI, die Microsoft mit Windows 2000 eingeführt hat. WMI ist die Redmond'sche COM-Implementierung des Industriestandards WBEM (Web-Based Enterprise Management), der es sich zum Ziel gesetzt den Zugriff auf Systeminformationen zu vereinheitlichen und zu vereinfachen. Microsoft bietet dem interessierten Entwickler ein kostenloses SDK an, dass so nützliche Tools wie den "WMI Object Browser" und das "WMI CIM Studio" enthält, mit denen man durch die einzelnen WMI-Objekte browsen kann, um sich einen Überblick zu verschaffen. Die komplette Dokumentation und die Tools gibt es in der WMI Platform SDK des MSDN.

Im Prinzip kann man mit WMI einen Rechner vollständig analysieren und administrieren. Wir konzentrieren uns hier jedoch erstmal auf das automatisierte Auslesen von ein paar Basis-Informationen. Dabei sollen die IP-Adressen eines kompletten Subnetzes gescannt werden und die Informationen aller gefundenen Maschinen in eine Excel-Tabelle eingetragen werden. Aus diesem Grund verwenden wird hier gleich ein Excel-Arbeitsblatt und schreiben VBA-Code.

Um die Ausgabe des Codes zu strukturieren und gut lesbar zu  machen, geben wir eine Tabellenstruktur vor, in der in den ersten 3 Zeilen Input-Daten und Schaltflächen abgelegt sind. Ab Zeile 5 beginnt der Datenbereich den der zu schreibende Code füllen soll:

Zwei Schaltflächen bzw. Funktionen sind für die Steuerung der Liste vorgesehen. Zum einen "Liste neu erstellen" (Funktion: GetInventar), die den kompletten Datenbereich neu aufbaut, und "Leere Zeilen aktualisieren" (Funktion: RefreshList), die all jene IP-Adressen noch einmal abfragt, deren Rechner bei einem früheren Lauf nicht verfügbar waren.

Funktion GetInventar

Diese Funktion beinhaltet lediglich die Steuerung über den Datenbereich der Tabelle. Die eigentlichen Daten werden in der weiter unten im Artikel beschriebenen Funktion GetWMIInfo ermittelt. Es wird zunächst aus dem Arbeitsblatt ausgelesen welches Subnetz und welcher IP-Adressbereich bearbeitet werden soll (Input-Daten in Zelle B1 und D1/D2) und dann wird in einer Schleife jede der daraus generierten IP-Adressen per WMI angesprochen.

Sub GetInventar()

   Dim i As Integer
   Dim j As Integer
   Dim strSubNetz As String
   Dim intRangeF As Integer
   Dim intRangeT As Integer
   Dim strIP As String
   Dim intRow As Integer

   Const intStartRow = 5

   Application.Cursor = xlWait

   'Tabellenbereich leeren
   Range("A" & intStartRow & ":Z500").Select
   Selection.ClearContents

   'SubNetz ermitteln
   strSubNetz = Cells(1, 2)
   If Len(strSubNetz) = 0 Then
      MsgBox "Bitte Subnetz angeben", vbExclamation
      Exit Sub
   End If

   'zu inventarisierenden IP-Bereich ermitteln
   intRangeF = CInt(Cells(1, 4).FormulaR1C1)
   intRangeT = CInt(Cells(2, 4).FormulaR1C1)

   'IP-Bereich überprüfen
   If intRangeT < intRangeF Or intRangeF <= 0 Or intRangeT > 255 Then
      MsgBox "Der angegebene IP-Bereich ist nicht korrekt!",vbExclamation
      Exit Sub
   End If

   intRow = intStartRow

   'Schleife durch IP-Bereich...
   For i = 0 To (intRangeT - intRangeF)

      Cells(intRow, 1).Select
      strIP = strSubNetz & "." & intRangeF + i

      'IP-Adresse eintragen
      Cells(intRow, 1).FormulaR1C1 = strIP

      'WMI-Infos abfragen und eintragen
      Call GetWMIInfo(strIP, intRow)

      intRow = intRow + 1

      ActiveWorkbook.RefreshAll

   Next

   Application.Cursor = xlDefault
   MsgBox "Fertig!", vbInformation

End Sub

Funktion RefreshList

Diese Funktion ist ebenso eine reine Steuerungsfunktion, die jedoch im Gegensatz zur vorhergehenden Funktion lediglich die noch nicht ermittelten Informationen im Datenbereich erneut überprüft. Steuerungsmerkmal ist hierbei der Hostname, d.h. der Rechnername. Ist dieser nicht vorhanden, war der Rechner mit der entsprechenden IP-Adresse in einem früheren Lauf nicht verfügbar.

Public Sub RefreshList()

   Dim i As Integer
   Dim strIP As String
   Dim intRow As Integer

   Const intStartRow = 5

   Application.Cursor = xlWait

   i = intStartRow

   'Alle Zeilen durchlaufen...
   Do Until Len(Cells(i, 1).FormulaR1C1) = 0

      strIP = Cells(i, 1).FormulaR1C1

      '... und prüfen, ob der Hostname eingetragen ist
      'Wenn nicht, WMI-Infos abfragen
      If Len(Cells(i, 2).FormulaR1C1) = 0 Then
         Cells(i, 1).Select
         Call GetWMIInfo(strIP, i)
      End If

      i = i + 1
      ActiveWorkbook.RefreshAll

   Loop

   Application.Cursor = xlDefault
   MsgBox "Fertig!", vbInformation

End Sub

Funktion GetWMIInfo

Diese, in beiden Steuerungsfunktionen verwendete Funktion, ist das eigentliche Arbeitstier der Inventur. Über die beiden Parameter strIP und intRow wird zum einen festgelegt welche IP-Adresse angesprochen werden soll und zum anderen in welche Zeile des Arbeitsblatts die ermittelten Daten eingetragen werden sollen.

Private Sub GetWMIInfo( _
   ByVal strIP As String, _
   ByVal intRow As Integer)

   Dim objWMIService As Object
   Dim col As Object
   Dim obj As Object
   Dim intCol As Integer

   On Error Resume Next

   'Erste Spalte zur Eintragung festlegen
   intCol = 2

   'WMIService mit der IP-Adresse initialisieren
   Set objWMIService = GetObject("winmgmts:" & _
      "{impersonationLevel=impersonate}!\\" & strIP & "\root\cimv2")

   'Wenn Computer erreichbar...
   If Err = 0 Then

      '...WMI-Abfrage auf 'Win32_ComputerSystem' ausführen
      Set col = objWMIService.ExecQuery( _
         "SELECT * FROM Win32_ComputerSystem")

      For Each obj In col
         'Hostname ermitteln
         Cells(intRow, intCol).FormulaR1C1 = obj.Name
         intCol = intCol + 1
         'Model ermitteln
         Cells(intRow, intCol).FormulaR1C1 = obj.Model
         intCol = intCol + 1
         'TotalPhysicalMemory ermitteln
         Cells(intRow, intCol).FormulaR1C1 = obj.TotalPhysicalMemory
         intCol = intCol + 1
         'Rolle ermitteln
         Select Case obj.DomainRole
            Case 0: strRole = "Standalone Workstation"
            Case 1: strRole = "Member Workstation"
            Case 2: strRole = "Standalone Server"
            Case 3: strRole = "Member Server"
            Case 4: strRole = "Backup Domain Controller"
            Case 5: strRole = "Primary Domain Controller"
         End Select
         Cells(intRow, intCol).FormulaR1C1 = strRole
         intCol = intCol + 1
         'Current User ermitteln
         Cells(intRow, intCol).FormulaR1C1 = obj.UserName
         intCol = intCol + 1
      Next

      '...WMI-Abfrage auf 'Win32_Processor' ausführen
      Set col = objWMIService.ExecQuery("SELECT * FROM Win32_Processor")

      For Each obj In col
         'Prozessor ermitteln
         Cells(intRow, intCol).FormulaR1C1 = Trim$(obj.Name)
         intCol = intCol + 1
      Next

      '...WMI-Abfrage auf 'Win32_NetworkAdapterConfiguration' ausführen
      Set col = objWMIService.ExecQuery( _
         "SELECT * FROM Win32_NetworkAdapterConfiguration WHERE IPEnabled = True")

      For Each obj In col
         'Netzwerkadapter ermitteln und String kürzen
         Cells(intRow, intCol).FormulaR1C1 = _
             Replace(obj.Description," - Paketplaner-Miniport", "")
         intCol = intCol + 1
         'MAC-Adresse ermitteln
         Cells(intRow, intCol).FormulaR1C1 = obj.MACAddress
         intCol = intCol + 1
         Exit For '(da nur der erste Adapter auslesen werden soll)
      Next

   Else
      Err.Clear
   End If

End Sub

Abschließend ist noch zu sagen, dass das Timeout bei der Initialisierung eines WMI-Objekts bei ca. 60 Sekunden liegt, d.h. ein Subnetz mit nur 10 Rechnern komplett zu scannen dauert sehr lange, da 254 IP-Adressen nicht vergeben sind. Man sollte daher die Inventarisierung zum einen tagsüber durchführen, wenn die Chance groß ist, dass viele Rechner an sind und eine Maschine verwenden, die in diesem Moment nicht weiteres zu tun hat, um sich nicht in der Arbeit zu blockieren, denn während die Inventarisierung läuft kann man mit Excel nicht weiterarbeiten.

Downloads

Inventar-Test.zip
kick it on dotnet-kicks.de AddThis 0 wikio-Stimme(n) Trackback-Url...

Schlagworte

8 Kommentare bislang...

  • Hi Werner,

    Zeile markieren -> dann Daten - Filter - Autofilter

    Gruss Roland
    8
    Roland : Freitag, 10. Oktober 2008 08:44
  • @Roland
    Lass dich umarmen ... du bist ein Held ;-)) ... funktioniert prächtig ... vielen Dank.

    Natürlich ist sofort ein neues Problem aufgetaucht, das ich aber selbst lösen konnte und weil vielleicht auch andere diese Problem haben könnten, beschreib ich hier mal kurz Problem und Lösung:

    Es gibt Prozessoren, wie z.B.:

    - Intel(R) Pentium(R) D CPU 2,80GHz
    - Intel Core(TM)2 CPU 6400 @ 2.13GHz

    die meinen zweimal vorhaden zu sein und durch die Abfrage mit der Schleife:




    # '...WMI-Abfrage auf 'Win32_Processor' ausführen
    # Set col = objWMIService.ExecQuery("SELECT * FROM Win32_Processor")
    #
    # For Each obj In col
    # 'Prozessor ermitteln
    # Cells(intRow, intCol).FormulaR1C1 = Trim$(obj.Name)
    # intCol = intCol + 1
    # Next



    dann auch zweimal in die Excel-Tabelle eingetragen werden (einmal richtigerweise in der Spalte Prozessor und das zweite Mal direkt daneben in der Spalte Netzwerkkarte) was dazu führt, dass die nachfolgend Informationen alle eine Spalte nach rechts verschoben sind und die Überschriften so nicht meh stimmen.

    Gelöst hab ich das Ganze dadurch, dass ich wie bei der Abfrage der Netzzwerkkarte, ein "Exit For" in die Schleife eingefügt habe. Das funktioniert und sieht dann so aus:




    # '...WMI-Abfrage auf 'Win32_Processor' ausführen
    # Set col = objWMIService.ExecQuery("SELECT * FROM Win32_Processor")
    #
    # For Each obj In col
    # 'Prozessor ermitteln
    # Cells(intRow, intCol).FormulaR1C1 = Trim$(obj.Name)
    # intCol = intCol + 1
    # Exit For '(da nur ein/der erste Prozessor auslesen werden soll)
    # Next



    So, da das alles so schön funktioniert, hab ich nun Feuer gefangen und würde das Projekt gerne an meine Vorstellungen anpassen und um bestimmte Informationen erweitern bzw. andere, die mir nicht so wichtig sind, weglassen.

    Ich bin jetzt mal so frech und behaupte, dass ich das mit dem WMI-Abfragen im Script selber irgendwie gebacken bekomme.

    Wovon ich aber überhaupt keinen Plan habe ist, wie ich die Spalten-Überschriften mit den Auswahlbutons für die Filter etc. löschen/ändern bzw. um zusätzliche Spalten erweitern kann.

    Auch hierzu würde ich mich über jede Hilfe freuen.

    lg
    Werner
    7
    Werner : Donnerstag, 9. Oktober 2008 15:16
  • @Werner
    versuche es mal so, ändere in der GetInventar IP Schleife folgendes:


    Cells(intRow, 1).Select
    strIP = strSubNetz & intRangeF + i

    Eingabe der IP dann mit xxx.xxx.xxx.
    Müsste gehen.
    Gruss Roland
    6
    Roland : Mittwoch, 8. Oktober 2008 13:58
  • Hallo Kristof,
    ich möchte nochmals höflichst an meinen Kommentar vom 12. August erinnern.
    Seither wurde der Artikel mehr als 400 mal aufgerufen. Vielleicht ist ja zufällig darunter jemand, der mir bei meinem Problem helfen könnte.
    Währe jedenfalls für jede Hilfe dankbar.

    lg
    Werner
    5
    Werner : Dienstag, 30. September 2008 09:19
  • Hallo,
    ich hab jetzt etwas weiter getestet und herausgefunden, dass der Kompilierungsfehler nur dann auftritt, wenn ich Excel 97 benutze. Mit Excel 2007 kommt es zu diesem Fehler nicht.
    Soweit scheint mein ursprüngliches Problem gelöst.

    Leider ist jetzt ein zweites Problem aufgetreten. Und zwar funktioniert das Skript soweit ganz gut, solange das Subnetz an der dritten Stelle ein- oder zweistellig ist (z.B. 192.168.1 oder 192.168.10).
    Wenn die dritte Stelle des Subnetzes aber dreistellig wird (z.B. 192.168.100) funktioniert das Skript nicht richtig.

    Der Fehler äußert sich folgendermaßen:

    In der Bearbeitungsleiste werden kein IP-Adressen (z.B. 192.168.100.101) angezeigt, sondern es steht dort jeweils 192168100,101 (also ohne Punkte und mit Komma vor der letzten Stelle.) "Nullen" an der vierten Stelle des Subnetzes werden nicht beachtet. D. h. 192.168.100.130 wird in der Bearbeitungsleiste als 192168100,13 angezeigt.

    Wählt man als Subnetz z.B. 192.168.100 und gibt den Bereich der vierten Stelle z.B. mit 100 bis 110 an, dann steht in der darunterliegenden Tabelle in der Spalte "IP-Adresse" jeweils 192168100,1 und das elf mal untereinander. Die restlichen Spalten bleiben verständlicherweise leer.

    lg
    Werner
    4
    Werner  : Dienstag, 12. August 2008 09:27

Dein Kommentar hierzu...


Kommentar-Feed für diesen Beitrag
Gravatare werden unterstützt .:. eMail-Adressen werden nicht veröffentlicht
 

RSS-Feed

Die URL des Standard-Newsfeed von zerbit.de lautet:

http://www.zerbit.de/rssfeed.aspx

Login


 

 

Statistik



kürzlich kommentiert

Artikel 9

  • Datum: 14.02.2005
    Kategorie: Windows, etc.
    Zugriffe: 7.321
    Kommentare: 8
    Trackbacks: 0

Letzte Beiträge

Kategorien

Buttons & More

Blog-Roll

Banner Piraten-Partei