Code Monkey home page Code Monkey logo

mcxtoprofile's Introduction

mcxToProfile

Overview

mcxToProfile is a simple command-line utility to create "Custom Settings" Configuration Profiles without the need for the Profile Manager Device Management service in OS X Server 10.7 and 10.8. It can take input from property list files on disk or directly from a Directory Services node (Local MCX or Open Directory).

Administrators who would like to move from MCX-based management to Profiles may find this tool useful to speed up the process of migrating and testing. Currently it only supports the "Custom Settings" type, as this seems to be the functional equivalent of key-value domain management in Workgroup Manager.

mcxToProfile should function on OS X 10.5 or greater. It also makes use of Greg Neagle's FoundationPlist library from the Munki project, which provides native plist support via PyObjC. FoundationPlist is licensed under the Apache License, version 2.0.

Example usage

Here's an example:

./mcxToProfile.py --plist /path/to/a/plist --identifier MyApplicationPrefs

This will create a .mobileconfig file in the same directory, which is equivalent to a "Custom Settings" profile configured in the Profile Manager web application included in Lion Server.

The --plist option can be specified multiple times:

./mcxToProfile.py --plist com.microsoft.office.plist --plist com.microsoft.autoupdate2.plist --identifier Office2011Prefs --manage Once

Here's another example, which will import an already-configured MCX preference defined in an available Directory Services computer object:

./mcxToProfile.py --dsobject /LDAPv3/od.my.org/ComputerGroups/StandardPreferences --identifier MyBasePreferences

The --dsobject option should work with objects defined in either a LocalMCX or standard Open Directory node on another server. This hasn't been tested with MCX attributes in OpenLDAP or Active Directory.

Plist input options:

Once/Often/Always management

One downside to the Profile Manager web GUI is that it does not provide a mechanism to choose the "management frequency" of an MCX-set preference, such as "Once" or "Often". It was discovered (again, by Greg Neagle) that it's possible to regain that functionality, by slightly altering the contents of the .mobileconfig file to match the MCX XML as when created in Workgroup Manager:

  • for "Often" behaviour, use the 'Set-Once' key instead of 'Forced' for a domain
  • for "Once" behaviour, do this and set an mcx_data_timestamp alongside the mcx_preference_settings which is an NSDate

mcxToProfile provides the same functionality:

./mcxToProfile.py --plist /path/to/a/plist --identifier MyApplicationPrefs --manage Once

When using the --dsobject option, the --manage option is ignored, as this information is already defined in the MCX object pulled from the DS node.

Note: It's been documented that in OS X Yosemite, the behaviour for the "Often"-equivalent can lead to undesirable results when the profile is installed, so mcxToProfile now discourages the use of "Often." Thanks to Eric Holtam and Patrick Fergus for documentation of this issue.

Domains

Plist files used for application preferences are typically named by a reverse-domain format, and end in '.plist'. Currently, mcxToProfile will assume that the name portion of the plist file is the domain to be used by MCX. In other words, application preferences won't function if you use something like --plist my.orgs.office.2011.prefs.plist, because it will assemble the profile to use the domain 'my.orgs.office.2011.prefs'. If you have collections of default preferences you would like to manage for various applications and system settings, it's best to store these settings in the properly-named plist files.

ByHost preferences

A plist that contains one of the following patterns in its filename will automatically be configured as a ByHost preference:

  • com.org.app.ByHost.plist (the literal string '.ByHost')
  • com.org.app.001122aabbcc.plist (a 12-hex-digit MAC address)
  • com.org.app.01234567-89AB-CDEF-0123-456789ABCDEF.plist (a hardware UUID)

Payload Identifiers

The only option required besides --plist or --dsobject is --identifier. The identifier is crucial: it is what is defined in the toplevel payload's PayloadIdentifier key, and is what would be used to identify the profile to remove using profiles -R -p [identifier].

If you attempt to install a profile with the same identifier, it will update the existing profile instead of installing another profile.

Specify an identifier using either the --identifier or --identifier-from-profile options. If one is building an updated version of a profile, it's strongly recommended to use --identifier-from-profile to guarantee a consistent identifier and UUID.

Two profiles with unique toplevel PayloadIdentifiers but matching toplevel PayloadUUIDs will both install successfully. However, Profile Manager maintains consistent UUIDs, so we aim to do the same (although currently only at the top-level).

Other functionality

  • Multiple plists can be defined (with --plist or -p) and they will be combined as individual payloads within the Configuration Profile
  • A profile can be made "Always removable" using --removal-allowed or -r (default is "Never removable")
  • An organization name for the profile can be specified using --organization or -g
  • A specific output filename for the .mobileconfig file can be specified using --output or -o

To-do

  • add status output and a verbose mode
  • append '.mobileconfig' to filename if not already specified
  • potentially 'convert' known existing preference types (loginwindow, dock, etc.) into their native payload types, rather than as Custom Settings payloads. This may not be able to ever cover all cases as some key names have changed from 10.6.

Acknowledgments

Special thanks to Greg Neagle for some very useful intial feedback, and for adding the --dsimport functionality.

mcxtoprofile's People

Contributors

azet avatar gregneagle avatar jessepeterson avatar owenwater avatar rmanly avatar scriptingosx avatar timsutton avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

mcxtoprofile's Issues

enhancement req: convert pre-exported MCX policy

The -dsobject flag will retrieve MCX policy from a given object -- a nice feature.

However, if the policy you wish to convert to a profile already exists as a Mac OS X Property List file (say, because you've already exported it), a nice addition might be to allow for parsing of such a policy file without the need for an intermediary directory object.

Example:

./mcxToProfile.py --mcxread exported_mcx_policy.plist --identifier org.bar.foo

Why use FoundationPlist instead of plistlib?

The Foundation module necessitates installation of macadmins python3 which would require an Xcode.app installation which would require an iCloud account sign-in which I'd prefer to not use. What is the reason for not using the built-in plistlib module?

Possible to update Read me info

Possible to update the Read me info on the github mcxtoprofile page on how to get mcxtoprofile to run on macOS versions without python 2 that I think changed with macOS 12.3?

I believe you have to get python 3 from macadmins github going by a closed issue on here:
https://github.com/macadmins/python

And then edit the mcxtoprofile.py script and change the first line to
#!/usr/local/bin/managed_python3

Think that is correct, seems to be working anyway. Didn't see any exact steps anywhere saying how to fix it. Testing on macOS 13.0.1

Bullets in Key Names Causes Script Error

When importing MCX from a Directory Service (Apple OD), a key with a bullet in the name causes the script to fail:

admin:~ admin$ /Users/admin/Desktop/mcxToProfile-master/mcxToProfile.py --dsobject /LDAPv3/theodserver.ad.mdp.com/Computers/guest --identifier MyBasePreferences
Traceback (most recent call last):
File "/Users/admin/Desktop/mcxToProfile-master/mcxToProfile.py", line 450, in
main()
File "/Users/admin/Desktop/mcxToProfile-master/mcxToProfile.py", line 441, in main
mcx_data = getMCXData(options.dsobject)
File "/Users/admin/Desktop/mcxToProfile-master/mcxToProfile.py", line 304, in getMCXData
mcx_item_data = readPlistFromString(str(mcx_item))
UnicodeEncodeError: 'ascii' codec can't encode character u'\u2022' in position 462: ordinal not in range(128)

The key in question is an old set of keys under the com.apple.internetconfig domain from years past:

http://pastie.org/8153682

Deleting the domain allows the script to work normally.

Script fails on macOS 13.2

Looking through other issues, guessing this isn't new per se. Looks like this all began as a Python v2 script that's been brought to v3 but still tied to some older modules.

For reference my system:

  • 2019 27" iMac with Core i5 and 32GB RAM
  • macOS 13.2
  • Python.org's Python 3.11.2
  • Command Line Tools for Xcode 14.2

Did a git clone of repo.
First attempt to run script:

% ./mcxToProfile.py 
zsh: ./mcxToProfile.py: bad interpreter: /usr/bin/python: no such file or directory

Looking at file, I see top line shows #!/usr/bin/python. Yeah, that's not gonna work. Modified it to #!/usr/bin/python3 and re-ran script. Now I get

 % ./mcxToProfile.py 
Traceback (most recent call last):
  File "/Users/frank/Desktop/mcxToProfile/./mcxToProfile.py", line 15, in <module>
    from Foundation import NSData, \
ModuleNotFoundError: No module named 'Foundation'

I did some digging and seems that the underbelly of this relies on something called PyObjC. I tried installing it after finding it on PyPi.org, but pip install pyobjc failed miserably.

Found the source code for that here: https://github.com/ronaldoussoren/pyobjc

So cloned it into the directory where I had this script. I setup a virtual environ using virtualenv venv followed by source venv/bin/activate, so I can sandbox this setup somewhat.

At that point I followed the instructions and tried to do python3 pyobjc/install.py but that failed due to not being able to import _install_tool. I moved down into ./pyobjc and re-ran it as python3 install.py, and THAT seemed to do the trick. Got lots of warnings/etc., but it spent the next 20+ minutes compiling. Sadly, that ended badly with

...
                                 ^
      1 error generated.
      error: command '/usr/bin/clang' failed with exit code 1
      [end of output]
  
  note: This error originates from a subprocess, and is likely not a problem with pip.
error: legacy-install-failure

× Encountered error while trying to install package.
╰─> pyobjc-framework-WebKit

note: This is an issue with the package mentioned above, not pip.
hint: See above for output from the failure.
Installing 'pyobjc-framework-WebKit' failed (status 1)
Cannot build one of the projects, bailing out

So still can't run this.

Anyway, so looks like this "Foundation" module isn't installed, nor can I get the bits going to do so.

If I had to guess, this script relies on features not found on stock macOS systems. Is that a fair assessment? If there are dependencies, might it not help to articulate them in the README.md file so users have a better chance of using this tool? It feels like this could do with a requirements.txt or similar file to let folks know what is expected.

I came here as I was dealing with a Munki issue and multiple references mentioned this particular tool. Sadly looks like it's not quite as simple to use as they made it sound.

-dsobject only returns payload for the first MCX preference domain

Performing an operation like...

./mcxToProfile.py --dsobject /LDAPv3/foo.bar.org/ComputerGroups/this_group --identifier org.bar.foo.this_group

Against an object with one or more MCX preference domains specified...

com.apple.loginwindow
com.apple.homeSync
com.apple.mcxMenuExtras
com.apple.MCX

Will produce a .mobileconfig with a single policy payload -- AFAICT just the first domain (maybe the last if it is reversing the order) that gets processed.

Exception when path contains unicode character

Hi Tim,
Thanks for your work, it's an awesome tool!

When the path contains a unicode character ("François") in my case, the script refuses to write the file:

[fti@Gramont Desktop]$ cd François\ CP/
[fti@Gramont François CP]$ ./mcx2profile.py --plist com.apple.security.firewall.plist --identifier com.apple.security.firewallTraceback (most recent call last):
  File "./mcx2profile.py", line 539, in <module>
    main()
  File "./mcx2profile.py", line 534, in main
    newPayload.finalizeAndSave(output_file)
  File "./mcx2profile.py", line 138, in finalizeAndSave
    writePlist(self.data, output_path)
  File "./mcx2profile.py", line 256, in writePlist
    "Failed to write plist data to %s" % filepath)
__main__.NSPropertyListWriteException: Failed to write plist data to /Users/fti/Desktop/François CP/com.apple.security.firewall.mobileconfig
[fti@Gramont François CP]$

Crash when importing Office2008 plist from DS

Experiencing a crash with mcxToProfile when trying to import my Office2008 MCX plist directly from directory services. Here's the output of the crash:
https://gist.github.com/nmcspadden/6033212

Here's the output of a dscl -read on the plist in question.
https://gist.github.com/nmcspadden/6033223

I do note it has a weird at the very beginning that shouldn't belong there. Even after deleting that key and restarting opendirectoryd, the crash still persists when running this command:

./mcxToProfile.py --dsobject /Local/MCX/computergroups/office2008 --indentifier Office2008

Feature Request: Specify custom PayloadType

macOS 10.13.2 beta 2 introduces a new MDM PayloadType to manage whitelisted KEXTs settings only thru UAMDM.

The new KEXT whitelist policy now has a PayloadType of com.apple.syspolicy.kernel-extension-policy instead of the default com.apple.ManagedClient.preferences. I'm sure there will be more PayloadTypes coming down the line as UAMDM seems to be the path for new security features so having an option to override the default Type would be handy in the future.

-Eric

Determining the identifier

Hi Guys,

I am trying to use mcxToProfile for the first time and it seems to make sense. I am having a tough time understanding the identifier component that is needed. For instance, I want to take the com.apple.dock.plist and set it once for a lab of Macs.

Using this I am getting an error saying: no such option --identifier

I guess I am really foggy about what is needed and how the identifier is determined and used.

Thank you, Mick

unable to combine multiple plists

Please can you provide an example

for example this fails and have tried multiple different syntax

./mcxToProfile.py org.tynsoe.geektool.prefpane.plist --plist org.tynsoe.geektool3.plist --plist --identifier GeekTool --manage Always
sh: Usage:: command not found

How can I get this to run on macos 12.4

Hi,
I used this app multiple times in the past to create mobileconfig files. I am not a macos or python expert. Now that my macbook has updated to macos 12, I cannot get this script to run. I assume it has to do with python 2 being removed in favor of python 3. I fixed the first issue with this script by changing the print options line to print(option...) but now I am getting this error
raceback (most recent call last):
File "./mcxToProfile.py", line 13, in
from Foundation import NSData,
ModuleNotFoundError: No module named 'Foundation'

pip3 and python help('modules') shows the package foundation is installed (not Foundation). I tried changing the code to foundation but it doesnt work either. I also tried using pyenv to run the script in python 2.7 but i can't seem to get that to work either. Any help is appreciated.
Thanks

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.