web-dev-qa-db-ja.com

C#でマシンのMACアドレスを取得する信頼できる方法

C#を使用して実行しているOSに関係なく、マシンのMACアドレスを取得する方法が必要です。アプリケーションは、XP/Vista/Win7 32ビットおよび64ビット、およびこれらのOSで動作する必要がありますが、デフォルトは外国語です。 C#コマンドとOSクエリの多くは、OS全体で機能しません。何か案は? 「ipconfig/all」の出力をスクレイピングしてきましたが、出力形式がすべてのマシンで異なるため、これはひどく信頼できません。

ありがとう

117
Chase

よりクリーンなソリューション

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

または:

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

次に、最初の動作可能なネットワークインターフェイスのMACアドレスを返すC#コードを示します。 NetworkInterfaceアセンブリが他のオペレーティングシステムで使用されるランタイム(つまりMono)に実装されていると仮定すると、これは他のオペレーティングシステムでも機能します。

新しいバージョン:有効なMACアドレスも持つ最速のNICを返します。

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

元のバージョン:最初のバージョンを返すだけです。

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

私がこのアプローチについて気に入らないのは、Nortel Packet Miniportまたは何らかのタイプのVPN接続があり、それが選択される可能性がある場合です。私が知る限り、実際の物理デバイスのMACをある種の仮想ネットワークインターフェイスと区別する方法はありません。

78
blak3r

Win32_NetworkAdapterConfiguration WMI classMACAddressプロパティは、アダプターのMACアドレスを提供できます。 (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"

WMI API(Windows Management Instrumentation)に慣れていない場合は、.NETアプリ用の こちらの概要 があります。

WMIは、.Netランタイムを備えたすべてのバージョンのウィンドウで使用できます。

コード例を次に示します。

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

接続しているマシンがWindowsマシンの場合、WMIが最適なソリューションですが、Linux、Mac、またはその他の種類のネットワークアダプターを使用している場合は、別のものを使用する必要があります。いくつかのオプションがあります:

  1. DOSコマンドnbtstat -aを使用します。プロセスを作成し、このコマンドを呼び出して、出力を解析します。
  2. 最初にIPをpingして、NICがコマンドをARPテーブルにキャッシュしていることを確認してから、DOSコマンドarp -aを使用します。オプション1のようにプロセスの出力を解析します。
  3. 恐ろしいアンマネージコールを使用してiphlpapi.dllのsendarpを使用します

アイテム#3のサンプルを示します。 WMIが実行可能なソリューションでない場合、これが最適なオプションのようです。

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

それが当然であるところに信用を与えるために、これはそのコードの基礎です: http://www.pinvoke.net/default.aspx/iphlpapi.sendarp#

9
Brian Duncan

WMIを使用して、最も低いメトリックのインターフェイスのMACアドレスを取得します。インターフェイスウィンドウは、次のように使用することを好みます。

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

または、Silverlightで(信頼を高める必要があります):

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

インターネットへの接続に使用されている実際のNICのMACを取得する必要がありました。クライアントアプリでWCFがどのインターフェイスを使用しているかを判断します。

ここには多くの答えがありますが、助けてくれるものはありません。この答えが誰かの助けになることを願っています。

このソリューションは、インターネットへの接続に使用されているNICのMACを返します。

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

これを呼び出すには、次のように接続するURLを渡す必要があります。

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

特に仮想マシンがホストされている場合、最初のMACアドレスを返すIMHOは良い考えではありません。したがって、送信/受信バイトの合計を確認し、最も使用されている接続を選択します。これは完全ではありませんが、9/10回正しいはずです。

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

NIC IDにアクセスできます:

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

これはMACアドレスではありませんが、探しているのであれば一意の識別子です。

4
mmr

IP接続メトリックが最小のAVeeのソリューションが本当に気に入っています!しかし、同じメトリックの2番目のNICがインストールされている場合、MAC比較は失敗する可能性があります...

MACを使用してインターフェイスの説明を保存する方が適切です。後の比較では、この文字列によって適切なnicを特定できます。サンプルコードを次に示します。

   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

この古い投稿を掘り下げることは本当に嫌いですが、この質問はWindows 8-10に固有の別の答えに値すると思います。

Windows.Networking.Connectivity 名前空間の NetworkInformation を使用すると、使用しているネットワークアダプターウィンドウのIDを取得できます。次に、前述のGetAllNetworkInterfaces()からインターフェイスMACアドレスを取得できます。

System.Net.NetworkInformationの NetworkInterface はGetAllNetworkInterfacesを公開しないため、これはWindowsストアアプリでは機能しません。

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

192.168.0.182のローカルIPを使用するTcpConnectionがあるとします。次に、そのNICのMACアドレスを知りたい場合は、次のように方法を呼び出します: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

Blak3rのコードを少し変更しました。同じ速度の2つのアダプターがある場合。 MACで並べ替えるので、常に同じ値を取得できます。

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

ipconfig.exeiphlpapi.dllを含むさまざまなDLLを使用して実装されます... iphlpapiのグーグルは、MSDNで文書化された対応するWin32 APIを明らかにします。

0
ChrisW

これを試して:

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