MacOS – Automatically Mount a Network Drive and Copy a File to a Network Folder (AppleScript)

applescriptfile-transfermacosNetwork

I've a rather complex task to solve. I don't use OS X, but now I have to provide some colleagues with a simple application that automatically copies a certain file to a network folder. Normally I'd use a shell script, but some minimal GUI is a must-have thing in this case. So I thought I could use AppleScript.

I'd have to perform these steps:

  1. Connect to a network drive (smb://myserver/public, where every user has different login names and passwords, so wiring the usernames and passwords in the code is not an option).
  2. Navigate to a folder on the network drive (every user has a different folder on the network drive).
  3. Copy a certain file from the user's desktop to the opened folder on the network drive.

So when running the script the user has to enter his or her username and password for connecting the network drive, and the user has to enter the name of the folder they should copy the file to.
Can the name of the folder be stored permanently somehow? So the user won't have to enter the folder name each time when he or she runs this script. But from time-to-time these folders may change, so there has to be an option to change the folder before copying.
Also how can I check if the network drive is already mounted, so the user won't be asked for username and password each time he or she runs this script?


Here is how far I've been able to go in assembling a script to accomplish this task:

I'm struggling to understand how AppleScript likes to store a path to a file/folder on a mounted network drive.

So here is what I have now:

property userName : "myfolder"
property folderName : "myusername"

property serverName : "public"
property serverAddress : "smb://myserver/public"
property serverStatus : 0

on connectToServer()
    global userName
    global folderName
    global serverName
    global serverAddress
    global serverStatus

    set mountedDisks to list disks
    if mountedDisks does not contain serverName then
        mount volume serverAddress as user name userName with password (display dialog "Enter password for" & quoted form of serverName with title "" default answer "" giving up after 3 with hidden answer)
    end if

    set mountedDisks to list disks
    if mountedDisks contains serverName then
        set serverStatus to 1
    else
        connectToServer()
    end if
end connectToServer

on mainLoop()
    global userName
    global folderName
    global serverName
    global serverAddress
    global serverStatus

    if serverStatus is equal to 0 then
        connectToServer()
    end if

    set mainDialog to display dialog ¬
        "Your username: " & userName & "
Your folder's name: " & folderName buttons {"Quit", "Settings", "Copy file"} with title "File Copier" default button 1
    set mainDialogAnswer to button returned of mainDialog

    if mainDialogAnswer is equal to "Quit" then
        quit
    end if

    if mainDialogAnswer is equal to "Settings" then
        display dialog "Enter your username" with title "Step 1 of 2" default answer userName
        set userName to {text returned of result}

        display dialog "Enter your folder's name" with title "Step 2 of 2" default answer folderName
        set folderName to {text returned of result}

        mainLoop()
    end if

    if mainDialogAnswer is equal to "Copy" then
        -- copy the file
    end if
end mainLoop

mainLoop()

Best Answer

Copying of files in Applescript is best done either through System Events or Finder, using the duplicate … to command, i.e.

tell application "System Events" to duplicate sourceFile to targetFolder

where both sourceFile and targetFolder need to be the correct object type for the application used – meaning disk item or finder item (both objects can be created from AppleScript alias objects, or textual path values with a bit of type coercion – I’d add the details, but you have not stated how the paths to both are stored / acquired in your script).

A few notes on your code:

  • There is no need to use globals when you have defined them as properties already. AppleScript properties are script scoped and persist across execution – they are only reset when the script is recompiled. If you assign those that need user setting missing value when declaring, you can even check if they are already set and skip re-prompting the user (there would be an even more comfortable and secure solution if Apple hadn’t deprecated Keychain Access Scripting).
  • There is no need for the repeated assignments and recursive call in your connectToServer() handler. The following code

    set timeOutCounter to 0
    repeat while (list disks) does not contain serverName and timeOutCounter is less than timeOutInterval
        -- mount drive
        delay someInterval -- recommended, so you don’t hectically loop
        set timeOutCounter to timeOutCounter + someInterval -- time out loop 
    end repeat
    

    will try to connect in the interval defined by someInterval, until the mount is available or timeOutIntervalis reached (assuming these values are declared. As properties, best – see above).

  • You might also want to offer your user a more comfortable way of selecting the target folder than typing a folder name from memory. Check out Standard Additions’s AppleScript dictionary for the choose folder command.
  • Finally, but that is mainly a matter of taste and coding style, I’d rather move the display dialog command into its own handler and call that, if needed repeatedly, from the script body, than use a C style mainLoop handler. I’ve found that, generally speaking, AppleScript runs out of Stack space easily when recursing and can get very confused about variable assignments, so it is a good idea to avoid recursive constructs where they are not necessary.