How to modify script to account for OS X 10.10?

rlindenmuth
New Contributor III

The additional character in 10.10 has broken another script we use, but I'm not sure how to fix this one due to my limited scripting skills. I tried to remove the if statements referring to OS type since we have nothing older than 10.7 in use, and even they will be gone shortly, but I just ended up breaking the script in different ways.

The unmodified script that breaks on 10.10:

#!/bin/bash

AP_NAME="NETWORK"
AP_SEC="WPA2E"
INDX=0

AIRPORT=""
ALLINTERFACES=""

IFS='
'

SW_VER=`/usr/bin/sw_vers -productVersion`

if [ `echo "if(${SW_VER%.*}>=10.7)r=1;r"|/usr/bin/bc` -eq 1 ]; then
   APNAME="Wi-Fi"
else
   APNAME="AirPort"
fi

#
# Look for AirPort interface 
#

for intf in `/usr/sbin/networksetup -listnetworkserviceorder | grep "^(H"`; do
   IFS=':,)'
   set $intf
   if [[ ($2 =~ ${APNAME} ) ]]; then AIRPORT=$4; fi
done

if [ `echo "if(${SW_VER%.*}>=10.6)r=1;r"|/usr/bin/bc` -eq 1 ]; then
   RM_AP_CMD="/usr/sbin/networksetup -removepreferredwirelessnetwork ${AIRPORT} ${AP_NAME}"
   ADD_AP_CMD="/usr/sbin/networksetup -addpreferredwirelessnetworkatindex ${AIRPORT} ${AP_NAME} ${INDX} ${AP_SEC}"
else
   RM_AP_CMD="/usr/sbin/networksetup -removepreferredwirelessnetwork ${APNAME} ${AP_NAME}"
   ADD_AP_CMD="/usr/sbin/networksetup -addpreferredwirelessnetworkatindex ${APNAME} ${AP_NAME} ${INDX} ${AP_SEC}"
fi

# Remove Existing WiFi Profile
profileTest=$(/usr/bin/profiles -C -v | /usr/bin/awk -F: '/profileIdentifier: com.domain.network/{print $NF}')
if [ -n "$profileTest" ]; then
  echo "Found WiFi Profile installed."
  echo "Removing existing WiFi Profile"
  /usr/bin/profiles -R -v -p com.domain.network -z Tw0wMQWKy123
fi

# Remove Wireless LAN from Preferred List
echo "Removing Wireless LAN $AP_NAME from Preferred List"
eval ${RM_AP_CMD}

# Add Wireless LAN to the Preferred List
echo "Adding Wireless LAN $AP_NAME to Preferred List"
eval ${ADD_AP_CMD}

Thanks for any tips and guidance!

-Bob

1 ACCEPTED SOLUTION

mm2270
Legendary Contributor III

@rlindenmuth While you could add the code that @pwskura shows above, the only reason for even getting the OS version is because 10.6 and lower referred to wireless as "AirPort" and 10.7 and up changed it to "Wi-Fi" Because the script you're using is trying to manipulate the preferred wireless entries using the wi-fi port name instead of the device id, its required to go through all that to work. But I contend its not even necessary. You can try something like this below. What I'm doing here is figuring out what either the AirPort or Wi-Fi device id is, like en0 or en1 and using that instead, which is more reliable.

#!/bin/bash

AP_NAME="NETWORK"
AP_SEC="WPA2E"

## Simple one liner to get the device id for the Wireless port, i.e, en0 or en1, etc.
WirelessPort=$(/usr/sbin/networksetup -listallhardwareports | awk -F': ' '/AirPort|Wi-Fi/{getline; print $NF}')

## Remove Existing WiFi Profile
profileTest=$(/usr/bin/profiles -C -v | /usr/bin/awk -F: '/profileIdentifier: com.domain.network/{print $NF}')
if [ -n "$profileTest" ]; then
  echo "Found WiFi Profile installed."
  echo "Removing existing WiFi Profile"
  /usr/bin/profiles -R -v -p com.domain.network -z Tw0wMQWKy123
fi

## Remove Wireless LAN from Preferred List
echo "Removing Wireless LAN $AP_NAME from Preferred List"
/usr/sbin/networksetup -removepreferredwirelessnetwork ${WirelessPort} "${AP_NAME}"

## Add Wireless LAN to the Preferred List
echo "Adding Wireless LAN $AP_NAME to Preferred List"
/usr/sbin/networksetup -addpreferredwirelessnetworkatindex ${WirelessPort} "${AP_NAME}" 0 ${AP_SEC}

This script should basically do the same thing as your original one, but is much simpler.

View solution in original post

7 REPLIES 7

mm2270
Legendary Contributor III

These two lines are the issue:

if [ `echo "if(${SW_VER%.*}>=10.7)r=1;r"|/usr/bin/bc` -eq 1 ]; then

and

if [ `echo "if(${SW_VER%.*}>=10.6)r=1;r"|/usr/bin/bc` -eq 1 ]; then

In both cases its using bc (bash calculator) to compare the base OS version, in this case 10.10, against either 10.7 or 10.6 to see if its equal or greater to those respective values. The thing is, bc handles decimal numbers, so it sees 10.10 as just 10.1. Obviously 10.1 is not equal or greater to 10.6 or 10.7, so its setting some variables incorrectly (under 10.6, the Wi-Fi network was called "AirPort") and the rest of the script fails.

If you only need to use this script against Macs that are at OS X 10.7 and up, I don't see any need for either of these parts of the script. The whole script could be simplified if you have pretty recent OS X versions you manage.

rlindenmuth
New Contributor III

I tried to remark those out earlier but kept getting failures. I've removed all if statements and all lines referring to versions prior to 10.7 and this is the error:

Script result: Removing Wireless LAN NETWORK from Preferred List
Wi-Fi is not a Wi-Fi interface.
Error: Error obtaining wireless information.
Adding Wireless LAN NETWORK to Preferred List
Wi-Fi is not a Wi-Fi interface.
Error: Error obtaining wireless information.

I believe those errors are occurring when these lines are run in the script:

RM_AP_CMD="/usr/sbin/networksetup -removepreferredwirelessnetwork ${APNAME} ${AP_NAME}"
ADD_AP_CMD="/usr/sbin/networksetup -addpreferredwirelessnetworkatindex ${APNAME} ${AP_NAME} ${INDX} ${AP_SEC}"

I'm going to need to rewrite it from scratch to cut out the extraneous stuff. It will be a good way to better understand scripting as well.

pwskura
New Contributor

Bob, Here is a snippet that just splits the version string to make the math work:

#!/bin/sh

known_os="10"        # highest OS minor release supported, 10.10
bottom_os="5"        # lowest OS minor release supported, 10.5

#
# Get OS version and exit for unsupported releases
#
os_major=$(sw_vers -productVersion | awk -F '.' '{print $1}')
os_minor=$(sw_vers -productVersion | awk -F '.' '{print $2}')
if [[ "${os_minor}" -lt "${bottom_os}" || "${os_minor}" -gt "${known_os}" ]]; then
    printf "unsupported os $os_major.$os_minor
"
    exit 1
fi
printf "OS version is $os_major.$os_minor
"

Enjoy!
-Pete

mm2270
Legendary Contributor III

@rlindenmuth While you could add the code that @pwskura shows above, the only reason for even getting the OS version is because 10.6 and lower referred to wireless as "AirPort" and 10.7 and up changed it to "Wi-Fi" Because the script you're using is trying to manipulate the preferred wireless entries using the wi-fi port name instead of the device id, its required to go through all that to work. But I contend its not even necessary. You can try something like this below. What I'm doing here is figuring out what either the AirPort or Wi-Fi device id is, like en0 or en1 and using that instead, which is more reliable.

#!/bin/bash

AP_NAME="NETWORK"
AP_SEC="WPA2E"

## Simple one liner to get the device id for the Wireless port, i.e, en0 or en1, etc.
WirelessPort=$(/usr/sbin/networksetup -listallhardwareports | awk -F': ' '/AirPort|Wi-Fi/{getline; print $NF}')

## Remove Existing WiFi Profile
profileTest=$(/usr/bin/profiles -C -v | /usr/bin/awk -F: '/profileIdentifier: com.domain.network/{print $NF}')
if [ -n "$profileTest" ]; then
  echo "Found WiFi Profile installed."
  echo "Removing existing WiFi Profile"
  /usr/bin/profiles -R -v -p com.domain.network -z Tw0wMQWKy123
fi

## Remove Wireless LAN from Preferred List
echo "Removing Wireless LAN $AP_NAME from Preferred List"
/usr/sbin/networksetup -removepreferredwirelessnetwork ${WirelessPort} "${AP_NAME}"

## Add Wireless LAN to the Preferred List
echo "Adding Wireless LAN $AP_NAME to Preferred List"
/usr/sbin/networksetup -addpreferredwirelessnetworkatindex ${WirelessPort} "${AP_NAME}" 0 ${AP_SEC}

This script should basically do the same thing as your original one, but is much simpler.

rlindenmuth
New Contributor III

@mm2270 That worked perfectly! Thank you. This board is fantastic.

calumhunter
Valued Contributor

Unix, theres always 42 ways to do the same thing better

sean
Valued Contributor

Yeah, I got pretty board with trying to call interfaces and port names and so bothered to write a python script to pump it into a plist. This way all scripts requiring this kind of info can just call this script and then read the plist.

#!/usr/bin/env python

# plistlib is outdated, but we are only writing to this file with this script so it does not matter
# that it will not work with binary files.
# https://github.com/wooster/biplist

from SystemConfiguration import *
import plistlib
import os
import glob

interface_dict = {}
interface_list = []

plist_file = "/Library/Preferences/yourdomain.networklist.plist"

for interface in SCNetworkInterfaceCopyAll():
    interface_name = SCNetworkInterfaceGetLocalizedDisplayName(interface)
    hw_addr = SCNetworkInterfaceGetBSDName(interface)

    if interface_name == "Ethernet 1":
        interface_name = "Ethernet"

    if interface_name == "Wi-Fi":
        interface_name = "AirPort"

    interface_dict[interface_name] = hw_addr
    interface_list.append(hw_addr)

interface_dict["Ports"] = interface_list

plistlib.writePlist(interface_dict, plist_file)

This will pump out something like the following into /Library/Preferences/yourdomain.networklist.plist

Subsequently, all scripts can then just run 'defaults' to read this and the names will be the same regardless of OS.

MacBookPro Retina (with Ethernet adaptor connected):

{
    AirPort = en0;
    "Bluetooth DUN" = "Bluetooth-Modem";
    "Bluetooth PAN" = en4;
    Ports =     (
        "Bluetooth-Modem",
        en3,
        en0,
        en4,
        en1,
        en2,
        bridge0
    );
    "Thunderbolt 1" = en1;
    "Thunderbolt 2" = en2;
    "Thunderbolt Bridge" = bridge0;
    "Thunderbolt Ethernet" = en3;
}

MacPro:

{
    AirPort = en2;
    "Bluetooth DUN" = "Bluetooth-Modem";
    "Bluetooth PAN" = en3;
    Ethernet = en0;
    "Ethernet 2" = en1;
    FireWire = fw0;
    Ports =     (
        "Bluetooth-Modem",
        en0,
        en1,
        fw0,
        en2,
        en3
    );
}

Just change, add other if statements if you want to rename anything else.