web-dev-qa-db-fra.com

Méthode fiable pour obtenir l'adresse MAC de la machine en C #

J'ai besoin d'un moyen d'obtenir l'adresse MAC d'une machine, quel que soit le système d'exploitation utilisé avec C #. L'application devra fonctionner sur XP/Vista/Win7 32 et 64 bits, ainsi que sur ces systèmes d'exploitation, mais avec une langue étrangère par défaut. De nombreuses commandes C # et requêtes OS ne fonctionnent pas sous OS. Des idées? J'ai gratté la sortie de "ipconfig/all" mais c'est terriblement peu fiable car le format de sortie diffère sur chaque machine.

Merci

109
Chase

Solution plus propre

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

Ou:

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

Voici un code C # qui renvoie l'adresse MAC de la première interface réseau opérationnelle. En supposant que l'assembly NetworkInterface est implémenté dans le moteur d'exécution (c'est-à-dire Mono) utilisé sur d'autres systèmes d'exploitation, cela fonctionnerait sur d'autres systèmes d'exploitation.

Nouvelle version: renvoie le NIC avec la vitesse la plus rapide et une adresse MAC valide.

/// <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;
}

Version originale: renvoie simplement le premier.

/// <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 seule chose que je n'aime pas dans cette approche, c'est que si vous avez un Nortel Packet Miniport ou un type de connexion VPN, vous avez le choix. Autant que je sache, il n’ya aucun moyen de distinguer le MAC d’un périphérique physique réel d’un type d’interface réseau virtuelle. 

76
blak3r

WMI est la meilleure solution si la machine à laquelle vous vous connectez est une machine Windows, mais si vous envisagez d'utiliser un type d'adaptateur réseau sous linux, mac ou autre, vous devrez utiliser autre chose. Voici quelques options:

  1. Utilisez la commande DOS nbtstat -a. Créez un processus, appelez cette commande, analysez la sortie.
  2. Commencez par exécuter une commande ping sur l’IP pour vous assurer que votre NIC cache la commande dans sa table ARP, puis utilisez la commande DOS arp -a. Analyser la sortie du processus comme dans l'option 1.
  3. Utilisez un appel non géré redouté à sendarp dans le iphlpapi.dll

Voici un échantillon de l'article n ° 3. Cela semble être la meilleure option si WMI n'est pas une solution 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);
}

Pour attribuer le mérite là où il est dû, voici la base de ce code: http://www.pinvoke.net/default.aspx/iphlpapi.sendarp#

10
Brian Duncan

La propriété MACAddress de la classe classe WMI Win32_NetworkAdapterConfiguration peut vous fournir l'adresse MAC d'un adaptateur. (Espace de noms System.Management)

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 vous n'êtes pas familier avec l'API WMI (Windows Management Instrumentation), il existe un bonne vue d'ensemble ici pour les applications .NET.

WMI est disponible sur toutes les versions de Windows avec le runtime .Net.

Voici un exemple de code:

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());
         }
     }
10
Bayard Randel

Nous utilisons WMI pour obtenir l'adresse mac de l'interface avec la métrique la plus basse, par exemple. les fenêtres d'interface préfèrent utiliser, comme ceci:

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;
}

Ou en Silverlight (besoin de confiance élevée):

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;
}
7
AVee
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;
}
6
Tony

J'avais besoin d'obtenir le MAC du NIC utilisé pour se connecter à Internet; pour déterminer quelle interface était utilisée par WCF dans mon application cliente.

Je vois beaucoup de réponses ici mais aucune ne m'a aidé. J'espère que cela répond à quelqu'un.

Cette solution renvoie le MAC du NIC utilisé pour se connecter à 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;
}

Pour l'appeler, vous devez passer une URL pour vous connecter comme ceci:

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

IMHO retournant la première adresse mac n'est pas une bonne idée, surtout quand les machines virtuelles sont hébergées. Par conséquent, je vérifie la somme des octets envoyés/reçus et sélectionne la connexion la plus utilisée, ce qui n’est pas parfait, mais devrait être correcte 9/10 fois.

public string GetDefaultMacAddress()
{
    Dictionary<string, long> macAddresses = new Dictionary<string, long>();
    foreach (NetworkInterface nic in NetworkInterface.GetAllNetworkInterfaces())
    {
        if (nic.OperationalStatus == OperationalStatus.Up)
            macAddresses[nic.GetPhysicalAddress().ToString()] = nic.GetIPStatistics().BytesSent + nic.GetIPStatistics().BytesReceived;
    }
    long maxValue = 0;
    string mac = "";
    foreach(KeyValuePair<string, long> pair in macAddresses)
    {
        if (pair.Value > maxValue)
        {
            mac = pair.Key;
            maxValue = pair.Value;
        }
    }
    return mac;
}
4
Ramunas

Vous pouvez choisir l’ID NIC:

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

Ce n'est pas l'adresse MAC, mais c'est un identifiant unique, si c'est ce que vous recherchez. 

4
mmr

J'aime beaucoup la solution AVee avec la métrique de connexion IP la plus basse! Mais si un deuxième nic avec la même métrique est installé, la comparaison MAC pourrait échouer ...

Mieux vaut stocker la description de l'interface avec le MAC. Lors de comparaisons ultérieures, vous pouvez identifier le bon nic par cette chaîne. Voici un exemple de code:

   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
Detlef

Déteste vraiment déterrer cet ancien post mais je pense que la question mérite une autre réponse spécifique à Windows 8-10. 

En utilisant NetworkInformation à partir de Windows.Networking.Connectivity namespace, vous pouvez obtenir l’ID de la fenêtre utilisée par l’adaptateur réseau. Ensuite, vous pouvez obtenir l'adresse MAC d'interface à partir de GetAllNetworkInterfaces () mentionné précédemment.

Cela ne fonctionnera pas dans le Windows Store Apps en tant que NetworkInterface dans System.Net.NetworkInformation n'expose pas 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;
}
2
Greg Gorman

disons que j'ai un TcpConnection en utilisant mon adresse IP locale de 192.168.0.182. Ensuite, si je souhaite connaître l'adresse mac de ce NIC, j'appellerai le message comme suit: 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;
    }
2
Tono Nam
string mac = "";
foreach (NetworkInterface nic in NetworkInterface.GetAllNetworkInterfaces())
            {

                if (nic.OperationalStatus == OperationalStatus.Up && (!nic.Description.Contains("Virtual") && !nic.Description.Contains("Pseudo")))
                {
                    if (nic.GetPhysicalAddress().ToString() != "")
                    {
                        mac = nic.GetPhysicalAddress().ToString();
                    }
                }
            }
MessageBox.Show(mac);
1
hadi safari

Blak3r changé un peu son code. Si vous avez deux adaptateurs avec la même vitesse. Triez par MAC pour que vous obteniez toujours la même valeur.

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;
}
0
user369122

ipconfig.exe est implémenté à l'aide de différentes DLL, dont iphlpapi.dll ... Googling for iphlpapi révèle une API Win32 correspondante documentée dans MSDN.

0
ChrisW

Essaye ça: 

    /// <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;
    }
0
Richard