2

I'm having a little bit of an issue here. Here's the situation: We will be deploying a new application soon, and the server configuration resides in a simple XML file, located somewhere deep in the ~/library/Preferences. I want to create a bash/shell script that will basically copy the XML file at the right place, but for every user folder that exists.

I was able to use the below script for Windows, but I'm wondering if there is something similar for Apple.

Here's the Windows script:

$sourceLocation = "C:\Users\suptech\Downloads\TEMP"

$targetLocation = "C:\Users"

$result = @()

$result += get-ChildItem $targetLocation | Where-Object {$_.PSIsContainer}  
$result | foreach-Object { copy-item $sourceLocation -Destination "C:\Users\$_\AppData\Roaming\TEST” -Recurse -Force}

Could someone help me ?

Thanks in advance! :)

2 Answers 2

3

Well, here's something that you can work with. It isn't tested in a real world environment and is offered AS IS- without any warranty.

# This script must run as root
if [ "$(id -u)" != "0" ]
then
    echo "This script must be run as root"
    exit 1
fi

source=/path/to/file
destination=Library/path/to/destination/directory

for u in /Users/*
do
    on=${u##*/}

    # If not a directory- do not process
    [ ! -d "$u" ] && continue

    # Check that the directory has a valid user name or do not process
    id "$on" >/dev/null 2>&1 || continue

    # Get the user's primary group id
    gn=$(id -gn "$on")

    # bug fix found by Alex Pilon
    # make destination directory if it doesn't exist
    install -o "$on" -g "$gn" -d "${u}/${destination}"

    install -b -o "$on" -g "$gn" -m 644 "$source" "${u}/${destination}"
done

Another solution based on bmike's suggestion

# This script must run as root
if [ "$(id -u)" = "0" ]
then
    : running as root
else
    echo "This script must be run as root"
    exit 1
fi

source=/path/to/file
destination=Library/path/to/destination/directory 

dscl . -list /Users NFSHomeDirectory |
awk 'BEGIN { OFS=":" } / \/Users/ { print $1, $2 }' |
while IFS=: read u hdir
do
    # Get the user's primary group id
    gn=$(id -gn "$u")

    install -o "$u" -g "$gn" -d "${hdir}/${destination}"    

    install -b -o "$u" -g "$gn" -m 644 "$source" "${hdir}/${destination}"
done
5
  • 1
    Nice script. I'd probably iterate over dscl . -list /Users to catch users with home directories not in / - and then request the NFSHomeDirectory for the users that pass the filter test ( maybe exclude root and ones with _ ) - dscl . -read /Users/${u} NFSHomeDirectory
    – bmike
    Commented Aug 23, 2016 at 17:46
  • @bmike that's a great idea.
    – fd0
    Commented Aug 23, 2016 at 18:28
  • Hey @fd0, thanks for the reply. Not at work right now, but will try this for sure tomorrow morning once I am. And bmike, this would be indeed useful, but in our cases, the laptops are forcefully configured so that the home directories are always in /users for everyone.
    – Alex Pilon
    Commented Aug 23, 2016 at 23:11
  • Hey @fd0 sorry the delay. Tried the script, and nothing happens. The only way to know what happens, is if I comment out the two "do not process" lines. I then get 'id: "??: no such user' and 'install: "??: Invalid argument'. Including the Shared folder, I have 4 different users on the computer, all local users (no network accounts).
    – Alex Pilon
    Commented Aug 26, 2016 at 20:42
  • Nevermind, works fine. Had to play around with it to make it create the folders if they didn't exist, and I think I had messed up something lol Thank you very much for the script!! It's been a big help
    – Alex Pilon
    Commented Aug 26, 2016 at 20:45
0

Writing a preference file is the wrong way to do things on OS X. Especially on 10.9 and later where preferences are cached and the file may not even be used.

You will want to use defaults delete to remove preferences and defaults write to set preferences and let the OS decide where / how to store and cache the settings.

So - anywhere you would write code to handle file writes, just write the preference using the API. Anywhere you would use a script to copy or write a file, use that script to call defaults and set things appropriately.

Here is a GitHub search to show you bash examples of using defaults write to get you started: https://github.com/search?l=bash&q=defaults+write&ref=searchresults&type=Code&utf8=

the reason to not write an XML file to each user account is the separation of privileges. You need to handle new user accounts created after you run your script, you need admin rights and not user rights which will break a subset of your user's workflows and will impede adoption of your application. There is a framework for writing system level preferences for an application and then for a user to over-ride or customize those settings - my advice is to use those frameworks and make your life easier as a developer of software running on OS X.

4
  • You didn't read properly what I wrote. Let me quote myself: [...]resides in a simple XML file[...]
    – Alex Pilon
    Commented Aug 23, 2016 at 13:34
  • We're not talking about a PLIST file here, we're talking about an actual XML file that the application reads to get the server configuration.
    – Alex Pilon
    Commented Aug 23, 2016 at 13:36
  • I guess I'm saying - don't use an XML file - your call @AlexPilon , though to take my advice or leave it. I'll explain why in my answer.
    – bmike
    Commented Aug 23, 2016 at 13:45
  • 1
    I don't think you understand here....I don't have a choice! The application is built like that. It's not like I'm choosing to push something and I can do it the way I want. The only two ways the server can be configured on the application is either manual input from every user, or auto-config by pushing the XML file to the right location.
    – Alex Pilon
    Commented Aug 23, 2016 at 15:33

You must log in to answer this question.

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