2

I am new here and just learning python. I need help to get the right mac-address of my network card in windows using python. I tried to search, and found these :

  1. Python - Get mac address

  2. Getting MAC Address

  3. Command output parsing in Python

  4. Parsing windows 'ipconfig /all' output

If I run "ipconfig /all" from command prompt, I get this :

Windows-IP-Konfiguration
Hostname  . . . . . . . . . . . . : DESKTOP-CIRBA63
Primäres DNS-Suffix . . . . . . . :
Knotentyp . . . . . . . . . . . . : Hybrid
IP-Routing aktiviert  . . . . . . : Nein
WINS-Proxy aktiviert  . . . . . . : Nein

Ethernet-Adapter Ethernet:
Verbindungsspezifisches DNS-Suffix:
Beschreibung. . . . . . . . . . . : Realtek PCIe FE Family Controller
Physische Adresse . . . . . . . . : 32-A5-2C-0B-14-D9
DHCP aktiviert. . . . . . . . . . : Nein
Autokonfiguration aktiviert . . . : Ja
IPv4-Adresse  . . . . . . . . . . : 192.168.142.35(Bevorzugt)
Subnetzmaske  . . . . . . . . . . : 255.255.255.0
Standardgateway . . . . . . . . . : 192.168.142.1
DNS-Server  . . . . . . . . . . . : 8.8.8.8
                                    8.8.4.4
NetBIOS über TCP/IP . . . . . . . : Deaktiviert

Ethernet-Adapter Ethernet 2:
Medienstatus. . . . . . . . . . . : Medium getrennt
Verbindungsspezifisches DNS-Suffix:
Beschreibung. . . . . . . . . . . : Norton Security Data Escort Adapter
Physische Adresse . . . . . . . . : 00-CE-35-1B-77-5A
DHCP aktiviert. . . . . . . . . . : Ja
Autokonfiguration aktiviert . . . : Ja

Tunneladapter isatap.{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}:
Medienstatus. . . . . . . . . . . : Medium getrennt
Verbindungsspezifisches DNS-Suffix:
Beschreibung. . . . . . . . . . . : Microsoft ISATAP Adapter
Physische Adresse . . . . . . . . : 00-00-00-00-00-00-00-A0
DHCP aktiviert. . . . . . . . . . : Nein
Autokonfiguration aktiviert . . . : Ja

I need to get the mac address of my Realtek network card (32-A5-2C-0B-14-D9), not the one created by Norton or windows tunneling. Python gave me another result of mac address if i am using : "uuid.getnode() or "getmac" I think the best way is to get the output of "ipconfig /all", looking at "Realtek" at "Beschreibung" and then get the "Physische Adresse" information to get my real mac address. How to do this in python on windows ? Any help is appreciated. Thanks in advance.

Community
  • 1
  • 1
thomasberg
  • 21
  • 1
  • 3
  • Did you try the suggested netifaces module? That seems simplest. Although if you're already looking for a specific adapter, why not just hardcode the MAC? – pvg Jan 02 '17 at 00:20
  • netiface is the best if it has the info you need. If you must scrape I suggest using powershell and wmi, instead of cmd and ipconfig. – Stephen Rauch Jan 02 '17 at 00:30
  • 1
    @StephenRauch, ipconfig.exe or wmic.exe can be run directly from Python via `subprocess.Popen`. There's no need for the cmd shell; it should be avoided as much as possible, especially if the command is based on user input. Also, wmic.exe can output as reliable XML, which is a suitable alternative for people who don't know PowerShell, or who want to avoid its startup lag (still noticeable in Windows 10, IMO -- it's a beast of a shell). – Eryk Sun Jan 02 '17 at 00:57

3 Answers3

4

You can retrieve the windows interface information using wmic in XML format, and then convert the xml to a dict. From the resulting dict you can gather any needed information:

def get_interfaces_with_mac_addresses(interface_name_substring=''):
    import subprocess
    import xml.etree.ElementTree

    cmd = 'wmic.exe nic'
    if interface_name_substring:
        cmd += ' where "name like \'%%%s%%\'" ' % interface_name_substring
    cmd += ' get /format:rawxml'

    DETACHED_PROCESS = 8
    xml_text = subprocess.check_output(cmd, creationflags=DETACHED_PROCESS)

    # convert xml text to xml structure
    xml_root = xml.etree.ElementTree.fromstring(xml_text)

    xml_types = dict(
        datetime=str,
        boolean=lambda x: x[0].upper() == 'T',
        uint16=int,
        uint32=int,
        uint64=int,
        string=str,
    )

    def xml_to_dict(xml_node):
        """ Convert the xml returned from wmic to a dict """
        dict_ = {}
        for child in xml_node:
            name = child.attrib['NAME']
            xml_type = xml_types[child.attrib['TYPE']]

            if child.tag == 'PROPERTY':
                if len(child):
                    for value in child:
                        dict_[name] = xml_type(value.text)
            elif child.tag == 'PROPERTY.ARRAY':
                if len(child):
                    assert False, "This case is not dealt with"
            else:
                assert False, "This case is not dealt with"

        return dict_

    # convert the xml into a list of dict for each interface
    interfaces = [xml_to_dict(x)
                  for x in xml_root.findall("./RESULTS/CIM/INSTANCE")]

    # get only the interfaces which have a mac address
    interfaces_with_mac = [
        intf for intf in interfaces if intf.get('MACAddress')]

    return interfaces_with_mac

This function will return a list of dicts, the desired information can be returned from the resulting dicts:

for intf in get_interfaces_with_mac_addresses('Realtek'):
    print intf['Name'], intf['MACAddress']
Shane
  • 489
  • 4
  • 9
Stephen Rauch
  • 47,830
  • 31
  • 106
  • 135
  • @eryksun, thanks for the tip re:wmic, I learned something today. – Stephen Rauch Jan 02 '17 at 02:50
  • `os.popen` uses the cmd shell and doesn't hide the console window, which is annoying in a GUI app. You can instead use `DETACHED_PROCESS = 8;` `xml_text = subprocess.check_output('wmic.exe nic where "name like \'Realtek%\'" get MACAddress /format:rawxml', creationflags=DETACHED_PROCESS)`. Running detached means Windows won't create a new console for wmic when the parent is a GUI app. I added a where clause and a get field, as an example of not retrieving all info about all interfaces. – Eryk Sun Jan 02 '17 at 04:29
  • @eryksun, thanks again. I added the subprocess call and the interface name match. I left off the 'just get the macAddr', because on my machine it returned multiple addresses for 'Intel'. Hopefully, if the OP returns he can get out of it what he needs. – Stephen Rauch Jan 02 '17 at 05:30
  • Hi , i tried to copy & paste the code above, save it in a file "testmac.py" and put it under "testpackage" folder. i create an empty __init__.py file and put there too. Then i copy the whole "testpackage" folder to python installed directory "...\python\Lib\site-packages". After that i create a file "callmodule.py" , which contain : intfs = get_mac_addresses('Realtek') - Then i open a command prompt, try to call that file using : python callmodule.py , but i get error message : "NameError : name 'get_mac_addresses' is not define. What is wrong ? I use python 2.7.x . Thanks. – thomasberg Jan 06 '17 at 05:12
  • With the described file structure, you need `from testpackage.testmac import get_mac_addresses`. Also you need `__init__.py` not `init.py`. But much easier would be to just put the `get_mac_addresses` code directly into your script to test. After you are happy, then you can figure out how to get into a package or module. – Stephen Rauch Jan 06 '17 at 07:55
  • Thanks Stephen. I changed the import part, and now i can get the result. But, it is the whole XML data `[{'Index': 1, 'PowerManagementSupported': ... etc ...` , not only the Mac Address part. If I tried to import the `xml_to_dict` after importing the `get_mac_addresses` , i got error (import error). What must i do ? – thomasberg Jan 07 '17 at 06:54
  • The returned data is a list of dicts because it is possible that more than one interface could meet the criteria. You need to look into the list to find the interface you want (there maybe one, zero or many). See edited code above for looping through the returned data. – Stephen Rauch Jan 07 '17 at 18:28
3

the python3 script below is based on the Stephen Rauch one (thanks for the wmic utility pointer it's really handy)

it retrieves only the IP and active interfaces from the computer, handles fields with multiple values (several ips/masks or gateways on one nic), creates IPv4Iinterface or v6 python objects from ip/mask, and ouputs a list with one dict per nic.

#python3
from subprocess import check_output
from xml.etree.ElementTree import fromstring
from ipaddress import IPv4Interface, IPv6Interface

def getNics() :

    cmd = 'wmic.exe nicconfig where "IPEnabled  = True" get ipaddress,MACAddress,IPSubnet,DNSHostName,Caption,DefaultIPGateway /format:rawxml'
    xml_text = check_output(cmd, creationflags=8)
    xml_root = fromstring(xml_text)

    nics = []
    keyslookup = {
        'DNSHostName' : 'hostname',
        'IPAddress' : 'ip',
        'IPSubnet' : '_mask',
        'Caption' : 'hardware',
        'MACAddress' : 'mac',
        'DefaultIPGateway' : 'gateway',
    }

    for nic in xml_root.findall("./RESULTS/CIM/INSTANCE") :
        # parse and store nic info
        n = {
            'hostname':'',
            'ip':[],
            '_mask':[],
            'hardware':'',
            'mac':'',
            'gateway':[],
        }
        for prop in nic :
            name = keyslookup[prop.attrib['NAME']]
            if prop.tag == 'PROPERTY':
                if len(prop):
                    for v in prop:
                        n[name] = v.text
            elif prop.tag == 'PROPERTY.ARRAY':
                for v in prop.findall("./VALUE.ARRAY/VALUE") :
                    n[name].append(v.text)
        nics.append(n)

        # creates python ipaddress objects from ips and masks
        for i in range(len(n['ip'])) :
            arg = '%s/%s'%(n['ip'][i],n['_mask'][i])
            if ':' in n['ip'][i] : n['ip'][i] = IPv6Interface(arg)
            else : n['ip'][i] = IPv4Interface(arg)
        del n['_mask']

    return nics

if __name__ == '__main__':
    nics = getNics()
    for nic in nics :
        for k,v in nic.items() :
            print('%s : %s'%(k,v))
        print()

import it or use it from a cmd prompt :

python.exe getnics.py

will output something like :

hardware : [00000000] Intel(R) Centrino(R) Wireless-N 2230 Driver
gateway : ['192.168.0.254']
ip : [IPv4Interface('192.168.0.40/24'), IPv6Interface('fe80::7403:9e12:f7db:60c/64')]
mac : xx:xx:xx:xx:xx:xx
hostname : mixer

hardware : [00000002] Killer E2200 Gigabit Ethernet Controller
gateway : ['192.168.0.254']
ip : [IPv4Interface('192.168.0.28/24')]
mac : xx:xx:xx:xx:xx:xx
hostname : mixer

tested with windows10. I have some doubts about the mac adress field, with VM or spoofing cases for example, it seems wmic returns one string only, and not an array.

jerome
  • 183
  • 2
  • 14
  • How can I print the script output to a variable to use within my script? Thanks – Stryker Apr 11 '18 at 21:21
  • actually the function getNics() returns a dict variable ( see nics under the __main__ part). so you can type nics[0]['hostname'] or nics[0]['ip'] for example – jerome Jul 23 '18 at 02:03
0
# Python 3.10.4
from getmac import get_mac_address

mac_address = get_mac_address(ip='192.168.1.20').upper()
user3458330
  • 973
  • 6
  • 3
  • What is `getmac`? It isn't part of the standard library in Python 3.10.4, or any other version. If you're going to recommend third-party modules, please be explicit about it. See [answer]. – ChrisGPT was on strike Apr 15 '22 at 13:05