├── EA-MakeMeAdmin_ComplianceCheck.py ├── LICENSE.md ├── README.md ├── grantTempAdmin.py └── removeTempAdmin.py /EA-MakeMeAdmin_ComplianceCheck.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import os, plistlib, subprocess 4 | 5 | workingDir = '/usr/local/jamfps/' # working directory for script 6 | statusFile = 'MakeMeAdmin.Status.plist' # compliancy check plist location 7 | 8 | if os.path.exists(workingDir + statusFile): 9 | status = plistlib.readPlist(workingDir + statusFile).Status 10 | if status == 'Compliant': 11 | print '' + status + '' 12 | else: 13 | newAdm = plistlib.readPlist(workingDir + statusFile).newAdmins 14 | orgAdm = plistlib.readPlist(workingDir + statusFile).orgAdmin 15 | print '' + status + ' - ' + newAdm + ' - ' + orgAdm + '' 16 | else: 17 | print '' + 'Compliant' + '' -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | **Copyright (c) 2017, Jamf. All rights reserved.** 2 | 3 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 4 | * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 5 | * 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. 6 | * Neither the name of the Jamf nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 7 | 8 | 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. 9 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MakeMeAdminPy 2 | ###### Updated MakeMeAdmin workflow from Andrina Kelly's JNUC2013 presentation now converted to Python with violation checking and remediation if additional accounts get created during the users time as a temporary admin. 3 | ___ 4 | This script was designed to be used in a Self Service policy to allow users to become temporary administrators on their system for the time specifed as 'adminTimer'. Once the timer reaches zero, the users admin rights will be revoked and the system will be checked for any admin accounts that may have been created during the 'adminTimer'. If a user created an admin account it will be logged and reported back to Jamf Pro and then the admin rights will be revoked for those newly created accounts. We've also added the ability to enter your orgAdmin account(s) and verify those accounts are still valid and haven't been changed. 5 | 6 | Requirements: 7 | * Jamf Pro 8 | * Policy for enabling tempAdmin via Self Service 9 | * Policy to remove tempAdmin via custom trigger 10 | * Scripts: grantTempAdmin.py & removeTempAdmin.py 11 | * EA's: EA-MakeMeAdmin_ComplianceCheck.py 12 | 13 | Please reference https://github.com/brysontyrrell/EncryptedStrings for generating the encrypting password, salt, and passphrase strings. 14 | 15 | 16 | Written By: Joshua Roskos | Professional Services Engineer | Jamf 17 | 18 | Created On: June 20th, 2017 | Updated On: July 26th, 2017 19 | ___ 20 | 21 | ### Why is this needed? 22 | 23 | This workflow has long been used by many organizations, however one issue always remained..."What if the user creates another admin account while they have admin rights?" Well, fear no more, as this script will capture the current admin users before granting temporary admin rights and then after it revokes the rights, it will check again and compare to see if any new accounts were created. If so, the status will be written to a plist and can then be captured via the EA (Extension Attribute) which can then be scoped via a Smart Computer Group. 24 | 25 | 26 | ### Implementation 27 | 28 | **Step 1 - Configure the Scripts** 29 | 30 | When you open the scripts you will find some user variables that will need to be defined as specified below: 31 | * grantTempAdmin.py - Lines 72-79 32 | * removeTempAdmin.py - Lines 70-77 33 | * EA-MakeMeAdmin_ComplianceCheck.py - Lines 5-6 34 | 35 | **Step 2 - Upload the EA** 36 | 37 | * Display Name: MakeMeAdmin - Compliance Status 38 | * Data Type: String 39 | * Inventory Display: {Your Choice} 40 | * Input Type: Script 41 | * Script: {Paste Contents of EA-MakeMeAdmin_ComplianceCheck.py} 42 | 43 | **Step 3 - Configure the Smart Group** 44 | 45 | *Create a Smart Group named "MakeMeAdmin - Violations" and ensure "Send email notification on membership change" is enabled.* 46 | 47 | | And/Or | Criteria | Operator | Value | 48 | | :---: | :---: | :---: | :---: | 49 | | | MakeMeAdmin - Compliance Status | Like | Remediated | 50 | | Or | MakeMeAdmin - Compliance Status | Like | Violation | 51 | 52 | **Step 4 - Create your policies** 53 | 54 | * Policy: MakeMeAdmin 55 | * Payload - General 56 | * Display Name: *MakeMeAdmin* 57 | * Enabled: *Checked* 58 | * Category: {Your Choice} 59 | * Trigger(s): *None* 60 | * Execution Frequency: *Once every day (recommended)* 61 | * Payload - Scripts 62 | * Scripts: *grantTempAdmin.py* 63 | * Scope 64 | * *Configure to your requirements* 65 | * Self Service 66 | * *Configure to your requirements* 67 | * User Interaction 68 | * Complete Message: *You have been granted admin rights for the next 30 minutes.* 69 | * Policy: MakeMeAdmin - Remove Admin Rights 70 | * Payload - General 71 | * Display Name: *MakeMeAdmin - Remove Admin Rights* 72 | * Enabled: *Checked* 73 | * Category: {Your Choice} 74 | * Trigger(s): Custom w/ Event *adminremove* 75 | * Execution Frequency: *Ongoing* 76 | * Payload - Scripts 77 | * Scripts: *removeTempAdmin.py* 78 | * Parameter 4: *Your orgAdmin password encrypted* 79 | * Scope 80 | * Targets: *All Computers* 81 | * User Interaction 82 | * Complete Message: *Time up! Your admin rights have been revoked.* 83 | 84 | -------------------------------------------------------------------------------- /grantTempAdmin.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # 4 | # 5 | # Copyright (c) 2017 Jamf. All rights reserved. 6 | # 7 | # Redistribution and use in source and binary forms, with or without 8 | # modification, are permitted provided that the following conditions are met: 9 | # * Redistributions of source code must retain the above copyright 10 | # notice, this list of conditions and the following disclaimer. 11 | # * Redistributions in binary form must reproduce the above copyright 12 | # notice, this list of conditions and the following disclaimer in the 13 | # documentation and/or other materials provided with the distribution. 14 | # * Neither the name of the Jamf nor the names of its contributors may be 15 | # used to endorse or promote products derived from this software without 16 | # specific prior written permission. 17 | # 18 | # THIS SOFTWARE IS PROVIDED BY JAMF SOFTWARE, LLC "AS IS" AND ANY 19 | # EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 20 | # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | # DISCLAIMED. IN NO EVENT SHALL JAMF SOFTWARE, LLC BE LIABLE FOR ANY 22 | # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 23 | # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 24 | # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 25 | # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 27 | # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | # 29 | # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # 30 | 31 | # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # 32 | # 33 | # This script was modified from Andrina Kelly's version presented at JNUC2013 for allowing 34 | # a user to elevate their privelages to administrator once per day for 30 minutes. After 35 | # the 30 minutes if a user created a new admin account that account will have admin rights 36 | # also revoked. If the user changed the organization admin account password, that will also 37 | # be reset. 38 | # 39 | # To accomplish this the following will be performed: 40 | # - A launch daemon will be put in place in order to remove admin rights 41 | # - Log will be written to tempAdmin.log 42 | # - This policy in Jamf will be set to only be allowed once per day 43 | # 44 | # REQUIREMENTS: 45 | # - Jamf Pro 46 | # - Policy for enabling tempAdmin via Self Service 47 | # - Policy to remove tempAdmin via custom trigger 48 | # - tempAdmin.sh & removeTempAdmin.sh Scripts 49 | # - orgAdmin encrypted password specified in Jamf Pro parameter #4 50 | # 51 | # 52 | # Written by: Joshua Roskos | Professional Services Engineer | Jamf 53 | # 54 | # Created On: June 20th, 2017 55 | # Updated On: July 26th, 2017 56 | # 57 | # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # 58 | 59 | # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # 60 | # IMPORTS 61 | # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # 62 | 63 | import os, plistlib, pwd, grp, subprocess, sys 64 | from SystemConfiguration import SCDynamicStoreCopyConsoleUser 65 | from datetime import datetime 66 | 67 | 68 | # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # 69 | # VARIABLES 70 | # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # 71 | 72 | userName = (SCDynamicStoreCopyConsoleUser(None, None, None) or [None])[0] # get the logged in user's name 73 | workingDir = '/usr/local/jamfps/' # working directory for script 74 | launchdFile = 'com.jamfps.adminremove.plist' # launch daemon file name 75 | launchdLabel = launchdFile.replace('.plist', '') # launch daemon label 76 | plistFile = 'MakeMeAdmin.plist' # settings file name 77 | tempAdminLog = 'tempAdmin.log' # script log file 78 | adminTimer = 1800 # how long should they have admin rights for (in seconds) 79 | policyCustomTrigger = 'adminremove' # custom trigger specified for removeTempAdmin.py policy 80 | 81 | # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # 82 | # LAUNCH DAEMON 83 | # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # 84 | 85 | # place launchd plist to call JSS policy to remove admin rights. 86 | print 'Creating LaunchDaemon...' 87 | launchDaemon = { 'Label':launchdLabel, 88 | 'LaunchOnlyOnce':True, 89 | 'ProgramArguments':['/usr/local/jamf/bin/jamf', 'policy', '-trigger', policyCustomTrigger], 90 | 'StartInterval':adminTimer, 91 | 'UserName':'root', 92 | } 93 | plistlib.writePlist(launchDaemon, '/Library/LaunchDaemons/' + launchdFile) 94 | 95 | # set the permission on the file just made. 96 | userID = pwd.getpwnam("root").pw_uid 97 | groupID = grp.getgrnam("wheel").gr_gid 98 | os.chown('/Library/LaunchDaemons/' + launchdFile, userID, groupID) 99 | os.chmod('/Library/LaunchDaemons/' + launchdFile, 0644) 100 | 101 | # load the removal plist timer. 102 | print 'Loading LaunchDaemon...' 103 | subprocess.call(["launchctl", "load", "-w", '/Library/LaunchDaemons/' + launchdFile]) 104 | 105 | # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # 106 | # APPLICATION 107 | # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # 108 | 109 | # build log files 110 | if not os.path.exists(workingDir): 111 | os.makedirs(workingDir) 112 | 113 | # record user that will need to have admin rights removed 114 | # record current existing admins 115 | print 'Retrieving List of Current Admins...' 116 | currentAdmins = grp.getgrnam('admin').gr_mem 117 | print 'Updating Plist...' 118 | plist = { 'User2Remove':userName, 119 | 'CurrentAdminUsers':currentAdmins} 120 | plistlib.writePlist(plist, workingDir + plistFile) 121 | 122 | # give current logged user admin rights 123 | subprocess.call(["dseditgroup", "-o", "edit", "-a", userName, "-t", "user", "admin"]) 124 | 125 | # add log entry 126 | log = open(workingDir + tempAdminLog, "a+") 127 | log.write("{} - MakeMeAdmin Granted Admin Rights for {}\r\n".format(datetime.now(), userName)) 128 | log.close() 129 | 130 | print 'Granted Admin Right to ' + userName 131 | -------------------------------------------------------------------------------- /removeTempAdmin.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # 4 | # 5 | # Copyright (c) 2017 Jamf. All rights reserved. 6 | # 7 | # Redistribution and use in source and binary forms, with or without 8 | # modification, are permitted provided that the following conditions are met: 9 | # * Redistributions of source code must retain the above copyright 10 | # notice, this list of conditions and the following disclaimer. 11 | # * Redistributions in binary form must reproduce the above copyright 12 | # notice, this list of conditions and the following disclaimer in the 13 | # documentation and/or other materials provided with the distribution. 14 | # * Neither the name of the Jamf nor the names of its contributors may be 15 | # used to endorse or promote products derived from this software without 16 | # specific prior written permission. 17 | # 18 | # THIS SOFTWARE IS PROVIDED BY JAMF SOFTWARE, LLC "AS IS" AND ANY 19 | # EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 20 | # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | # DISCLAIMED. IN NO EVENT SHALL JAMF SOFTWARE, LLC BE LIABLE FOR ANY 22 | # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 23 | # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 24 | # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 25 | # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 27 | # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | # 29 | # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # 30 | 31 | # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # 32 | # 33 | # This script was modified from Andrina Kelly's version presented at JNUC2013 for allowing 34 | # a user to elevate their privelages to administrator once per day for 30 minutes. After 35 | # the 30 minutes if a user created a new admin account that account will have admin rights 36 | # also revoked. If the user changed the organization admin account password, that will also 37 | # be reset. 38 | # 39 | # To accomplish this the following will be performed: 40 | # - A launch daemon will be put in place in order to remove admin rights 41 | # - Log will be written to tempAdmin.log 42 | # - This policy in Jamf will be set to only be allowed once per day 43 | # 44 | # REQUIREMENTS: 45 | # - Jamf Pro 46 | # - Policy for enabling tempAdmin via Self Service 47 | # - Policy to remove tempAdmin via custom trigger (adminremove) 48 | # - tempAdmin.sh & removeTempAdmin.sh Scripts 49 | # - orgAdmin encrypted password specified in Jamf Pro parameter #4 50 | # 51 | # 52 | # Written by: Joshua Roskos | Professional Services Engineer | Jamf 53 | # 54 | # Created On: June 20th, 2017 55 | # Updated On: July 26th, 2017 56 | # 57 | # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # 58 | 59 | # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # 60 | # IMPORTS 61 | # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # 62 | 63 | import os, plistlib, grp, subprocess, time, sys 64 | from datetime import datetime 65 | 66 | # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # 67 | # VARIABLES 68 | # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # 69 | 70 | workingDir = '/usr/local/jamfps/' # working directory for script 71 | launchdFile = 'com.jamfps.adminremove.plist' # launch daemon file location 72 | plistFile = 'MakeMeAdmin.plist' # working plist location 73 | statusFile = 'MakeMeAdmin.Status.plist' # compliancy check plist location 74 | tempAdminLog = 'tempAdmin.log' # script log file 75 | orgAdmins = {'orgadmin': sys.argv[4]} # replace orgAdmin with your organizational admin / password passed via Jamf Pro Parameter #4 76 | salt = '34599b64b8d44a7e' # decrypt salt 77 | passphrase = 'c0495bebbed8ce26115d66a2' # decrypt passphrase 78 | 79 | # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # 80 | # FUNCTIONS 81 | # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # 82 | 83 | def DecryptString(inputString, salt, passphrase): 84 | '''Usage: >>> DecryptString("Encrypted String", "Salt", "Passphrase")''' 85 | p = subprocess.Popen(['/usr/bin/openssl', 'enc', '-aes256', '-d', '-a', '-A', '-S', salt, '-k', passphrase], stdin = subprocess.PIPE, stdout = subprocess.PIPE) 86 | return p.communicate(inputString)[0] 87 | 88 | # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # 89 | # APPLICATION 90 | # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # 91 | 92 | if os.path.exists(workingDir + plistFile): 93 | # remove user admin rights 94 | user2Remove = plistlib.readPlist(workingDir + plistFile).User2Remove 95 | subprocess.call(["dseditgroup", "-o", "edit", "-d", user2Remove, "-t", "user", "admin"]) 96 | # add log entry 97 | log = open(workingDir + tempAdminLog, "a+") 98 | log.write("{} - MakeMeAdmin Removed Admin Rights for {}\r\n".format(datetime.now(), user2Remove)) 99 | log.close() 100 | print 'Revoked Admin Rights for ' + user2Remove 101 | # compre prior to current admin lists 102 | print 'Checking for newly created admin accounts...' 103 | priorAdmins = plistlib.readPlist(workingDir + plistFile).CurrentAdminUsers 104 | currentAdmins = grp.getgrnam('admin').gr_mem 105 | newAdmins = set(currentAdmins).difference(set(priorAdmins)) 106 | newAdm = '' 107 | if not newAdmins: 108 | print ' No New Accounts Found!' 109 | # update compliancy plist 110 | status = { 'Status':'Compliant'} 111 | plistlib.writePlist(status, workingDir + statusFile) 112 | else: 113 | print ' New Admin Accounts Found!' 114 | log = open(workingDir + tempAdminLog, "a+") 115 | log.write("{} - MakeMeAdmin Discovered New Admin Accounts: {}\r\n".format(datetime.now(), list(newAdmins))) 116 | log.close() 117 | # update status plist 118 | status = { 'Status':'Remediated', 119 | 'newAdmins':'newAdmin Created', 120 | 'orgAdmin':'orgAdmin OK'} 121 | plistlib.writePlist(status, workingDir + statusFile) 122 | newAdm = plistlib.readPlist(workingDir + statusFile).newAdmins 123 | # loop through new admin accounts and remove admin rights 124 | print ' Removing Admin Rights for New Admin Accounts...' 125 | for user in newAdmins: 126 | subprocess.call(["dseditgroup", "-o", "edit", "-d", user, "-t", "user", "admin"]) 127 | log = open(workingDir + tempAdminLog, "a+") 128 | log.write("{} - MakeMeAdmin Removed Admin Rights for: {}\r\n".format(datetime.now(), user)) 129 | log.close() 130 | print ' Removed Admin Rights for ' + user 131 | time.sleep(1) 132 | # check if organization admin(s) are valid 133 | print 'Checking organizational admin passwords...' 134 | for admin, admpass in orgAdmins.iteritems(): 135 | # decrypt password 136 | admpassDecrypted = DecryptString(admpass, salt, passphrase) 137 | time.sleep(1) 138 | valid = subprocess.call(["dscl", "/Local/Default", "-authonly", admin, admpassDecrypted]) 139 | time.sleep(1) 140 | if valid == 0: 141 | log = open(workingDir + tempAdminLog, "a+") 142 | log.write("{} - orgAdmin Password is Valid \r\n".format(datetime.now())) 143 | log.close() 144 | print 'Password for orgAdmin: ' + admin + ' is valid!' 145 | else: 146 | log = open(workingDir + tempAdminLog, "a+") 147 | log.write("{} - orgAdmin Password is Invalid! \r\n".format(datetime.now())) 148 | log.close() 149 | result = subprocess.call(["dscl", ".", "passwd", "/Users/" + admin, admpassDecrypted]) 150 | time.sleep(3) 151 | print 'Password for orgAdmin: ' + admin + ' was invalid!' 152 | if result == 0: 153 | log = open(workingDir + tempAdminLog, "a+") 154 | log.write("{} - orgAdmin Password Successfully Reset! \r\n".format(datetime.now())) 155 | log.close() 156 | print 'Password Successfully Reset for ' + admin + "!" 157 | if not newAdm: 158 | # update status plist 159 | status = { 'Status':'Remediated', 160 | 'newAdmins':'No newAdmins', 161 | 'orgAdmin':'orgAdmin OK'} 162 | plistlib.writePlist(status, workingDir + statusFile) 163 | else: 164 | # update status plist 165 | status = { 'Status':'Remediated', 166 | 'newAdmins':'newAdmin Created', 167 | 'orgAdmin':'orgAdmin OK'} 168 | plistlib.writePlist(status, workingDir + statusFile) 169 | else: 170 | log = open(workingDir + tempAdminLog, "a+") 171 | log.write("{} - Error Resetting orgAdmin Password! \r\n".format(datetime.now())) 172 | log.close() 173 | print 'Error Resetting Password for ' + admin + "!" 174 | if not newAdm: 175 | # update status plist 176 | status = { 'Status':'Violation', 177 | 'newAdmins':'No newAdmins', 178 | 'orgAdmin':'orgAdmin ERROR'} 179 | plistlib.writePlist(status, workingDir + statusFile) 180 | else: 181 | # update status plist 182 | status = { 'Status':'Violation', 183 | 'newAdmins':'newAdmin Created', 184 | 'orgAdmin':'orgAdmin ERROR'} 185 | plistlib.writePlist(status, workingDir + statusFile) 186 | os.remove(workingDir + plistFile) 187 | 188 | if os.path.exists('/Library/LaunchDaemons/' + launchdFile): 189 | print 'Removing LaunchDaemon...' 190 | os.remove('/Library/LaunchDaemons/' + launchdFile) 191 | 192 | # Submit Jamf Pro Inventory 193 | subprocess.call(["/usr/local/jamf/bin/jamf", "recon"]) 194 | --------------------------------------------------------------------------------