def upload_mobileconfig(
    jamf_url,
    enc_creds,
    mobileconfig_name,
    description,
    category,
    mobileconfig_plist,
    computergroup_name,
    template_contents,
    profile_uuid,
    verbosity,
    obj_id=None,
):
    """Update Configuration Profile metadata."""

    # if we find an object ID we put, if not, we post
    if obj_id:
        url = "{}/JSSResource/osxconfigurationprofiles/id/{}".format(jamf_url, obj_id)
    else:
        url = "{}/JSSResource/osxconfigurationprofiles/id/0".format(jamf_url)

    # remove newlines, tabs, leading spaces, and XML-escape the payload
    mobileconfig_plist = mobileconfig_plist.decode("UTF-8")
    mobileconfig_list = mobileconfig_plist.rsplit("\n")
    mobileconfig_list = [x.strip("\t") for x in mobileconfig_list]
    mobileconfig_list = [x.strip(" ") for x in mobileconfig_list]
    mobileconfig = "".join(mobileconfig_list)

    # substitute user-assignable keys
    replaceable_keys = {
        "mobileconfig_name": mobileconfig_name,
        "description": description,
        "category": category,
        "payload": mobileconfig,
        "computergroup_name": computergroup_name,
        "uuid": "com.github.grahampugh.jamf-upload.{}".format(profile_uuid),
    }

    # substitute user-assignable keys (escaping for XML)
    template_contents = actions.substitute_assignable_keys(
        template_contents, replaceable_keys, verbosity, xml_escape=True
    )

    if verbosity > 2:
        print("Configuration Profile to be uploaded:")
        print(template_contents)

    print("Uploading Configuration Profile..")
    # write the template to temp file
    template_xml = curl.write_temp_file(template_contents)

    count = 0
    while True:
        count += 1
        if verbosity > 1:
            print("Configuration Profile upload attempt {}".format(count))
        method = "PUT" if obj_id else "POST"
        r = curl.request(method, url, enc_creds, verbosity, template_xml)
        # check HTTP response
        if curl.status_check(r, "Configuration Profile", mobileconfig_name) == "break":
            break
        if count > 5:
            print(
                "ERROR: Configuration Profile upload did not succeed after 5 attempts"
            )
            print("\nHTTP POST Response Code: {}".format(r.status_code))
            break
        sleep(10)

    if verbosity > 1:
        api_get.get_headers(r)

    return r
Example #2
0
def main():
    """Do the main thing here"""
    print("\n** Jamf policy upload script")
    print("** Creates a policy in Jamf Pro.")

    # parse the command line arguments
    args, cli_custom_keys = get_args()
    verbosity = args.verbose

    # grab values from a prefs file if supplied
    jamf_url, _, _, enc_creds = api_connect.get_creds_from_args(args)

    # import computer group from file and replace any keys in the XML
    with open(args.template, "r") as file:
        template_contents = file.read()

    # substitute user-assignable keys
    template_contents = actions.substitute_assignable_keys(
        template_contents, cli_custom_keys, verbosity)

    #  set a list of names either from the CLI args or from the template if no arg provided
    if args.names:
        names = args.names
    else:
        names = [get_policy_name(template_contents, verbosity)]

    # now process the list of names
    for policy_name in names:
        # where a policy name was supplied via CLI arg, replace this in the template
        if args.names:
            template_contents = replace_policy_name(policy_name,
                                                    template_contents,
                                                    verbosity)

        # check for existing policy
        print("\nChecking '{}' on {}".format(policy_name, jamf_url))
        obj_id = api_get.check_api_obj_id_from_name(jamf_url, "policy",
                                                    policy_name, enc_creds,
                                                    verbosity)
        if obj_id:
            print("Policy '{}' already exists: ID {}".format(
                policy_name, obj_id))
            if args.replace:
                r = upload_policy(
                    jamf_url,
                    enc_creds,
                    policy_name,
                    template_contents,
                    cli_custom_keys,
                    verbosity,
                    obj_id,
                )
            else:
                print(
                    "Not replacing existing policy. Use --replace to enforce.")
        else:
            print("Policy '{}' not found - will create".format(policy_name))
            r = upload_policy(
                jamf_url,
                enc_creds,
                policy_name,
                template_contents,
                cli_custom_keys,
                verbosity,
            )

        # now upload the icon to the policy if specified in the args
        if args.icon:
            # get the policy_id returned from the HTTP response
            try:
                policy_id = ElementTree.fromstring(r.text).findtext("id")
                upload_policy_icon(
                    jamf_url,
                    enc_creds,
                    policy_name,
                    args.icon,
                    args.replace_icon,
                    verbosity,
                    policy_id,
                )
            except UnboundLocalError:
                upload_policy_icon(
                    jamf_url,
                    enc_creds,
                    policy_name,
                    args.icon,
                    args.replace_icon,
                    verbosity,
                )

    print()
def main():
    """Do the main thing here"""
    print("\n** Jamf computer group upload script")
    print("** Creates a computer group in Jamf Pro.")

    # parse the command line arguments
    args, cli_custom_keys = get_args()
    verbosity = args.verbose

    # grab values from a prefs file if supplied
    jamf_url, _, _, _, enc_creds = api_connect.get_creds_from_args(args)

    # import computer group from file and replace any keys in the XML
    with open(args.template, "r") as file:
        template_contents = file.read()

    # substitute user-assignable keys
    # pylint is incorrectly stating that 'verbosity' has no value. So...
    # pylint: disable=no-value-for-parameter
    template_contents = actions.substitute_assignable_keys(template_contents,
                                                           cli_custom_keys,
                                                           verbosity,
                                                           xml_escape=True)

    #  set a list of names either from the CLI args or from the template if no arg provided
    if args.names:
        names = args.names
    else:
        names = [get_computergroup_name(template_contents, verbosity)]

    # now process the list of names
    for computergroup_name in names:
        # where a group name was supplied via CLI arg, replace this in the template
        if args.names:
            template_contents = replace_computergroup_name(
                computergroup_name, template_contents, verbosity)

        # check for existing group
        print("\nChecking '{}' on {}".format(computergroup_name, jamf_url))
        obj_id = api_get.get_api_obj_id_from_name(jamf_url, "computer_group",
                                                  computergroup_name,
                                                  enc_creds, verbosity)
        if obj_id:
            print("Computer Group '{}' already exists: ID {}".format(
                computergroup_name, obj_id))
            if args.replace:
                upload_computergroup(
                    jamf_url,
                    enc_creds,
                    computergroup_name,
                    template_contents,
                    cli_custom_keys,
                    verbosity,
                    obj_id,
                )
            else:
                print(
                    "Not replacing existing Computer Group. Use --replace to enforce."
                )
        else:
            print("Computer Group '{}' not found - will create".format(
                computergroup_name))
            upload_computergroup(
                jamf_url,
                enc_creds,
                computergroup_name,
                template_contents,
                cli_custom_keys,
                verbosity,
            )

    print()
def upload_script(
    jamf_url,
    script_name,
    script_path,
    category_id,
    category_name,
    script_info,
    script_notes,
    script_priority,
    script_parameter4,
    script_parameter5,
    script_parameter6,
    script_parameter7,
    script_parameter8,
    script_parameter9,
    script_parameter10,
    script_parameter11,
    script_os_requirements,
    verbosity,
    token,
    cli_custom_keys,
    obj_id=None,
):
    """Update script metadata."""

    # import script from file and replace any keys in the script
    # script_contents = Path(script_path).read_text()
    with open(script_path, "r") as file:
        script_contents = file.read()

    # substitute user-assignable keys
    # pylint is incorrectly stating that 'verbosity' has no value. So...
    # pylint: disable=no-value-for-parameter
    script_contents = actions.substitute_assignable_keys(
        script_contents, cli_custom_keys, verbosity)

    # priority has to be in upper case. Let's make it nice for the user
    if script_priority:
        script_priority = script_priority.upper()

    # build the object
    script_data = {
        "name": script_name,
        "info": script_info,
        "notes": script_notes,
        "priority": script_priority,
        "categoryId": category_id,
        "categoryName": category_name,
        "parameter4": script_parameter4,
        "parameter5": script_parameter5,
        "parameter6": script_parameter6,
        "parameter7": script_parameter7,
        "parameter8": script_parameter8,
        "parameter9": script_parameter9,
        "parameter10": script_parameter10,
        "parameter11": script_parameter11,
        "osRequirements": script_os_requirements,
        "scriptContents": script_contents,
    }
    # ideally we upload to the object ID but if we didn't get a good response
    # we fall back to the name
    if obj_id:
        url = "{}/uapi/v1/scripts/{}".format(jamf_url, obj_id)
        script_data["id"] = obj_id
    else:
        url = "{}/uapi/v1/scripts".format(jamf_url)

    if verbosity > 2:
        print("Script data:")
        print(script_data)

    print("Uploading script..")

    count = 0
    script_json = curl.write_json_file(script_data)

    while True:
        count += 1
        if verbosity > 1:
            print("Script upload attempt {}".format(count))
        method = "PUT" if obj_id else "POST"
        r = curl.request(method, url, token, verbosity, script_json)
        # check HTTP response
        if curl.status_check(r, "Script", script_name) == "break":
            break
        if count > 5:
            print("ERROR: Script upload did not succeed after 5 attempts")
            print("\nHTTP POST Response Code: {}".format(r.status_code))
            break
        sleep(10)

    if verbosity > 1:
        api_get.get_headers(r)

    # clean up temp files
    if os.path.exists(script_json):
        os.remove(script_json)
def upload_extatt(
    jamf_url,
    enc_creds,
    extatt_name,
    script_path,
    verbosity,
    cli_custom_keys,
    obj_id=None,
):
    """Update extension attribute metadata."""

    # import script from file and replace any keys in the script
    with open(script_path, "r") as file:
        script_contents = file.read()

    # substitute user-assignable keys
    script_contents = actions.substitute_assignable_keys(
        script_contents, cli_custom_keys, verbosity)

    #  XML-escape the script
    script_contents_escaped = escape(script_contents)

    # build the object
    extatt_data = (
        "<computer_extension_attribute>" +
        "<name>{}</name>".format(extatt_name) + "<enabled>true</enabled>" +
        "<description/>" + "<data_type>String</data_type>" + "<input_type>" +
        "  <type>script</type>" + "  <platform>Mac</platform>" +
        "  <script>{}</script>".format(script_contents_escaped) +
        "</input_type>" +
        "<inventory_display>Extension Attributes</inventory_display>" +
        "<recon_display>Extension Attributes</recon_display>" +
        "</computer_extension_attribute>")
    headers = {
        "authorization": "Basic {}".format(enc_creds),
        "Accept": "application/xml",
        "Content-type": "application/xml",
    }
    # if we find an object ID we put, if not, we post
    if obj_id:
        url = "{}/JSSResource/computerextensionattributes/id/{}".format(
            jamf_url, obj_id)
    else:
        url = "{}/JSSResource/computerextensionattributes/id/0".format(
            jamf_url)

    http = requests.Session()
    if verbosity > 2:
        http.hooks["response"] = [api_connect.logging_hook]
        print("Extension Attribute data:")
        print(extatt_data)

    print("Uploading Extension Attribute..")

    count = 0
    while True:
        count += 1
        if verbosity > 1:
            print("Extension Attribute upload attempt {}".format(count))
        if obj_id:
            r = http.put(url, headers=headers, data=extatt_data, timeout=60)
        else:
            r = http.post(url, headers=headers, data=extatt_data, timeout=60)
        if r.status_code == 200 or r.status_code == 201:
            print("Extension Attribute uploaded successfully")
            break
        if r.status_code == 409:
            print("ERROR: Extension Attribute upload failed due to a conflict")
            break
        if count > 5:
            print(
                "ERROR: Extension Attribute upload did not succeed after 5 attempts"
            )
            print("\nHTTP POST Response Code: {}".format(r.status_code))
            break
        sleep(10)

    if verbosity > 1:
        api_get.get_headers(r)

    return r
Example #6
0
def upload_ea(
    jamf_url, enc_creds, ea_name, script_path, verbosity, cli_custom_keys, obj_id=None,
):
    """Update extension attribute metadata."""

    # import script from file and replace any keys in the script
    with open(script_path, "r") as file:
        script_contents = file.read()

    # substitute user-assignable keys
    # pylint is incorrectly stating that 'verbosity' has no value. So...
    # pylint: disable=no-value-for-parameter
    script_contents = actions.substitute_assignable_keys(
        script_contents, cli_custom_keys, verbosity
    )

    # XML-escape the script
    script_contents_escaped = escape(script_contents)

    # build the object
    ea_data = (
        "<computer_extension_attribute>"
        + "<name>{}</name>".format(ea_name)
        + "<enabled>true</enabled>"
        + "<description/>"
        + "<data_type>String</data_type>"
        + "<input_type>"
        + "  <type>script</type>"
        + "  <platform>Mac</platform>"
        + "  <script>{}</script>".format(script_contents_escaped)
        + "</input_type>"
        + "<inventory_display>Extension Attributes</inventory_display>"
        + "<recon_display>Extension Attributes</recon_display>"
        + "</computer_extension_attribute>"
    )

    # if we find an object ID we put, if not, we post
    if obj_id:
        url = "{}/JSSResource/computerextensionattributes/id/{}".format(
            jamf_url, obj_id
        )
    else:
        url = "{}/JSSResource/computerextensionattributes/id/0".format(jamf_url)

    if verbosity > 2:
        print("Extension Attribute data:")
        print(ea_data)

    print("Uploading Extension Attribute..")

    #  write the template to temp file
    template_xml = curl.write_temp_file(ea_data)

    count = 0
    while True:
        count += 1
        if verbosity > 1:
            print("Extension Attribute upload attempt {}".format(count))
        method = "PUT" if obj_id else "POST"
        r = curl.request(method, url, enc_creds, verbosity, template_xml)
        # check HTTP response
        if curl.status_check(r, "Extension Attribute", ea_name) == "break":
            break
        if count > 5:
            print("ERROR: Extension Attribute upload did not succeed after 5 attempts")
            print("\nHTTP POST Response Code: {}".format(r.status_code))
            break
        sleep(10)

    if verbosity > 1:
        api_get.get_headers(r)

    # clean up temp files
    if os.path.exists(template_xml):
        os.remove(template_xml)
Example #7
0
def upload_script(
    jamf_url,
    script_name,
    script_path,
    category_id,
    category_name,
    script_info,
    script_notes,
    script_priority,
    script_parameter4,
    script_parameter5,
    script_parameter6,
    script_parameter7,
    script_parameter8,
    script_parameter9,
    script_parameter10,
    script_parameter11,
    script_os_requirements,
    verbosity,
    token,
    cli_custom_keys,
    obj_id=None,
):
    """Update script metadata."""

    # import script from file and replace any keys in the script
    # script_contents = Path(script_path).read_text()
    with open(script_path, "r") as file:
        script_contents = file.read()

    # substitute user-assignable keys
    script_contents = actions.substitute_assignable_keys(
        script_contents, cli_custom_keys, verbosity)

    # priority has to be in upper case. Let's make it nice for the user
    if script_priority:
        script_priority = script_priority.upper()

    # build the object
    script_data = {
        "name": script_name,
        "info": script_info,
        "notes": script_notes,
        "priority": script_priority,
        "categoryId": category_id,
        "categoryName": category_name,
        "parameter4": script_parameter4,
        "parameter5": script_parameter5,
        "parameter6": script_parameter6,
        "parameter7": script_parameter7,
        "parameter8": script_parameter8,
        "parameter9": script_parameter9,
        "parameter10": script_parameter10,
        "parameter11": script_parameter11,
        "osRequirements": script_os_requirements,
        "scriptContents": script_contents,
    }
    headers = {
        "authorization": "Bearer {}".format(token),
        "content-type": "application/json",
        "accept": "application/json",
    }
    # ideally we upload to the object ID but if we didn't get a good response
    # we fall back to the name
    if obj_id:
        url = "{}/uapi/v1/scripts/{}".format(jamf_url, obj_id)
        script_data["id"] = obj_id
    else:
        url = "{}/uapi/v1/scripts".format(jamf_url)

    http = requests.Session()
    if verbosity > 2:
        http.hooks["response"] = [api_connect.logging_hook]
        print("Script data:")
        print(script_data)

    print("Uploading script..")

    count = 0
    script_json = json.dumps(script_data)
    while True:
        count += 1
        if verbosity > 1:
            print("Script upload attempt {}".format(count))
        if obj_id:
            r = http.put(url, headers=headers, data=script_json, timeout=60)
        else:
            r = http.post(url, headers=headers, data=script_json, timeout=60)
        if r.status_code == 200 or r.status_code == 201:
            print("Script uploaded successfully")
            break
        if r.status_code == 409:
            print("ERROR: Script upload failed due to a conflict")
            break
        if count > 5:
            print("ERROR: Script upload did not succeed after 5 attempts")
            print("\nHTTP POST Response Code: {}".format(r.status_code))
            break
        sleep(10)

    if verbosity > 1:
        api_get.get_headers(r)

    return r