Get Specific MAC Address - vb.net

My VS2015 VB app is reading the MAC address of the users computer. This has worked well except some users are using laptops with docking stations that assign their own MAC address. The code I am using returns the first one it finds, can a specific one be searched for?
Dim mc As New ManagementClass(New ManagementPath("Win32_Processor"), New ObjectGetOptions(New ManagementNamedValueCollection()))
Dim moc As ManagementObjectCollection = mc.GetInstances()
mc.Path = New ManagementPath("Win32_NetworkAdapterConfiguration")
moc = mc.GetInstances()
Dim sMac As String = String.Empty
For Each mo As ManagementObject In moc
If (mo.GetPropertyValue("IPEnabled") = True) Then
If (sMac = String.Empty) Then
sMac = mo.GetPropertyValue("MacAddress").ToString()
End If
End If
Next

This method is using System.Net.NetworkInformation.NetworkInterface instead of directly querying the WMI interface.
It returns informations on all the current Network Interfaces, except the Loopback interface, where the Operational Status is UP. This usually filters the Teredo and ISATAP interfaces and, of course, all the Network Interfaces that are not currently active.
The NetworkInterfaceType could also be used to filter other specific interface type, the NetworkInterfaceType.Wireless80211 for example.
I'm proposing this variant because it's simpler to modify/expand when required.
Each instance of the NetInterfaceMac class povides:
The Interface human-friendly description
The IPV4 addresses of the Interface
The MAC address if string format ("BF:D1:E8:8C:2B:A4")
The MAC address bytes
Public Class NetInterfaceMac
Public Property InterfaceDescription() As String
Public Property IPAddress() As IPAddress
Public Property MacAddress() As String
Public Property MacAddressBytes() As Byte()
End Class
Public Shared Function GetNetworkMACAddresses() As List(Of NetInterfaceMac)
Dim Macs As New List(Of NetInterfaceMac)()
Dim NetInterfaces As NetworkInterface() = NetworkInterface.GetAllNetworkInterfaces()
Macs.AddRange(NetInterfaces.Where(
Function(ni) ni.NetworkInterfaceType <> NetworkInterfaceType.Loopback AndAlso
ni.OperationalStatus = OperationalStatus.Up).
Select(Function(ni) New NetInterfaceMac() With {
.IPAddress = ni.GetIPProperties().UnicastAddresses?.
Where(Function(ip) ip.IsDnsEligible = True)?.Select(Function(ip) ip.Address).ToArray(),
.InterfaceDescription = ni.Description,
.MacAddress = ni.GetPhysicalAddress().GetAddressBytes().
Select(Function(b) b.ToString("X")).Aggregate(Function(s1, s2) s2 + ":" + s1),
.MacAddressBytes = ni.GetPhysicalAddress().GetAddressBytes()
}))
Return Macs
End Function
Sample call:
Dim Macs As List(Of NetInterfaceMac) = GetNetworkMACAddresses()

Related

Vb.NET Device Unique Identifier Win10

I'm trying to get a Device Unique Identifier in vb.net code. I have tried with
Private Function SystemSerialNumber() As String
Dim value As String = ""
Dim baseBoard As ManagementClass = New ManagementClass("Win32_BaseBoard")
Dim board As ManagementObjectCollection = baseBoard.GetInstances()
If board.Count > 0 Then
value = board(0)("SerialNumber")
If value.Length > 0 Then value = value.Substring(2)
End If
Return value
End Function
Which works on some computers but of the board doesn't have a serial number it returns "Default String" or whatever they put in there. Even tried with Win32_Processor and some have it and others just return "To be filled by O.E.M" lol
Also tried with,
Private Function SystemSerialNumber() As String
Dim value As String
Dim q As New SelectQuery("Win32_bios")
Dim search As New ManagementObjectSearcher(q)
Dim info As New ManagementObject
For Each info In search.Get
value = info("SerialNumber").ToString
Return value
Next
End Function
But its the same some devices have it some don't and just returns default string.
So I'm now trying is:
Private Function SystemSerialNumber() As String
Dim value As String
value = Windows.System.Profile.SystemIdentification.GetSystemIdForPublisher()
End Function
But I'm having trouble referencing to it. I tried Imports Windows.System but it just gives the error it cant be found.
As a side note I'm using this program in tablets with windows10, laptops, and desktops.
UPDATE: I'll be using as suggested by Heinzi. Thanks!
Also changed variable names to be more accurate.
Private Function NetworkAdapterMacAddress() As String
Dim McAddress As String
Dim netadapter As ManagementClass = New ManagementClass("Win32_NetworkAdapterConfiguration")
Dim mo As ManagementObject
Dim adapter As ManagementObjectCollection = netadapter.GetInstances()
For Each mo In adapter
If mo.Item("IPEnabled") = True Then
McAddress = mo.Item("MacAddress").ToString()
Return McAddress
End If
Next
End Function
Well, there is no guaranteed ID that identifies every PC out there uniquely (fortunately, I might add. Privacy is a good thing).
You best bets are probably
the MAC of the network adapter (changes when the network adapter is replaced) or
the Windows Computer SID (changes when Windows is reinstalled).
Oh, and on a philosophical note, you might want to ponder on the Ship of Theseus.

Get current NIC settings

So, cutting a long story short the section of my code that I am currently unable to figure out is designed to report the current IP settings of a given NIC, so I want it to essentially spit out the IP, Subnet and default Gateway that it is currently set to. I have a solution working but it only seems to play nice when the NIC is set to DHCP which is not good for my application.
Here is my current code:
Public Sub NetGet()
MainForm.NetLabelIP.Text = "IPv4 Address: "
MainForm.NetLabelIP.Text = "subnet Mask: "
MainForm.NetLabelIP.Text = "Default Gateway: "
MainForm.NetLabelCN.Text = "Computer Name: " + System.Net.Dns.GetHostName()
For Each ip In System.Net.Dns.GetHostEntry(System.Net.Dns.GetHostName()).AddressList
If ip.AddressFamily = Net.Sockets.AddressFamily.InterNetwork Then
'IPv4 Adress
MainForm.NetLabelIP.Text = "IPv4 Address: " + ip.ToString()
For Each adapter As Net.NetworkInformation.NetworkInterface In Net.NetworkInformation.NetworkInterface.GetAllNetworkInterfaces()
If adapter.Name = MainForm.interfaceSelector.SelectedItem Then
For Each unicastIPAddressInformation As Net.NetworkInformation.UnicastIPAddressInformation In adapter.GetIPProperties().UnicastAddresses
If unicastIPAddressInformation.Address.AddressFamily = Net.Sockets.AddressFamily.InterNetwork Then
If ip.Equals(unicastIPAddressInformation.Address) Then
'Subnet Mask
MainForm.NetLabelSM.Text = "Subnet Mask: " + unicastIPAddressInformation.IPv4Mask.ToString()
Dim adapterProperties As Net.NetworkInformation.IPInterfaceProperties = adapter.GetIPProperties()
For Each gateway As Net.NetworkInformation.GatewayIPAddressInformation In adapterProperties.GatewayAddresses
'Default Gateway
MainForm.NetLabelDG.Text = "Default Gateway: " + gateway.Address.ToString()
Next
If unicastIPAddressInformation.PrefixOrigin = 3 Then
DHCP = True
MainForm.NetLabelDHCP.Text = "DHCP Enabled: TRUE"
Else
DHCP = False
MainForm.NetLabelDHCP.Text = "DHCP Enabled: FALSE"
End If
''DNS1
'if adapterproperties.dnsaddresses.count > 0 then
' label5.text = adapterproperties.dnsaddresses(0).tostring()
'end if
''DNS2
'if adapterproperties.dnsaddresses.count > 1 then
' label6.text = adapterproperties.dnsaddresses(1).tostring()
'end if
End If
End If
Next
End If
Next
End If
Next
End Sub
I'm assuming it's going to be something abhorrently daft in hindsight, however I feel it best to share my request with the community so that anyone else looking for a similar solution can find their answers here.
Thanks in advance, guys.
This NetInterfacesInfo class implements two static (shared) methods the return informations on the Network Interfaces of a Machine:
NetInterfacesInfo.GetNetworkInterfaces()
This method returns all the Network Interfaces that support IPV4 except the Loopback interface.
The informations are returned in a List(Of NetWorkInterfacesInfo), which exposes these properties:
ConnectionName: The name assigned to the connection (Local Area Network (LAN))
Description: The firendly name of the Interface
IPV4Addresses: A simplified list of each Ip Address as string, the associated NetMask and Default Gateway.
IpAddresses: A list ot the IP Addresses associated with the Network Interface.
DHCPSservers: A list of the DHCP Servers associated with the Network Interface.
DnsServers: A list of the DNS Servers associated with the Network Interface.
Gateways: A list of Gateways addresses associated with the Network Interface.
IsDHCPEnabled: Specifies whether the IP Address is provided by a DHCP server or is a Static Address.
MacAddress: The MAC address of the NIC
Status: The Interface is functional (Up) or not (Down)
InterfaceType: The type of the Interface. This value can be one of the many possible types of Interfaces: Wireless80211, Tunnel, FastEthernetFx etc.
The IPV4Addresses property return a simplified list of the IP Addresses associated with the Network Interface. These informations are contained in a IpV4AddressInfo class, which provides these properties:
IpAddress: String representation of the IP Address.
NetMask: String representation of the NetMask of the Ip Address.
DefaultGateway: String representation of the Default Gateway address.
IsDnsEligible: Specifies that the IP Address can appear in a DNS (is routable)
Sample usage:
Dim allNicsInfo = NetInterfacesInfo.GetNetworkInterfaces()
For Each nic As NetInterfacesInfo.NetWorkInterfacesInfo In allNicsInfo
Console.WriteLine($"Description: {nic.Description} Type: {nic.InterfaceType}")
Next
Dim Wireless = allNicsInfo.Where(Function(nic) nic.InterfaceType = NetworkInterfaceType.Wireless80211)
NetInterfacesInfo.IpV4AddressSimpleList
The simplified list of IP Addresses associated with a Network Interface can also be retrieved using this static (shared) method, providing the Name (actually, the Description property) of a Network Interface.
This method returns a List(Of IpV4AddressInfo), a simplified, string only version, of each IP Address (of the specified Network Interface), its NetMask and the associated Default Gateway.
Sample usage:
Dim nicInfo = NetInterfacesInfo.IpV4AddressSimpleList("Some NIC Name")
For Each ipV4Addr As NetInterfacesInfo.IpV4AddressInfo In nicInfo
Console.WriteLine(ipV4Addr.IpAddress)
Console.WriteLine(ipV4Addr.NetMask)
Console.WriteLine(ipV4Addr.DefaultGateway)
Next
Attach the main class to a ComboBox:
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim allNicsInfo = NetInterfacesInfo.GetNetworkInterfaces()
ComboBox1.DisplayMember = "ConnectionName"
ComboBox1.DataSource = allNicsInfo
End Sub
Private Sub ComboBox1_SelectedIndexChanged(sender As Object, e As EventArgs) Handles ComboBox1.SelectedIndexChanged
Dim cbo = DirectCast(sender, ComboBox)
If cbo.SelectedIndex = -1 Then Return
Dim nicInfo = DirectCast(cbo.SelectedItem, NetInterfacesInfo.NetWorkInterfacesInfo)
TextBox1.Text = String.Join(Environment.NewLine, nicInfo.IPV4Addresses.
Select(Function(nic) $"IP Address: {nic.IpAddress} NetMask: {nic.NetMask}"))
TextBox2.Text = nicInfo.IPV4Addresses.First().DefaultGateway
End Sub
Imports System.Linq
Imports System.Net
Imports System.Net.NetworkInformation
Imports System.Net.Sockets
Public Class NetInterfacesInfo
Public Shared Function GetNetworkInterfaces() As List(Of NetWorkInterfacesInfo)
Dim ifInfo As New List(Of NetWorkInterfacesInfo)()
ifInfo.AddRange(GetNetworInterfaces().
Where(Function(nic) nic.NetworkInterfaceType <> NetworkInterfaceType.Loopback AndAlso
nic.Supports(NetworkInterfaceComponent.IPv4)).
Select(Function(nic) New NetWorkInterfacesInfo() With {
.Description = nic.Description,
.ConnectionName = nic.Name,
.IsDHCPEnabled = nic.GetIPProperties().GetIPv4Properties().IsDhcpEnabled,
.DHCPSservers = nic.GetIPProperties().DhcpServerAddresses.ToList(),
.DnsServers = nic.GetIPProperties().DnsAddresses.ToList(),
.Gateways = nic.GetIPProperties().GatewayAddresses.Select(Function(ipa) ipa.Address).ToList(),
.InterfaceType = nic.NetworkInterfaceType,
.IpAddresses = nic.GetIPProperties().UnicastAddresses.Select(Function(ipa) ipa.Address).ToList(),
.MacAddress = nic.GetPhysicalAddress().GetAddressBytes().
Select(Function(b) b.ToString("X")).Aggregate(Function(s1, s2) s2 + ":" + s1),
.Status = nic.OperationalStatus,
.IPV4Addresses = GetIpV4AddressInfo(nic)
}))
Return ifInfo
End Function
Public Shared Function IpV4AddressSimpleList(nicName As String) As List(Of IpV4AddressInfo)
Dim nic = GetNetworInterfaceByName(nicName)
If nic Is Nothing Then Return Nothing
Return nic.GetIPProperties().UnicastAddresses.
Where(Function(ipa) ipa.Address.AddressFamily = AddressFamily.InterNetwork).
Select(Function(ipa) New IpV4AddressInfo() With {
.IpAddress = ipa.Address?.ToString(),
.NetMask = ipa.IPv4Mask?.ToString(),
.IsDnsEligible = ipa.IsDnsEligible,
.DefaultGateway = nic.GetIPProperties().GatewayAddresses.FirstOrDefault()?.Address?.ToString()
}).ToList()
End Function
Private Shared Function GetIpV4AddressInfo(nic As NetworkInterface) As List(Of IpV4AddressInfo)
Return nic.GetIPProperties().UnicastAddresses.
Where(Function(ipa) ipa.Address.AddressFamily = AddressFamily.InterNetwork).
Select(Function(ipa) New IpV4AddressInfo() With {
.IpAddress = ipa.Address?.ToString(),
.NetMask = ipa.IPv4Mask?.ToString(),
.IsDnsEligible = ipa.IsDnsEligible,
.DefaultGateway = nic.GetIPProperties().GatewayAddresses.FirstOrDefault()?.Address?.ToString()
}).ToList()
End Function
Private Shared Function GetNetworInterfaces() As NetworkInterface()
Return NetworkInterface.GetAllNetworkInterfaces()
End Function
Private Shared Function GetNetworInterfaceByName(nicName As String) As NetworkInterface
Return NetworkInterface.GetAllNetworkInterfaces().FirstOrDefault(Function(nic) nic.Name = nicName)
End Function
Public Class NetWorkInterfacesInfo
Public Property ConnectionName As String
Public Property Description As String
Public Property IPV4Addresses As List(Of IpV4AddressInfo)
Public Property IpAddresses As List(Of IPAddress)
Public Property DHCPSservers As List(Of IPAddress)
Public Property DnsServers As List(Of IPAddress)
Public Property Gateways As List(Of IPAddress)
Public Property IsDHCPEnabled As Boolean
Public Property MacAddress As String
Public Property Status As OperationalStatus
Public Property InterfaceType As NetworkInterfaceType
End Class
Public Class IpV4AddressInfo
Public Property IpAddress As String
Public Property NetMask As String
Public Property DefaultGateway As String
Public Property IsDnsEligible As Boolean
End Class
End Class

list of class with members from derived class

I'd like to create list of class of different devices with its designed members. It this possible?
Public lstDevices As New List(Of Device)
Public Class Device
Public strName As String
Public iKind As Integer
End Class
Then I'll have particular kind of Device named Printer
Public Class Printer : Inherits Device
public shared iAge as integer
End Class
How can I reach for ex.
lstDevices.Find(Function(p) p.strName = strName).iAge = 10
if I make clsPrinter = new Printer()
I can reach clsPrinter.iAge
But with list, is this possible?
The lstDevices-list stores Devices, so the parent class of Printer which has the iAge property. You have to cast it appropriately. But you also have to store the result of List.Find in a variable:
Dim foundDevice As Device = lstDevices.Find(Function(p) p.strName = strName)
If foundDevice IsNot Nothing AndAlso TypeOf foundDevice Is Printer Then
Dim foundPrinter As Printer = DirectCast(foundDevice, Printer)
foundPrinter.iAge = 10
End If
Another nice LINQ approach is:
Dim foundPrinters = From p In lstDevices.OfType(Of Printer)()
Where p.strName = strName
Dim firstPrinter As Printer = foundPrinters.FirstOrdefault()
I just want to remind you that iAge property of Printer class is a shared property.
I prefer the LINQ methods over LINQ queries. So I tried converting Tim's query to LINQ method (minus the where criteria). I intentionally use First() instead of FirstOrDefault(). Code looks like this:
Module Module1
Public lstDevices As New List(Of Device)
Sub Main()
lstDevices.Add(New Printer() With {.strName = "Epson", .iKind = 1})
lstDevices.Add(New Printer() With {.strName = "HP", .iKind = 2})
lstDevices.OfType(Of Printer).First().iAge = 10
Console.WriteLine(lstDevices.OfType(Of Printer).First().iAge)
Console.ReadKey(True)
End Sub
End Module
Public Class Device
Public strName As String
Public iKind As Integer
End Class
Public Class Printer : Inherits Device
Public Shared iAge As Integer
End Class
VS shows warnings in these lines:
lstDevices.OfType(Of Printer).First().iAge = 10
Console.WriteLine(lstDevices.OfType(Of Printer).First().iAge)
The warning for both lines is:
Access of shared member, constant member, enum member or nested type
through an instance; qualifying expression will not be evaluated.
It means that the expression won't be evaluated because iAge is a shared property. Even if I remove the 2 lines where I add Printer instances to the list, the code won't throw any exception. That's because iAge property is tied to the Printer class, not instance of Printer class.
Sub Main()
'lstDevices.Add(New Printer() With {.strName = "Epson", .iKind = 1})
'lstDevices.Add(New Printer() With {.strName = "HP", .iKind = 2})
' these 2 lines won't throw any exceptions eventhough the list is empty
lstDevices.OfType(Of Printer).First().iAge = 10
Console.WriteLine(lstDevices.OfType(Of Printer).First().iAge)
Console.ReadKey(True)
End Sub
So there 2 lines can be simplified to:
'lstDevices.OfType(Of Printer).First().iAge = 10
'Console.WriteLine(lstDevices.OfType(Of Printer).First().iAge)
Printer.iAge = 10
Console.WriteLine(Printer.iAge)
If you remove the Shared keyword from iAge, then the code might throw exception if the list if empty. Tim's code is safe because he use FirstOrDefault(), you can check whether firstPrinter is nothing (null) or not, then use the iAge property.

Most efficient way to count properties in object collection which are not null

What is the fastest/most efficient way to count how many Computer objects in the collection have a MAC address (I.e. Computer.MACAddress <> "")
<Serializable>
Public Class Computer
Public Property Name As String
Public Property FQDN As String
Public Property Path As String
Public Property GUID As String
Public Property MACAddress As String
Public Property IPAddress As Net.IPAddress
End Class
<Serializable>
Public Class ComputerCollection
Inherits Collection(Of Computer)
End Class
At the moment I'm using LINQ:
Dim macCount = From comp In computers Where comp.MACAddress <> "" Select comp
ssMACDisc.Text = macCount.Count.ToString + " MAC Addresses Discovered"
Thanks in advance
LINQ also uses loops. But you should prefer the most readable way normally.
Dim nonEmptyMacs = From comp In computers
Where Not String.IsNullOrEmpty(comp.MACAddress)
Dim countNonEmptyMacs = nonEmptyMacs.Count()
If you need something more efficient you could use a Lookup(Of Tkey, TElement) to count all the null/empty macs. You can initialize a lookup only via ToLookup. If the collection doesn't change often you can persist it in a field that you can access later. Perhaps you also recreate it from the method that adds new computers. You need a custom IEqualityComparer(Of Computer) which treats null and empty macs equal:
Public Class ComputerMacComparer
Implements IEqualityComparer(Of Computer)
Public Function Equals1(x As Computer, y As Computer) As Boolean Implements System.Collections.Generic.IEqualityComparer(Of Computer).Equals
If x Is Nothing OrElse y Is Nothing Then
Return False
End If
If String.IsNullOrEmpty(x.MACAddress) AndAlso String.IsNullOrEmpty(y.MACAddress) Then Return True
Return x.MACAddress = y.MACAddress
End Function
Public Function GetHashCode1(obj As Computer) As Integer Implements System.Collections.Generic.IEqualityComparer(Of Computer).GetHashCode
If String.IsNullOrEmpty(obj.MACAddress) Then Return 0
Return obj.MACAddress.GetHashCode()
End Function
End Class
The good thing: you can use this class for many other LINQ methods like GroupBy or Intesect.
I've used this sample data:
Dim computers As New ComputerCollection
computers.Add(New Computer With {.MACAddress = ""})
computers.Add(New Computer With {.MACAddress = nothing})
computers.Add(New Computer With {.MACAddress = "1"})
computers.Add(New Computer With {.MACAddress = "2"})
computers.Add(New Computer With {.MACAddress = "3"})
computers.Add(New Computer With {.MACAddress = Nothing})
As you can see, there are three computers that have either a null- or empty-mac.
You need one examplary "Null"-Computer that you can use later:
Dim nullComp = New Computer With {.MACAddress = Nothing}
Here is the only code that is necessary to create the lookup and to count all computers:
Dim macLookup = computers.ToLookup(Function(comp) comp, New ComputerMacComparer())
Dim countNull = macLookup(nullComp).Count() ' 3
This should be more efficient since a lookup is similar to a Dictionary. It returns an empty sequence if the key is not contained.

How to searching part of object inside array list without looping method

I save the client data into an array list. How to find part of data(currentIP) inside the array list(clientList) with fast method ?
Code as follow:
' Array list to keep Clients Object
Protected Friend clientList As ArrayList = ArrayList.Synchronized(New ArrayList())
Public Class Clients
public clientIPAdrress As IPAddress
public clientTCP As TcpClient
public clientStream As SslStream
End Class
Public Sub Test()
' Create objClients Object from Clients Class
Dim objClients as new Clients
' Add objClients to Array List
clientList.Add(objClients)
Dim currentIP as IPAdress = IPAddress.Parse("192.168.1.2")
Dim isIPFound as Boolean = False
' Search currentIP inside clientList with looping method
For Each ip As Clients In clientList
If ip.ClientIPAdrress = currentIP Then
isIPFound = True
Exit For
End If
Next
End Sub
Thanks for the advice.
You should use a typed List(Of Clients) instead, then cou can use LINQ:
Dim clientList As New List(Of Clients)
clientList.Add(new Clients())
Dim isIPFound=clientList.Any(Function(ip) ip.ClientIPAdrress = currentIP)
But essentially it is the same as your loop just in one row.
If you need to find the fastest way, you could sort your list and BinarySearch the IP with a custom comparer. Or, if the IP is unique in the list, you could use a Dictionary(Of IPAdress,Clients) instead.