2009-05-12 70 views
93

Necesito una forma de obtener la dirección MAC de una máquina, independientemente del sistema operativo que esté ejecutando con C#. La aplicación deberá funcionar en XP/Vista/Win7 de 32 y 64 bits, así como en esos sistemas operativos, pero con un idioma extranjero predeterminado. Muchos de los comandos C# y consultas de OS no funcionan en todo el sistema operativo. ¿Algunas ideas? He estado raspando la salida de "ipconfig/all", pero esto es terriblemente poco confiable ya que el formato de salida difiere en cada máquina.Método confiable para obtener la dirección MAC de la máquina en C#

Gracias

+6

Cuando dices a través de sistema operativo, ¿te refieres a diferentes sistemas operativos de Microsoft? –

Respuesta

9

El MACAddress propiedad del Win32_NetworkAdapterConfiguration WMI class le puede proporcionar la dirección MAC de un adaptador. (System.Management Espacio de nombres)

MACAddress 

    Data type: string 
    Access type: Read-only 

    Media Access Control (MAC) address of the network adapter. A MAC address is assigned by the manufacturer to uniquely identify the network adapter. 

    Example: "00:80:C7:8F:6C:96" 

Si usted no está familiarizado con la API de WMI (Windows Management Instrumentation), hay una good overview here para aplicaciones .NET.

WMI está disponible en todas las versiones de Windows con .NET runtime.

Aquí está un ejemplo de código:

System.Management.ManagementClass mc = default(System.Management.ManagementClass); 
ManagementObject mo = default(ManagementObject); 
mc = new ManagementClass("Win32_NetworkAdapterConfiguration"); 

ManagementObjectCollection moc = mc.GetInstances(); 
    foreach (var mo in moc) { 
     if (mo.Item("IPEnabled") == true) { 
       Adapter.Items.Add("MAC " + mo.Item("MacAddress").ToString()); 
     } 
    } 
4

usted podría ir para el NIC ID:

foreach (NetworkInterface nic in NetworkInterface.GetAllNetworkInterfaces()) { 
    if (nic.OperationalStatus == OperationalStatus.Up){ 
     if (nic.Id == "yay!") 
    } 
} 

No es la dirección MAC, pero es un identificador único, si eso es lo que eres buscando.

0

ipconfig.exe se implementa utilizando varias DLL que incluyen iphlpapi.dll ... Google buscando iphlpapi revela una API de Win32 correspondiente documentada en MSDN.

9

WMI es la mejor solución si la máquina a la que se está conectando es una máquina de Windows, pero si está mirando un linux, mac u otro tipo de adaptador de red, necesitará usar algo más. Aquí hay algunas opciones:

  1. Use el comando DOS nbtstat -a. Crea un proceso, llama a este comando, analiza el resultado.
  2. Primero haga ping a la IP para asegurarse de que su NIC almacena en caché el comando en su tabla ARP, luego use el comando DOS arp -a. Analizar la salida del proceso al igual que en la opción 1.
  3. utilizar una llamada temida no administrado a sendarp en el iphlpapi.dll

Aquí está una muestra del artículo # 3. Esta parece ser la mejor opción si WMI no es una solución viable:

using System.Runtime.InteropServices; 
... 
[DllImport("iphlpapi.dll", ExactSpelling = true)] 
     public static extern int SendARP(int DestIP, int SrcIP, byte[] pMacAddr, ref uint PhyAddrLen); 
... 
private string GetMacUsingARP(string IPAddr) 
{ 
    IPAddress IP = IPAddress.Parse(IPAddr); 
    byte[] macAddr = new byte[6]; 
    uint macAddrLen = (uint)macAddr.Length; 

    if (SendARP((int)IP.Address, 0, macAddr, ref macAddrLen) != 0) 
     throw new Exception("ARP command failed"); 

    string[] str = new string[(int)macAddrLen]; 
    for (int i = 0; i < macAddrLen; i++) 
     str[i] = macAddr[i].ToString("x2"); 

    return string.Join(":", str); 
} 

dar crédito donde es debido, esta es la base para ese código: http://www.pinvoke.net/default.aspx/iphlpapi.sendarp#

+0

¡Estaba buscando lo mismo que el OP y esto es exactamente lo que necesitaba! – QueueHammer

+1

¡Increíble, gracias! – detay

68

Aquí hay algo de código C#, que devuelve la dirección MAC de la primera interfaz de red operativa. Suponiendo que el ensamblaje NetworkInterface se implementa en el tiempo de ejecución (es decir, Mono) utilizado en otros sistemas operativos, esto funcionaría en otros sistemas operativos.

Nueva versión: devuelve la NIC con la velocidad más rápida que también tiene una dirección MAC válida.

/// <summary> 
/// Finds the MAC address of the NIC with maximum speed. 
/// </summary> 
/// <returns>The MAC address.</returns> 
private string GetMacAddress() 
{ 
    const int MIN_MAC_ADDR_LENGTH = 12; 
    string macAddress = string.Empty; 
    long maxSpeed = -1; 

    foreach (NetworkInterface nic in NetworkInterface.GetAllNetworkInterfaces()) 
    { 
     log.Debug(
      "Found MAC Address: " + nic.GetPhysicalAddress() + 
      " Type: " + nic.NetworkInterfaceType); 

     string tempMac = nic.GetPhysicalAddress().ToString(); 
     if (nic.Speed > maxSpeed && 
      !string.IsNullOrEmpty(tempMac) && 
      tempMac.Length >= MIN_MAC_ADDR_LENGTH) 
     { 
      log.Debug("New Max Speed = " + nic.Speed + ", MAC: " + tempMac); 
      maxSpeed = nic.Speed; 
      macAddress = tempMac; 
     } 
    } 

    return macAddress; 
} 

Versión original: sólo devuelve la primera.

/// <summary> 
/// Finds the MAC address of the first operation NIC found. 
/// </summary> 
/// <returns>The MAC address.</returns> 
private string GetMacAddress() 
{ 
    string macAddresses = string.Empty; 

    foreach (NetworkInterface nic in NetworkInterface.GetAllNetworkInterfaces()) 
    { 
     if (nic.OperationalStatus == OperationalStatus.Up) 
     { 
      macAddresses += nic.GetPhysicalAddress().ToString(); 
      break; 
     } 
    } 

    return macAddresses; 
} 

La única cosa que no me gusta de este enfoque es que si tienes como un paquete de Nortel Minipuerto o algún tipo de conexión VPN que tiene el potencial de ser elegido. Por lo que puedo decir, no hay forma de distinguir el MAC de un dispositivo físico real de algún tipo de interfaz de red virtual.

+6

No solo elija la primera interfaz operativa. Esto podría devolver interfaces de bucle invertido, tarjetas 3G ocasionalmente conectadas, etc., que probablemente no sean las que usted desea. NetworkInterfaceType (http://msdn.microsoft.com/en-us/library/system.net.networkinformation.networkinterface.networkinterfacetype.aspx) le dará más información acerca de la conexión NetworkInterface para que pueda tomar una decisión más informada. También tenga en cuenta que podría haber muchas conexiones activas en una máquina y que su orden puede no ser predecible. –

+0

@DaveR. Miré NetworkInterfaceType, básicamente casi siempre devuelve Ethernet incluso cuando era un adaptador virtual en mi experiencia, así que me pareció bastante inútil. – blak3r

+1

Debe elegir la interfaz con el GatewayMetric más bajo. Esta debería ser la conexión que tiene la "ruta más rápida, más confiable o que requiere menos recursos". Básicamente le dará la interfaz que Windows prefiere usar. Sin embargo, creo que necesita WMI para obtener eso. Veré si puedo hacer que funcione ... – AVee

92

Limpiador solución

var macAddr = 
    (
     from nic in NetworkInterface.GetAllNetworkInterfaces() 
     where nic.OperationalStatus == OperationalStatus.Up 
     select nic.GetPhysicalAddress().ToString() 
    ).FirstOrDefault(); 

O:

String firstMacAddress = NetworkInterface 
    .GetAllNetworkInterfaces() 
    .Where(nic => nic.OperationalStatus == OperationalStatus.Up && nic.NetworkInterfaceType != NetworkInterfaceType.Loopback) 
    .Select(nic => nic.GetPhysicalAddress().ToString()) 
    .FirstOrDefault(); 
+38

O lambda, si eso es lo tuyo! 'return NetworkInterface.GetAllNetworkInterfaces(). Where (nic => nic.OperationalStatus == OperationalStatus.Up) .Select (nic => nic.GetPhysicalAddress(). ToString()). FirstOrDefault();' (Si no lo es) Lo suyo, debería ser lo tuyo.) – GONeale

+7

Manera concisa de obtener el más rápido: 'var networks = NetworkInterface.GetAllNetworkInterfaces(); var activeNetworks = networks.Where (ni => ni.OperationalStatus == OperationalStatus.Up && ni.NetworkInterfaceType! = NetworkInterfaceType.Loopback); var sortedNetworks = activeNetworks.OrderByDescending (ni => ni.Speed); return sortedNetworks.First(). GetPhysicalAddress(). ToString(); ' –

7

Utilizamos WMI para obtener la dirección MAC de la interfaz con la métrica más baja, por ejemplo, las ventanas de la interfaz preferirán utilizar, así:

public static string GetMACAddress() 
{ 
    ManagementObjectSearcher searcher = new ManagementObjectSearcher("SELECT * FROM Win32_NetworkAdapterConfiguration where IPEnabled=true"); 
    IEnumerable<ManagementObject> objects = searcher.Get().Cast<ManagementObject>(); 
    string mac = (from o in objects orderby o["IPConnectionMetric"] select o["MACAddress"].ToString()).FirstOrDefault(); 
    return mac; 
} 

O en Silverlight (necesita la confianza elevada):

public static string GetMACAddress() 
{ 
    string mac = null; 
    if ((Application.Current.IsRunningOutOfBrowser) && (Application.Current.HasElevatedPermissions) && (AutomationFactory.IsAvailable)) 
    { 
     dynamic sWbemLocator = AutomationFactory.CreateObject("WbemScripting.SWBemLocator"); 
     dynamic sWbemServices = sWbemLocator.ConnectServer("."); 
     sWbemServices.Security_.ImpersonationLevel = 3; //impersonate 

     string query = "SELECT * FROM Win32_NetworkAdapterConfiguration where IPEnabled=true"; 
     dynamic results = sWbemServices.ExecQuery(query); 

     int mtu = int.MaxValue; 
     foreach (dynamic result in results) 
     { 
      if (result.IPConnectionMetric < mtu) 
      { 
       mtu = result.IPConnectionMetric; 
       mac = result.MACAddress; 
      } 
     } 
    } 
    return mac; 
} 
2

me gusta mucho la solución de AVEE con la conexión IP métrica más baja! Pero si se instala un segundo NIC con la misma métrica, la comparación MAC podría fallar ...

Será mejor que almacene la descripción de la interfaz con el MAC. En comparaciones posteriores, puede identificar el nic correcto con esta cadena. Aquí es un ejemplo de código:

public static string GetMacAndDescription() 
    { 
     ManagementObjectSearcher searcher = new ManagementObjectSearcher("SELECT * FROM Win32_NetworkAdapterConfiguration where IPEnabled=true"); 
     IEnumerable<ManagementObject> objects = searcher.Get().Cast<ManagementObject>(); 
     string mac = (from o in objects orderby o["IPConnectionMetric"] select o["MACAddress"].ToString()).FirstOrDefault(); 
     string description = (from o in objects orderby o["IPConnectionMetric"] select o["Description"].ToString()).FirstOrDefault(); 
     return mac + ";" + description; 
    } 

    public static string GetMacByDescription(string description) 
    { 
     ManagementObjectSearcher searcher = new ManagementObjectSearcher("SELECT * FROM Win32_NetworkAdapterConfiguration where IPEnabled=true"); 
     IEnumerable<ManagementObject> objects = searcher.Get().Cast<ManagementObject>(); 
     string mac = (from o in objects where o["Description"].ToString() == description select o["MACAddress"].ToString()).FirstOrDefault(); 
     return mac; 
    } 
2

vamos a decir que tengo un TcpConnection usando mi IP local del 192.168.0.182. Entonces, si me gustaría saber la dirección MAC de ese NIC voy a llamar a la meothod como: GetMacAddressUsedByIp("192.168.0.182")

public static string GetMacAddressUsedByIp(string ipAddress) 
    { 
     var ips = new List<string>(); 
     string output; 

     try 
     { 
      // Start the child process. 
      Process p = new Process(); 
      // Redirect the output stream of the child process. 
      p.StartInfo.UseShellExecute = false; 

      p.StartInfo.RedirectStandardOutput = true; 
      p.StartInfo.UseShellExecute = false; 
      p.StartInfo.CreateNoWindow = true; 
      p.StartInfo.FileName = "ipconfig"; 
      p.StartInfo.Arguments = "/all"; 
      p.Start(); 
      // Do not wait for the child process to exit before 
      // reading to the end of its redirected stream. 
      // p.WaitForExit(); 
      // Read the output stream first and then wait. 
      output = p.StandardOutput.ReadToEnd(); 
      p.WaitForExit(); 

     } 
     catch 
     { 
      return null; 
     } 

     // pattern to get all connections 
     var pattern = @"(?xis) 
(?<Header> 
    (\r|\n) [^\r]+ : \r\n\r\n 
) 
(?<content> 
    .+? (?= ((\r\n\r\n)|($))) 
)"; 

     List<Match> matches = new List<Match>(); 

     foreach (Match m in Regex.Matches(output, pattern)) 
      matches.Add(m); 

     var connection = matches.Select(m => new 
     { 
      containsIp = m.Value.Contains(ipAddress), 
      containsPhysicalAddress = Regex.Match(m.Value, @"(?ix)Physical \s Address").Success, 
      content = m.Value 
     }).Where(x => x.containsIp && x.containsPhysicalAddress) 
     .Select(m => Regex.Match(m.content, @"(?ix) Physical \s address [^:]+ : \s* (?<Mac>[^\s]+)").Groups["Mac"].Value).FirstOrDefault(); 

     return connection; 
    } 
+0

Esto no es eficiente ... No recomendaría hacer esto. –

4
public static PhysicalAddress GetMacAddress() 
{ 
    var myInterfaceAddress = NetworkInterface.GetAllNetworkInterfaces() 
     .Where(n => n.OperationalStatus == OperationalStatus.Up && n.NetworkInterfaceType != NetworkInterfaceType.Loopback) 
     .OrderByDescending(n => n.NetworkInterfaceType == NetworkInterfaceType.Ethernet) 
     .Select(n => n.GetPhysicalAddress()) 
     .FirstOrDefault(); 

    return myInterfaceAddress; 
} 
0

Prueba esto:

/// <summary> 
    /// returns the first MAC address from where is executed 
    /// </summary> 
    /// <param name="flagUpOnly">if sets returns only the nic on Up status</param> 
    /// <returns></returns> 
    public static string[] getOperationalMacAddresses(Boolean flagUpOnly) 
    { 
     string[] macAddresses = new string[NetworkInterface.GetAllNetworkInterfaces().Count()]; 

     int i = 0; 
     foreach (NetworkInterface nic in NetworkInterface.GetAllNetworkInterfaces()) 
     { 
      if (nic.OperationalStatus == OperationalStatus.Up || !flagUpOnly) 
      { 
       macAddresses[i] += ByteToHex(nic.GetPhysicalAddress().GetAddressBytes()); 
       //break; 
       i++; 
      } 
     } 
     return macAddresses; 
    } 
4

que necesitaba para obtener la MAC para el actual NIC que se usa para conectarse a internet; para determinar qué interfaz usaba WCF en mi aplicación cliente.

Veo muchas respuestas aquí pero ninguna que me haya ayudado. Espero que esta respuesta ayude a alguien.

Esta solución devuelve el MAC de la NIC que se utiliza para conectarse a Internet.

private static PhysicalAddress GetCurrentMAC(string allowedURL) 
{ 
    TcpClient client = new TcpClient(); 
    client.Client.Connect(new IPEndPoint(Dns.GetHostAddresses(allowedURL)[0], 80)); 
    while(!client.Connected) 
    { 
    Thread.Sleep(500); 
    } 
    IPAddress address2 = ((IPEndPoint)client.Client.LocalEndPoint).Address; 
    client.Client.Disconnect(false); 
    NetworkInterface[] allNetworkInterfaces = NetworkInterface.GetAllNetworkInterfaces(); 
    client.Close(); 
    if(allNetworkInterfaces.Length > 0) 
    { 
    foreach(NetworkInterface interface2 in allNetworkInterfaces) 
    { 
     UnicastIPAddressInformationCollection unicastAddresses = interface2.GetIPProperties().UnicastAddresses; 
     if((unicastAddresses != null) && (unicastAddresses.Count > 0)) 
     { 
     for(int i = 0; i < unicastAddresses.Count; i++) 
      if(unicastAddresses[i].Address.Equals(address2)) 
      return interface2.GetPhysicalAddress(); 
     } 
    } 
    } 
    return null; 
} 

llamarlo lo necesario para pasar una URL para conectarse a como este:

PhysicalAddress mac = GetCurrentMAC("www.google.com"); 
2

realmente odio a desenterrar este viejo post, pero me siento la cuestión merece otra respuesta específica a las ventanas 8- 10.

Utilizando NetworkInformation desde el espacio de nombre Windows.Networking.Connectivity, puede obtener el ID de las ventanas del adaptador de red. Luego puede obtener la dirección MAC de la interfaz de los GetAllNetworkInterfaces() mencionados anteriormente.

Esto no funcionará en Windows Store Apps como NetworkInterface en System.Net.NetworkInformation no expone GetAllNetworkInterfaces.

string GetMacAddress() 
{ 
    var connectionProfile = NetworkInformation.GetInternetConnectionProfile(); 
    if (connectionProfile == null) return ""; 

    var inUseId = connectionProfile.NetworkAdapter.NetworkAdapterId.ToString("B").ToUpperInvariant(); 
    if(string.IsNullOrWhiteSpace(inUseId)) return ""; 

    var mac = NetworkInterface.GetAllNetworkInterfaces() 
     .Where(n => inUseId == n.Id) 
     .Select(n => n.GetPhysicalAddress().GetAddressBytes().Select(b=>b.ToString("X2"))) 
     .Select(macBytes => string.Join(" ", macBytes)) 
     .FirstOrDefault(); 

    return mac; 
} 
0

Cambié blak3r su código un poco. En caso de que tengas dos adaptadores con la misma velocidad. Ordene por MAC, para que siempre obtenga el mismo valor.

public string GetMacAddress() 
{ 
    const int MIN_MAC_ADDR_LENGTH = 12; 
    string macAddress = string.Empty; 
    Dictionary<string, long> macPlusSpeed = new Dictionary<string, long>(); 
    try 
    { 
     foreach(NetworkInterface nic in NetworkInterface.GetAllNetworkInterfaces()) 
     { 
      System.Diagnostics.Debug.WriteLine("Found MAC Address: " + nic.GetPhysicalAddress() + " Type: " + nic.NetworkInterfaceType); 

      string tempMac = nic.GetPhysicalAddress().ToString(); 

      if(!string.IsNullOrEmpty(tempMac) && tempMac.Length >= MIN_MAC_ADDR_LENGTH) 
       macPlusSpeed.Add(tempMac, nic.Speed); 
     } 

     macAddress = macPlusSpeed.OrderByDescending(row => row.Value).ThenBy(row => row.Key).FirstOrDefault().Key; 
    } 
    catch{} 

    System.Diagnostics.Debug.WriteLine("Fastest MAC address: " + macAddress); 

    return macAddress; 
} 
Cuestiones relacionadas