Click here to Skip to main content
Click here to Skip to main content

How to Scan Computers in Your Network Using the Registry or WMI

, 24 Oct 2007
Rate this:
Please Sign up or sign in to vote.
A command-line tool that scans computers in your network using either a remote registry connection or the Windows Management Instrumentation (WMI).

Introduction

This is an inventory application that scans computers in your network. You can list computers of particular types (i.e., SQL servers), and you can extract computer information from two different sources: the registry or Windows Management Instrumentation (WMI).

Run netinventory.exe -? to see how it is used. Here is an example:

Screenshot - NetInventory.jpg

The command above will produce a file, NetInventory.xml - 3.3 KB, containing the operating system name and the service pack for all SQL servers in the network.

Background

I built the tool to solve recurring problems such as:

  • List SQL servers in the network (you can use Server Management Objects (SMO), but that is painfully slow)
  • List primary domain controllers
  • List operating systems for computers in the network
  • List computer types and serial number
  • List installed software for computers in the network

In order to get this kind of inventory information, I needed MS System Center Configuration Manager, or some other inventory system or asset management system. This tool requires no installation, and does the job (almost) as well.

Using the code

There are five basic problems to solve in this application:

  • List computers in the network
  • Control the timeout of the network connection to a computer that doesn't respond
  • Get registry information from a remote computer
  • Get WMI information from a remote computer
  • Manage command line switches

Listing computers in the network is described in another article. The class NetWorkBrowser, written by Sacha barber, encapsulates the use of the Win32 API function Netapi32.dll: NetServerEnum. I used Sacha's class as is, except for adding the enumeration ServerType. To list SQL servers in your network, simply call the function getNetworkComputers() and specify the server type:

// List SQL servers in your network

NetworkBrowser nb = new NetworkBrowser();
ArrayList arr = nb.getNetworkComputers(ServerType.SV_TYPE_SQLSERVER);
Console.WriteLine("{0} : {1}", serverType.ToString(), arr.Count);
foreach (string name in arr)
{
  Console.WriteLine(name);
}
Console.WriteLine();

One of the issues that need to be addressed when connecting to computers in your network is dealing with computers that don't respond. When connecting to the registry or WMI on a remote computer, you don't have control over the timeout. If a number of computers don't respond and you have to wait, say 30 seconds for each connection timeout, scanning the network will take forever. The class TimeoutOperation is designed to run operations impatiently. To use the class, inherit it and override DoWork() with the operation logic. On timeout, isCancelled will be set to true and the main thread will resume execution:

// Implement an impatient operation

class WaitAMinute : TimeoutOperation
{
  public int counter = 0;
  public WaitAMinute(int timeoutMiliseconds) : base(timeoutMiliseconds)
  {
  }
  protected override void DoWork()
  {
    for (counter = 0; counter < 60; counter++)
    {
      if (isCancelled)
        break;
      Thread.Sleep(1000);
    }
  }
}

// Run the operation with timeout

WaitAMinute w = new WaitAMinute(3000);
w.Start();
Console.WriteLine("{0}", w.counter); // 3

Getting registry information from a remote computer is encapsulated in the class RegistryReader. To use the class, call the static method GetRegistryKey(). In the example below, the method is used to get all the values from the registry key HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion on the machine with the hostname MYPC. The timeout is set to 500 milliseconds. If the machine does not respond within the timeout period, an ApplicationException will be thrown.

ArrayList arr = new ArrayList();
try
{
  RegistryReader.GetRegistryKey("MYPC",
    @"HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion", 
    null, 500, ref arr);
}
catch (Exception exc)
{
  Console.WriteLine(exc.Message); // Timed out

}
foreach (IDictionary dict in arr)
{
  foreach (DictionaryEntry de in dict)
  {
    Console.WriteLine("{0} = {1}", de.Key, de.Value);
    // Registry.ProgramFilesDir = C:\Program Files

    // Registry.CommonFilesDir = C:\Program Files\Common Files

    // ...

  }
}

Getting WMI information from a remote computer is encapsulated in the class WMIQuery. To use the class, call the static method Execute(). You must specify a valid query using the WQL syntax, a valid WMI namespace, hostname of the remote computer, and a connection timeout. The timeout works the same way as in the class RegistryReader as described above. This example will get the BIOS name and the serial number from the machine with the hostname MYPC:

ArrayList arr = null;
try
{
  arr = WMIQuery.Execute("select Caption, SerialNumber from Win32_BIOS", 
    @"root\CIMV2", "MYPC", 500);
}
catch (Exception exc)
{
  Console.WriteLine(exc.Message); // Timed out

}
foreach (IDictionary dict in arr)
{
  foreach (DictionaryEntry de in dict)
  {
    Console.WriteLine("{0} = {1}", de.Key, de.Value);
    // Win32_BIOS.Caption = KBC Version 43.1C

    // Win32_BIOS.SerialNumber = CNU5510SRH  

  }
}

To manage command line switches, I used the classes Parser and CommandLineSwitchAttribute written by Ray Hayes. These are described in another article. I made one modification to the class Parser (actually to SwitchRecord.BuildPattern(), to be precise) that allowed enumerated values as integers, because I wanted to be able to combine ServerType values.

Points of interest

TimeoutOperation may not scale well up to thousands of computers since the number of running threads waiting to connect to remote computers could be growing depending on your network configuration and the specified timeout value. I recommend setting the timeout to 0 when scanning large networks, letting the program run overnight, setting the timeout to the default value of 500 milliseconds when scanning a limited number of workstations, and getting the result set immediately.

History

  • Version 1.0.0.0 - November 2007.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Henrik Thomsen
Software Developer (Senior)
Denmark Denmark
No Biography provided

Comments and Discussions

 
GeneralDetails on Localhost only PinmemberD3s78-Nov-07 3:16 
Generalrun NetInventory.exe PinmemberJonnyTwoShoes1-Nov-07 1:28 
GeneralRe: run NetInventory.exe PinmemberHenrik Thomsen1-Nov-07 10:01 
GeneralRe: run NetInventory.exe PinmemberJonnyTwoShoes1-Nov-07 20:41 
QuestionLarge network Pinmembernick_journals25-Oct-07 1:54 
AnswerRe: Large network PinmemberKristof Verbiest25-Oct-07 2:08 
GeneralRe: Large network Pinmembernick_journals25-Oct-07 2:15 
GeneralRe: Large network PinmemberCool Cassis25-Oct-07 3:42 
GeneralRe: Large network Pinmembernick_journals25-Oct-07 3:47 
AnswerRe: Large network PinmemberHenrik Thomsen25-Oct-07 21:13 
AnswerRe: Large network PinmemberESTANNY25-Oct-07 21:46 
GeneralStatistics PinmemberESTANNY24-Oct-07 23:32 
GeneralRe: Statistics PinmemberHenrik Thomsen25-Oct-07 21:36 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web04 | 2.8.140709.1 | Last Updated 25 Oct 2007
Article Copyright 2007 by Henrik Thomsen
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid