Search code examples
c#network-scan

How to find Windows PCs in an IP range


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.


Solution

  • 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.