Вопрос: Как сделать сканирование COM-портов и добавление в ComboBox?

Лучший ответ:
Я не настоящий программист, но делал так и все работает:

При загрузке формы вычитываем список портов и пихаем их в комбобокс
private void Main_Load(object sender, EventArgs e)
        {
            var portNames = SerialPort.GetPortNames();
            portSelectorComboBox.Items.AddRange(portNames);
        }

Выбранный в комбобоксе элемент кидаем в переменную

private void portSelectorComboBox_TextChanged(object sender, EventArgs e)
        {
            _portName = portSelectorComboBox.SelectedItem.ToString();
        }

По нажатию кнопки OpenButton пытаемся соединиться

private void portOpenButton_Click(object sender, EventArgs e)
        {
            try
            {
                port = new SerialPort(_portName, 115200, Parity.None, 8, StopBits.Two);
                port.ReceivedBytesThreshold = 1;
                port.DataReceived += new SerialDataReceivedEventHandler(port_DataReceived);
                port.Open();
                portStatusText.Text = "Ok, port open";
            }
            catch (Exception)
            {
                portStatusText.Text = "Error";
                MessageBox.Show("неправильно выбран порт, попробуйте еще раз");
            }
        }

Ну и реализуем чтение того что пришло

void port_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {

        }

Худший ответ:
В своё время делал перечисление последовательных портов так, но не уверен, что это есть хорошо.
Тоже интересно было бы узнать, можно ли сделать поэлегантнее:
using System.Management;

public static Dictionary<string, ManagementBaseObject> EnumerateComPorts()
{
    Dictionary<string, ManagementBaseObject> result = new Dictionary<string, ManagementBaseObject>();
    string[] ports = SerialPort.GetPortNames();
    foreach (string port in ports)
    {
        using (var entitySearcher = new ManagementObjectSearcher(
            "root\\CIMV2", $"SELECT * FROM Win32_PnPEntity WHERE Caption LIKE '%{port}%'"))
        {
            var matchingEntity = entitySearcher.Get().Cast<ManagementBaseObject>().FirstOrDefault();
            if (null != matchingEntity)
            {
                result.Add(port, matchingEntity);
            }
        } // using
    } // foreach
    return result;
} // EnumerateComPorts

Далее, уже сделал Listener на нужный порт и ждал данные:
public RS232Listener(string portname)
        {
            m_queue = new Queue<string>();
            try
            {
                if (null != m_port)
                {
                    m_port.Close();
                    m_port.Dispose();
                    GC.Collect();
                    GC.WaitForPendingFinalizers();
                }
                m_port = new SerialPort(portname, 9600, Parity.None, 8, StopBits.One);
                m_port.DataReceived += this.M_port_DataReceived;
                m_port.ErrorReceived += this.M_port_ErrorReceived;
                m_port.Open();
            } // try
            catch(Exception ex)
            {
                Logger.LogError("RS232Listener constructor", ex.Message, ex);
                ErrorMessage = ex.Message;
                ErrorState = true;
            }
        } // RS232Listener constructor