Connect to WiFi using AppleScript

Discussion in 'Mac Programming' started by Ipodize, Feb 19, 2011.

  1. Ipodize macrumors member

    Ipodize

    #1
    I'd like to make a simple AppleScript (or XCode, doesn't really matter as long as i can compile it into a Mac application) utility that connects to a WPA network automatically for me. Anyone have any ideas as to how it could work? I've tried some stuff from this page: http://hints.macworld.com/article.php?story=20060921045743404 but can't figure out how to find the name of the wifi menu bar item. If you have any ideas as to how i could do it a different way, please let me know. Thanks!
     
  2. McGordon, Feb 20, 2011
    Last edited: Feb 20, 2011

    McGordon macrumors member

    Joined:
    Dec 28, 2010
    Location:
    Scotland
    #2
    To find out the name of the menu items, you need a tool called UIElementInspector, or the newer Accessibility Inspector, which can be found here:

    /Developer/Applications/Utilities/Accessibility Tools/Accessibility Inspector.app

    ... if you have the latest developer tools installed. I can't find a simple download link of UIElementInspector, but its available as sample code to compile yourself, which again would require developer tools installed.

    These tools display the names of all the menus, menu items, buttons, etc to let you write UI Applescripts. You just mouse over a UI element anywhere on the screen and it shows you all the details in a window.

    I don't have wireless on this mac, so can't get the names of the menu for you.

    I've done one for Bluetooth which works for me here on Snow Leopard 10.6.6:

    Code:
    tell application "System Events"
       tell process "SystemUIServer"
          tell menu bar 1
             set menuExtras to (value of attribute "AXChildren")
             tell menuExtras
                set bluetooth to (first item whose (value of attribute "AXDescription") contains "bluetooth")
             end tell
             tell bluetooth
                perform action "AXPress"
                tell menu 1
                   if name of menu item 1 ends with "Off" then
                      click menu item "Turn Bluetooth On"
                   else
                      -- just close the menu if Bluetooth is already on
                      tell bluetooth to perform action "AXPress"
                   end if
                end tell
             end tell
             
          end tell
       end tell
    end tell
    
    
    Which is taken from coolsoldier's post here:
    http://hints.macworld.com/article.php?story=20060921045743404

    Edit:
    Ok, tried this on an iBook with 10.4.11 Tiger and it works to turn Airport on. Selecting a network would require you to know the name of it and I'll leave that up to you.
    Code:
    tell application "System Events"
       tell process "SystemUIServer"
          tell menu bar 1
             set menuExtras to (value of attribute "AXChildren")
             set airport to -1
             repeat with aMenu in menuExtras
                tell aMenu
                   if value of attribute "AXDescription" contains "AirPort Menu Extra" then
                      set airport to aMenu
                      exit repeat
                   end if
                end tell
             end repeat
             
             if airport is -1 then
                display dialog "Could not find AirPort Menu Extra"
             else
                tell airport
                   perform action "AXPress"
                   tell menu 1
                      if name of menu item 1 ends with "Off" then
                         click menu item "Turn Airport On"
                      else
                         -- just close the menu if airport is already on
                         tell airport to perform action "AXPress"
                      end if
                   end tell
                end tell
             end if
          end tell
       end tell
    end tell
    
     
  3. Ipodize, Feb 20, 2011
    Last edited: Feb 20, 2011

    Ipodize thread starter macrumors member

    Ipodize

    #3
    Thanks! I do have developer tools installed, and this script works fine, with a small modification (I'm on 10.5.8, and the first menu item for me is airport's status, eg. "Airport Off", and isn't clickable. To turn airport on, you need to click the item below which, if Airport is off, is "Turn Airport On" and, if Airport is on, is "Turn Airport Off".) To get the script to work i just modified this:

    Code:
    if name of menu item 1 ends with "Off" then
    click menu item "Turn Airport On"
    
    into this:

    Code:
    if name of menu item 2 ends with "On" then
    click menu item "Turn Airport On"
    
    The thing is, because the network I'd like to connect to has a hidden SSID, the network doesn't display on the list (even though I've already connected to it a quintillion times, and I've clicked "Remember this network" pretty much all of those times...) so i need to re-enter the 25-character password every time i wake my mac up, which is annoying. What i'd need to do in Applescript is select the "Join Other Network..." menu item (which for some reason doesn't work with the code " click menu item "Join Other Network" ", here's the Accessibility Inspector output from hovering over it:

    Code:
    <AXApplication: “SystemUIServer”>
     <AXMenuBar>
    
    Attributes:
       AXRole:  “AXMenuBar”
       AXRoleDescription:  “menu bar”
       AXChildren:  “<array of size 2>”
       AXParent:  “<AXApplication: “SystemUIServer”>”
       AXEnabled:  “true”
       AXPosition:  “x=0 y=0”
       AXSize:  “w=1440 h=22”
       AXSelectedChildren (W):  “<array of size 0>”
       AXVisibleChildren:  “<array of size 2>”
       AXTitleUIElement:  “(null)”
    
    Actions:
       AXCancel - cancel

    ,i posted a screenshot of the error below), then enter the SSID, then select "WPA Personal" in the dropdown menu, then select the password field, then enter the password, then press OK... which could get a bit difficult for an Applescript newbie like me :rolleyes:

    I'll see if i can get it to work. Thanks again for your effort!
     

    Attached Files:

  4. McGordon macrumors member

    Joined:
    Dec 28, 2010
    Location:
    Scotland
    #4
    If that works for you then that's all that matters. Did you try it first? The first one checks for the status in the first non-selectable menu item "Airport Off", it doesn't try to click it. Your one checks for the "On" at the end of "Turn Airport On", which should work too.

    Notice the difference between the menu item name and your applescript command. You have to type those full stops at the end so it matches exactly.

    Applescript can be a pain, especially UI scripting where the names, positions and types of the elements changes with different versions of OS X. It seems like we're in different time zones, so this is going a bit slowly.
     
  5. chown33 macrumors 604

    Joined:
    Aug 9, 2009
    #5
    If it's your wireless network, then give it a non-empty SSID.

    The network isn't any more secure for being nameless. Attackers can still see it, and still attack it using the BSSID:
    http://en.wikipedia.org/wiki/Service_set_(802.11_network)#Security_gains_of_SSID_hiding
    "Unfortunately, turning off the broadcast of the SSID may lead to a false sense of security. The method discourages only casual wireless snooping, but does not stop a person trying to attack the network."​
     
  6. McGordon macrumors member

    Joined:
    Dec 28, 2010
    Location:
    Scotland
    #6
    Here's the problem:

    click menu item "Join Other Network"

    Should be:

    click menu item "Join Other Network..."

    BUT that's not three full stops, it's an ellipsis character, ONE character.
    Unfortunately, I'm on my phone just now so can't type it in. I'll try later.

    That was what I noticed on 10.4 where the menu item was "Other..."
     
  7. Ipodize, Feb 21, 2011
    Last edited by a moderator: Feb 22, 2011

    Ipodize thread starter macrumors member

    Ipodize

    #7
    I'm in Australia, so yes, we are in different time zones.

    The network isn't mine, I talked to the owner but he reasons that, as far as he knows, no one would bother to launch a proper attack on the network ( it's just a home network ) and the only people who know about the networks existence are friends and family who have no idea how to connect to a network, let alone hack one ;)

    I'm not sure if I entirely accept that reasoning, but it isn't my network, so that's the end of it (according to the network owner)

    That makes sense! I'd already tried adding three full stops, but it didn't work. Here's some updated code that clicks on "Join Other Network…" and types in the SSID:
    Code:
    tell application "System Events"
    	tell process "SystemUIServer"
    		tell menu bar 1
    			set menuExtras to (value of attribute "AXChildren")
    			set airport to -1
    			repeat with aMenu in menuExtras
    				tell aMenu
    					if value of attribute "AXDescription" contains "AirPort Menu Extra" then
    						set airport to aMenu
    						exit repeat
    					end if
    				end tell
    			end repeat
    			
    			if airport is -1 then
    				display dialog "Could not find AirPort Menu Extra"
    			else
    				tell airport
    					perform action "AXPress"
    					tell menu 1
    						if name of menu item 2 ends with "On" then
    							click menu item "Turn Airport On"
    						else
    							-- just close the menu if airport is already on
    							click menu item "Join Other Network…"
    							keystroke "SSID"
    						end if
    					end tell
    				end tell
    			end if
    		end tell
    	end tell
    end tell
    Now I just need to select "WPA Personal" in the dropdown and then enter the password (which is just as easy as entering the SSID, as after I select WPA Personal, the password box automatically gets focused) and press the "Join" button, and its done! I'll post the Accessibility Inspector output in a seperate post (for some reason it cuts off the last bit if i try and put it in this post), but I've put a screenshot of the dialog in this post.

    The Accessibility Inspector output from hovering over the "Security" dropdown:

    Code:
    <AXApplication: “SystemUIServer”>
     <AXWindow>
      <AXPopUpButton: “None”>
    Attributes:
       AXRole:  “AXPopUpButton”
       AXRoleDescription:  “pop up button”
       AXHelp:  “(null)”
       AXEnabled:  “true”
       AXFocused (W):  “false”
       AXParent:  “<AXWindow>”
       AXWindow:  “<AXWindow>”
       AXTopLevelUIElement:  “<AXWindow>”
       AXPosition:  “x=893 y=338”
       AXSize:  “w=240 h=26”
       AXValue:  “None”
       AXChildren:  “<array of size 0>”
    Actions:
       AXShowMenu - show menu
       AXPress - press
    and from hovering over the dropdown menu item "WPA Personal":

    Code:
    <AXApplication: “SystemUIServer”>
     <AXWindow>
      <AXPopUpButton: “None”>
       <AXMenu>
        <AXMenuItem: “WPA Personal”>
    
    Attributes:
       AXRole:  “AXMenuItem”
       AXRoleDescription:  “menu item”
       AXParent:  “<AXMenu>”
       AXEnabled:  “true”
       AXPosition:  “x=666 y=417”
       AXSize:  “w=240 h=18”
       AXTitle:  “WPA Personal”
       AXHelp:  “(null)”
       AXSelected (W):  “true”
       AXMenuItemCmdChar:  “(null)”
       AXMenuItemCmdVirtualKey:  “(null)”
       AXMenuItemCmdGlyph:  “(null)”
       AXMenuItemCmdModifiers:  “0”
       AXMenuItemMarkChar:  “”
       AXMenuItemPrimaryUIElement:  “(null)”
    
    Actions:
       AXCancel - cancel
       AXPress - press
    
     

    Attached Files:

  8. McGordon, Feb 22, 2011
    Last edited: Feb 22, 2011

    McGordon macrumors member

    Joined:
    Dec 28, 2010
    Location:
    Scotland
    #8
    Try this:
    Code:
    tell application "System Events"
       tell process "SystemUIServer"
          tell menu bar 1
             set menuExtras to (value of attribute "AXChildren")
             set airport to -1
             repeat with aMenu in menuExtras
                tell aMenu
                   if value of attribute "AXDescription" contains "AirPort Menu Extra" then
                      set airport to aMenu
                      exit repeat
                   end if
                end tell
             end repeat
             
             if airport is -1 then
                display dialog "Could not find Menu Extra"
                return
             else
                tell airport
                   perform action "AXPress"
                   tell menu 1
                      click menu item "Join Other Network…"
                   end tell
                end tell
             end if
          end tell
          tell window 1
             delay 0.5 -- wait for dialog to open
             keystroke "SSID"
             
             tell pop up button 1
                click
                click menu item "WPA Personal" of menu 1
                delay 0.5 -- wait for password field to appear
                keystroke tab
                keystroke tab
                keystroke "TopSecretPassword"
             end tell
             click button "Join"
          end tell
       end tell
    end tell
    
    This worked for me on an iBook with 10.4, with the only change being "Other…" instead of "Join Other Network…" and "OK" instead of "Join" for your 10.5 version.

    The UI scripts often need you to click to open a menu, then maybe a delay, before they "see" that the menu items exist. The dialog needs to appear before the applescript can "see" it.

    If you're on a faster mac, you can reduce the delays a bit.

    I don't see any harm in turning off broadcast of SSID. I do it on my wireless network, even though I know it won't stop someone who is determined to find it out. The same with restricting MAC addresses of machines that can connect. It won't stop a determined attacker who can listen in to the MAC addresses being broadcast and spoof it. Most casual users won't be able to do this so it might stop them having a go at the password.

    I'm not relying on it as the only security, its a little bit of additional help on top of WPA2-PSK [AES].
     
  9. chown33 macrumors 604

    Joined:
    Aug 9, 2009
    #9
    Maybe the absence of an SSID is contributing to the inability of the computer to remember the network. From the OP's second post:
    In other words, if the network had an SSID, the computer might correctly remember the network, the entire script that drives the UI to connect to a nameless network might never have been needed. And this whole thread would be unnecessary.
     
  10. McGordon macrumors member

    Joined:
    Dec 28, 2010
    Location:
    Scotland
    #10
    Turning off broadcast of SSID doesn't stop my wife's iBook from remembering the network. On the same network, it's been the same with every phone that has been set up to connect. They've never forgotten the network. The password is usually just typed once on each device.

    This thread may not be needed if the network settings On Ipodize's mac were changed to work properly.

    I didn't think it was nameless, I thought it had an SSID, but that it was hidden.
     
  11. Ipodize, Feb 22, 2011
    Last edited: Feb 22, 2011

    Ipodize thread starter macrumors member

    Ipodize

    #11
    It does have a SSID, but for some reason my Mac still won't connect. Strangely enough, my iPod touch (which I am currently using to type this post) reconnects fine. I don't get what the difference is. :confused:

    Also, that script looks like it will work, but I can't be sure until I get to my Mac.

    And another question, is it possible to get that password out of the keychain (as it has been stored in there, along with the SSID and everything else) for some more security? I don't mind having to type in my administrator password, it's a third shorter than the network password...

    EDIT: Works perfectly! Now i just need to find a way to make it a lot harder to recover the password from the script (like the keychain idea above, or the read-only option in the editor, though i'm not sure how secure that is?) or, i can use this:
    Code:
    tell application "System Events"
    	tell process "SystemUIServer"
    		tell menu bar 1
    			set menuExtras to (value of attribute "AXChildren")
    			set airport to -1
    			repeat with aMenu in menuExtras
    				tell aMenu
    					if value of attribute "AXDescription" contains "AirPort Menu Extra" then
    						set airport to aMenu
    						exit repeat
    					end if
    				end tell
    			end repeat
    			
    			if airport is -1 then
    				display dialog "Could not find AirPort Menu Extra"
    			else
    				tell application "System Events"
    					activate
    					local pass
    					set pass to text returned of (display dialog "Enter your password" default answer "" with hidden answer)
    				end tell
    				tell airport
    					perform action "AXPress"
    					tell menu 1
    						click menu item "Join Other Network…"
    					end tell
    				end tell
    			end if
    		end tell
    		tell window 1
    			delay 0.1 -- wait for dialog to open
    			keystroke "SSID"
    			
    			tell pop up button 1
    				click
    				click menu item "WPA Personal" of menu 1
    				delay 0.1 -- wait for password field to appear
    				keystroke pass
    			end tell
    			click button "Join"
    		end tell
    	end tell
    end tell
    
    which makes it a bit easier by eliminating the mouse clicks (when used with QuickSilver) but I'd prefer to have it enter the password automatically, but still have it stored securely.
     

Share This Page