Metodo affidabile per ottenere l’indirizzo MAC della macchina in C #

Ho bisogno di un modo per ottenere l’indirizzo MAC di una macchina indipendentemente dal sistema operativo in esecuzione usando C #. L’applicazione dovrà funzionare su XP / Vista / Win7 a 32 e 64 bit e su quei sistemi operativi ma con una lingua straniera predefinita. Molti dei comandi C # e le query del sistema operativo non funzionano su tutto il sistema operativo. Qualche idea? Ho raschiato l’output di “ipconfig / all” ma questo è terribilmente inaffidabile in quanto il formato di output è diverso su ogni macchina.

Grazie

Soluzione più pulita

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

Ecco un codice C # che restituisce l’indirizzo MAC della prima interfaccia di rete operativa. Supponendo che l’assembly NetworkInterface sia implementato nel runtime (ad es. Mono) utilizzato su altri sistemi operativi, ciò funzionerebbe su altri sistemi operativi.

Nuova versione: restituisce la NIC con la velocità più veloce che ha anche un indirizzo MAC valido.

 ///  /// Finds the MAC address of the NIC with maximum speed. ///  /// The MAC address. 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; } 

Versione originale: restituisce solo il primo.

 ///  /// Finds the MAC address of the first operation NIC found. ///  /// The MAC address. 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; } 

L’unica cosa che non mi piace di questo approccio è che se hai un Nortel Packet Miniport o qualche tipo di connessione VPN ha il potenziale di essere scelto. Per quanto posso dire, non c’è modo di distinguere un MAC di un dispositivo fisico reale da un qualche tipo di interfaccia di rete virtuale.

La proprietà MACAddress della class WMI Win32_NetworkAdapterConfiguration può fornire l’indirizzo MAC di una scheda. (Spazio dei nomi 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" 

Se non hai familiarità con l’API WMI (Strumentazione gestione Windows), qui c’è una buona panoramica per le app .NET.

WMI è disponibile su tutte le versioni di Windows con il runtime .Net.

Ecco un esempio di codice:

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

WMI è la soluzione migliore se la macchina alla quale ci si connette è una macchina Windows, ma se si sta guardando un linux, mac o un altro tipo di scheda di rete, sarà necessario utilizzare qualcos’altro. Ecco alcune opzioni:

  1. Usa il comando DOS nbtstat -a. Crea un processo, chiama questo comando, analizza l’output.
  2. Prima fai un ping sull’IP per assicurarti che la tua NIC memorizzi il comando nella sua tabella ARP, quindi usa il comando DOS arp -a. Analizza l’output del processo come nell’opzione 1.
  3. Utilizzare una chiamata non gestita temuta a sendarp in iphlpapi.dll

Ecco un esempio dell’articolo n. 3. Questa sembra essere l’opzione migliore se WMI non è una soluzione praticabile:

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

Per dare credito dove è dovuto, questa è la base per quel codice: http://www.pinvoke.net/default.aspx/iphlpapi.sendarp#

Usiamo WMI per ottenere l’indirizzo mac dell’interfaccia con la metrica più bassa, ad esempio l’interfaccia Windows preferirà usare, come questo:

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

O in Silverlight (ha bisogno di una fiducia elevata):

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

Si può andare per l’ID NIC:

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

Non è l’indirizzo MAC, ma è un identificatore univoco, se è quello che stai cercando.

Avevo bisogno di ottenere il MAC per la NIC utilizzata per connettersi a Internet; per determinare quale interfaccia è stata utilizzata da WCF nella mia app client.

Vedo molte risposte qui ma nessuna che mi ha aiutato. Spero che questa risposta aiuti qualcuno.

Questa soluzione restituisce il MAC della NIC utilizzata per connnettere 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; } 

Per chiamarlo è necessario passare un URL per connettersi in questo modo:

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

Mi piace molto la soluzione di AVee con la metrica di connessione IP più bassa! Ma se viene installato un secondo dispositivo con la stessa metrica, il confronto con MAC potrebbe fallire …

Meglio memorizzare la descrizione dell’interfaccia con il MAC. Nei confronti successivi è ansible identificare la nic giusta con questa stringa. Ecco un codice di esempio:

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

diciamo che ho un TcpConnection usando il mio ip locale di 192.168.0.182. Quindi se mi piacerebbe conoscere l’indirizzo mac di quella NIC chiamerò il meothod come: GetMacAddressUsedByIp("192.168.0.182")

 public static string GetMacAddressUsedByIp(string ipAddress) { var ips = new List(); 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) (?
(\r|\n) [^\r]+ : \r\n\r\n ) (? .+? (?= ( (\r\n\r\n)|($)) ) )"; List matches = new List(); 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* (?[^\s]+)").Groups["Mac"].Value).FirstOrDefault(); return connection; }

Odio davvero scavare su questo vecchio post ma ritengo che la domanda meriti un’altra risposta specifica per Windows 8-10.

Utilizzando NetworkInformation dallo spazio dei nomi Windows.Networking.Connectivity , è ansible ottenere l’Id delle windows della scheda di rete in uso. Quindi è ansible ottenere l’indirizzo MAC dell’interfaccia dal precedente GetAllNetworkInterfaces ().

Ciò non funzionerà nelle app di Windows Store come NetworkInterface in System.Net.NetworkInformation non espone 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; } 
 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); 

IMHO che restituisce il primo indirizzo mac non è una buona idea, specialmente quando le macchine virtuali sono ospitate. Quindi controllo la sum dei byte inviati / ricevuti e seleziono la connessione più utilizzata, che non è perfetta, ma dovrebbe essere corretta 9/10 volte.

 public string GetDefaultMacAddress() { Dictionary macAddresses = new Dictionary(); 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 pair in macAddresses) { if (pair.Value > maxValue) { mac = pair.Key; maxValue = pair.Value; } } return mac; } 

ipconfig.exe è implementato utilizzando varie DLL tra cui iphlpapi.dll … Googling per iphlpapi rivela una corrispondente API Win32 documentata in MSDN.

Prova questo:

  ///  /// returns the first MAC address from where is executed ///  /// if sets returns only the nic on Up status ///  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; } 

Cambiato un po ‘il suo codice blak3r. Nel caso in cui hai due adattatori con la stessa velocità. Ordina per MAC, quindi ottieni sempre lo stesso valore.

 public string GetMacAddress() { const int MIN_MAC_ADDR_LENGTH = 12; string macAddress = string.Empty; Dictionary macPlusSpeed = new Dictionary(); 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; }