PC Information und installierte Software über WMI/Registry mit VB.NET Remote auslesen

Sa, 27.06.2009 - 14:42 -- admin

In einem Windows-Netzwerk kann ohne weiteres, hat man denn die Rechte, von außen auf einen PC zugegriffen und verwaltet werden. Microsoft bietet hier einige Möglichkeiten. Zum einen gibt es WMI (Windows Management Instrumentation) zum anderen kann man auch ohne weiteres auf die Windows-Registrierung per Remote zu greifen.
Hierfür habe ich zwei Klassen zusammengebastelt, welche die für mich relevante Daten von einem Remote PC auslesen. Ich generiere mir so eine Liste über Software- und Hardwareausstattung sowie Informationen über das Betriebsystem es Computers.
Damit der Zugriff von außen für möglich ist braucht man Adminrechte auf dem fremden PC, sollte in der Windows-Domäne für einen Administrator kein Thema sein. Die Firewall sollte nicht zu restriktiv eingestellt sein. Die Ports 135 für WMI und 445 für den Registry Zugriff müssen frei sein.
In den Klassen, wird bevor irgendeine Anfrage gesendet wurde, zu erst überprüft ob diese Ports zu erreichen sind. Wie in den Beispielen an den IF-Bedingungen zu sehen ist. Zur Veranschaulichung der Funktionweise steht unter den Downloads eine kleine VB.NET Anwendung bereit.
Zum Einbinden der WMI-Klassen mus ein Verweis auf System.Management vorhanden.

x64 und 32Bit Installationen

Microsoft stellt 32Bit Anwendungen unter einem 64Bit Betriebssystem quasi eine eigene Umgebung zur Verfügung. Dazu werden unter anderem auch die Installationroutinen "umgeleitet". Wird also eine Anwendung installiert so werden alle Informationen der Installation unter SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall abgelegt. Für 32-Bit Anwendung wird hingeben der Zweig SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall genutzt.

Methoden, Eigenschften

clsRegSoftware.vb

  • CheckRegistryMode:Soll nur x86 und x64 oder beide Registry-Pfade durchsucht werden (default:beide)
  • CheckOnlineStatus:Soll vor einer Anfrage überprüft werden ob die benötigten Ports geöffnet sind (default:true)
  • SoftwareItems.DisplayName: Name der installierten Software
  • SoftwareItems.DisplayVersion: Version der Software*
  • SoftwareItems.RegistryMode: 0 für x86, 1 für x64
  • SoftwareItems.ParentDisplayName: Updates werden meistens geschachtelt. Der Wert gibt das dazugehörte Programm (DisplayName) an*

* stehen nicht zwingend immer zur Verfügung

clsWMI.vb

  • CheckOnlineStatus:Soll vor einer Anfrage überprüft werden ob die benötigten Ports geöffnet sind (default:true)
  • Connected:Wurde erfolgreich eine Verbindung aufgebaut?
  • User.ClearCurrentLoggedIn: Username ohne Domäne oder PCName
  • User.CurrentLoggedIn: kompletter Username mit Domäne und PCName
  • CPU.Name: Name des Processors
  • CPU.Speed: Geschwindigkeit in MHZ
  • SystemOS.Name: Betriessystemname
  • SystemOS.Version: Versionsnummer des Betriebssystem
  • SystemOS.ServicePack: ServicePack Version
  • Memory.MegaByte: kompletter Arbeitsspeicher in MB
  • Memory.Banks: eingebaute Speicherbänke MB; getrennt durch | (z.B. 512|512)
  • Graphic.Name: Name der Grafikkarte
  • Graphic.RAM: interner Speicher der Grafikkarte
  • Graphic.DriverVersion: Version des installierten Grafikkartentreibers

Beispiele

'Read installed software over registry
Dim SoftItem As New clsRegSoftware("hostname or ip") 'localhost possible
If SoftItem.GetInfo() = True Then
     For Each SoftwareItem In SoftItem.SoftwareItems
          MsgBox(SoftwareItem.DisplayName)
     Next
End If
 
'read pc details over wmi
Dim wmi As New clsWMI("hostname or ip") 'localhost possible
If wmi.connect = True Then
     MsgBox(WMI.CPU.Name)
End If

Klassen-Diagramme

Quelltext

clsRegSoftware.vb

Imports System.Net.Sockets
Imports Microsoft.Win32
 
Public Class clsRegSoftware
    Dim _ComputerName As String
    Dim _CheckOnlineStatus As Boolean = True
    Dim _SoftwareItems As New List(Of sSoftwareItem)
    Dim _CheckRegistryMode As enumCheckRegistryMode = enumCheckRegistryMode.Both
    Enum enumRegistryMode
        [default] = 0
        WoW64 = 1
    End Enum
    Public Enum enumCheckRegistryMode
        Both = 0
        defaultOnly = 1
        WoW64Only = 2
    End Enum
    Public Sub New(ByVal ComputerName As String)
        _ComputerName = ComputerName
    End Sub
    '''<summary>Check if Remote Manchine is running and accessible; default = true</summary>
    Public WriteOnly Property CheckOnlineStatus() As Boolean
        Set(ByVal value As Boolean)
            _CheckOnlineStatus = value
        End Set
    End Property
    '''<summary>
    ''' Which RegistryKeys should use to get Software Information (default both)
    ''' Both=ALL
    ''' defaultOnly=SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall
    ''' WoW64Only=SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall
    ''' </summary>
    Public WriteOnly Property CheckRegistryMode() As enumCheckRegistryMode
        Set(ByVal value As enumCheckRegistryMode)
            _CheckRegistryMode = value
        End Set
    End Property
    '''<summary>
    '''Read Remote registry
    ''' </summary>
    '''<returns>return false if pc offline</returns>
    Function GetInfo() As Boolean
        If _CheckOnlineStatus = True Then
            If IfOnline() = False Then Return False
        End If
 
        If _CheckRegistryMode = enumCheckRegistryMode.Both Or _CheckRegistryMode = enumCheckRegistryMode.defaultOnly _
           Then ReadUninstall(enumRegistryMode.default)
 
        If _CheckRegistryMode = enumCheckRegistryMode.Both Or _CheckRegistryMode = enumCheckRegistryMode.WoW64Only _
           Then ReadUninstall(enumRegistryMode.WoW64)
 
        Return True
    End Function
    Public ReadOnly Property SoftwareItems() As List(Of sSoftwareItem)
        Get
            Return _SoftwareItems
        End Get
    End Property
    '' <summary>
    '' Removes double space characters.
    '' </summary>
    ''<param name="text">The text.</param>
    ''<returns></returns>
    Private Function RemoveDoubleSpaceCharacters(ByVal text As String)
        Return System.Text.RegularExpressions.Regex.Replace(text, "[ ]+", " ")
    End Function
    Private Sub ReadUninstall(ByVal rRegistryMode As enumRegistryMode)
        Dim key As String = ""
        Select Case rRegistryMode
            Case enumRegistryMode.default
                key = "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall"
            Case enumRegistryMode.WoW64
                key = "SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall"
        End Select
 
 
        Dim RemoteRegistry As RegistryKey
        Dim UninstallItems() As String
 
        Try
 
 
            RemoteRegistry = RegistryKey.OpenRemoteBaseKey(RegistryHive.LocalMachine, _ComputerName)
            Dim RemoteRegistryUninstallNode As RegistryKey = RemoteRegistry.OpenSubKey(key)
 
            If Not IsNothing(RemoteRegistryUninstallNode) Then
                UninstallItems = RemoteRegistryUninstallNode.GetSubKeyNames()
                For i As Integer = 0 To UninstallItems.Length - 1
                    Dim SoftwareItem As RegistryKey = RemoteRegistry.OpenSubKey(key & "\" & UninstallItems(i))
                    Dim SoftwareDisplayName As String = RemoveDoubleSpaceCharacters(SoftwareItem.GetValue("DisplayName", "unknown"))
                    If Not SoftwareDisplayName = "unknown" And SoftwareDisplayName.Length > 0 Then
                        Dim ItemHolder As New sSoftwareItem
                        ItemHolder.DisplayName = SoftwareDisplayName
                        ItemHolder.RegistryMode = rRegistryMode
                        ItemHolder.DisplayVersion = SoftwareItem.GetValue("DisplayVersion", "")
                        ItemHolder.ParentDisplayName = SoftwareItem.GetValue("ParentDisplayName", "")
 
                        _SoftwareItems.Add(ItemHolder)
                    End If
                Next
            End If
        Catch ex As Exception
            MsgBox(ex.Message)
        End Try
 
    End Sub
    Private Function IfOnline() As Boolean
        Try
            Dim client As New TcpClient
            client.LingerState = New LingerOption(False, 1)
            client.Connect(_ComputerName, 445)
            client.Close()
            Return True
        Catch ex As Exception
            Return False
        End Try
    End Function
    Public Class sSoftwareItem
        Dim _DisplayName As String = ""
        Dim _DisplayVersion As String = ""
        Dim _ParentDisplayName As String = ""
 
        Dim _RegistryMode As enumRegistryMode = enumRegistryMode.default
        Property ParentDisplayName() As String
            Get
                Return _ParentDisplayName
            End Get
            Set(ByVal value As String)
                _ParentDisplayName = value
            End Set
        End Property
        Property DisplayName() As String
            Get
                Return _DisplayName
            End Get
            Set(ByVal value As String)
                _DisplayName = value
            End Set
        End Property
        Property DisplayVersion() As String
            Get
                Return _DisplayVersion
            End Get
            Set(ByVal value As String)
                _DisplayVersion = value
            End Set
        End Property
        Property RegistryMode() As enumRegistryMode
            Get
                Return _RegistryMode
            End Get
            Set(ByVal value As enumRegistryMode)
                _RegistryMode = value
            End Set
        End Property
    End Class
End Class

clsWMI.vb

Imports System.Management
 
Public Class clsWMI
    Dim myManagementScope As New System.Management.ManagementScope
 
    Private _isConnected As Boolean = False
    Private _CheckOnlineStatus As Boolean = True
    Private _MaschineName As String
    Public Sub New(ByVal MaschineName As String)
        _MaschineName = MaschineName
    End Sub
    ReadOnly Property Connected() As Boolean
        Get
            Return _isConnected
        End Get
    End Property
    '''<summary>Check if Remote Manchine is running and accessible; default = true</summary>
    Public WriteOnly Property CheckOnlineStatus() As Boolean
        Set(ByVal value As Boolean)
            _CheckOnlineStatus = value
        End Set
    End Property
    Function connect() As Boolean
        Try
            If _CheckOnlineStatus = True Then
                If IfOnline(_MaschineName) = False Then Return False
            End If
 
            Dim myConnectionOptions As New ConnectionOptions
            With myConnectionOptions
                .Impersonation = ImpersonationLevel.Impersonate
                '* Use next line for XP
                '.Authentication = System.Management.AuthenticationLevel.Packet
                '* Use next line for Win prior XP
                .Authentication = AuthenticationLevel.Connect
            End With
 
            '* Replace the "." with an actual servername for remote connection
            myManagementScope = New ManagementScope("\\" & _MaschineName & "\root\cimv2", myConnectionOptions)
            '* connect to WMI namespace
            myManagementScope.Connect()
            If myManagementScope.IsConnected = False Then
                'MsgBox("Could not connect to WMI namespace")
                myManagementScope = Nothing
                _isConnected = False
                Return False
            End If
            _isConnected = True
            Return True
        Catch ex As Exception
            _isConnected = False
            Return False
        End Try
    End Function
    Private Function IfOnline(ByVal _ComputerName As String) As Boolean
        Try
            Dim client As New System.Net.Sockets.TcpClient
            client.LingerState = New System.Net.Sockets.LingerOption(False, 1)
            client.Connect(_ComputerName, 135)
            client.Close()
            Return True
        Catch ex As Exception
            Return False
        End Try
    End Function
    Private Function Search(ByVal sql As String) As ManagementObjectCollection
        Dim myObjectSearcher As New System.Management.ManagementObjectSearcher( _
          myManagementScope.Path.ToString, sql)
        '* execute query
        Return myObjectSearcher.Get()
        '* list packages installed
    End Function
    Function CPU() As WmiValueCPU
        Dim back As New WmiValueCPU
        If myManagementScope.IsConnected = True Then
            For Each myObject As ManagementObject In Search("Select Name,Caption,SocketDesignation,MaxClockSpeed from Win32_Processor")
                back.Name = RemoveDoubleSpaceCharacters(myObject.GetPropertyValue("Name").ToString)
                back.Speed = myObject.GetPropertyValue("MaxClockSpeed")
            Next
        End If
        Return back
    End Function
    Function Memory() As WmiValueMemory
        Dim back As New WmiValueMemory
        Dim splitter As String = ""
        If myManagementScope.IsConnected = True Then
            For Each myObject As ManagementObject In Search("Select Capacity from WIN32_PhysicalMemory")
                Dim bRAM As Integer = Math.Round(myObject.GetPropertyValue("Capacity") / 1024 / 1024, 0)
                If bRAM > 1 Then
                    back.Banks = back.Banks & splitter & bRAM
                    back.MegaByte += bRAM
                    splitter = "|"
                End If
            Next
        End If
        Return back
    End Function
    Function Graphic() As WmiValueGraphic
        Dim back As New WmiValueGraphic
        If myManagementScope.IsConnected = True Then
            For Each myObject As ManagementObject In Search("Select Caption,AdapterRAM,DriverVersion from Win32_VideoController WHERE DeviceID='VideoController1'")
                back.Name = RemoveDoubleSpaceCharacters(myObject.GetPropertyValue("Caption"))
                back.RAM = Math.Round(myObject.GetPropertyValue("AdapterRAM") / 1024 / 1024, 0)
                back.DriverVersion = myObject.GetPropertyValue("DriverVersion")
            Next
        End If
        Return back
    End Function
    Function SystemOS() As WmiValueSystemOS
        Dim back As New WmiValueSystemOS
        If myManagementScope.IsConnected = True Then
            For Each myObject As ManagementObject In Search("Select Caption,Version,CSDVersion from Win32_OperatingSystem")
                back.Name = myObject.GetPropertyValue("Caption")
                back.Version = myObject.GetPropertyValue("Version")
                back.ServicePack = myObject.GetPropertyValue("CSDVersion")
            Next
        End If
        Return back
    End Function
    Function User() As WmiValueUser
        Dim back As New WmiValueUser
        If myManagementScope.IsConnected = True Then
            For Each myObject As ManagementObject In Search("Select * from Win32_ComputerSystem")
                back.CurrentLoggedIn = myObject.GetPropertyValue("UserName")
                back.ClearCurrentLoggedIn = Me.ClearUserName(back.CurrentLoggedIn)
            Next
        End If
        Return back
    End Function
    Private Function ClearUserName(ByVal str As String) As String
        If Not IsNothing(str) Then
            If str.Contains("\") Then
                Return str.Remove(0, str.LastIndexOf("\") + 1)
            Else
                Return str
            End If
        End If
        Return str
    End Function
    '' <summary>
    '' Removes double space characters.
    '' </summary>
    ''<param name="text">The text.</param>
    ''<returns></returns>
    Private Function RemoveDoubleSpaceCharacters(ByVal text As String)
        Return System.Text.RegularExpressions.Regex.Replace(text, "[ ]+", " ")
    End Function
    Structure WmiValueUser
        Dim CurrentLoggedIn As String
        Dim ClearCurrentLoggedIn As String
    End Structure
    Structure WmiValueCPU
        Dim Name As String
        Dim Speed As String
    End Structure
    Structure WmiValueMemory
        Dim Banks As String
        Dim MegaByte As String
    End Structure
    Structure WmiValueGraphic
        Dim Name As String
        Dim RAM As String
        Dim DriverVersion As String
    End Structure
    Structure WmiValueSystemOS
        Dim Name As String
        Dim Version As String
        Dim ServicePack As String
    End Structure
End Class

Disqus - noscript

Ist es auch möglich andere Benutzerdaten zu verwerden ? Zum Beispiel benutzer : test und kennwort 12345 anstatt den benutzerdaten, mit denen man aktuell eingeloggt ist .
thx für das Tool

@pokermaster2007
einfach z.B. auf die \\hostname oder ip\c$ Freigabe mit dem entsprechenden Benutzer verbinden
netter Ansatz.
Für Zugriff auf remote Computer forlgende kleine Änderungen, dann klappt das auch im Domänenfreien umfeld:
            With myConnectionOptions                '.EnablePrivileges = True                .Impersonation = ImpersonationLevel.Impersonate                .Authentication = AuthenticationLevel.Default               
                If _MaschineName <> "." Then                    .Username = _UserName                    .Password = _Password                End If            End With
In search() noch eine kleine Änderung:
        Dim myObjectSearcher As New System.Management.ManagementObjectSearcher(myManagementScope.Path.ToString, sql)        myObjectSearcher.Scope = myManagementScope'Interessanterweise wird im konstruktor der scope nicht übergeben