Search criteria for computers that have Desktop and Documents in the cloud?

cyberspread_71
New Contributor III

Need to find out who in my company has this turned on. Don't seemed to see any search criteria for that specifically...

Any help appreciated.

18 REPLIES 18

cyberspread_71
New Contributor III

Anyone. I can't believe this isn't a problem. There has to be a solution.

Thanks.

thebrucecarter
Contributor II

I just started poking around in the Finder plist file and found FXICloudDriveDesktop. I'm not sure what that is, and Google is unrevealing so far, but it is TRUE for me, so it might be worth checking into.

mottertektura
Contributor

We're using this EA to find that info. I think I grabbed this from a similar Jamf Nation post...

#!/bin/bash

# Purpose: to grab iCloud Drive Desktop and Document Sync status.
# If Drive has been setup previously then values should be: "false" or "true"
# If Drive has NOT been setup previously then values will be: "iCloud Account Enabled, Drive Not Enabled" or "iCloud Account Disabled"

#Variable to determine major OS version
OSver="$(/usr/bin/sw_vers -productVersion | /usr/bin/cut -d . -f 2)"

#Determine OS is 10.12 or greater as Doc Sync is only available on 10.12+
if [ "$OSver" -ge "12" ]; then
    #Path to PlistBuddy
    plistBud="/usr/libexec/PlistBuddy"

    #Determine logged in user
    loggedInUser=$(python -c 'from SystemConfiguration import SCDynamicStoreCopyConsoleUser; import sys; username = (SCDynamicStoreCopyConsoleUser(None, None, None) or [None])[0]; username = [username,""][username in [u"loginwindow", None, u""]]; sys.stdout.write(username + "
");')

    #Determine whether user is logged into iCloud
    if [[ -e "/Users/$loggedInUser/Library/Preferences/MobileMeAccounts.plist" ]]; then
        iCloudStatus=$("$plistBud" -c "print :Accounts:0:LoggedIn" /Users/$loggedInUser/Library/Preferences/MobileMeAccounts.plist 2> /dev/null )

        #Determine whether user has enabled Drive enabled. Value should be either "false" or "true"
        if [[ "$iCloudStatus" = "true" ]]; then
            DriveStatus=$("$plistBud" -c "print :Accounts:0:Services:2:Enabled" /Users/$loggedInUser/Library/Preferences/MobileMeAccounts.plist 2> /dev/null )
            if [[ "$DriveStatus" = "true" ]]; then
                if [[ -e "/Users/$loggedInUser/Library/Mobile Documents/com~apple~CloudDocs/Desktop" ]] && [[ -e "/Users/$loggedInUser/Library/Mobile Documents/com~apple~CloudDocs/Documents" ]] && [[ $(ls -la "/Users/$loggedInUser/Library/Mobile Documents/com~apple~CloudDocs/" | grep "->") ]]; then
                    DocSyncStatus="true"
                else
                    DocSyncStatus="false"
                fi
            fi
            if [[ "$DriveStatus" = "false" ]] || [[ -z "$DriveStatus" ]]; then
                DocSyncStatus="iCloud Account Enabled, Drive Not Enabled"
            fi
        fi
        if [[ "$iCloudStatus" = "false" ]] || [[ -z "$iCloudStatus" ]]; then
            DocSyncStatus="iCloud Account Disabled"
        fi
    else
        DocSyncStatus="iCloud Account Disabled"
    fi
else
    DocSyncStatus="OS Not Supported"
fi

/bin/echo "<result>$DocSyncStatus</result>"

cyberspread_71
New Contributor III

I am getting a "False" result on both machines. One with it turned on and one that does not have it turned on.

Not sure what I am doing wrong....

andy_granger
New Contributor III

<deleted>

andy_granger
New Contributor III

Hi @ktermin.

I don't know if you're still in need of a solution to your original post. However, I'm working on implementing the script posted by @mottertektura within my own environment, and I think I may have figured out at least one reason why you're seeing false negative results.

One of the conditional statements in the script requires three separate, individual checks all to be true:

  1. Does /Users/<current_user>/Library/Mobile Documents/com~apple~CloudDocs/Desktop exist?
  2. Does /Users/<current_user>/Library/Mobile Documents/com~apple~CloudDocs/Documents exist?
  3. Is there any occurrence of the text pattern -> within the /Users/<current_user>/Library/Mobile Documents/com~apple~CloudDocs/ directory?

If all three of these checks are true, then the result of the script is "True". However, if any of these three checks returns as false, then the result of the script is "False". I got a false negative ("False") result on a machine where iCloud Desktop & Documents was clearly enabled. Here's the problem as I understand it:

On my test machine I logged into my own personal iCloud account and enabled iCloud Desktop & Documents. Now, I don't normally use this feature because reasons. That being the case, there was no already-existing Desktop or Documents folder within my iCloud Drive. So, when I logged into my iCloud account, the symbolic links pointing to the local user's Desktop and Documents folders didn't exist and had to be created. The Documents symlink seemed to create itself just fine, but none existed for the Desktop folder. Thus, when I ran the policy pointing to this script (I modified it to be able to run as a policy and write the result into a text field style EA via an API call), I got a "False" result. I then randomly created an empty folder on the Desktop on the test machine in the process of doing something else. Later, when I ran the policy again, I got a "True" result. I went back and looked in the /Users/<current_user>/Library/Mobile Documents/com~apple~CloudDocs/ directory, and now there was a symlink pointing to the local Desktop folder. So, at that point, all three criteria for the check were true, so I got a positive result.

It seems to me that the three-way check is pretty fragile. I'm not 100% sold that all three need to be true, and I'm frankly kind of baffled by the need for the third one, as it's really only checking whether there exists any symlink at the top level of the /Users/<current_user>/Library/Mobile Documents/com~apple~CloudDocs/ directory, regardless of whether it's either of the ones we're interested in (Desktop or Documents). I just haven't yet been able to wrap my head around the need for that particular check, though I'm sure there was a reason that was clear to the original author.

I'm currently researching whether there's a more robust and reliable method to determine if iCloud Desktop & Documents is enabled. If I find one and get the modified script working, I'll post it back here.

andy_granger
New Contributor III

I figured it out.

In /Users/<current_user>/Library/Preferences/com.apple.finder.plist, there are a few key/value pairs that safely identify whether iCloud Desktop & Documents is enabled. We only need to check one of them.

In the original script we have this conditional check:

if [[ -e "/Users/$loggedInUser/Library/Mobile Documents/com~apple~CloudDocs/Desktop" ]] && [[ -e "/Users/$loggedInUser/Library/Mobile Documents/com~apple~CloudDocs/Documents" ]] && [[ $(ls -la "/Users/$loggedInUser/Library/Mobile Documents/com~apple~CloudDocs/" | grep "->") ]]; then
    DocSyncStatus="true"
else
    DocSyncStatus="false"
fi

This is not a reliable check, because it requires all three of those conditions to be true, and in testing I've found that if there is nothing on the Desktop when iCloud Desktop & Documents gets turned on, the [[ -e "/Users/$loggedInUser/Library/Mobile Documents/com~apple~CloudDocs/Desktop" ]] part of that three-way conditional check will fail, thus giving a false negative result. The symlink to the Desktop only gets created once any item is added to the Desktop. Now, I understand that it's probably pretty safe to assume users will have things on their Desktops, so the symlink will be there. I'm just not that comfortable using code which relies on people behaving in a certain way; I don't want to risk missing someone who keeps a pristine Desktop, only to be siphoning company data out via their Documents folder.

In place of that, I'm now doing two things. First, I define a variable to contain the results of checking the status of iCloud Desktop & Docs:

iCloudDesktop=$(defaults read /Users/$loggedInUser/Library/Preferences/com.apple.finder.plist FXICloudDriveDesktop)

And then, the actual conditional check becomes much simpler:

if [[ "$iCloudDesktop" = "1" ]]; then
    DocSyncStatus="Enabled"
else
    DocSyncStatus="Not Enabled"
fi

Since I'm doing a simple check inside that plist file, I saw no need to use PlistBuddy and instead chose to use a simple defaults read command to get the value of the key I'm interested in. There are two keys we could use:

FXICloudDriveDesktop
FXICloudDriveDocuments

I chose the first one, just because. In fact, the more I look at that com.apple.finder.plist file, the more I think this whole script could be somewhat simplified, since there also are these two keys:

FXICloudDriveEnabled
FXICloudDriveLoggedIn

Hmmm... I'll have to think on that some more.

At any rate, here's the working script with my changes:

#!/bin/bash

# Purpose: to grab iCloud Drive Desktop and Document Sync status.
# If Drive has been setup previously then values should be: "Enabled" or "Not Enabled"
# If Drive has NOT been set up previously then values will be: "iCloud Account Enabled, Drive Not Enabled" or "iCloud Account Disabled"

#Variable to determine major OS version
OSver="$(/usr/bin/sw_vers -productVersion | /usr/bin/cut -d . -f 2)"

#Determine OS is 10.12 or greater as Doc Sync is only available on 10.12+
if [ "$OSver" -ge "12" ]; then
    #Path to PlistBuddy
    plistBud="/usr/libexec/PlistBuddy"

    #Determine logged in user
    loggedInUser=$(python -c 'from SystemConfiguration import SCDynamicStoreCopyConsoleUser; import sys; username = (SCDynamicStoreCopyConsoleUser(None, None, None) or [None])[0]; username = [username,""][username in [u"loginwindow", None, u""]]; sys.stdout.write(username + "
");')

    #Variable to determine status of iCloud Drive Desktop & Documents setting
    iCloudDesktop=$(defaults read /Users/$loggedInUser/Library/Preferences/com.apple.finder.plist FXICloudDriveDesktop)

    #Determine whether user is logged into iCloud
    if [[ -e "/Users/$loggedInUser/Library/Preferences/MobileMeAccounts.plist" ]]; then
        iCloudStatus=$("$plistBud" -c "print :Accounts:0:LoggedIn" /Users/$loggedInUser/Library/Preferences/MobileMeAccounts.plist 2> /dev/null )

        #Determine whether user has iCloud Drive enabled. Value should be either "False" or "True"
        if [[ "$iCloudStatus" = "true" ]]; then
            DriveStatus=$("$plistBud" -c "print :Accounts:0:Services:2:Enabled" /Users/$loggedInUser/Library/Preferences/MobileMeAccounts.plist 2> /dev/null )
            if [[ "$DriveStatus" = "true" ]]; then
                if [[ "$iCloudDesktop" = "1" ]]; then
                    DocSyncStatus="Enabled"
                else
                    DocSyncStatus="Not Enabled"
                fi
            fi
            if [[ "$DriveStatus" = "false" ]] || [[ -z "$DriveStatus" ]]; then
                DocSyncStatus="iCloud Account Enabled, Drive Not Enabled"
            fi
        fi
        if [[ "$iCloudStatus" = "false" ]] || [[ -z "$iCloudStatus" ]]; then
            DocSyncStatus="iCloud Account Disabled"
        fi
    else
        DocSyncStatus="iCloud Account Disabled"
    fi
else
    DocSyncStatus="OS Not Supported"
fi

#Update the iCloud Desktop & Documents Status extension attribute with discovered value of $DocSyncStatus
/usr/bin/curl -H "Content-Type: application/xml" -sfku $4:$5 https://jamf-pro.server.address:8443/JSSResource/computers/name/$2 -d 
    "<computer><extension_attributes><extension_attribute><id>$6</id><value>$DocSyncStatus</value></extension_attribute></extension_attributes></computer>" -X PUT

Remember that I mentioned I modified the script so that it can run as a policy payload which writes its result back to a Text Field style Extension Attribute. Since this identifies a potentially pretty big security risk, I didn't want to wait as long as computers checking in with recon results usually takes. There are times I like to get EA data much more quickly, so I implement them this way.

Anyway, I hope this helps someone.

Is there anything that needs to be done to make this now work in Big Sur and Monterey?  We know for a fact one of our lab machines has iCloud signed in and Desktop and Document syncing on but it shows OS is not supported.  We tried tweaking this and figured some stuff out but now all we get is "iCloud Account Enabled, Drive Not Enabled"

daniel_ross
Contributor III

@andy.granger is this script still working for you? I tried using it the other day but haven't had success getting any results.

andy_granger
New Contributor III

Hi @daniel_ross,

Yes, it's working fine for me.

Have you deployed the script as a policy payload? What is your policy trigger? Have you configured a String/Text Field style EA to receive the script result? Have you set up a user in Jamf Pro that only has access to make API calls, and are you using its credentials?

Attached are some screenshots showing how I have my script/policy/EA combination set up. The Extension Attribute ID script parameter field in the 1st screenshot needs to contain the ID number of the EA that is shown in the 3rd screenshot.

Lastly, I'm sure I don't have to mention this but I will for the sake of completeness: make sure to enter your own JSS URL and port number in the API call at the end of the script. I sanitized the script for my own privacy before posting it to JamfNation.

https://jamf-pro.server.address:8443

115c959c27094d46b16549141006c94a

a2818de4a49a4725ac904abdbe6d4e19

a7d3610c22b540809739faad787fc17f

Can this be used without the API connection?

Yes, and you should plan to do this when Jamf deprecates the use of Basic Auth in Summer 2022.  You'll have to generate a "Token" to call the API, and these will only be good for 30 minutes.  They also require you to authenticate with user/pass to generate said API token, which makes them wholly unsuitable for use in Extension Attributes.

Your non-daily policy script should write a reverse extension attribute that leaves a text file in a special folder that users can't access.  

Many orgs will use locations like /var/acmeinc, or /etc/pretendco.

These folders are good candidates for four reasons:

  1. The folders /var/ and /etc/ don't appear in Finder by default;
  2. Subfolders created here are not subject to SIP restrictions;
  3. The contents of these folders are not wiped on reboot*
  4. These were shown to migrate correctly during upgrades from Mojave to Catalina and beyond.

*while /var/tmp is not wiped on reboot, /tmp is definitely wiped every startup.  Don't store important things there.

 

Your secret folder should be owned by root/wheel, and the permission should be 500 (r-x --- ---), or 755 (rwx r-x r-x) if you don't mind other users casually exploring their contents. 

Permissions for files in this secret folder should be 400 (r-- --- ---), owned by root/wheel, or 644 (rw- r-- r--) if you don't care about perusal by others.

Jamf, the root user, and system extensions will always be able to read these files.

The data in such files needs to be read by your daily Extension Attributes.  If you're super paranoid, encrypt the local data with a known hash that only your team knows, and decrypt in the EA at runtime.  This is potentially risky, as it can leave you with a lot of useless EA data if the hash source is forgotten.

technokowski
New Contributor

Hey all, just wanted to share something I came up with for our environment. It's a modification of what @iJake came up with on this thread:

https://www.jamf.com/jamf-nation/discussions/21993/find-computers-using-icloud-drive

And the above script posted by @mottertektura

#!/bin/sh

iCloudDrivePath="/Library/Mobile Documents/com~apple~CloudDocs"

# It was discovered that Catalina at one point moved the iCloud drive folder
# On macs upgraded to 10.15 the folder is still 'Mobile Documents'.
# If discovered that some 10.15 macs have it moved to CloudStorage
# Then uncomment out the lines below.

# OSver="$(/usr/bin/sw_vers -productVersion | /usr/bin/cut -d . -f 2)"
# if [ "$OSver" -ge "15" ]; then
#   iCloudDrivePath="/Library/CloudStorage/iCloud Drive";
# else iCloudDrivePath="/Library/Mobile Documents/com~apple~CloudDocs" echo 'not cat';
# fi

# Get the logged in user and their home folder
grabConsoleUserAndHome()
{
currentUser=$(stat -f %Su "/dev/console")
homeFolder=$(dscl . read "/Users/$currentUser" NFSHomeDirectory | cut -d: -f 2 | sed 's/^ *//'| tr -d '
')
  case "$homeFolder" in
     * * )
           homeFolder=$(printf %q "$homeFolder")
          ;;
       *)
           ;;
esac
}

grabConsoleUserAndHome

if [[ "$currentUser" == "root" ]]
    then
        exit
fi

# Checks if the drive path and file exists
if [[ -e "$homeFolder""$iCloudDrivePath" ]]
    then
        # Checks status of iCloud Drive Desktop and Documents setting
        iCloudDesktop=$(defaults read /Users/$currentUser/Library/Preferences/com.apple.finder.plist FXICloudDriveDesktop)
        if [[ "$iCloudDesktop" = 1 ]];
            then
                echo 'iCloud Desktop Enabled';
                echo "<result>true</result>"

        else
            echo 'Drive enabled, Desktop Disabled';
            echo "<result>false</result>"

        fi;

    else
        echo "User does not have iCloud Drive setup"
        echo "<result>false</result>"
fi

exit 0

Although mottertektura's script works great as is, and so does iJake's, I wanted to have a simple version that did both.

Additionally, I would like to add the ability to check if the signed-in iCloud account is from our domain or a personal, but I haven't gotten that far yet; this is good enough for now.

Also, If someone could confirm or deny the commented out line about the iCloud Drive folder location on Catalina, that would be much appreciated. It's in the "/Library/Mobile Documents/com~apple~CloudDocs" for me (10.15.3), but I've seen it in "/Library/CloudStorage/iCloud Drive" on a few 10.15 machines in the past. Just need clarification.

seanism
New Contributor III

I set this up and my computer shows 0 as the output.  Any idea why that would be?

 

Ditto here except ours is blank?

Mkh
New Contributor III

@andy.granger sorry but how can I see the result of your script ?

andy_granger
New Contributor III

Hi @Mkh.

The results of the script get written to a "text field" type computer Extension Attribute, so you have to make sure you've created such an EA to receive the script results. If you have everything set up correctly, then you can view the results within any individual computer record, in the section where you set up your EA to be displayed. What's great is that you can then set up a Smart Computer Group which will always give you a running list of machines that have the value of the EA you've set for its criteria.

Please let me know if you need further clarification.

marcelp
New Contributor II

I had an issue with com.apple.finder.plist where FXICloudDriveDesktop wasn't 1 when Documents and Desktop sync was active. I enabled it to fast after turning on iCloud Drive and something broke. I tried to turn it on and off without help. Reboot didn't do anything either. Turning off iCloud Drive fixed the problem.

This means that FXICloudDriveDesktop may not be 100% reliable.

The problem was on a 2020 M1 MacBook Pro