@@ -503,139 +503,72 @@ func TestInterfaceAddrsWithNetsh(t *testing.T) {
503
503
}
504
504
}
505
505
506
- // check that getmac exists as a powershell command, and that it
507
- // speaks English.
508
- func checkGetmac (t * testing.T ) {
509
- out , err := runCmd ("getmac" , "/?" )
510
- if err != nil {
511
- if strings .Contains (err .Error (), "term 'getmac' is not recognized as the name of a cmdlet" ) {
512
- t .Skipf ("getmac not available" )
506
+ func contains (needle string , haystack []string ) bool {
507
+ for _ , v := range haystack {
508
+ if v == needle {
509
+ return true
513
510
}
514
- t .Fatal (err )
515
- }
516
- if ! bytes .Contains (out , []byte ("network adapters on a system" )) {
517
- t .Skipf ("skipping test on non-English system" )
518
511
}
512
+ return false
519
513
}
520
514
521
- func TestInterfaceHardwareAddrWithGetmac (t * testing.T ) {
522
- if isWindowsXP (t ) {
523
- t .Skip ("Windows XP does not have powershell command" )
524
- }
525
- checkGetmac (t )
526
-
515
+ func TestInterfaceHardwareAddrWithWmic (t * testing.T ) {
527
516
ift , err := Interfaces ()
528
517
if err != nil {
529
518
t .Fatal (err )
530
519
}
531
- have := make (map [string ]string )
520
+ goMacToName := make (map [string ]string )
532
521
for _ , ifi := range ift {
533
522
if ifi .Flags & FlagLoopback != 0 {
534
523
// no MAC address for loopback interfaces
535
524
continue
536
525
}
537
- have [ifi .Name ] = ifi .HardwareAddr . String ()
526
+ goMacToName [ifi .HardwareAddr . String () ] = ifi .Name
538
527
}
539
528
540
- out , err := runCmd ("getmac" , "/fo" , "list" , "/v" )
529
+ //wmic nic get MACAddress,NetConnectionID /format:csv
530
+ //
531
+ //Node,MACAddress,NetConnectionID
532
+ //SERVER-2008R2-V,,
533
+ //SERVER-2008R2-V,42:01:0A:F0:00:18,Local Area Connection
534
+ //SERVER-2008R2-V,42:01:0A:F0:00:18,Duplicate Adapter
535
+ //SERVER-2008R2-V,20:41:53:59:4E:FF,
536
+ out , err := exec .Command ("wmic" , "nic" , "get" , "MACAddress,NetConnectionID" , "/format:csv" ).CombinedOutput ()
541
537
if err != nil {
542
538
t .Fatal (err )
543
539
}
544
- // getmac output looks like:
545
- //
546
- //Connection Name: Local Area Connection
547
- //Network Adapter: Intel Gigabit Network Connection
548
- //Physical Address: XX-XX-XX-XX-XX-XX
549
- //Transport Name: \Device\Tcpip_{XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}
550
- //
551
- //Connection Name: Wireless Network Connection
552
- //Network Adapter: Wireles WLAN Card
553
- //Physical Address: XX-XX-XX-XX-XX-XX
554
- //Transport Name: Media disconnected
555
- //
556
- //Connection Name: Bluetooth Network Connection
557
- //Network Adapter: Bluetooth Device (Personal Area Network)
558
- //Physical Address: N/A
559
- //Transport Name: Hardware not present
560
- //
561
- //Connection Name: VMware Network Adapter VMnet8
562
- //Network Adapter: VMware Virtual Ethernet Adapter for VMnet8
563
- //Physical Address: Disabled
564
- //Transport Name: Disconnected
565
- //
566
- want := make (map [string ]string )
567
- group := make (map [string ]string ) // name / values for single adapter
568
- getValue := func (name string ) string {
569
- value , found := group [name ]
570
- if ! found {
571
- t .Fatalf ("%q has no %q line in it" , group , name )
572
- }
573
- if value == "" {
574
- t .Fatalf ("%q has empty %q value" , group , name )
575
- }
576
- return value
577
- }
578
- processGroup := func () {
579
- if len (group ) == 0 {
580
- return
581
- }
582
- tname := strings .ToLower (getValue ("Transport Name" ))
583
- if tname == "n/a" {
584
- // skip these
585
- return
586
- }
587
- addr := strings .ToLower (getValue ("Physical Address" ))
588
- if addr == "disabled" || addr == "n/a" {
589
- // skip these
590
- return
591
- }
592
- addr = strings .Replace (addr , "-" , ":" , - 1 )
593
- cname := getValue ("Connection Name" )
594
- want [cname ] = addr
595
- group = make (map [string ]string )
596
- }
540
+ winMacToNames := make (map [string ][]string )
597
541
lines := bytes .Split (out , []byte {'\r' , '\n' })
542
+
598
543
for _ , line := range lines {
599
- if len (line ) == 0 {
600
- processGroup ()
544
+ entry := strings .Split (string (line ), "," )
545
+ if len (entry ) != 3 || entry [1 ] == "MACAddress" {
546
+ // skip empty lines, header
601
547
continue
602
548
}
603
- i := bytes .IndexByte (line , ':' )
604
- if i == - 1 {
605
- t .Fatalf ("line %q has no : in it" , line )
549
+
550
+ mac , name := strings .ToLower (entry [1 ]), strings .TrimSpace (entry [2 ])
551
+ if mac == "" || name == "" {
552
+ // skip non-physical devices
553
+ continue
606
554
}
607
- group [string (line [:i ])] = string (bytes .TrimSpace (line [i + 1 :]))
555
+
556
+ winMacToNames [mac ] = append (winMacToNames [mac ], name )
608
557
}
609
- processGroup ()
610
558
611
- dups := make (map [string ][]string )
612
- for name , addr := range want {
613
- if _ , ok := dups [addr ]; ! ok {
614
- dups [addr ] = make ([]string , 0 )
615
- }
616
- dups [addr ] = append (dups [addr ], name )
559
+ if len (goMacToName ) != len (winMacToNames ) {
560
+ t .Errorf ("go interface count (%d, %v) differs from wmic count (%d, %v)" , len (goMacToName ), goMacToName , len (winMacToNames ), winMacToNames )
617
561
}
618
562
619
- nextWant:
620
- for name , wantAddr := range want {
621
- if haveAddr , ok := have [name ]; ok {
622
- if haveAddr != wantAddr {
623
- t .Errorf ("unexpected MAC address for %q - %v, want %v" , name , haveAddr , wantAddr )
624
- }
625
- continue
626
- }
627
- // We could not find the interface in getmac output by name.
628
- // But sometimes getmac lists many interface names
629
- // for the same MAC address. If that is the case here,
630
- // and we can match at least one of those names,
631
- // let's ignore the other names.
632
- if dupNames , ok := dups [wantAddr ]; ok && len (dupNames ) > 1 {
633
- for _ , dupName := range dupNames {
634
- if haveAddr , ok := have [dupName ]; ok && haveAddr == wantAddr {
635
- continue nextWant
636
- }
563
+ for mac , name := range goMacToName {
564
+ // Windows appears to associate multiple names to a single MAC
565
+ // Consider it a success if one of those names was found
566
+ if cmdNames , ok := winMacToNames [mac ]; ok {
567
+ if contains (name , cmdNames ) {
568
+ continue
637
569
}
638
570
}
639
- t .Errorf ("getmac lists %q, but it could not be found among Go interfaces %v" , name , have )
571
+
572
+ t .Errorf ("go found interface (name: %s, mac: %s) not found by wmic (%v)" , name , mac , winMacToNames )
640
573
}
641
574
}
0 commit comments