Applescript: Screenshot with hide desktop items?

I put together an applescript from the internet to take a screenshot and hide the desktop items.

As I'm a beginner with Applescript, I wanted to talk to the experts and ask if you can/must improve on this one :thinking:

set spacechar to ASCII character 32
do shell script "ls -Ol ~/Desktop/" -- Read chflags in ls 
if result contains "staff" & spacechar & spacechar & "hidden" then
	do shell script "chflags nohidden ~/Desktop/*"
	do shell script "chflags hidden ~/Desktop/*"
end if

delay 2

set theDesktop to POSIX path of (path to desktop as string)
set theCurrentDate to current date
set shellCommand to "/usr/sbin/screencapture " & quoted form of (theDesktop & "Screen Shot " & theCurrentDate & ".png")
do shell script shellCommand

delay 1.5

set spacechar to ASCII character 32
do shell script "ls -Ol ~/Desktop/" -- Read chflags in ls 
if result contains "staff" & spacechar & spacechar & "hidden" then
	do shell script "chflags nohidden ~/Desktop/*"
	do shell script "chflags hidden ~/Desktop/*"
end if

Screenshot Hide- Time & Date.kmmacros (2,3 KB)

Another approach to toggling between a clear Desktop and a populated one is to toggle the CreateDesktop setting.

For a Keyboard Maestro Execute Shell Script action you could write something like:

if [ $(defaults read CreateDesktop) = true ]; then
    defaults write CreateDesktop false
    defaults write CreateDesktop true
killall Finder
echo $(defaults read CreateDesktop)

or if you prefer to keep it in an Execute AppleScript or Execute JavaScript for Automation action then things like:


-- toggleDesktop :: () -> IO Bool
on toggleDesktop()
    (do shell script (unlines({"if [ $(defaults read CreateDesktop) = true ]; then", ¬
        "    defaults write CreateDesktop false", ¬
        "else", ¬
        "    defaults write CreateDesktop true", ¬
        "fi", ¬
        "killall Finder", ¬
        "echo $(defaults read CreateDesktop)"}))) = "true"
end toggleDesktop

-- MAIN ---------------------------------------------------
on run
end run

-- GENERIC FUNCTIONS --------------------------------------

-- concat :: [[a]] -> [a]
-- concat :: [String] -> String
on concat(xs)
    if length of xs > 0 and class of (item 1 of xs) is string then
        set acc to ""
        set acc to {}
    end if
    repeat with i from 1 to length of xs
        set acc to acc & item i of xs
    end repeat
end concat

-- intercalate :: String -> [String] -> String
-- intercalate :: [a] -> [[a]] -> [a]
on intercalate(sep, xs)
    concat(intersperse(sep, xs))
end intercalate

-- intersperse(0, [1,2,3]) -> [1, 0, 2, 0, 3]
-- intersperse :: Char -> String -> String
-- intersperse :: a -> [a] -> [a]
on intersperse(sep, xs)
    set lng to length of xs
    if lng > 1 then
        set acc to {item 1 of xs}
        repeat with i from 2 to lng
            set acc to acc & {sep, item i of xs}
        end repeat
        if class of xs is string then
        end if
    end if
end intersperse

-- unlines :: [String] -> String
on unlines(xs)
    intercalate(linefeed, xs)
end unlines

JavaScript for Automation:

(() => {
    'use strict';

    // toggleDesktop :: () -> IO Bool
    const toggleDesktop = () =>
            "if [ $(defaults read CreateDesktop) = true ]; then\n\
               defaults write CreateDesktop false\n\
               defaults write CreateDesktop true\n\
            killall Finder\n\
            echo $(defaults read CreateDesktop)"
        ) === 'true';

    // standardAdditions :: () -> Library Object
    const standardAdditions = () =>
            Application.currentApplication(), {
                includeStandardAdditions: true

    return toggleDesktop();

Thank you very much for posting the different possibilities @ComplexPoint :+1: Now I’m spoilt for choice, which I can decide on.

1 Like

FWIW you can also use 0 and 1 in place of false and true


TOGGLED=$((1-$(defaults read CreateDesktop)))
defaults write CreateDesktop $TOGGLED
killall Finder


Here is an improved version of your first script (the approach with the hidden flag):

set ssDir to POSIX path of (path to desktop as text)
set ssDate to current date
# For a shorter date string:
# set ssDate to short date string of ssDate & space & time string of ssDate
set ssName to "Screen Shot" & space & ssDate & ".png"

do shell script "chflags -h hidden ~/Desktop/*"
delay 2

do shell script "screencapture" & space & quoted form of (ssDir & ssName)

do shell script "chflags -h nohidden ~/Desktop/*"


  • The script now simply hides all files before the screen shot and makes them visible again after the screen shot.
  • The original script had a toggle: if one of your files was already hidden it would make all files visible. IMO, this makes no sense for your purposes.
  • A cleaner variable structure.
  • For a shorter date format uncomment line #4
  • The -h switch in the chflags shell command is necessary in case you have symlinks on the Desktop.

However, I’m undecided if this approach (setting the hidden flags) or @ComplexPoint’s approach (changing the Finder setting) is the better one.

@ComplexPoint’s approach has some advantages:

  • It is using the Finder setting, which is made exactly for that.
  • It also hides Volume icons on the Desktop.

The drawback is that after changing the Finder setting the Finder has to be relaunched, which can take a bit of time if you have lots of windows open. (Two Finder relaunches per screen shot.)


Two launches per screenshot

Assuming that you want a desktop display of file and device icons at all :slight_smile:

( I personally have mixed feelings about it – go through quite long periods of just using a ~/Desktop window in the Finder )

1 Like

Thank you very much @Tom & @ComplexPoint for your detailed help :ok_hand::clap: