if I run
networksetup -setairportnetwork en0 myssid
it takes between 10 and 15 seconds.
If I manually click the Wi-Fi icon in the notification bar and select myssid, it's instant.
Alternatively, I'd love to be able to make an applescript that manually clicks to change Wi-Fi networks, but I can't find a good example, everyone just says "use networksetup".
Answer:
@CJK's solution works great, I'm using his second script that does the manual click. The first one works in most cases except where I'm trying to connect to an enterprise network that uses a certificate. For some reason connecting this way doesn't work in that case. But in all other cases both scripts work great.
Best Answer
I note what @Allan has stated in his comment below your question.
Whilst I don't get a delay as long as 10-15 seconds using the commandline, I do find it demonstrably and consistently slower (by a few seconds) than clicking the WiFi icon. I don't know the underlying operations performed by
networksetup
, but I'm wondering if it performs a network scan each and every time a request is made to join a new network, which may account for the delay. Network scanning times can be influenced by many factors, so this delay would likely vary between users in different environments. This is just hypothesis, though.I'll give you two scripts.
1. Service-scripting with AppleScriptObjC
The first script uses AppleScriptObjC to interface with the system directly and control the WiFi interface. A quick summary, which I expand on below:
networksetup
You would then call the
joinNetwork
handler from within your script like so:This script will be robust and reliable (barring any human error on my part, which I will correct if you find a bug I've overlooked during testing). It preferentially uses cached scan results to connect to networks; if none are available, or the specified SSID didn't appear when the scan results were last cached, it will perform a fresh network scan. Therefore, if my hypothesis about
networksetup
is a contributing factor, this script will be faster than the commandline on the majority of runs, but may take the same amount of time on the occasional run when forced to do a scan.One benefit is that, because you can specify a network password when calling the
joinNetwork
handler, you won't need to enter it manually when joining a new network.The SSID—specified by the
name
parameter—is case-insensitive in both scripts; the password, obviously, is not. The script above has elected to perform an entire phrase match on the SSID, i.e. "my net" will not ever join a network called "my network"; the script below has elected to do a fuzzy matching, i.e. "net" will potentially join "my net" or "my network".2. UI Scripting
This second script is actually the one you requested: it interfaces with the UI to click the WiFi menu icon and then select the network (if it appears in the list). A summary:
Scripts that try to control the UI are using a method called UI or GUI scripting. These are popular amongst and popularised by novice scripters, simply because these are the most commonly-found scripts on the internet. I won't go into it here too much other than to caution you against using scripts that rely on clicks and keystrokes—they're inherently fragile and unreliable even when well written, but most UI scripts (written by novices) are terribly written, which compounds the problem. There's almost always a better way to achieve the desired outcome.
That said, this is one of the few sorts of UI scripts that are perhaps an exception to my warning, and in my view, a pretty acceptable implementation. This is because it's targeting an aspect of the UI (a menu bar icon owned by the system) that is virtually guaranteed to always be accessible regardless of what window or desktop has focus, etc. The one situation where the script of this nature would potentially break is if the menu bar icon wasn't there (i.e. the user has specifically set a preference not to have the WiFi icon available); however, I've put a line in the script that checks for this, and performs a graceful exit in that situation.
This script appears to be the speediest implementation, which doesn't surprise me as it will be equal in speed to clicking the icon manually; but, it impresses me in that I can't think of many UI scripts that would end up out-performing an application- or service-targetted script. The network is joined almost instantly, provided the password is already saved in your keychain. On occasion, the network you'd expect to see in the menu list might not be there until the background scanning refreshes and the list updates. Therefore, I built in a 10-second period within which the script checks every half second to see if the menu item has appeared; if it doesn't, the script exits and you'll have to try again.
The drawback is the absence of a keychain password for a network will necessitate you needing to manually enter the password when asked for it. It is possible to script this using UI techniques as well, but this immediately makes the script highly susceptible to the issues I mentioned and then I, personally, wouldn't use it.
System info: AppleScript version: 2.7 System version: 10.13.6