I want to scan a network and enumerate hostname of all windows machines. There is an interface method that takes an ip range as input and returns hostnames. I have to implement it. So, here is my code:
public ICollection<string> EnumerateWindowsComputers(ICollection<string> ipList)
{
ICollection<string> hostNames = new List<string>();
foreach (var ip in ipList)
{
var hostName = GetHostName(ip);
if (string.IsNullOrEmpty(hostName) == false)
{
hostNames.Add(hostName)
}
}
return hostNames;
}
private static string GetHostName(string ipAddress)
{
try
{
IPHostEntry entry = Dns.GetHostEntry(ipAddress);
if (entry != null)
{
return entry.HostName;
}
}
catch (SocketException ex)
{
System.Console.WriteLine(ex.Message + " - " + ipAddress);
}
return null;
}
This method enumerates all windows machines successfully, but there are network printers in it. I can easily ignore my printers' hostname, but it will not be a good solution. I have to make sure that only the devices with the Windows operating system returned.
Any idea how to do it without a third party library? If there is a better way, we don't have to use GetHostName
method.
P.S. Linux, MacOS, Android and IOS devices are not found as expected.
According to @Jeroen van Langen's comment, I changed my GetHostName
method with GetWindowsHostName
.
private string GetWindowsHostName(string ipAddress)
{
try
{
IPHostEntry entry = Dns.GetHostEntry(ipAddress);
if (entry != null)
{
try
{
using (TcpClient tcpClient = new TcpClient())
{
// 445 is default TCP SMB port
tcpClient.Connect(ipAddress, 445);
}
using (TcpClient tcpClient = new TcpClient())
{
// 139 is default TCP NetBIOS port.
tcpClient.Connect(ipAddress, 139);
}
return entry.HostName;
}
catch (Exception ex)
{
System.Console.WriteLine(ex.Message);
}
}
}
catch (SocketException ex)
{
System.Console.WriteLine(ex.Message + " - " + ipAddress);
}
return null;
}
There can be false positive, but this is unlikely and acceptable for me.