3

Here's my situation. I created an AppleScript for cleaning up my desktop. It essentially selects all files and folders on my desktop, creates a new folder with a specific name and date format, and moves all the files from my desktop to the new folder. This script works beautifully until I realized that occasionally there were files or folders I wanted to remain on my desktop. My solution was to open the get info window for each file or folder that I wanted to remain on my desktop, and select the “lock” option in the get info window.

My problem is now because of the locked files, the script cannot completely execute without displaying an error message. If I click “OK” on the error message, the script will finish and move every file with the exception of the ones that are locked.

I would prefer not to have to go through this extra step by clicking the okay button. I tried adding some system event actions to the script to automatically click the “ok” button and that did not work.

I'm starting to think that the only real solution would be to not select those locked files or folders in the first place. This is where I am lost. Can anyone help direct me as to how to avoid selecting the locked files in the first place?

enter image description here


Here is the script in its entirety.


set scriptPath to (load script file "Macintosh HD:Users:Smokestack:Library:Mobile Documents:com~apple~ScriptEditor2:Documents:Cleanup Desktop.scptd:Contents:Resources:Scripts:Current Time A.M. P.M. And Short Date.scpt")

tell scriptPath
    timeandDate() -- This will get the time and date in this format "05/31/2017 @ 9:10:48 PM" called from the loaded script file above
end tell

set timeandDate to the result -- This will copy the time and date results from the previous step and and set it as this new variable

tell application "Finder"
    if running then
        close every window
        activate
        make new Finder window
        set target of Finder window 1 to folder "Desktop" of folder "Smokestack" of folder "Users" of startup disk
    end if
    open Finder window 1
    activate
end tell

delay 1
tell application "System Events"
    key code 0 using (command down) -- This will select all files and folders on the desktop in the active finder window
end tell

tell application "Finder"
    set these_items to the selection
    set destinationFolder to make new folder at POSIX file "/Users/Smokestack/Jimz_Important_Stuff/Desktop_Cleanups/" with properties {name:timeandDate}
    move these_items to destinationFolder
    reveal destinationFolder
end tell

Here is a revised version of the script without calling handlers from external files

on timeandDate()
    set CurrentTime to (time string of (current date))
    set AppleScript's text item delimiters to ","
    set theLongDate to (current date)
    set theLongDate to (date string of theLongDate)
    set currentMonth to (word 1 of text item 2 of theLongDate)
    set currentDay to (word 2 of text item 2 of theLongDate)
    set currentYear to (word 1 of text item 3 of theLongDate)
    set monthList to {January, February, March, April, May, June, July, August, September, October, November, December}
    repeat with x from 1 to 12
        if currentMonth = ((item x of monthList) as string) then
            set theRequestNumber to (text -2 thru -1 of ("0" & x))
            exit repeat
        end if
    end repeat
    set currentMonth to theRequestNumber
    set currentDay to (text -2 thru -1 of ("0" & currentDay))
    set theShortDate to (currentMonth & "/" & currentDay & "/" & currentYear) as string
    set CurrentTime to (time string of (current date))
    set CurrentTimeandShortDate to (theShortDate & " @ " & CurrentTime)
    set AppleScript's text item delimiters to ""
end timeandDate

timeandDate()

set timeandDate to the result

tell application "Finder"
    close every window
    activate
    make new Finder window
    set target of Finder window 1 to folder "Desktop" of folder "Smokestack" of folder "Users" of startup disk
    select every file of the front Finder window 
    delay 1
    set these_items to the selection
    set destinationFolder to make new folder at POSIX file "/Users/Smokestack/Jimz_Important_Stuff/Desktop_Cleanups/" with properties {name:timeandDate}
    try
        move these_items to destinationFolder
    end try
    reveal destinationFolder
end tell

After making some revisions to the script, as long as the locked items on my desktop are only folders and not files, now this script works beautifully. However it will still generate an error if there are any individual locked files.

  • Thank you for your Insights. Very good points on your Finder Comments and I will make changes in the script. Thank you – wch1zpink Jun 1 '17 at 17:57
  • Is there possibly a way we can use a shorter command something like... tell application "Finder" to set selection to every file whose properties is equal to {locked:false} <----- I've tried about 20 different variations of that with no success – wch1zpink Jun 1 '17 at 18:16
  • So I should add set AppleScript's text item delimiters to "" At the end of the timeandDate() handler, just before the end timeandDate? Or do I add it to the main body of my script itself, after i call the handler? – wch1zpink Jun 1 '17 at 18:40
  • Let us continue this discussion in chat. – user3439894 Jun 1 '17 at 18:44
  • 1
    I've updated my answer and would like you to test the new code and suggest you use it over the other example code. – user3439894 Jun 5 '17 at 18:59
3

Update: As I mentioned somewhere in the comments that I'd build out a 10.12.5 system this past weekend and do some testing, I did.

Here is what I found out:

  • The code of my answer, inclusive of edit 5 on Jun 2 at 15:34, works on my system without issue.
  • After a review of all code and comments, it dawned on me that while my code, as is, worked on my system and I gave note referencing the delay command having to adjust values and or add/remove as/if necessary, etc., that this mainly comes down to timing issues and the pitfalls of that particular form of event coding.

Therefore, and while I'll leave the original answer at the bottom of this update, I decided to look at this from a different programatic angle and offer the following code as a better way to code this script to accomplish the task at hand.

This new code, does not rely on closing opened Finder windows and then opening a Finder window to the Desktop folder of the User to then have System Events select all items in the target folder, or the use of the delay command to deal with timing issues etc. All of which I personally don't like, because I don't want all Finder windows I have opened, closed to accomplish a task such as this. Or code it to leave the existing windows opened while ensuring the Finder window of the Desktop folder within the Home folder is the topmost Finder window to ensure System Events selects the correct items and get the timings right, etc.!

The following AppleScript code offers a more safe and faster way to accomplish the task at hand and I encourage you to use it over the previous code examples.

Note: With the previous caveats in play, (the existence of the folder the destination folder is created in, etc.), you should not not need to modify this code and should be able to use it as is. That is to say, you're certainly free to modify the code anyway you need/want, but as is, it should work.

New AppleScript code:

tell current application
    try
        tell application "Finder"
            if running then
                set theseFileSystemObjects to (get every item of (path to desktop))
                set theFileSystemObjectsNotLocked to {}
                repeat with i from 1 to (count of theseFileSystemObjects)
                    set thisFileSystemObject to (item i of theseFileSystemObjects)
                    if not locked of (get properties of thisFileSystemObject) then
                        set end of theFileSystemObjectsNotLocked to thisFileSystemObject
                    end if
                end repeat
                if theFileSystemObjectsNotLocked is not equal to {} then
                    tell current application to set theDateTimeNow to ¬
                        (do shell script "date '+%m.%d.%Y @ %I.%M.%S %p'") as string
                    set theDestinationFolder to make new folder at ¬
                        ((path to home folder as string) & "Jimz_Important_Stuff:Desktop_Cleanups:") with properties {name:theDateTimeNow}
                    move theFileSystemObjectsNotLocked to theDestinationFolder
                    open theDestinationFolder
                    activate theDestinationFolder
                end if
            else
                tell current application
                    activate
                    display dialog "Finder is not currently running!" & linefeed & linefeed & ¬
                        "Open Finder, then run Desktop Clean Up again." buttons {"OK"} ¬
                        default button 1 with title "Desktop Clean Up"
                end tell
            end if
        end tell
    on error eStr number eNum
        activate
        display dialog eStr & " number " & eNum buttons {"OK"} ¬
            default button 1 with title "Desktop Clean Up" with icon caution
        return
    end try
end tell

Original Answer:

This is an example of how I'd write the entire script to be run, as is, as either a .scpt file or an .app file, on your system. I'm saying your system, because the target destination folder is set for your system.

There is no need to load an outside resource and no handler to set the value of the variable used for the destination folder name. I choose to use a do shell script command for that, using the date command to return a custom date time string variable, as it's one line of code compared to the amount of code in the on timeandDate() handler, and it returns the same pattern.

I will continue to use this on my system with appropriately adjusted pathnames and a different pattern for the destination folders name, replacing the / and : with . in the custom date time string variable used in the destination folder name.

As coded, this first version of the script moves all file system objects, that are not locked, currently in the Desktop folder to the destination folder. The script includes minimal appropriate error handling and as coded you shouldn't have the issues you were previously having. This of course assumes that the $HOME/Jimz_Important_Stuff/Desktop_Cleanups folder exists. If not, you'll get the appropriate error message, however additional error handling could be added to create the hierarchical folded structure as/if necessary.

This first script should resolve all issues you are/were having with your own code and IMO is a better way to code it then just trapping and eating the error with just a try statement alone, because as coded, it can only move files that are not locked and doesn't even try to move a locked file.

This was tested under macOS 10.12.3 and should work for you on macOS 10.12.5, which you're presently running.

AppleScript Code:


tell current application
    try
        set theDateTimeNow to (do shell script "date '+%m/%d/%Y @ %I:%M:%S %p'") as string
        tell application "Finder"
            if running then
                close every window
                set target of (make new Finder window) to (path to desktop)
                activate
                delay 0.5
                tell application "System Events" to key code 0 using {command down}
                delay 0.5
                set theseFileSystemObjects to the selection
                set theDestinationFolder to make new folder at ¬
                    ((path to home folder as string) & "Jimz_Important_Stuff:Desktop_Cleanups:") with properties {name:theDateTimeNow}
                set theListOfFileSystemObjectsNotLocked to {}
                repeat with i from 1 to (count of theseFileSystemObjects)
                    set thisFileSystemObject to (item i of theseFileSystemObjects)
                    if not locked of thisFileSystemObject then
                        set end of theListOfFileSystemObjectsNotLocked to thisFileSystemObject
                    end if
                end repeat
                move theListOfFileSystemObjectsNotLocked to theDestinationFolder
                reveal theDestinationFolder
            else
                tell current application
                    activate
                    display dialog "Finder is not currently running!" & linefeed & linefeed & ¬
                        "Open Finder, then run Desktop Clean Up again." buttons {"OK"} ¬
                        default button 1 with title "Desktop Clean Up" with icon caution
                end tell
            end if
        end tell
    on error eStr number eNum
        activate
        display dialog eStr & " number " & eNum buttons {"OK"} ¬
            default button 1 with title "Desktop Clean Up" with icon caution
        return
    end try
end tell

Note: As to the value of the delay commands, they may need to be adjusted for your system and or additional ones added as/if necessary and or removed if not needed. As presently coded, this script worked without issue, dozens of times in testing on my system, with varying counts and sizes of file system objects being acted upon in the Desktop folder. Make any adjustments as necessary.

The file system objects tested were, files, folders, aliases, symlinks, application bundles and document bundles, the latter two of which are just folders. These FSOs were of various sizes, both locked and not locked.


This second version of the script goes beyond your expressed needs and makes a duplicate of the locked file system objects currently in the Desktop folder to the destination folder, while reseting the locked flag on the duplicates so they can be deleted without raising a flag at the time you may choose to delete them. I'm including it as it may have added value and you find it useful.

AppleScript Code:


tell current application
    try
        set theDateTimeNow to (do shell script "date '+%m/%d/%Y @ %I:%M:%S %p'") as string
        tell application "Finder"
            if running then
                close every window
                set target of (make new Finder window) to (path to desktop)
                activate
                delay 0.5
                tell application "System Events" to key code 0 using {command down}
                delay 0.5
                set theseFileSystemObjects to the selection
                set theDestinationFolder to make new folder at ¬
                    ((path to home folder as string) & "Jimz_Important_Stuff:Desktop_Cleanups:") with properties {name:theDateTimeNow}
                set theListOfFileSystemObjectsNotLocked to {}
                set theListOfLockedFileSystemObjects to {}
                repeat with i from 1 to (count of theseFileSystemObjects)
                    set thisFileSystemObject to (item i of theseFileSystemObjects)
                    if not locked of thisFileSystemObject then
                        set end of theListOfFileSystemObjectsNotLocked to thisFileSystemObject
                    else
                        set end of theListOfLockedFileSystemObjects to thisFileSystemObject
                    end if
                end repeat
                move theListOfFileSystemObjectsNotLocked to theDestinationFolder
                duplicate theListOfLockedFileSystemObjects to theDestinationFolder
                repeat with i from 1 to (count of theListOfLockedFileSystemObjects)
                    set thisFileSystemObject to (item i of theListOfLockedFileSystemObjects)
                    set locked of alias ((theDestinationFolder as string) & name of thisFileSystemObject) to false
                end repeat
                reveal theDestinationFolder
            else
                tell current application
                    activate
                    display dialog "Finder is not currently running!" & linefeed & linefeed & ¬
                        "Open Finder, then run Desktop Clean Up again." buttons {"OK"} ¬
                        default button 1 with title "Desktop Clean Up" with icon caution
                end tell
            end if
        end tell
    on error eStr number eNum
        activate
        display dialog eStr & " number " & eNum buttons {"OK"} ¬
            default button 1 with title "Desktop Clean Up" with icon caution
        return
    end try
end tell
  • Okay I ran this first version of your script several times and each time and scripteditor, It threw an error message tell application "Script Editor" display dialog "The folder “” can’t be moved into itself. number -122" buttons {"OK"} default button 1 with icon caution --> {button returned:"OK"} end tell – wch1zpink Jun 2 '17 at 16:26
  • Running this second version of the script I got the same error message… I think it maybe because on my desktop I have mounted Macintosh HD, Boot Camp, and two separate time capsules. Once the script throws the error, I look at my desktop and every single item is selected including those mounted driveS – wch1zpink Jun 2 '17 at 16:33
  • In finder preferences I chose not to show those mounted drives on the desktop and then I ran the script and it ran beautifully. If you can figure out a way to exclude the mounted drives from being selected in the script, you would be a mad genius LOL – wch1zpink Jun 2 '17 at 16:38
  • @wch1zpink, If the first vision is having an issue the second version isn't going to fix it. Without seeing your full logs it's going to be a bit harder to diagnose the issue. I'd say test with replacing the / and : with . in the do shell script "date ..." command, so as to avoid any issue in the naming convention. Also, it would be good to see the output of ls -al@ "$HOME/Desktop/" with devices showing. Mounted devices, while they appear on the Desktop of the Display, they don't exist in $HOME/Desktop folder and that should have no bearing on the functionality of the script! – user3439894 Jun 2 '17 at 16:47
  • 1
    @wch1zpink, Obviously there is something quite different between my system and yours, but what!? This weekend I'll try to make time to setup a 10.12.5 system and see if I can reproduce the issue. A workaround option might be to programmatically, if possible, toggle the flag(s) that show/hide external devices..., move the target files, and toggle the flag(s) again. (That is, if you what those devices to always show.) I'll look at that, but I'd like to be able to reproduce your issue and then code appropriately for it vs. a workaround. – user3439894 Jun 2 '17 at 17:08
3

My approach would be to put some of your code into a try block and also use on error to ignore that specific error message, but to still display a message if it encounters a different error instead.

The advantage of this approach is that you're not telling your script to ignore all errors, just in case something else occurs and you should be aware of it.

In order to achieve this, try the following:

set scriptPath to (load script file "Macintosh HD:Users:Smokestack:Library:Mobile Documents:com~apple~ScriptEditor2:Documents:Cleanup Desktop.scptd:Contents:Resources:Scripts:Current Time A.M. P.M. And Short Date.scpt")

tell scriptPath
    timeandDate() -- This will get the time and date in this format "05/31/2017 @ 9:10:48 PM" called from the loaded script file above
end tell

set timeandDate to the result -- This will copy the time and date results from the previous step and and set it as this new variable

tell application "Finder"
    if running then
        close every window
        activate
        make new Finder window
        set target of Finder window 1 to folder "Desktop" of folder "Smokestack" of folder "Users" of startup disk
    end if
    open Finder window 1
    activate
end tell

delay 1
tell application "System Events"
    key code 0 using (command down) -- This will select all files and folders on the desktop in the active finder window
end tell

tell application "Finder"
    try
        set these_items to the selection
        set destinationFolder to make new folder at POSIX file "/Users/Smokestack/Jimz_Important_Stuff/Desktop_Cleanups/" with properties {name:timeandDate}
        move these_items to destinationFolder
        reveal destinationFolder
    on error error_message number error_number
        if the error_number is not -50 then
            display dialog error_message buttons {"OK"} default button 1
        end if
    end try

end tell

Now, you'll see that I've placed the second block of tell application "Finder" code within a try block (you'll notice the use of try and end try. And, within that block I've inserted the following code:

    on error error_message number error_number
    if the error_number is not -50 then
        display dialog error_message buttons {"OK"} default button 1
    end if

Basically, this should have the effect of telling the script that in the event of a Finder error of -50 to just ignore it, but if it's not -50 then display the error. (I'm assuming that this is the error your script gets - if not you can just replace the -50 with the correct error number.

Obviously I can't test this at my end, so please let me know how you go.

  • I couldn't replicate wch1zpink's exact error message, but I agree with your answer... using appropriate error handling. +1 – user3439894 Jun 1 '17 at 16:54
  • @Monomeeth I ran your version of the code and saved it as an application and it produced the exact same error message – wch1zpink Jun 1 '17 at 17:40

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .