diff --git a/Jamf Pro/Scripts/jamf_Patcher.py b/Jamf Pro/Scripts/jamf_Patcher.py index a1c122c..75256da 100644 --- a/Jamf Pro/Scripts/jamf_Patcher.py +++ b/Jamf Pro/Scripts/jamf_Patcher.py @@ -1,13 +1,13 @@ #!/opt/ManagedFrameworks/Python.framework/Versions/Current/bin/python3 -################################################################################################### +#################################################################################################### # Script Name: jamf_Patcher.py # By: Zack Thompson / Created: 7/10/2019 -# Version: 1.1.0 / Updated: 9/20/2023 / By: ZT +# Version: 1.1.1 / Updated: 9/20/2023 / By: ZT # # Description: This script handles patching of applications with user notifications. # -################################################################################################### +#################################################################################################### import os import platform @@ -17,477 +17,477 @@ import subprocess import sys try: - import requests # Use requests if available + import requests # Use requests if available except ImportError: - from urllib import request as urllib # For Python 3 + from urllib import request as urllib # For Python 3 def run_utility(command, continue_on_error=True): - """A helper function for subprocess. - Args: - command (str): String containing the commands and - arguments that will be passed to a shell. - continue_on_error (bool): Whether to continue on error or not - Returns: - stdout: output of the command - """ + """A helper function for subprocess. + Args: + command (str): String containing the commands and + arguments that will be passed to a shell. + continue_on_error (bool): Whether to continue on error or not + Returns: + stdout: output of the command + """ - try: - return subprocess.check_output(command, shell=True) + try: + return subprocess.check_output(command, shell=True) - except subprocess.CalledProcessError as error: + except subprocess.CalledProcessError as error: - if continue_on_error: - return "continue" + if continue_on_error: + return "continue" - print(f"Error code: {error.returncode}\nError: {error}") - return "error" + print(f"Error code: {error.returncode}\nError: {error}") + return "error" def plist_reader(plist_file): - """A helper function to get the contents of a Property List file. - Args: - plist_file (str): A .plist file path to read in. - Returns: - stdout: Returns the contents of the plist file. - """ + """A helper function to get the contents of a Property List file. + Args: + plist_file (str): A .plist file path to read in. + Returns: + stdout: Returns the contents of the plist file. + """ - if os.path.exists(plist_file): - # print(f"Reading {plist_file}...") + if os.path.exists(plist_file): + # print(f"Reading {plist_file}...") - try: - plist_contents = plistlib.load(plist_file) - except Exception: - file_cmd = f"/usr/bin/file --mime-encoding {plist_file}" - file_response = run_utility(file_cmd) - file_type = file_response.split(": ")[1].strip() - # print(f"File Type: {file_type}") + try: + plist_contents = plistlib.load(plist_file) + except Exception: + file_cmd = f"/usr/bin/file --mime-encoding {plist_file}" + file_response = run_utility(file_cmd) + file_type = file_response.split(": ")[1].strip() + # print(f"File Type: {file_type}") - if file_type == "binary": - # print("Converting plist...") - plutil_cmd = f"/usr/bin/plutil -convert xml1 {plist_file}" - _ = run_utility(plutil_cmd) + if file_type == "binary": + # print("Converting plist...") + plutil_cmd = f"/usr/bin/plutil -convert xml1 {plist_file}" + _ = run_utility(plutil_cmd) - plist_contents = plistlib.load(plist_file) - else: - print("Something's terribly wrong here...") + plist_contents = plistlib.load(plist_file) + else: + print("Something's terribly wrong here...") - return plist_contents + return plist_contents def prompt_to_patch(**parameters): - """Uses Jamf Helper to prompt a user to patch a software title, - optionally allowing them to delay the patch. + """Uses Jamf Helper to prompt a user to patch a software title, + optionally allowing them to delay the patch. - Args: - parameters (kwargs): Key word arguments - """ + Args: + parameters (kwargs): Key word arguments + """ - # Prompt user to quit app. - prompt = f"""\ - '{parameters.get("jamf_helper")}' \ - -window_type '{parameters.get("window_type")}' \ - -title '{parameters.get("title")}' \ - -icon '{parameters.get("icon")}' \ - -heading '{parameters.get("heading")}' \ - -description '{parameters.get("description")}' \ - -button1 OK \ - -timeout 3600 \ - -countdown \ - -countdownPrompt 'If you wish to delay this patch, please make a selection in ' \ - -alignCountdown center \ - -lockHUD \ - -showDelayOptions ', 600, 3600, 86400' \ - """ + # Prompt user to quit app. + prompt = f"""\ + '{parameters.get("jamf_helper")}' \ + -window_type '{parameters.get("window_type")}' \ + -title '{parameters.get("title")}' \ + -icon '{parameters.get("icon")}' \ + -heading '{parameters.get("heading")}' \ + -description '{parameters.get("description")}' \ + -button1 OK \ + -timeout 3600 \ + -countdown \ + -countdownPrompt 'If you wish to delay this patch, please make a selection in ' \ + -alignCountdown center \ + -lockHUD \ + -showDelayOptions ', 600, 3600, 86400' \ + """ - selection = run_utility(prompt) - print(f"SELECTION: {selection}") + selection = run_utility(prompt) + print(f"SELECTION: {selection}") - if selection == "1": - print("User selected to patch now.") - kill_and_install(**parameters) + if selection == "1": + print("User selected to patch now.") + kill_and_install(**parameters) - elif selection[:-1] == "600": - print("DELAY: 600 seconds") - create_delay_daemon(delayTime=600, **parameters) + elif selection[:-1] == "600": + print("DELAY: 600 seconds") + create_delay_daemon(delayTime=600, **parameters) - elif selection[:-1] == "3600": - print("DELAY: 3600 seconds") - create_delay_daemon(delayTime=3600, **parameters) + elif selection[:-1] == "3600": + print("DELAY: 3600 seconds") + create_delay_daemon(delayTime=3600, **parameters) - elif selection[:-1] == "86400": - print("DELAY: 86400 seconds") - create_delay_daemon(delayTime=86400, **parameters) + elif selection[:-1] == "86400": + print("DELAY: 86400 seconds") + create_delay_daemon(delayTime=86400, **parameters) - elif selection == "243": - print("TIMED OUT: user did not make a selection") - kill_and_install(**parameters) + elif selection == "243": + print("TIMED OUT: user did not make a selection") + kill_and_install(**parameters) - else: - print("Unknown action was taken at prompt.") - kill_and_install(**parameters) + else: + print("Unknown action was taken at prompt.") + kill_and_install(**parameters) def kill_and_install(**parameters): - """Kills the application by PID, if running and then executes - the Jamf Pro Policy to update the application. + """Kills the application by PID, if running and then executes + the Jamf Pro Policy to update the application. - Args: - parameters (kwargs): Key word arguments - """ + Args: + parameters (kwargs): Key word arguments + """ - try: - print("Attempting to close app if it's running...") - # Get PID of the application - pid = int(parameters.get("status").split(" ")[0]) - print(f"Process ID: {pid}") - # Kill PID - os.kill(pid, signal.SIGTERM) #or signal.SIGKILL - except Exception: - print("Unable to terminate app, assuming it was manually closed...") + try: + print("Attempting to close app if it's running...") + # Get PID of the application + pid = int(parameters.get("status").split(" ")[0]) + print(f"Process ID: {pid}") + # Kill PID + os.kill(pid, signal.SIGTERM) #or signal.SIGKILL + except Exception: + print("Unable to terminate app, assuming it was manually closed...") - print("Performing install...") + print("Performing install...") - # Run Policy - run_utility(parameters.get("install_policy")) - # print("Test run, don't run policy!") + # Run Policy + run_utility(parameters.get("install_policy")) + # print("Test run, don't run policy!") - prompt = f"""\ - '{parameters.get("jamf_helper")}' \ - -window_type '{parameters.get("window_type")}' \ - -title '{parameters.get("title")}' \ - -icon '{parameters.get("icon")}' \ - -heading '{parameters.get("heading")}' \ - -description '{parameters.get("description_complete")}' \ - -button1 OK \ - -timeout 60 \ - -alignCountdown center \ - -lockHUD \ - """ + prompt = f"""\ + '{parameters.get("jamf_helper")}' \ + -window_type '{parameters.get("window_type")}' \ + -title '{parameters.get("title")}' \ + -icon '{parameters.get("icon")}' \ + -heading '{parameters.get("heading")}' \ + -description '{parameters.get("description_complete")}' \ + -button1 OK \ + -timeout 60 \ + -alignCountdown center \ + -lockHUD \ + """ - run_utility(prompt) + run_utility(prompt) def create_delay_daemon(**parameters): - """Creates a LaunchDaemon based on the user selected delay time - which will the call a "Delayed Patch" Policy in Jamf Pro. + """Creates a LaunchDaemon based on the user selected delay time + which will the call a "Delayed Patch" Policy in Jamf Pro. - Args: - parameters (kwargs): Key word arguments - """ + Args: + parameters (kwargs): Key word arguments + """ - application_name = parameters.get("application_name") - launch_daemon_label = parameters.get('launch_daemon_label') - launch_daemon_location = parameters.get("launch_daemon_location") - os_minor_version = parameters.get("os_minor_version") - patch_plist = parameters.get("patch_plist") + application_name = parameters.get("application_name") + launch_daemon_label = parameters.get('launch_daemon_label') + launch_daemon_location = parameters.get("launch_daemon_location") + os_minor_version = parameters.get("os_minor_version") + patch_plist = parameters.get("patch_plist") - # Configure for delay. - if os.path.exists(patch_plist): - patch_plist_contents = plist_reader(patch_plist) - patch_plist_contents.update( { application_name : "Delayed" } ) - else: - patch_plist_contents = { application_name : "Delayed" } + # Configure for delay. + if os.path.exists(patch_plist): + patch_plist_contents = plist_reader(patch_plist) + patch_plist_contents.update( { application_name : "Delayed" } ) + else: + patch_plist_contents = { application_name : "Delayed" } - plistlib.dump(patch_plist_contents, patch_plist) + plistlib.dump(patch_plist_contents, patch_plist) - print("Creating the Patcher LaunchDaemon...") + print("Creating the Patcher LaunchDaemon...") - launch_daemon_plist = { - "Label": "com.github.mlbz521.jamf.patcher", - "ProgramArguments": [ - "/usr/local/jamf/bin/jamf", - "policy", - "-id", - f"{parameters.get('patch_id')}", - ], - "StartInterval": parameters.get("delayTime"), - "AbandonProcessGroup": True, - } + launch_daemon_plist = { + "Label": "com.github.mlbz521.jamf.patcher", + "ProgramArguments": [ + "/usr/local/jamf/bin/jamf", + "policy", + "-id", + f"{parameters.get('patch_id')}", + ], + "StartInterval": parameters.get("delayTime"), + "AbandonProcessGroup": True, + } - plistlib.dump(launch_daemon_plist, launch_daemon_location) + plistlib.dump(launch_daemon_plist, launch_daemon_location) - if os.path.exists(launch_daemon_location): - # Start the LaunchDaemon - start_daemon(os_minor_version, launch_daemon_label, launch_daemon_location) + if os.path.exists(launch_daemon_location): + # Start the LaunchDaemon + start_daemon(os_minor_version, launch_daemon_label, launch_daemon_location) def clean_up(**parameters): - """Cleans up a configured delay for the application - and stops and deletes the delay LaunchDaemon. + """Cleans up a configured delay for the application + and stops and deletes the delay LaunchDaemon. - Args: - parameters (kwargs): Key word arguments - """ + Args: + parameters (kwargs): Key word arguments + """ - print("Performing cleanup...") + print("Performing cleanup...") - application_name = parameters.get("application_name") - launch_daemon_label = parameters.get('launch_daemon_label') - launch_daemon_location = parameters.get("launch_daemon_location") - os_minor_version = parameters.get("os_minor_version") - patch_plist = parameters.get("patch_plist") + application_name = parameters.get("application_name") + launch_daemon_label = parameters.get('launch_daemon_label') + launch_daemon_location = parameters.get("launch_daemon_location") + os_minor_version = parameters.get("os_minor_version") + patch_plist = parameters.get("patch_plist") - # Clean up patch_plist. - if os.path.exists(patch_plist): - patch_plist_contents = plist_reader(patch_plist) + # Clean up patch_plist. + if os.path.exists(patch_plist): + patch_plist_contents = plist_reader(patch_plist) - if patch_plist_contents.get(application_name): - patch_plist_contents.pop(application_name, None) - print(f"Removing previously delayed app: {application_name}") - plistlib.dump(patch_plist_contents, patch_plist) - else: - print(f"App not listed in patch_plist: {application_name}") + if patch_plist_contents.get(application_name): + patch_plist_contents.pop(application_name, None) + print(f"Removing previously delayed app: {application_name}") + plistlib.dump(patch_plist_contents, patch_plist) + else: + print(f"App not listed in patch_plist: {application_name}") - # Stop LaunchDaemon before deleting it - stop_daemon(os_minor_version, launch_daemon_label, launch_daemon_location) + # Stop LaunchDaemon before deleting it + stop_daemon(os_minor_version, launch_daemon_label, launch_daemon_location) - if os.path.exists(launch_daemon_location): - os.remove(launch_daemon_location) + if os.path.exists(launch_daemon_location): + os.remove(launch_daemon_location) def execute_launchctl(sub_cmd, service_target, exit_code_only=False): - """A helper function to run launchctl. + """A helper function to run launchctl. - Args: - sub_cmd (str): A launchctl subcommand (option) - service_target (str): A launchctl service target (parameter) - exit_code_only (bool, optional): Whether to report only success or failure. - Defaults to False. + Args: + sub_cmd (str): A launchctl subcommand (option) + service_target (str): A launchctl service target (parameter) + exit_code_only (bool, optional): Whether to report only success or failure. + Defaults to False. - Returns: - bool | str: Depending on `exit_code_only`, returns either a bool or - the output from launchctl - """ + Returns: + bool | str: Depending on `exit_code_only`, returns either a bool or + the output from launchctl + """ - launchctl_cmd = f"/bin/launchctl {sub_cmd} {service_target}" + launchctl_cmd = f"/bin/launchctl {sub_cmd} {service_target}" - if exit_code_only: - launchctl_cmd = f"{launchctl_cmd} > /dev/null 2>&1; echo $?" + if exit_code_only: + launchctl_cmd = f"{launchctl_cmd} > /dev/null 2>&1; echo $?" - return run_utility(launchctl_cmd) + return run_utility(launchctl_cmd) def is_daemon_running(os_minor_version, launch_daemon_label): - """Checks if the daemon is running. + """Checks if the daemon is running. - Args: - os_minor_version (int): Used to determines the proper launchctl - syntax based on OS Version of the device - launch_daemon_label (str): The LaunchDaemon's Label + Args: + os_minor_version (int): Used to determines the proper launchctl + syntax based on OS Version of the device + launch_daemon_label (str): The LaunchDaemon's Label - Returns: - bool: True or False whether or not the LaunchDaemon is running - """ + Returns: + bool: True or False whether or not the LaunchDaemon is running + """ - if os_minor_version >= 11: - return execute_launchctl("print", f"system/{launch_daemon_label}", exit_code_only=True) + if os_minor_version >= 11: + return execute_launchctl("print", f"system/{launch_daemon_label}", exit_code_only=True) - elif os_minor_version <= 10: - return execute_launchctl("list", launch_daemon_label, exit_code_only=True) + elif os_minor_version <= 10: + return execute_launchctl("list", launch_daemon_label, exit_code_only=True) def start_daemon(os_minor_version, launch_daemon_label, launch_daemon_location): - """Starts a daemon, if it is running, it will be restarted in - case a change was made to the plist file. + """Starts a daemon, if it is running, it will be restarted in + case a change was made to the plist file. - Args: - os_minor_version (int): Used to determines the proper launchctl - syntax based on OS Version of the device - launch_daemon_label (str): The LaunchDaemon's Label - launch_daemon_location (str): The file patch to the LaunchDaemon + Args: + os_minor_version (int): Used to determines the proper launchctl + syntax based on OS Version of the device + launch_daemon_label (str): The LaunchDaemon's Label + launch_daemon_location (str): The file patch to the LaunchDaemon - """ + """ - restart_daemon(os_minor_version, launch_daemon_label, launch_daemon_location) + restart_daemon(os_minor_version, launch_daemon_label, launch_daemon_location) - print("Loading LaunchDaemon...") + print("Loading LaunchDaemon...") - if os_minor_version >= 11: - execute_launchctl("bootstrap", f"system {launch_daemon_location}") - execute_launchctl("enable", f"system/{launch_daemon_label}") + if os_minor_version >= 11: + execute_launchctl("bootstrap", f"system {launch_daemon_location}") + execute_launchctl("enable", f"system/{launch_daemon_label}") - elif os_minor_version <= 10: - execute_launchctl("load", launch_daemon_location) + elif os_minor_version <= 10: + execute_launchctl("load", launch_daemon_location) def restart_daemon(os_minor_version, launch_daemon_label, launch_daemon_location): - """Restarts a daemon if it is running. + """Restarts a daemon if it is running. - Args: - os_minor_version (int): Used to determines the proper launchctl - syntax based on OS Version of the device - launch_daemon_label (str): The LaunchDaemon's Label - launch_daemon_location (str): The file patch to the LaunchDaemon + Args: + os_minor_version (int): Used to determines the proper launchctl + syntax based on OS Version of the device + launch_daemon_label (str): The LaunchDaemon's Label + launch_daemon_location (str): The file patch to the LaunchDaemon - """ + """ - # Check if the LaunchDaemon is running. - exit_code = is_daemon_running(os_minor_version, launch_daemon_label) + # Check if the LaunchDaemon is running. + exit_code = is_daemon_running(os_minor_version, launch_daemon_label) - if int(exit_code) == 0: - print("LaunchDaemon is currently started; stopping now...") + if int(exit_code) == 0: + print("LaunchDaemon is currently started; stopping now...") - if os_minor_version >= 11: - execute_launchctl("bootout", f"system/{launch_daemon_label}") + if os_minor_version >= 11: + execute_launchctl("bootout", f"system/{launch_daemon_label}") - elif os_minor_version <= 10: - execute_launchctl("unload", launch_daemon_location) + elif os_minor_version <= 10: + execute_launchctl("unload", launch_daemon_location) def stop_daemon(os_minor_version, launch_daemon_label, launch_daemon_location): - """Stops a daemon. + """Stops a daemon. - Args: - os_minor_version (int): Used to determines the proper launchctl - syntax based on OS Version of the device - launch_daemon_label (str): The LaunchDaemon's Label - launch_daemon_location (str): The file patch to the LaunchDaemon + Args: + os_minor_version (int): Used to determines the proper launchctl + syntax based on OS Version of the device + launch_daemon_label (str): The LaunchDaemon's Label + launch_daemon_location (str): The file patch to the LaunchDaemon - """ + """ - # Check if the LaunchDaemon is running. - exit_code = is_daemon_running(os_minor_version, launch_daemon_label) + # Check if the LaunchDaemon is running. + exit_code = is_daemon_running(os_minor_version, launch_daemon_label) - if int(exit_code) == 0: - print("Stopping the LaunchDaemon...") + if int(exit_code) == 0: + print("Stopping the LaunchDaemon...") - if os_minor_version >= 11: - execute_launchctl("bootout", f"system/{launch_daemon_label}") - elif os_minor_version <= 10: - execute_launchctl("unload", launch_daemon_location) + if os_minor_version >= 11: + execute_launchctl("bootout", f"system/{launch_daemon_label}") + elif os_minor_version <= 10: + execute_launchctl("unload", launch_daemon_location) - else: - print("LaunchDaemon not running") + else: + print("LaunchDaemon not running") def main(): - print("***** jamf_Patcher process: START *****") + print("***** jamf_Patcher process: START *****") - ################################################## - # Define Script Parameters - print(f"All args: {sys.argv}") - department_name = sys.argv[4] # " Technology Office" - application_name = sys.argv[5] # "zoom.us" - icon_id = sys.argv[6] # "https://jps.server.com:8443/icon?id=49167" - patch_id = sys.argv[7] - policy_id = sys.argv[8] + ################################################## + # Define Script Parameters + print(f"All args: {sys.argv}") + department_name = sys.argv[4] # " Technology Office" + application_name = sys.argv[5] # "zoom.us" + icon_id = sys.argv[6] # "https://jps.server.com:8443/icon?id=49167" + patch_id = sys.argv[7] + policy_id = sys.argv[8] - ################################################## - # Define Variables - jamf_pro_server = plist_reader("/Library/Preferences/com.jamfsoftware.jamf.plist")["jss_url"] - patch_plist = "/Library/Preferences/com.github.mlbz521.jamf.patcher.plist" - jamf_helper = "/Library/Application Support/JAMF/bin/jamfHelper.app/Contents/MacOS/jamfHelper" - launch_daemon_label = f"com.github.mlbz521.jamf.patcher.{application_name}" - launch_daemon_location = f"/Library/LaunchDaemons/{launch_daemon_label}.plist" - os_minor_version = platform.mac_ver()[0].split(".")[1] - install_policy = f"/usr/local/jamf/bin/jamf policy -id {policy_id}" + ################################################## + # Define Variables + jamf_pro_server = plist_reader("/Library/Preferences/com.jamfsoftware.jamf.plist")["jss_url"] + patch_plist = "/Library/Preferences/com.github.mlbz521.jamf.patcher.plist" + jamf_helper = "/Library/Application Support/JAMF/bin/jamfHelper.app/Contents/MacOS/jamfHelper" + launch_daemon_label = f"com.github.mlbz521.jamf.patcher.{application_name}" + launch_daemon_location = f"/Library/LaunchDaemons/{launch_daemon_label}.plist" + os_minor_version = platform.mac_ver()[0].split(".")[1] + install_policy = f"/usr/local/jamf/bin/jamf policy -id {policy_id}" - ################################################## - # Define jamfHelper window values - title="Security Patch Notification" - window_type="hud" - description = f"{application_name} will be updated to patch a security vulnerability. \ - Please quit {application_name} to apply this update.\n\nIf you have questions, \ - please contact your deskside support group." - description_force = f"{application_name} will be updated to patch a security vulnerability. \ - Please quit {application_name} within the allotted time to apply this update.\n\n\ - If you have questions, please contact your deskside support group." - description_complete = f"{application_name} has been patched!\n\n." - local_icon_path = f"/private/tmp/{application_name}_icon.png" + ################################################## + # Define jamfHelper window values + title="Security Patch Notification" + window_type="hud" + description = f"{application_name} will be updated to patch a security vulnerability. \ + Please quit {application_name} to apply this update.\n\nIf you have questions, \ + please contact your deskside support group." + description_force = f"{application_name} will be updated to patch a security vulnerability. \ + Please quit {application_name} within the allotted time to apply this update.\n\n\ + If you have questions, please contact your deskside support group." + description_complete = f"{application_name} has been patched!\n\n." + local_icon_path = f"/private/tmp/{application_name}_icon.png" - if department_name: - heading = f"My Organization - {department_name}" - else: - heading = "My Organization" + if department_name: + heading = f"My Organization - {department_name}" + else: + heading = "My Organization" - ################################################## - # Bits staged... + ################################################## + # Bits staged... - process_check = f"/bin/ps -ax -o pid,command | \ - /usr/bin/grep -E '/Applications/{application_name}' | \ - /usr/bin/grep -v 'grep' 2> /dev/null" - status = run_utility(process_check) - print(f"APP STATUS: {status}") + process_check = f"/bin/ps -ax -o pid,command | \ + /usr/bin/grep -E '/Applications/{application_name}' | \ + /usr/bin/grep -v 'grep' 2> /dev/null" + status = run_utility(process_check) + print(f"APP STATUS: {status}") - parameters = { - "application_name": application_name, - "patch_plist": patch_plist, - "launch_daemon_label": launch_daemon_label, - "launch_daemon_location": launch_daemon_location, - "os_minor_version": os_minor_version, - "patch_id": patch_id, - "status": status, - "install_policy": install_policy - } + parameters = { + "application_name": application_name, + "patch_plist": patch_plist, + "launch_daemon_label": launch_daemon_label, + "launch_daemon_location": launch_daemon_location, + "os_minor_version": os_minor_version, + "patch_id": patch_id, + "status": status, + "install_policy": install_policy + } - jamf_helper_parameters = { - "jamf_helper": jamf_helper, - "window_type": window_type, - "title": title, - "heading": heading, - "description": description, - "description_complete": description_complete, - "icon": local_icon_path - } + jamf_helper_parameters = { + "jamf_helper": jamf_helper, + "window_type": window_type, + "title": title, + "heading": heading, + "description": description, + "description_complete": description_complete, + "icon": local_icon_path + } - if status == "continue": - print(f"{application_name} is not running, installing now...") - run_utility(install_policy) - # print("Test run, don't run policy!") + if status == "continue": + print(f"{application_name} is not running, installing now...") + run_utility(install_policy) + # print("Test run, don't run policy!") - clean_up(**parameters) + clean_up(**parameters) - else: - print(f"{application_name} is running...") + else: + print(f"{application_name} is running...") - # Download the icon from the JPS - icon_url = f"{jamf_pro_server}icon?id={icon_id}" + # Download the icon from the JPS + icon_url = f"{jamf_pro_server}icon?id={icon_id}" - try: - downloaded_icon = requests.get(icon_url) - open(local_icon_path, "wb").write(downloaded_icon.content) - except Exception: - sys.exc_clear() - urllib.urlretrieve(icon_url, filename=local_icon_path) + try: + downloaded_icon = requests.get(icon_url) + open(local_icon_path, "wb").write(downloaded_icon.content) + except Exception: + sys.exc_clear() + urllib.urlretrieve(icon_url, filename=local_icon_path) - if os.path.exists(patch_plist): - patch_plist_contents = plist_reader(patch_plist) + if os.path.exists(patch_plist): + patch_plist_contents = plist_reader(patch_plist) - # Delay Check - if patch_plist_contents.get(application_name): - print("STATUS: Patch has already been delayed; forcing upgrade.") + # Delay Check + if patch_plist_contents.get(application_name): + print("STATUS: Patch has already been delayed; forcing upgrade.") - # Prompt user with one last warning. - prompt = f"\ - '{jamf_helper}' \ - -window_type '{window_type}' \ - -title '{title}' \ - -icon '{local_icon_path}' \ - -heading '{heading}' \ - -description '{description_force}' \ - -button1 OK \ - -timeout 600 \ - -countdown \ - -countdownPrompt '{application_name} will be force closed in ' \ - -alignCountdown center \ - -lockHUD \ - > /dev/null 2>&1 \ - " + # Prompt user with one last warning. + prompt = f"\ + '{jamf_helper}' \ + -window_type '{window_type}' \ + -title '{title}' \ + -icon '{local_icon_path}' \ + -heading '{heading}' \ + -description '{description_force}' \ + -button1 OK \ + -timeout 600 \ + -countdown \ + -countdownPrompt '{application_name} will be force closed in ' \ + -alignCountdown center \ + -lockHUD \ + > /dev/null 2>&1 \ + " - run_utility(prompt) - kill_and_install(**parameters, **jamf_helper_parameters) - clean_up(patch_plist_contents=patch_plist_contents, **parameters) + run_utility(prompt) + kill_and_install(**parameters, **jamf_helper_parameters) + clean_up(patch_plist_contents=patch_plist_contents, **parameters) - else: - print("STATUS: Patch has not been delayed; prompting user.") - prompt_to_patch(**parameters, **jamf_helper_parameters) + else: + print("STATUS: Patch has not been delayed; prompting user.") + prompt_to_patch(**parameters, **jamf_helper_parameters) - else: - print("STATUS: Patch has not been delayed; prompting user.") - prompt_to_patch(**parameters, **jamf_helper_parameters) + else: + print("STATUS: Patch has not been delayed; prompting user.") + prompt_to_patch(**parameters, **jamf_helper_parameters) - print("***** jamf_Patcher process: SUCCESS *****") + print("***** jamf_Patcher process: SUCCESS *****") if __name__ == "__main__": - main() + main()