Preferred Wireless Network priority

cbrewer
Valued Contributor II

When importing an 802.1x system wireless profile, anybody know a way to make it go to the top of the preferred networks list? By default it seems to be putting it at the bottom of the list. I know how to remove it by running 'networksetup -removepreferredwirelessnetwork' but putting it back into the list seems to be more of a challenge.

31 REPLIES 31

bbass
Contributor

I have not found a way take an existing SSID and put it at the top of the list. In order to get that to work, I've had to remove it first and then re-add it with a "0" priority.

I've got a script that looks like this:

#!/bin/bash

wifi=/usr/sbin/networksetup -listallhardwareports | grep -A 1 Wi-Fi | grep Device | awk '{print $2}'
SSIDcheck=networksetup -listpreferredwirelessnetworks $wifi | grep yourSSID

if [ $SSIDcheck = "yourSSID" ]; then /usr/sbin/networksetup -removepreferredwirelessnetwork $wifi yourSSID /usr/sbin/networksetup -addpreferredwirelessnetworkatindex $wifi yourSSID 0 WPA2E
else /usr/sbin/networksetup -addpreferredwirelessnetworkatindex $wifi yourSSID 0 WPA2E
fi
exit 0

----

There are probably more efficient ways of doing this but this seems to work fine in our environment.

cbrewer
Valued Contributor II

The issue with using '/usr/sbin/networksetup -addpreferredwirelessnetworkatindex $wifi yourSSID 0 WPA2E' is that once it adds the network back in, it is no longer tied to my 802.1x system profile.

cbrewer
Valued Contributor II

The root of my problem is that adding a wireless configuration profile adds the network to the bottom of the machine's wireless list. This seems backward. In 10.6 importing an 802.1x configuration would put the network at the top of the list.

techmchs
New Contributor III

Did you figure this out?

We are having the same issue.. seems worse after 10.8.2

Our wireless network set in configuration profile is always last in line...

Sanchi
Contributor

@cbrewer Check out this github: https://gist.github.com/pudquick/fcbdd3924ee230592ab4

I know its an old post but....

My issue similar to yours is that I had a WiFi network set up as a configuration profile but the client Macs would sometimes jump on other WiFi networks in the building. We have 4 internal networks where I work.

The python script by Pudquick stuck my preferred network to the top of the list so the Mac will default to it when searching for a network. Before my preferred network was at the bottom of the list as seems to be the case with WiFi configuration profiles - shouldn't be like that but it is for them moment until Apple make a change.

K0ss
New Contributor

I had a similar issue, we have populated 802.1x settings for users and need to set SSID at top of the list.
We deleted all existing SSID corporate (like guest and production SSID`s) uses command

networksetup -removepreferredwirelessnetwork $hardwareport $SSIDname

In this case existing Wi-Fi network will removed from preferred networks (but credentials not deleted from keychain).
User will be able to connect to this deleted SSID (without password input), and your SSID which was installed from 802.1x setting will has preferred level.

mmacpherson
New Contributor II

Just curious if anyone has found a solution for this? I too am facing the same problem.

jason_d
New Contributor III

This python script worked for me: https://gist.github.com/pudquick/fcbdd3924ee230592ab4

mm2270
Legendary Contributor III

I've also used the python script mentioned above, with great success. It works perfectly and doesn't involve any wacky scripting magic, like what we had been trying to use before.

sdagley
Esteemed Contributor II

Here's a tweaked version of pudquick's script that uses an array of preferred SSIDs rather than hard coding a certain number (this way you don't need additional edits to the script when you change the SSIDs list):

#!/usr/bin/python

# As written, this requires the following:
# - OS X 10.6+ (has been reported working through 10.12.3)
# - python 2.6 or 2.7 (for collections.namedtuple usage, should be fine as default python in 10.6 is 2.6)
# - pyObjC (as such, recommended to be used with native OS X python install)

# Run with root

import objc, ctypes.util, os.path, collections
from Foundation import NSOrderedSet

# List of preferred SSIDs in priority order - edit/add/delete as needed
PreferredSSIDs = ["SSID_1", "SSID_2", "SSID_3"]

def load_objc_framework(framework_name):
    # Utility function that loads a Framework bundle and creates a namedtuple where the attributes are the loaded classes from the Framework bundle
    loaded_classes = dict()
    framework_bundle = objc.loadBundle(framework_name, bundle_path=os.path.dirname(ctypes.util.find_library(framework_name)), module_globals=loaded_classes)
    return collections.namedtuple('AttributedFramework', loaded_classes.keys())(**loaded_classes)

# Load the CoreWLAN.framework (10.6+)
CoreWLAN = load_objc_framework('CoreWLAN')

# Load all available wifi interfaces
interfaces = dict()
for i in CoreWLAN.CWInterface.interfaceNames():
    interfaces[i] = CoreWLAN.CWInterface.interfaceWithName_(i)

# Repeat the configuration with every wifi interface
for i in interfaces.keys():
    # Grab a mutable copy of this interface's configuration
    configuration_copy = CoreWLAN.CWMutableConfiguration.alloc().initWithConfiguration_(interfaces[i].configuration())
    # Find all the preferred/remembered network profiles
    profiles = list(configuration_copy.networkProfiles())
    # Grab all the SSIDs, in order
    SSIDs = [x.ssid() for x in profiles]
    # Loop through PreferredSSIDs list in reverse order sorting each entry to the front of profiles array so it
    # ends up sorted with PreferredSSIDs as the first items.
    # Order is preserved for other SSIDs, example where PreferredSSIDs is [ssid3, ssid4]:
    #    Original: [ssid1, ssid2, ssid3, ssid4]
    #   New order: [ssid3, ssid4, ssid1, ssid2]
    for aSSID in reversed(PreferredSSIDs):
        profiles.sort(key=lambda x: x.ssid() == aSSID, reverse=True)
    # Now we have to update the mutable configuration
    # First convert it back to a NSOrderedSet
    profile_set = NSOrderedSet.orderedSetWithArray_(profiles)
    # Then set/overwrite the configuration copy's networkProfiles
    configuration_copy.setNetworkProfiles_(profile_set)
    # Then update the network interface configuration
    result = interfaces[i].commitConfiguration_authorization_error_(configuration_copy, None, None)

ben_hertenstein
Release Candidate Programs Tester

FWIW, this worked for me a MacOS Mojave (10.14) @sdagley

sdagley
Esteemed Contributor II

Thanks for the update @ben.hertenstein.

MatG
Contributor III

Seems Catalina is not happy with this script, any alternatives?

sdagley
Esteemed Contributor II

@MatG I'd suggest using Feedback Assistant to ask about this as scripted management of Wi-Fi configurations is not that uncommon.

KrisMallory
New Contributor III

@MatG Catalina stopped shipping with Python installed. Might that be the issue? I haven't looked into it yet, just a thought.

clint5047
New Contributor III

@KrisMallory depreciated != removed.
Catalina still has Python 2.7 installed.

pete_c
Contributor III

FYI I just tested this successfully on 10.13.6, but only when hard-coding SSID values into the script - when passing parameters $4, $5, $6 instead, the script did not reorder the existing networks.

paulr4
New Contributor

I'll throw this implementation using a Bash shell script into the ring as a slightly different approach. Hopefully it's useful to someone!

Eigger
Contributor III

@sdagley does your script work at startup? Or I need to run this as a Login Script per user?

sdagley
Esteemed Contributor II

@Eigger I usually ran this script on a Recurring Check-In trigger with the Frequency set to once a day

Eigger
Contributor III

Thanks @sdagley I have an ongoing Login and Logout trigger. I added the following script also to connect the client to the Top Preferred Network after the re-order. Its working great for us so far, thank you!

# Power cycle Wireless Interface to connect to the Top Preferred Network
import os 
os.system("networksetup -setairportpower airport off")
os.system("networksetup -setairportpower airport on")

jameson
Contributor II

@sdagley I used you above script for selecting wifi order. It works fine - but issue I have is that even I have our 802.1x in the top, it does not connect to it - also not after restart
If I manually pick it it connects so it works. I am running it in Mojave - any idea ?

sdagley
Esteemed Contributor II

@jameson Just re-ordering shouldn't force a connection, but it's odd it doesn't re-connect after a restart. What if you turn Wi-Fi off and back on? Does that make it reconnections to your 802.1x network when it's at the top of the priority list?

jameson
Contributor II

Seems like there is another issue. If the wifi network has not been connected before (which is not have on any clients) it will not be listed in the arrangement and will now show in the list. Both tried on Mojave and Catalina

sdagley
Esteemed Contributor II

@jameson The script does not add any SSIDs to the Preferred Networks list, it simply makes the SSIDs you identify the 1st ones in that list. You have to configure the Mac for your Wi-Fi network first.

GabeShack
Valued Contributor III

So question, does this script interrupt the network connection as it sets a priority? IE does it take you offline and then back online?

Gabe Shackney
Princeton Public Schools

Gabe Shackney
Princeton Public Schools

sdagley
Esteemed Contributor II

@gshackney It shouldn't

luke_reagor
Contributor II

Any word on this working with Big Sur?

dstranathan
Valued Contributor II

@luke.reagor I have it running on both Big Sur 11.3.1 and Catalina 10.15.7 (with native/old Python 2.7)

This script doesn't handle missing SSIDs. Example:

I populated the variables (The 'PreferredSSIDs' array) with fake (non-existent) SSIDs, and the script exits cleanly as if it actually moved the bogus SSIDs up/down in the 'Preferred Network' list. Has anyone else tested this?

Has anyone added logic to verify the target SSID(s) and exit with an error if the SSIDs aren't in the 'Preferred Network' list? Example:

Example: “Error: The SSID ‘preferred_SSID’ was not located in the Preferred Networks list.”

Note: I'm using Mike Lynns original script version (https://gist.github.com/pudquick/fcbdd3924ee230592ab4#file-reorder_wifi_alt-py)

Also a reminder to those using 802.1x for Wi-fi: Don't use the networksetup tool in a shell script to add/delete SSIDs to manage your 'Preferred Network' SSID list, as it may break your corporate 802.1x settings and/or Keychain cert entries. Use python (like the script above) that can make macOS API calls to move the SSIDs order in the list.

el2493
Contributor III

Does anyone have a solution that works with networks labeled as WPA2/WPA3 Enterprise? `networksetup` only seems to support up to wpa2e, and while I am able to connect to a WPA2/WPA3 Enterprise network if it's added back as WPA2 Enterprise, it doesn't seem like a good idea to be changing the security when adding the network back.

I had been using the python script linked above (by sdagley in 2017) and it works, but I'm trying to move away from python since in 12.3 it won't be part of macOS. I tried converting the script to python3 but got hung up on the line:

`return collections.namedtuple('AttributedFramework', loaded_classes.keys())(**loaded_classes)`

From what I could find, in python3 loaded_classes.keys() includes items that start with _ (underscores), while with python2 running the same command doesn't. The problem seems to be namedtuple doesn't play well with underscores, but I don't know enough about python3 to figure out how to account for it. It's also possible there'd be problems down the line with other parts of the script, but I can't get past that.

I'm using the macadmins python3, so it's able to import all the modules at the top of the script (that may not be the case for other python3 packages).

el2493
Contributor III

I found a solution for python3, based off https://gist.github.com/pudquick/fcbdd3924ee230592ab4. Check the comments for the changes that need to be made to the script for python3.