title: Is it possible to get PC's # of physical USB ports?
body: <p>I'm trying to get number of physical USB ports of PC for different Windows operating systems. To start with it seemed like an easy task but now I'm getting desperate.</p>
  
  <p>Maybe this question is not even valid since I don't know how USB ports are treated on hardware level.</p>
  
  <p>I thought using <code>WMI(C)</code> and <code>ManagementObjectSearcher</code> would be the right path to take and it returned right values... on certain operating systems. Or that's what I thought.</p>
  
  <p>For example, I tried the following:</p>
  
  <pre><code>// &gt;wmic path win32_usbhub get name
  
  private const string UsbProperty = "Name";
  private const string UsbPath = "Win32_USBHub";
  private const string UsbPortName = "USB ROOT HUB";
  
  ...
  
  // Get USB Ports
  public IEnumerable&lt;string&gt; GetUsbPorts()
  {
      // All from Win32_USBHub where name contains USB ROOT HUB
      return GetManagementObjectValues(UsbProperty, UsbPath).Where(name =&gt; 
          CultureInfo.CurrentCulture.CompareInfo.IndexOf(
              name, UsbPortName, CompareOptions.IgnoreCase) &gt;= 0);
  }
  </code></pre>
  
  <p>.</p>
  
  <pre><code>// Query
  private static IEnumerable&lt;string&gt; GetManagementObjectValues(
      string properties, string path, Func&lt;object, string&gt; formatter = null)
  {
      var values = new List&lt;string&gt;();
      string query = string.Format("SELECT {0} FROM {1}", properties, path);
      var search = new ManagementObjectSearcher(query);
  
      try
      {
          foreach (ManagementObject item in search.Get())
          {
              string value = string.Empty;
              foreach (string property in properties.Split(',')
                  .Select(prop =&gt; prop.Trim()))
              {
                  if (item[property] == null)
                      continue;
  
                  if (value.Length &gt; 0)
                      value += " ";
  
                  if (formatter != null)
                      value += formatter(item[properties]);
                  value += item[property].ToString();
              }
              values.Add(value.TrimEnd());
          }
      }
      catch (Exception e)
      {
          if (e is ManagementException)
              Logger.Warn(string.Format(
                  "Can't extract {0} properties of {1}", properties, path), e);
          else
              Logger.Error(e);
      }
  
      return values.Count &gt;= 1 ? values : new List&lt;string&gt; { DefaultValue };
  }
  </code></pre>
  
  <p>This seemed to get me the right amount on Windows8 but on WindowsXP it was totally off. </p>
  
  <p>Next, I tried (for example) the following. I noticed that on Win8 I have <code>USB&lt;number&gt;</code> as <code>ExternalReferenceDesignator</code> but on WinXP, there's plain <code>USB</code> as <code>InternalReferenceDesignator</code> and external is empty.</p>
  
  <p>For XP this seemed to work just fine but then again on Win8 amount of ports was six (6). Actual port count is 3 and with docking station station seven (7).</p>
  
  <pre><code>// &gt;wmic path Win32_PortConnector get ExternalReferenceDesignator,InternalReferenceDesignator
  
  private const string UsbPortName = "USB";     
  private const string PortProperties = 
      "ExternalReferenceDesignator, InternalReferenceDesignator";
  private const string PortPath = @"Win32_PortConnector";
  
  ...
  
  public IEnumerable&lt;string&gt; GetEthernetPorts()
  {
      // All where external includes USB or internal equals USB
      return GetManagementObjectValues(PortProperties, PortPath).Where(name =&gt; 
          CultureInfo.CurrentCulture.CompareInfo.IndexOf(
              name, UsbPortName, CompareOptions.IgnoreCase) &gt;= 0 ||
          string.Compare(name, UsbPortName, StringComparison.OrdinalIgnoreCase) == 0);
  }    
  </code></pre>
  
  <p>So is it even possible or am I just looking from the wrong place?</p>