Skip to content

Instantly share code, notes, and snippets.

@mrpnelson
Last active November 16, 2022 15:22
Show Gist options
  • Save mrpnelson/c65302efed6c18300fb28c8da87bc69a to your computer and use it in GitHub Desktop.
Save mrpnelson/c65302efed6c18300fb28c8da87bc69a to your computer and use it in GitHub Desktop.
Mac WiFi Preferred Network Refresh Script
#!/bin/bash
# ------------------------------------------------------------------------------------------
# May 4, 2021 Update
# This is maintained here for reference, but it seems like the networksetup script
# is capable of doing this, at least in Big Sur. I haven't tested this on older versions.
# See https://gist.github.com/mrpnelson/c65302efed6c18300fb28c8da87bc69a#gistcomment-3731567
# for details on using the native tooling
# ------------------------------------------------------------------------------------------
# A tool to set an existing remembered SSID as the most preferred network by script.
# Copyright (C) 2019 Paul Nelson
# This program is free software: you can redistribute it and/or modify it under the
# terms of the GNU General Public License as published by the Free Software Foundation,
# version 3.
# This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
# without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See the GNU General Public License for more details.
# https://www.gnu.org/licenses/gpl-3.0.html
# To run: mac_wipri "SSID"
# Wrap the SSID in double quotes.
# Requires sudo/administrative rights
if [ -z "$1" ]; then
echo "No SSID name supplied. Exiting.";
exit;
fi
SSIDNAME=$1
NETFILE="/Library/Preferences/\
SystemConfiguration/com.apple.airport.preferences.plist"
#Get SSID for desired network
SSIDID=`xpath $NETFILE "\
(//dict/dict/dict/string[text()='$SSIDNAME'])\
[1]/parent::dict/preceding-sibling::key[1]" \
2>/dev/null | sed -e 's/key/string/g'`
# Make sure the desired SSID exists in the list.
if [ -z "$SSIDID" ]; then
echo "No matching SSID value can be found in $NETFILE. Exiting.";
exit;
fi;
# Get the current preferred network list
ORDERLIST=`xpath $NETFILE "(//dict/key[text()='PreferredOrder'])\
[1]/following-sibling::array[1]" 2>/dev/null | sed '1d;$d'`
# Count number of current entries in the network list
NUMENTRIES=`echo "$ORDERLIST" | wc -l | sed -e 's/ //g'`
echo "There are $NUMENTRIES entries in preferred network list."
# Don't make changes if it's the only network
if [ "$NUMENTRIES" -le "1" ]; then
echo "Only one network, so no need to make priority changes. Exiting.";
exit;
fi;
# Get the row number for the first preferred network entry
PREFTOP=`/usr/bin/grep -n -x "$ORDERLIST" $NETFILE | \
cut -f1 -d: | head -n 1`
echo "Preferred network list starts at row $PREFTOP in $NETFILE."
# Get the row number of network we want to set as highest priority
SSIDTOMOVE=`echo "$ORDERLIST" | /usr/bin/grep -n $SSIDID | cut -f1 -d:`
if [ "$SSIDTOMOVE" -eq "1" ]; then
echo "$SSIDNAME is already top of the priority list. Exiting.";
exit;
fi
# Print the SSID and current row number for the entry
echo "$SSIDNAME is position number $SSIDTOMOVE in preferred ordering list."
# Now actually make the changes to the file
echo "Moving $SSIDNAME to top of preferred network list..."
printf %s\\n $(( PREFTOP - 1 + SSIDTOMOVE ))m$(( PREFTOP - 1)) w q \
| ed -s $NETFILE
# With knowledge of the starting row you could add additional networks
# and handle relative priorities for additional networks if desired.
# Verify that the change worked by checking current position in list
ORDERLIST=`xpath $NETFILE "(//dict/key[text()='PreferredOrder'])\
[1]/following-sibling::array[1]" 2>/dev/null | sed '1d;$d'`
NEWLOCATION=`echo "$ORDERLIST" | /usr/bin/grep -n $SSIDID | cut -f1 -d:`
echo "$SSIDNAME is now at position number $NEWLOCATION in preferred network list"
@PhillyPhoto
Copy link

@dstranathan simpler seems better. It looks like these can be changed with the following command sequence. It also renders the other/old code unnecessary (and maybe it always was?).

# Remove the network first. The password in the keychain is decoupled from this entry in the list, so will persist.
# You'll need to know the SSID, network interface, and the network security type for the network.

networksetup -removepreferredwirelessnetwork en0 "<SSID_NAME>"

# Now add back the network at index 0. This works at least for WPA2, and presumably all other types:

networksetup -addpreferredwirelessnetworkatindex en0 "<SSID_NAME>" 0 WPA2

This won't work for 802.1x networks configured via config profile with things like certificates.

I think our best bet would be to keep going down this path and figure out how to grab the key/dict pair of the selected network and reorder it in the plist. I just wish I was more versed in python to help.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment