Where did managed preferences run off to?

Asnyder
Contributor III

I can see my managed preferences being targeted to the computers in their management tab but I can't find the preferences themselves anymore.

08a83e933862471ca681939c5c969119

2 ACCEPTED SOLUTIONS

Asnyder
Contributor III

Jamf support sent me a message as to how I could access what I need to so I can remove them.

View solution in original post

macbofh
New Contributor III

You can remove managed preferences using the API;

First go to your API page and use the GET /managedpreferenceprofiles button to list all your managed preferences. If you want to delete one of the preferences make a note of the ID and use the following command to remove this managed preference

for example: if you want to delete ID number 1

curl -k -u API_USERNAME:API_PASSWORD https://yourjamfserver.jamfcloud.com/JSSResource/managedpreferenceprofiles/id/1 -X Delete

View solution in original post

17 REPLIES 17

davidthornton
Community Manager
Community Manager

Hello @Asnyder

http://docs.jamf.com/10.0.0/jamf-pro/release-notes/Deprecations_and_Removals.html

Managed Preferences—Support for managed preferences has been removed. It is recommended that you use macOS configuration profiles to define settings and restrictions for computers and users.

Apple has been deprecating MCX (Managed Preferences) for some time now.

Asnyder
Contributor III

@david.thornton I understand the removal of it, but I can still see it being scoped to devices (I scope by department). I don't have any way to remove the scoping unless it's just a bug and it isn't actually scoping to machines anymore. So if I add devices I'm unsure if the preferences will still scope to any new devices or not.

Cornoir
Contributor II

Also be aware that config profiles are not 100% reliable. As an example make a com.apple.finder.plist that unselects the Show Icon Preview checkbox.
Placing it in the User Template will work 100% of the time in unselecting the Show Icon Preview, however if you use the exact same plist and convert it to a config profile the Show Icon Preview checkbox is selected everytime.
Not good for Apple to recommend (i.e., force) config files if they are not 100% reliable.
fcf78000990d4f17a8abc1ae9b2d2800

Asnyder
Contributor III

@Cornoir I use scripts for a lot of things but was hoping to move towards config profiles for simplicity and ease of use.

Asnyder
Contributor III

Jamf support sent me a message as to how I could access what I need to so I can remove them.

wayneb
New Contributor

That's great, but we have to ask on a case by case basis? Will contact them, Thanks

macbofh
New Contributor III

You can remove managed preferences using the API;

First go to your API page and use the GET /managedpreferenceprofiles button to list all your managed preferences. If you want to delete one of the preferences make a note of the ID and use the following command to remove this managed preference

for example: if you want to delete ID number 1

curl -k -u API_USERNAME:API_PASSWORD https://yourjamfserver.jamfcloud.com/JSSResource/managedpreferenceprofiles/id/1 -X Delete

Asnyder
Contributor III

@macbofh I didn't even think about using the api. Good call.

wakco
Contributor

Be careful to get the correct URL, I tried it @macbofh's way, and didn't get the address for our hosted JAMF Pro correct, make sure JSSResource is at the topmost level of the URL you are using to access your MDM instance.

mike_paul
Contributor III
Contributor III

FYI - MCX is a persistent thing and just deleting or un-scopping them them via the GUI or the API will not remove the settings from the computers that have installed them.

The only way to reverse settings applied via MCX is to modify the MCX payload and apply the opposite (set True to False or 1 to 0, etc) or change the "Level" from its existing setting; e.g. "User Level at Every Login" (often), "User Level at Next Login Only" (once), "User Level Enforced" (always), "Computer Level Enforced" (always w/ state_metadata saying System Level Enforced) to "Make this Preference Unmanaged" (unset).

Often, once, and always at the keys that would be shown via the API that would need to be changed to unset and the the computers in scope would need to apply those settings either via startup/login/logout management framework scripts or running 'jamf mcx' or 'jamf mcx -username $username' depending on if the settings are computer level or user level respectively.

Also, dont follow old instructions floating around for deleting MCX locally where it has you delete "/Library/Managed Preferences/" as that is SIP protected in 10.13 and prior to that, deleting the folder would wipe out Configuration Profile settings as thats where Config Profiles store the plists since its built off of MCX.

mike_paul
Contributor III
Contributor III

Here is a script that a coworker made that will modify all MCX payloads in your JSS via the API and turn all the enforced settings of Often, Once, and Always to Unset. Just deleting the MCX settings from the JSS will leave your computers with all the previous MCX settings and doesnt solve the problem.

Once this is done you will still have to have computers download those changes by running 'jamf mcx' and 'jamf mcx -username $username' for system and user level settings respectively. You may already have your management framework startup and login scripts set to enforce MCX so these commands would be ran at after a restart and login.

Save it as a .py and give it a go.

#!/usr/bin/python
# -*- coding: utf-8 -*-
####################################################################################################
#
# Copyright (c) 2017, JAMF Software, LLC.  All rights reserved.
#
#       Redistribution and use in source and binary forms, with or without
#       modification, are permitted provided that the following conditions are met:
#               * Redistributions of source code must retain the above copyright
#                 notice, this list of conditions and the following disclaimer.
#               * Redistributions in binary form must reproduce the above copyright
#                 notice, this list of conditions and the following disclaimer in the
#                 documentation and/or other materials provided with the distribution.
#               * Neither the name of the JAMF Software, LLC nor the
#                 names of its contributors may be used to endorse or promote products
#                 derived from this software without specific prior written permission.
#
#       THIS SOFTWARE IS PROVIDED BY JAMF SOFTWARE, LLC "AS IS" AND ANY
#       EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
#       WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
#       DISCLAIMED. IN NO EVENT SHALL JAMF SOFTWARE, LLC BE LIABLE FOR ANY
#       DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
#       (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
#       LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
#       ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
#       (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
#       SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
####################################################################################################
#
# SUPPORT FOR THIS PROGRAM
#
#       This program is distributed "as is" by JAMF Software, LLC.
#
####################################################################################################
#    
# DESCRIPTION
#    This script was designed to update all managed preference profiles, setting their
#    enforcement level to "unmanaged"
#
####################################################################################################
#
# HISTORY
#
#    Version: 1.0
#
#    - Created by Sam Fortuna on Dec. 6, 2017
#
#####################################################################################################
#
# DEFINE VARIABLES & READ IN PARAMETERS
#
#####################################################################################################
#
# HARDCODED VALUES SET HERE
#
jss_host = "" #Example: 127.0.0.1 if run on server
jss_port = 8443
jss_path = "" #Example: "jss" for a JSS at https://www.company.com:8443/jss
jss_username = ""
jss_password = ""

##DONT EDIT BELOW THIS LINE
import sys 
import json
import httplib
import base64
import urllib2
import string

##Computer Object Definition
class MCX:
    id = -1

##Check variable
def verifyVariable(name, value):
    if value == "":
        print "Error: Please specify a value for variable "" + name + """
        sys.exit(1)

## the main function.
def main():
    verifyVariable("jss_host",jss_host)
    verifyVariable("jss_port",jss_port)
    verifyVariable("jss_username",jss_username)
    verifyVariable("jss_password",jss_password)
    mcx=grabMCXIDs()
    updateMCX(mcx)

##Grab and parse the MCX and return them in an array.
def grabMCXIDs():
    mcx=[];
    ## parse the list
    for MCXListJSON in (getMCXListFromJSS()["managed_preference_profiles"]):
        m = MCX()
        m.id = MCXListJSON.get("id")
        mcx.append(m)  
    print "Found " + str(len(mcx)) + " MCX Profiles."
    return mcx

##Create a header for the request
def getAuthHeader(u,p):
    # Compute base64 representation of the authentication token.
    token = base64.b64encode('%s:%s' % (u,p))
    return "Basic %s" % token

##Download a list of all MCX from the JSS API
def getMCXListFromJSS():
    print "Getting MCX list from the JSS..."
    headers = {"Authorization":getAuthHeader(jss_username,jss_password),"Accept":"application/json"}
    try:
        conn = httplib.HTTPSConnection(jss_host,jss_port)
        conn.request("GET",jss_path + "/JSSResource/managedpreferenceprofiles",None,headers)
        data = conn.getresponse().read()
        conn.close()
        jsonData = json.loads(data)
        return jsonData
    except httplib.HTTPException as inst:
        print "Exception: %s" % inst
        sys.exit(1)
    except ValueError as inst:
        print "Exception decoding JSON: %s" % inst
        sys.exit(1)

##Loop to submit the updates for all MCX profiles, and track progress
def updateMCX(mcx):
    ##Parse through each device and submit the command to update inventory
    for index, profile in enumerate(mcx):
        percent = "%.2f" % (float(index) / float(len(mcx)) * 100)
        print str(percent) + "% Complete"
        submitDataToJSS(profile)
    print "100.00% Complete"

##Get data for individual MCX Profile
def submitDataToJSS(Profile):
    headers = {"Authorization":getAuthHeader(jss_username,jss_password),"Accept":"application/xml"}
    try:
        print "Setting MCX Profile ID %s to unmanaged" % Profile.id
        MCXdata = None
        conn = httplib.HTTPSConnection(jss_host,jss_port)
        conn.request("GET",jss_path + "/JSSResource/managedpreferenceprofiles/id/" + str(Profile.id),None,headers)
        MCXdata = conn.getresponse().read()
        conn.close()
        MCXdata = string.replace(MCXdata,"<string>always</string>","<string>unset</string>")
        MCXdata = string.replace(MCXdata,"<string>often</string>","<string>unset</string>")
        MCXdata = string.replace(MCXdata,"<string>once</string>","<string>unset</string>")
        ##print "Data: %s" % MCXdata
        conn.request("PUT",jss_path + "/JSSResource/managedpreferenceprofiles/id/" + str(Profile.id),None,headers)
        url = "https://" + str(jss_host) + ":" + str(jss_port) + str(jss_path) + "/JSSResource/managedpreferenceprofiles/id/" + str(Profile.id)
        opener = urllib2.build_opener(urllib2.HTTPHandler)
        request = urllib2.Request(url,MCXdata)
        request.add_header("Authorization", getAuthHeader(jss_username,jss_password))
        request.add_header('Content-Type', 'application/xml')
        request.get_method = lambda: 'PUT'
        opener.open(request)
    except httplib.HTTPException as inst:
        print "	Exception: %s" % inst
    except ValueError as inst:
        print "	Exception submitting PUT XML: %s" % inst
    except urllib2.HTTPError as inst:
        print "	Exception submitting PUT XML: %s" % inst
    except:
        print "	Unknown error submitting PUT XML."
## Code starts executing here. Just call main.
main()

gersteina1
New Contributor III

I fixed a type on the command, but it's not really doing what I had hoped. It might help someone get to where they need to...



Not sure if it's due to Jamf Pro version differences or what, but when I try to run a properly configured script, I get:

oitajg070822:2018-04-23-managed preferences gersteina1$ ./fixup.py 
Getting MCX list from the JSS...
Exception decoding JSON: No JSON object could be decoded

I was able to just play with the curl command and eventually stumbled on using:

curl -k -u USERNAME:'PASSWORD' https://JSS_URL/JSSResource/managedpreferenceprofiles/id/ID_NUM_TO_DELETE -H 'MCXdata = <string>unset</string>'

But if I can save someone else some time....

gersteina1
New Contributor III

I was wrong - my curl command had no effect. The python script isn't working either.

I'm a little lost in the API - if I wanted to change an existing MCX so I can undo it and then delete it, what's the best way to go about it?

leslie
Contributor II
Contributor II

@gersteina1 - what do you have set for jss_host, jss_port, and jss_path?
Should be something like the following unless you have a multi-context environment.

jss_host = "your.jamf.server" #Example: 127.0.0.1 if run on server
jss_port = 8443    # default port if locally hosted, 443 is default for jamfcloud hosted
jss_path = "https://your.jamf.server:8443"    # no trailing forward slash

gersteina1
New Contributor III

@leslie I had "https://" in the jss_host, updated that, and tried to re-run - and got this:

Getting MCX list from the JSS...
Found 27 MCX Profiles.
0.00% Complete
Setting MCX Profile ID 23 to unmanaged
    Unknown error submitting PUT XML.
3.70% Complete
Setting MCX Profile ID 26 to unmanaged
    Unknown error submitting PUT XML.
7.41% Complete
Setting MCX Profile ID 24 to unmanaged
    Unknown error submitting PUT XML.
11.11% Complete
...
Setting MCX Profile ID 27 to unmanaged
    Unknown error submitting PUT XML.
100.00% Complet

On the other hand, I had some great success with CocoaRestClient, so I'm going to wrap things up with that - and hopefully write it up so others can take advantage of my learning process.

doug_brown
New Contributor II

Just wanted to share, not sure if it was the difference in versioning or what but macbofh's command was throwing an error for me. I was able to delete the managed preference successfully by changing it to:

curl -XDELETE -u username:password https://yourinstance.jamfcloud.com/JSSResource/managedpreferenceprofiles/id/1 -H "accept: application/xml"

Thank you for this, worked like a charm to delete some legacy managed preferences I noticed were still getting pushed to computers. It's strange how the legacy API GUI allows you to do do all managedpreferenceprofiles commands except delete.